Email Subscribers & Newsletters - Version 4.6.6

Version Description

Download this release

Release Info

Developer Icegram
Plugin Icon 128x128 Email Subscribers & Newsletters
Version 4.6.6
Comparing to
See all releases

Code changes from version 4.6.5 to 4.6.6

Files changed (38) hide show
  1. email-subscribers.php +3 -3
  2. lite/admin/class-email-subscribers-admin.php +69 -0
  3. lite/admin/css/email-subscribers-admin.css +52 -0
  4. lite/admin/dist/main.css +1 -1
  5. lite/admin/dist/main.js +1 -1
  6. lite/admin/js/email-subscribers-admin.js +2 -2
  7. lite/admin/js/subscribers.js +280 -0
  8. lite/includes/class-email-subscribers.php +32 -3
  9. lite/includes/class-es-common.php +165 -91
  10. lite/includes/class-es-install.php +30 -2
  11. lite/includes/classes/class-es-campaigns-table.php +5 -3
  12. lite/includes/classes/class-es-contacts-table.php +27 -23
  13. lite/includes/classes/class-es-cron.php +83 -8
  14. lite/includes/classes/class-es-export-subscribers.php +4 -9
  15. lite/includes/classes/class-es-forms-table.php +16 -47
  16. lite/includes/classes/class-es-import-subscribers.php +710 -312
  17. lite/includes/classes/class-es-list-table.php +128 -0
  18. lite/includes/classes/class-es-lists-table.php +4 -6
  19. lite/includes/classes/class-es-queue.php +2 -2
  20. lite/includes/classes/class-es-reports-table.php +44 -45
  21. lite/includes/classes/class-ig-es-background-process-helper.php +3 -1
  22. lite/includes/classes/class-ig-es-wc-session-tracker.php +1 -0
  23. lite/includes/classes/ig-es-wc-cookies.php +2 -0
  24. lite/includes/db/class-es-db-actions.php +2 -2
  25. lite/includes/db/class-es-db-campaigns.php +22 -15
  26. lite/includes/db/class-es-db-contacts.php +43 -56
  27. lite/includes/db/class-es-db-lists-contacts.php +16 -21
  28. lite/includes/db/class-es-db-lists.php +1 -1
  29. lite/includes/db/class-es-db-mailing-queue.php +3 -6
  30. lite/includes/db/class-es-db-sending-queue.php +18 -25
  31. lite/includes/es-core-functions.php +0 -19
  32. lite/includes/feedback.php +1 -1
  33. lite/includes/feedback/class-ig-feedback.php +4 -4
  34. lite/includes/feedback/class-ig-tracker.php +6 -6
  35. lite/includes/upgrade/es-update-functions.php +24 -7
  36. lite/includes/workflows/class-es-workflows-table.php +5 -3
  37. lite/includes/workflows/db/class-es-db-workflows.php +2 -3
  38. readme.txt +7 -1
email-subscribers.php CHANGED
@@ -3,7 +3,7 @@
3
  * Plugin Name: Email Subscribers & Newsletters
4
  * Plugin URI: https://www.icegram.com/
5
  * Description: Add subscription forms on website, send HTML newsletters & automatically notify subscribers about new blog posts once it is published.
6
- * Version: 4.6.5
7
  * Author: Icegram
8
  * Author URI: https://www.icegram.com/
9
  * Requires at least: 3.9
@@ -67,7 +67,7 @@ if ( ! version_compare( PHP_VERSION, IG_ES_MIN_PHP_VER, '>=' ) ) {
67
  * @since 4.3.0
68
  */
69
  if ( ! defined( 'IG_ES_FEEDBACK_TRACKER_VERSION' ) ) {
70
- define( 'IG_ES_FEEDBACK_TRACKER_VERSION', '1.2.4' );
71
  }
72
 
73
 
@@ -177,7 +177,7 @@ if ( 'premium' === $ig_es_plan ) {
177
  /* ***************************** Initial Compatibility Work (End) ******************* */
178
 
179
  if ( ! defined( 'ES_PLUGIN_VERSION' ) ) {
180
- define( 'ES_PLUGIN_VERSION', '4.6.5' );
181
  }
182
 
183
  // Plugin Folder Path.
3
  * Plugin Name: Email Subscribers & Newsletters
4
  * Plugin URI: https://www.icegram.com/
5
  * Description: Add subscription forms on website, send HTML newsletters & automatically notify subscribers about new blog posts once it is published.
6
+ * Version: 4.6.6
7
  * Author: Icegram
8
  * Author URI: https://www.icegram.com/
9
  * Requires at least: 3.9
67
  * @since 4.3.0
68
  */
69
  if ( ! defined( 'IG_ES_FEEDBACK_TRACKER_VERSION' ) ) {
70
+ define( 'IG_ES_FEEDBACK_TRACKER_VERSION', '1.2.5' );
71
  }
72
 
73
 
177
  /* ***************************** Initial Compatibility Work (End) ******************* */
178
 
179
  if ( ! defined( 'ES_PLUGIN_VERSION' ) ) {
180
+ define( 'ES_PLUGIN_VERSION', '4.6.6' );
181
  }
182
 
183
  // Plugin Folder Path.
lite/admin/class-email-subscribers-admin.php CHANGED
@@ -94,6 +94,8 @@ class Email_Subscribers_Admin {
94
  // Disable Icegram server cron when plugin is deactivated.
95
  add_action( 'ig_es_plugin_deactivate', array( $this, 'disable_server_cron' ) );
96
 
 
 
97
  // Filter to hook custom validation for specific service request.
98
  add_filter( 'ig_es_service_request_custom_validation', array( $this, 'maybe_override_service_validation' ), 10, 2 );
99
 
@@ -189,6 +191,38 @@ class Email_Subscribers_Admin {
189
 
190
  // Load required html/js for dynamic WordPress editor.
191
  ig_es_wp_js_editor_admin_scripts();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
192
  }
193
 
194
  //timepicker
@@ -1110,4 +1144,39 @@ class Email_Subscribers_Admin {
1110
 
1111
  return $is_request_valid;
1112
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1113
  }
94
  // Disable Icegram server cron when plugin is deactivated.
95
  add_action( 'ig_es_plugin_deactivate', array( $this, 'disable_server_cron' ) );
96
 
97
+ //add_action( 'admin_init', array( $this, 'ig_es_send_additional_data_for_tracking' ) );
98
+
99
  // Filter to hook custom validation for specific service request.
100
  add_filter( 'ig_es_service_request_custom_validation', array( $this, 'maybe_override_service_validation' ), 10, 2 );
101
 
191
 
192
  // Load required html/js for dynamic WordPress editor.
193
  ig_es_wp_js_editor_admin_scripts();
194
+ } else if ( ES()->is_es_admin_screen( $page_prefix . '_page_es_subscribers' ) ) {
195
+ wp_enqueue_script( $this->email_subscribers . '-subscribers', plugin_dir_url( __FILE__ ) . 'js/subscribers.js', array( 'jquery', 'plupload-all' ), $this->version, false );
196
+
197
+ $subscribers_data = array(
198
+ 'security' => wp_create_nonce( 'ig-es-admin-ajax-nonce' ),
199
+ 'i18n' => array(
200
+ 'select_status' => esc_html__( 'Please select the status for the importing contacts!', 'email-subscribers' ),
201
+ 'select_emailcolumn' => esc_html__( 'Please select at least the column with the email addresses!', 'email-subscribers' ),
202
+ 'prepare_data' => esc_html__( 'Preparing Data', 'email-subscribers' ),
203
+ /* translators: %s: Upload progress */
204
+ 'uploading' => esc_html__( 'Uploading...%s', 'email-subscribers' ),
205
+ /* translators: %s: Import progress */
206
+ 'import_contacts' => esc_html__( 'Importing contacts...%s', 'email-subscribers' ),
207
+ /* translators: %s: Import failed svg icon */
208
+ 'import_failed' => esc_html__( 'Import failed! %s', 'email-subscribers' ),
209
+ 'no_windowclose' => esc_html__( 'Please do not close this window until it completes...', 'email-subscribers' ),
210
+ 'prepare_import' => esc_html__( 'Preparing Import...', 'email-subscribers' ),
211
+ /* translators: 1. Imported contacts count 2. Total contacts count 3. Failed to import count 4. Memory usage */
212
+ 'current_stats' => esc_html__( 'Currently %1$s of %2$s imported with %3$s errors. %4$s memory usage', 'email-subscribers' ),
213
+ /* translators: %s: Time left in minutes */
214
+ 'estimate_time' => esc_html__( 'Estimate time left: %s minutes', 'email-subscribers' ),
215
+ /* translators: %s: Next attempt delaly time */
216
+ 'continues_in' => esc_html__( 'Continues in %s seconds', 'email-subscribers' ),
217
+ 'error_importing' => esc_html__( 'There was a problem during importing contacts. Please check the error logs for more information!', 'email-subscribers' ),
218
+ 'confirm_import' => esc_html__( 'Do you really like to import these contacts?', 'email-subscribers' ),
219
+ /* translators: %s: Process complete svg icon */
220
+ 'import_complete' => esc_html__( 'Import complete! %s', 'email-subscribers' ),
221
+ 'onbeforeunloadimport' => esc_html__( 'You are currently importing subscribers! If you leave the page all pending subscribers don\'t get imported!', 'email-subscribers' ),
222
+ ),
223
+ );
224
+
225
+ wp_localize_script( $this->email_subscribers . '-subscribers', 'ig_es_subscribers_data', $subscribers_data );
226
  }
227
 
228
  //timepicker
1144
 
1145
  return $is_request_valid;
1146
  }
1147
+
1148
+ /**
1149
+ * Send additional data to Icegram Server for tracking purpose
1150
+ *
1151
+ * @param
1152
+ *
1153
+ * @since 4.6.6
1154
+ */
1155
+ /*public function ig_es_send_additional_data_for_tracking() {
1156
+
1157
+ // Send data only if user had opted for trial or user is on a premium plan.
1158
+ $is_plan_valid = ES()->is_trial() || ES()->is_premium();
1159
+
1160
+ // Check if the data is already sent once
1161
+ $can_send_data = get_option( 'ig_es_send_additional_data_for_tracking', 'yes' );
1162
+
1163
+ if ( $is_plan_valid && 'yes' === $can_send_data ) {
1164
+
1165
+ update_option( 'ig_es_send_additional_data_for_tracking', 'no' );
1166
+
1167
+ $url = 'https://api.icegram.com/';
1168
+ $data = array(
1169
+
1170
+ );
1171
+
1172
+ $options = array(
1173
+ 'timeout' => 50,
1174
+ 'method' => 'POST',
1175
+ 'body' => $data
1176
+ );
1177
+
1178
+ $response = wp_remote_post( $url, $options );
1179
+ }
1180
+
1181
+ }*/
1182
  }
lite/admin/css/email-subscribers-admin.css CHANGED
@@ -1781,4 +1781,56 @@ div.broadcast_side_content{
1781
  }
1782
  .es-mail-toggle-line{
1783
  height: 1.2rem !important;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1784
  }
1781
  }
1782
  .es-mail-toggle-line{
1783
  height: 1.2rem !important;
1784
+ }
1785
+
1786
+ /* Import Subscriber */
1787
+
1788
+ .step2 {
1789
+ display: none;
1790
+ overflow:auto !important;
1791
+ }
1792
+
1793
+ .step2-status, .step2-list,.progress.finished,.importing-progress.finished{
1794
+ display: none;
1795
+ }
1796
+
1797
+ .progress.paused span.bar,
1798
+ .progress.error span.bar,
1799
+ .importing-progress.paused span.bar,
1800
+ .importing-progress.error span.bar{
1801
+ background: #D54E21;
1802
+ opacity: 0.8;
1803
+ }
1804
+
1805
+ .progress span.bar:before,.importing-progress span.bar:before{
1806
+ content: '';
1807
+ display: block;
1808
+ top: -2px;
1809
+ bottom: -2px;
1810
+ width: 20%;
1811
+ min-width: 50px;
1812
+ left: 0%;
1813
+ position: absolute;
1814
+ background: -webkit-linear-gradient(left, rgba(255,255,255,0) 0%,rgba(255,255,255,0.2) 50%,rgba(255,255,255,0) 100%);
1815
+ background: linear-gradient(to right, rgba(255,255,255,0) 0%,rgba(255,255,255,0.2) 50%,rgba(255,255,255,0) 100%);
1816
+ -webkit-animation: progressindicator 0.75s ease infinite;
1817
+ animation: progressindicator 0.75s ease infinite;
1818
+ }
1819
+
1820
+ @-webkit-keyframes progressindicator {
1821
+ 0%{left:-20%;}
1822
+ 100%{left:120%;}
1823
+ }
1824
+
1825
+ @keyframes progressindicator {
1826
+ 0%{left:-20%;}
1827
+ 100%{left:120%;}
1828
+ }
1829
+
1830
+ /* Import Subscriber: end; */
1831
+
1832
+
1833
+ .tablenav {
1834
+ padding-top: 0px !important;
1835
+ clear: none !important;
1836
  }
lite/admin/dist/main.css CHANGED
@@ -1 +1 @@
1
- /*! normalize.css v8.0.1 | MIT License | github.com/necolas/normalize.css */html{line-height:1.15;-webkit-text-size-adjust:100%}body{margin:0}main{display:block}h1{font-size:2em;margin:.67em 0}hr{-webkit-box-sizing:content-box;box-sizing:content-box;height:0;overflow:visible}pre{font-family:monospace,monospace;font-size:1em}a{background-color:transparent}abbr[title]{border-bottom:none;text-decoration:underline;-webkit-text-decoration:underline dotted;text-decoration:underline dotted}b,strong{font-weight:bolder}code,kbd,samp{font-family:monospace,monospace;font-size:1em}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}img{border-style:none}button,input,optgroup,select,textarea{font-family:inherit;font-size:100%;line-height:1.15;margin:0}button,input{overflow:visible}button,select{text-transform:none}[type=button],[type=reset],[type=submit],button{-webkit-appearance:button}[type=button]::-moz-focus-inner,[type=reset]::-moz-focus-inner,[type=submit]::-moz-focus-inner,button::-moz-focus-inner{border-style:none;padding:0}[type=button]:-moz-focusring,[type=reset]:-moz-focusring,[type=submit]:-moz-focusring,button:-moz-focusring{outline:1px dotted ButtonText}fieldset{padding:.35em .75em .625em}legend{-webkit-box-sizing:border-box;box-sizing:border-box;color:inherit;display:table;max-width:100%;padding:0;white-space:normal}progress{vertical-align:baseline}textarea{overflow:auto}[type=checkbox],[type=radio]{-webkit-box-sizing:border-box;box-sizing:border-box;padding:0}[type=number]::-webkit-inner-spin-button,[type=number]::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}[type=search]::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}details{display:block}summary{display:list-item}[hidden],template{display:none}blockquote,dd,dl,figure,h1,h2,h3,h4,h5,h6,hr,p,pre{margin:0}button{background-color:transparent;background-image:none}button:focus{outline:1px dotted;outline:5px auto -webkit-focus-ring-color}fieldset,ol,ul{margin:0;padding:0}ol,ul{list-style:none}html{font-family:system-ui,-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica Neue,Arial,Noto Sans,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol,Noto Color Emoji;line-height:1.5}*,:after,:before{-webkit-box-sizing:border-box;box-sizing:border-box;border:0 solid #d2d6dc}hr{border-top-width:1px}img{border-style:solid}textarea{resize:vertical}input::-webkit-input-placeholder,textarea::-webkit-input-placeholder{color:#a0aec0}input::-moz-placeholder,textarea::-moz-placeholder{color:#a0aec0}input::-ms-input-placeholder,textarea::-ms-input-placeholder{color:#a0aec0}input::placeholder,textarea::placeholder{color:#a0aec0}[role=button],button{cursor:pointer}table{border-collapse:collapse}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;text-decoration:inherit}button,input,optgroup,select,textarea{padding:0;line-height:inherit;color:inherit}code,kbd,pre,samp{font-family:Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace}audio,canvas,embed,iframe,img,object,svg,video{display:block;vertical-align:middle}img,video{max-width:100%;height:auto}a{--text-opacity:1;color:#5850ec;color:rgba(88,80,236,var(--text-opacity))}img{border-width:0}.container{width:100%}@media (min-width:640px){.container{max-width:640px}}@media (min-width:768px){.container{max-width:768px}}@media (min-width:1024px){.container{max-width:1024px}}@media (min-width:1280px){.container{max-width:1280px}}.form-input{-webkit-appearance:none;-moz-appearance:none;appearance:none;background-color:#fff;border-color:#d2d6dc;border-width:1px;border-radius:.375rem;padding:.5rem .75rem;font-size:1rem;line-height:1.5}.form-input::-webkit-input-placeholder{color:#9fa6b2;opacity:1}.form-input::-moz-placeholder{color:#9fa6b2;opacity:1}.form-input::-ms-input-placeholder{color:#9fa6b2;opacity:1}.form-input::placeholder{color:#9fa6b2;opacity:1}.form-input:focus{outline:none;-webkit-box-shadow:0 0 0 3px rgba(164,202,254,.45);box-shadow:0 0 0 3px rgba(164,202,254,.45);border-color:#a4cafe}.form-textarea{-webkit-appearance:none;-moz-appearance:none;appearance:none;background-color:#fff;border-color:#d2d6dc;border-width:1px;border-radius:.375rem;padding:.5rem .75rem;font-size:1rem;line-height:1.5}.form-textarea::-webkit-input-placeholder{color:#9fa6b2;opacity:1}.form-textarea::-moz-placeholder{color:#9fa6b2;opacity:1}.form-textarea::-ms-input-placeholder{color:#9fa6b2;opacity:1}.form-textarea::placeholder{color:#9fa6b2;opacity:1}.form-textarea:focus{outline:none;-webkit-box-shadow:0 0 0 3px rgba(164,202,254,.45);box-shadow:0 0 0 3px rgba(164,202,254,.45);border-color:#a4cafe}.form-multiselect{-webkit-appearance:none;-moz-appearance:none;appearance:none;background-color:#fff;border-color:#d2d6dc;border-width:1px;border-radius:.375rem;padding:.5rem .75rem;font-size:1rem;line-height:1.5}.form-multiselect:focus{outline:none;-webkit-box-shadow:0 0 0 3px rgba(164,202,254,.45);box-shadow:0 0 0 3px rgba(164,202,254,.45);border-color:#a4cafe}.form-select{background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20' fill='none'%3E%3Cpath d='M7 7l3-3 3 3m0 6l-3 3-3-3' stroke='%239fa6b2' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");-webkit-appearance:none;-moz-appearance:none;appearance:none;-webkit-print-color-adjust:exact;color-adjust:exact;background-repeat:no-repeat;background-color:#fff;border-color:#d2d6dc;border-width:1px;border-radius:.375rem;padding:.5rem 2.5rem .5rem .75rem;font-size:1rem;line-height:1.5;background-position:right .5rem center;background-size:1.5em 1.5em}.form-select::-ms-expand{color:#9fa6b2;border:none}@media not print{.form-select::-ms-expand{display:none}}@media print and (-ms-high-contrast:active),print and (-ms-high-contrast:none){.form-select{padding-right:.75rem}}.form-select:focus{outline:none;-webkit-box-shadow:0 0 0 3px rgba(164,202,254,.45);box-shadow:0 0 0 3px rgba(164,202,254,.45);border-color:#a4cafe}.form-checkbox{-webkit-appearance:none;-moz-appearance:none;appearance:none;-webkit-print-color-adjust:exact;color-adjust:exact;display:inline-block;vertical-align:middle;background-origin:border-box;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;-ms-flex-negative:0;flex-shrink:0;height:1rem;width:1rem;color:#3f83f8;background-color:#fff;border-color:#d2d6dc;border-width:1px;border-radius:.25rem}.form-checkbox:checked{background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg viewBox='0 0 16 16' fill='%23fff' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M5.707 7.293a1 1 0 00-1.414 1.414l2 2a1 1 0 001.414 0l4-4a1 1 0 00-1.414-1.414L7 8.586 5.707 7.293z'/%3E%3C/svg%3E");border-color:transparent;background-color:currentColor;background-size:100% 100%;background-position:50%;background-repeat:no-repeat}@media not print{.form-checkbox::-ms-check{border-width:1px;color:transparent;background:inherit;border-color:inherit;border-radius:inherit}}.form-checkbox:focus{outline:none;-webkit-box-shadow:0 0 0 3px rgba(164,202,254,.45);box-shadow:0 0 0 3px rgba(164,202,254,.45);border-color:#a4cafe}.form-checkbox:checked:focus{border-color:transparent}.form-radio{-webkit-appearance:none;-moz-appearance:none;appearance:none;-webkit-print-color-adjust:exact;color-adjust:exact;display:inline-block;vertical-align:middle;background-origin:border-box;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;-ms-flex-negative:0;flex-shrink:0;border-radius:100%;height:1rem;width:1rem;color:#3f83f8;background-color:#fff;border-color:#d2d6dc;border-width:1px}.form-radio:checked{background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg viewBox='0 0 16 16' fill='%23fff' xmlns='http://www.w3.org/2000/svg'%3E%3Ccircle cx='8' cy='8' r='3'/%3E%3C/svg%3E");border-color:transparent;background-color:currentColor;background-size:100% 100%;background-position:50%;background-repeat:no-repeat}@media not print{.form-radio::-ms-check{border-width:1px;color:transparent;background:inherit;border-color:inherit;border-radius:inherit}}.form-radio:focus{outline:none;-webkit-box-shadow:0 0 0 3px rgba(164,202,254,.45);box-shadow:0 0 0 3px rgba(164,202,254,.45);border-color:#a4cafe}.form-radio:checked:focus{border-color:transparent}.ig-es-primary-button,.ig-es-send-queue-emails{border-color:transparent;padding:.5rem 1rem;background-color:#fff;background-color:rgba(255,255,255,var(--bg-opacity));color:#fff;color:rgba(255,255,255,var(--text-opacity));background-color:#5850ec;background-color:rgba(88,80,236,var(--bg-opacity))}.ig-es-primary-button,.ig-es-send-queue-emails,.ig-es-title-button,.wp-heading-inline+.page-title-action{display:-webkit-inline-box;display:-ms-inline-flexbox;display:inline-flex;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center;border-radius:.375rem;border-width:1px;font-size:.875rem;line-height:1.25rem;font-weight:500;--text-opacity:1;--bg-opacity:1;-webkit-transition-property:background-color,border-color,color,fill,stroke,opacity,-webkit-box-shadow,-webkit-transform;transition-property:background-color,border-color,color,fill,stroke,opacity,-webkit-box-shadow,-webkit-transform;transition-property:background-color,border-color,color,fill,stroke,opacity,box-shadow,transform;transition-property:background-color,border-color,color,fill,stroke,opacity,box-shadow,transform,-webkit-box-shadow,-webkit-transform;-webkit-transition-timing-function:cubic-bezier(.4,0,.2,1);transition-timing-function:cubic-bezier(.4,0,.2,1);-webkit-transition-duration:.15s;transition-duration:.15s}.ig-es-title-button,.wp-heading-inline+.page-title-action{--border-opacity:1;border-color:#d2d6dc;border-color:rgba(210,214,220,var(--border-opacity));color:#374151;color:rgba(55,65,81,var(--text-opacity));background-color:#fff;background-color:rgba(255,255,255,var(--bg-opacity));padding:.25rem .75rem}.wrap .wp-heading-inline+.page-title-action{margin-left:.5rem}.ig-es-title-button:hover,.wp-heading-inline+.page-title-action:hover{--bg-opacity:1;background-color:#f9fafb;background-color:rgba(249,250,251,var(--bg-opacity));--text-opacity:1;color:#374151;color:rgba(55,65,81,var(--text-opacity))}.ig-es-title-button:focus,.wp-heading-inline+.page-title-action:focus{outline:0;-webkit-box-shadow:0 0 0 3px rgba(118,169,250,.45);box-shadow:0 0 0 3px rgba(118,169,250,.45);--border-opacity:1;border-color:#a4cafe;border-color:rgba(164,202,254,var(--border-opacity))}.ig-es-primary-button:hover{--bg-opacity:1;background-color:#6875f5;background-color:rgba(104,117,245,var(--bg-opacity));--text-opacity:1;color:#fff;color:rgba(255,255,255,var(--text-opacity))}.ig-es-primary-button:focus{outline:0;-webkit-box-shadow:0 0 0 3px rgba(164,202,254,.45);box-shadow:0 0 0 3px rgba(164,202,254,.45)}.ig-es-imp-button{display:-webkit-inline-box!important;display:-ms-inline-flexbox!important;display:inline-flex!important;-webkit-box-pack:center!important;-ms-flex-pack:center!important;justify-content:center!important;border-radius:.375rem!important;border-width:1px!important;border-color:transparent!important;background-color:#fff!important;background-color:rgba(255,255,255,var(--bg-opacity))!important;font-size:.875rem!important;line-height:1.25rem!important;font-weight:500!important;background-color:#0e9f6e!important;background-color:rgba(14,159,110,var(--bg-opacity))!important;-webkit-transition-property:background-color,border-color,color,fill,stroke,opacity,-webkit-box-shadow,-webkit-transform!important;transition-property:background-color,border-color,color,fill,stroke,opacity,-webkit-box-shadow,-webkit-transform!important;transition-property:background-color,border-color,color,fill,stroke,opacity,box-shadow,transform!important;transition-property:background-color,border-color,color,fill,stroke,opacity,box-shadow,transform,-webkit-box-shadow,-webkit-transform!important;-webkit-transition-timing-function:cubic-bezier(.4,0,.2,1)!important;transition-timing-function:cubic-bezier(.4,0,.2,1)!important;-webkit-transition-duration:.15s!important;transition-duration:.15s!important}.ig-es-imp-button,.ig-es-imp-button:hover{--text-opacity:1!important;color:#fff!important;color:rgba(255,255,255,var(--text-opacity))!important;--bg-opacity:1!important}.ig-es-imp-button:hover{background-color:#31c48d!important;background-color:rgba(49,196,141,var(--bg-opacity))!important}.ig-es-imp-button:focus{outline:0!important;-webkit-box-shadow:0 0 0 3px rgba(132,225,188,.45)!important;box-shadow:0 0 0 3px rgba(132,225,188,.45)!important}.ig-es-link-button{display:-webkit-inline-box;display:-ms-inline-flexbox;display:inline-flex;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center;border-radius:.375rem;border-width:1px;border-color:transparent;background-color:#fff;background-color:rgba(255,255,255,var(--bg-opacity));font-size:.875rem;line-height:1.25rem;font-weight:500;background-color:#ff5a1f;background-color:rgba(255,90,31,var(--bg-opacity));-webkit-transition-property:background-color,border-color,color,fill,stroke,opacity,-webkit-box-shadow,-webkit-transform;transition-property:background-color,border-color,color,fill,stroke,opacity,-webkit-box-shadow,-webkit-transform;transition-property:background-color,border-color,color,fill,stroke,opacity,box-shadow,transform;transition-property:background-color,border-color,color,fill,stroke,opacity,box-shadow,transform,-webkit-box-shadow,-webkit-transform;-webkit-transition-timing-function:cubic-bezier(.4,0,.2,1);transition-timing-function:cubic-bezier(.4,0,.2,1);-webkit-transition-duration:.15s;transition-duration:.15s}.ig-es-link-button,.ig-es-link-button:hover{--text-opacity:1;color:#fff;color:rgba(255,255,255,var(--text-opacity));--bg-opacity:1}.ig-es-link-button:hover{background-color:#ff8a4c;background-color:rgba(255,138,76,var(--bg-opacity))}.ig-es-link-button:focus{outline:0;-webkit-box-shadow:0 0 0 3px rgba(253,186,140,.45);box-shadow:0 0 0 3px rgba(253,186,140,.45)}.ig-es-action.js-open .ig-es-action__header{--bg-opacity:1;background-color:#d2d6dc;background-color:rgba(210,214,220,var(--bg-opacity));--text-opacity:1;color:#374151;color:rgba(55,65,81,var(--text-opacity));--border-opacity:1;border-color:#d2d6dc;border-color:rgba(210,214,220,var(--border-opacity))}.form-input{--bg-opacity:1!important;background-color:#fff!important;background-color:rgba(255,255,255,var(--bg-opacity))!important;border-width:1px!important;border-radius:.375rem!important;-webkit-box-shadow:0 1px 2px 0 rgba(0,0,0,.05)!important;box-shadow:0 1px 2px 0 rgba(0,0,0,.05)!important;--border-opacity:1!important;border-color:#d2d6dc!important;border-color:rgba(210,214,220,var(--border-opacity))!important}.form-input:focus{outline:0!important;-webkit-box-shadow:0 0 0 3px rgba(164,202,254,.45)!important;box-shadow:0 0 0 3px rgba(164,202,254,.45)!important}.form-checkbox{content:url("data:image/svg+xml;charset=utf-8,%3Csvg viewBox='0 0 16 16' fill='%23fff' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M5.707 7.293a1 1 0 00-1.414 1.414l2 2a1 1 0 001.414 0l4-4a1 1 0 00-1.414-1.414L7 8.586 5.707 7.293z'/%3E%3C/svg%3E")}.form-radio{content:url("data:image/svg+xml;charset=utf-8,%3Csvg viewBox='0 0 16 16' fill='%23fff' xmlns='http://www.w3.org/2000/svg'%3E%3Ccircle cx='8' cy='8' r='3'/%3E%3C/svg%3E")}.form-checkbox:checked,.form-radio:checked{--text-opacity:1!important;color:#5850ec!important;color:rgba(88,80,236,var(--text-opacity))!important}.form-select{font-size:.875rem!important;--border-opacity:1!important;border-color:#9fa6b2!important;border-color:rgba(159,166,178,var(--border-opacity))!important;background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20' fill='none'%3E%3Cpath d='M7 7l3-3 3 3m0 6l-3 3-3-3' stroke='%239fa6b2' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E")!important}.form-select:focus,input[type=number]:focus{outline:0!important;-webkit-box-shadow:0 0 0 3px rgba(164,202,254,.45)!important;box-shadow:0 0 0 3px rgba(164,202,254,.45)!important;--border-opacity:1!important;border-color:#a4cafe!important;border-color:rgba(164,202,254,var(--border-opacity))!important}.es-check-toggle:checked~.es-mail-toggle-line{--bg-opacity:1;background-color:#5850ec;background-color:rgba(88,80,236,var(--bg-opacity))}.es-check-toggle:checked~.es-mail-toggle-dot{--transform-translate-x:0;--transform-translate-y:0;--transform-rotate:0;--transform-skew-x:0;--transform-skew-y:0;--transform-scale-x:1;--transform-scale-y:1;-webkit-transform:translateX(var(--transform-translate-x)) translateY(var(--transform-translate-y)) rotate(var(--transform-rotate)) skewX(var(--transform-skew-x)) skewY(var(--transform-skew-y)) scaleX(var(--transform-scale-x)) scaleY(var(--transform-scale-y));transform:translateX(var(--transform-translate-x)) translateY(var(--transform-translate-y)) rotate(var(--transform-rotate)) skewX(var(--transform-skew-x)) skewY(var(--transform-skew-y)) scaleX(var(--transform-scale-x)) scaleY(var(--transform-scale-y));--transform-translate-x:100%}.es-mail-toggle-line{width:2.25rem;height:1.25rem;background-color:#d2d6dc;background-color:rgba(210,214,220,var(--bg-opacity));-webkit-box-shadow:inset 0 2px 4px 0 rgba(0,0,0,.06);box-shadow:inset 0 2px 4px 0 rgba(0,0,0,.06)}.es-mail-toggle-dot,.es-mail-toggle-line{display:block;--bg-opacity:1;border-radius:9999px}.es-mail-toggle-dot{width:.875rem;height:.875rem;margin-left:.25rem;position:absolute;top:0;bottom:0;-webkit-transition-property:all;transition-property:all;-webkit-transition-duration:.3s;transition-duration:.3s;-webkit-transition-timing-function:cubic-bezier(.4,0,.2,1);transition-timing-function:cubic-bezier(.4,0,.2,1);background-color:#fff;background-color:rgba(255,255,255,var(--bg-opacity));-webkit-box-shadow:0 1px 3px 0 rgba(0,0,0,.1),0 1px 2px 0 rgba(0,0,0,.06);box-shadow:0 1px 3px 0 rgba(0,0,0,.1),0 1px 2px 0 rgba(0,0,0,.06)}.es-mail-toggle-dot:focus-within{-webkit-box-shadow:0 0 0 3px rgba(118,169,250,.45);box-shadow:0 0 0 3px rgba(118,169,250,.45)}[type=radio]:checked+.es-mailer-logo{-webkit-transition-property:all;transition-property:all;-webkit-transition-duration:.1s;transition-duration:.1s;-webkit-transition-timing-function:cubic-bezier(.4,0,.2,1);transition-timing-function:cubic-bezier(.4,0,.2,1);--transform-translate-x:0;--transform-translate-y:0;--transform-rotate:0;--transform-skew-x:0;--transform-skew-y:0;--transform-scale-x:1;--transform-scale-y:1;-webkit-transform:translateX(var(--transform-translate-x)) translateY(var(--transform-translate-y)) rotate(var(--transform-rotate)) skewX(var(--transform-skew-x)) skewY(var(--transform-skew-y)) scaleX(var(--transform-scale-x)) scaleY(var(--transform-scale-y));transform:translateX(var(--transform-translate-x)) translateY(var(--transform-translate-y)) rotate(var(--transform-rotate)) skewX(var(--transform-skew-x)) skewY(var(--transform-skew-y)) scaleX(var(--transform-scale-x)) scaleY(var(--transform-scale-y));--transform-scale-x:1.1;--transform-scale-y:1.1;-webkit-box-shadow:0 0 3px 1px #5a67d8;box-shadow:0 0 3px 1px #5a67d8}[type=radio]:checked+.es-mailer-logo:hover{border-width:1px;--border-opacity:1;border-color:#e5e7eb;border-color:rgba(229,231,235,var(--border-opacity))}.wp-core-ui .button,.wp-core-ui .button-secondary{--border-opacity:1;border-color:#5850ec;border-color:rgba(88,80,236,var(--border-opacity));color:#5850ec;color:rgba(88,80,236,var(--text-opacity))}.wp-core-ui .button,.wp-core-ui .button-primary,.wp-core-ui .button-secondary{font-size:.875rem;border-radius:.375rem;border-width:1px;line-height:1.25rem;font-weight:500;--text-opacity:1}.wp-core-ui .button-primary{--bg-opacity:1;background-color:#5850ec;background-color:rgba(88,80,236,var(--bg-opacity));color:#fff;color:rgba(255,255,255,var(--text-opacity));-webkit-transition-property:background-color,border-color,color,fill,stroke,opacity,-webkit-box-shadow,-webkit-transform;transition-property:background-color,border-color,color,fill,stroke,opacity,-webkit-box-shadow,-webkit-transform;transition-property:background-color,border-color,color,fill,stroke,opacity,box-shadow,transform;transition-property:background-color,border-color,color,fill,stroke,opacity,box-shadow,transform,-webkit-box-shadow,-webkit-transform;-webkit-transition-timing-function:cubic-bezier(.4,0,.2,1);transition-timing-function:cubic-bezier(.4,0,.2,1);-webkit-transition-duration:.15s;transition-duration:.15s}.wp-core-ui .button-primary:hover,.wp-core-ui .button:hover{--border-opacity:1;border-color:#5850ec;border-color:rgba(88,80,236,var(--border-opacity));--text-opacity:1;color:#6875f5;color:rgba(104,117,245,var(--text-opacity))}.wp-core-ui .search-box input[name=s],.wp-core-ui select{border-radius:.375rem}.wp-core-ui #bulk-action-selector-top,.wp-core-ui #doaction,.wp-core-ui #doaction2,.wp-core-ui #filter-by-date,.wp-core-ui #post-query-submit,.wp-core-ui #poststuff select,.wp-core-ui #search-submit{cursor:pointer;line-height:1.25rem;--text-opacity:1;color:#4b5563;color:rgba(75,85,99,var(--text-opacity));background-color:transparent;font-size:.875rem}.wp-core-ui #search-submit{margin-left:.375rem}.wp-core-ui #doaction2:hover .wp-core-ui #post-query-submit:hover,.wp-core-ui #doaction:hover,.wp-core-ui #search-submit:hover{--bg-opacity:1;background-color:#f4f5f7;background-color:rgba(244,245,247,var(--bg-opacity));--border-opacity:1;border-color:#6b7280;border-color:rgba(107,114,128,var(--border-opacity))}.wp-core-ui #doaction2:focus .wp-core-ui #post-query-submit:focus,.wp-core-ui #doaction:focus,.wp-core-ui #search-submit:focus{outline:0;-webkit-box-shadow:0 0 0 3px rgba(159,166,178,.45);box-shadow:0 0 0 3px rgba(159,166,178,.45)}.es-items-lists table.fixed,.post-type-es_template table.fixed{margin-top:1.5rem;margin-bottom:1rem;-webkit-box-shadow:0 1px 3px 0 rgba(0,0,0,.1),0 1px 2px 0 rgba(0,0,0,.06);box-shadow:0 1px 3px 0 rgba(0,0,0,.1),0 1px 2px 0 rgba(0,0,0,.06);border-radius:.5rem;overflow:hidden}.es-items-lists table.fixed tfoot td,.es-items-lists table.fixed tfoot th,.es-items-lists table.fixed thead td,.es-items-lists table.fixed thead th,.post-type-es_template table.fixed tfoot th,.post-type-es_template table.fixed thead td,.post-type-es_template table.fixed thead th{--bg-opacity:1;background-color:#f4f5f7;background-color:rgba(244,245,247,var(--bg-opacity));border-bottom-width:1px;--border-opacity:1;border-color:#e5e7eb;border-color:rgba(229,231,235,var(--border-opacity));--text-opacity:1;color:#6b7280;color:rgba(107,114,128,var(--text-opacity));font-weight:500;letter-spacing:.05em}.es-items-lists table.fixed tfoot th,.es-items-lists table.fixed thead th,.post-type-es_template table.fixed tfoot th,.post-type-es_template table.fixed thead th{padding-top:.5rem;padding-bottom:.5rem}.es-items-lists .widefat thead td input,.post-type-es_template .widefat thead td input{margin-right:1.5rem}.post-type-es_template .wrap{padding-top:1rem;font-family:system-ui,-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica Neue,Arial,Noto Sans,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol,Noto Color Emoji}.post-type-es_template .wrap>h1{padding-top:0;font-weight:600;--text-opacity:1;color:#374151;color:rgba(55,65,81,var(--text-opacity));line-height:2.25rem}.es-items-lists .striped>tbody tr,.post-type-es_template .striped>tbody tr{border-bottom-width:1px;--border-opacity:1;border-color:#e5e7eb;border-color:rgba(229,231,235,var(--border-opacity));padding-top:.5rem;padding-bottom:.5rem}.es-items-lists .striped>tbody>:nth-child(odd),.post-type-es_template .striped>tbody>:nth-child(odd){--bg-opacity:1;background-color:#fff;background-color:rgba(255,255,255,var(--bg-opacity))}.es_onboard_email{padding:.25rem .75rem!important}.es_reports_table_header{border-bottom-width:1px;--border-opacity:1;border-color:#e5e7eb;border-color:rgba(229,231,235,var(--border-opacity));--bg-opacity:1;background-color:#f4f5f7;background-color:rgba(244,245,247,var(--bg-opacity));text-align:left;font-size:.875rem;line-height:1rem;font-weight:500;--text-opacity:1;color:#6b7280;color:rgba(107,114,128,var(--text-opacity));letter-spacing:.05em}.space-y-1>:not(template)~:not(template){--space-y-reverse:0;margin-top:calc(0.25rem*(1 - var(--space-y-reverse)));margin-bottom:calc(0.25rem*var(--space-y-reverse))}.space-y-2>:not(template)~:not(template){--space-y-reverse:0;margin-top:calc(0.5rem*(1 - var(--space-y-reverse)));margin-bottom:calc(0.5rem*var(--space-y-reverse))}.space-y-3>:not(template)~:not(template){--space-y-reverse:0;margin-top:calc(0.75rem*(1 - var(--space-y-reverse)));margin-bottom:calc(0.75rem*var(--space-y-reverse))}.space-x-3>:not(template)~:not(template){--space-x-reverse:0;margin-right:calc(0.75rem*var(--space-x-reverse));margin-left:calc(0.75rem*(1 - var(--space-x-reverse)))}.space-y-4>:not(template)~:not(template){--space-y-reverse:0;margin-top:calc(1rem*(1 - var(--space-y-reverse)));margin-bottom:calc(1rem*var(--space-y-reverse))}.space-y-5>:not(template)~:not(template){--space-y-reverse:0;margin-top:calc(1.25rem*(1 - var(--space-y-reverse)));margin-bottom:calc(1.25rem*var(--space-y-reverse))}.bg-white{--bg-opacity:1;background-color:#fff;background-color:rgba(255,255,255,var(--bg-opacity))}.bg-gray-50{--bg-opacity:1;background-color:#f9fafb;background-color:rgba(249,250,251,var(--bg-opacity))}.bg-gray-100{--bg-opacity:1;background-color:#f4f5f7;background-color:rgba(244,245,247,var(--bg-opacity))}.bg-gray-200{--bg-opacity:1;background-color:#e5e7eb;background-color:rgba(229,231,235,var(--bg-opacity))}.bg-gray-300{--bg-opacity:1;background-color:#d2d6dc;background-color:rgba(210,214,220,var(--bg-opacity))}.bg-red-50{--bg-opacity:1;background-color:#fdf2f2;background-color:rgba(253,242,242,var(--bg-opacity))}.bg-red-100{--bg-opacity:1;background-color:#fde8e8;background-color:rgba(253,232,232,var(--bg-opacity))}.bg-yellow-100{--bg-opacity:1;background-color:#fdf6b2;background-color:rgba(253,246,178,var(--bg-opacity))}.bg-green-100{--bg-opacity:1;background-color:#def7ec;background-color:rgba(222,247,236,var(--bg-opacity))}.bg-green-300{--bg-opacity:1;background-color:#84e1bc;background-color:rgba(132,225,188,var(--bg-opacity))}.bg-green-600{--bg-opacity:1;background-color:#057a55;background-color:rgba(5,122,85,var(--bg-opacity))}.bg-teal-50{--bg-opacity:1;background-color:#edfafa;background-color:rgba(237,250,250,var(--bg-opacity))}.bg-blue-50{--bg-opacity:1;background-color:#ebf5ff;background-color:rgba(235,245,255,var(--bg-opacity))}.bg-blue-300{--bg-opacity:1;background-color:#a4cafe;background-color:rgba(164,202,254,var(--bg-opacity))}.bg-indigo-200{--bg-opacity:1;background-color:#cddbfe;background-color:rgba(205,219,254,var(--bg-opacity))}.bg-indigo-500{--bg-opacity:1;background-color:#6875f5;background-color:rgba(104,117,245,var(--bg-opacity))}.bg-indigo-600{--bg-opacity:1;background-color:#5850ec;background-color:rgba(88,80,236,var(--bg-opacity))}.bg-indigo-700{--bg-opacity:1;background-color:#5145cd;background-color:rgba(81,69,205,var(--bg-opacity))}.bg-indigo-800{--bg-opacity:1;background-color:#42389d;background-color:rgba(66,56,157,var(--bg-opacity))}.bg-pink-200{--bg-opacity:1;background-color:#fad1e8;background-color:rgba(250,209,232,var(--bg-opacity))}.group:focus .group-focus\:bg-gray-400,.group:hover .group-hover\:bg-gray-400{--bg-opacity:1;background-color:#9fa6b2;background-color:rgba(159,166,178,var(--bg-opacity))}.hover\:bg-gray-50:hover{--bg-opacity:1;background-color:#f9fafb;background-color:rgba(249,250,251,var(--bg-opacity))}.hover\:bg-gray-100:hover{--bg-opacity:1;background-color:#f4f5f7;background-color:rgba(244,245,247,var(--bg-opacity))}.hover\:bg-green-500:hover{--bg-opacity:1;background-color:#0e9f6e;background-color:rgba(14,159,110,var(--bg-opacity))}.hover\:bg-indigo-500:hover{--bg-opacity:1;background-color:#6875f5;background-color:rgba(104,117,245,var(--bg-opacity))}.hover\:bg-indigo-600:hover{--bg-opacity:1;background-color:#5850ec;background-color:rgba(88,80,236,var(--bg-opacity))}.focus\:bg-gray-50:focus{--bg-opacity:1;background-color:#f9fafb;background-color:rgba(249,250,251,var(--bg-opacity))}.focus\:bg-gray-100:focus{--bg-opacity:1;background-color:#f4f5f7;background-color:rgba(244,245,247,var(--bg-opacity))}.border-collapse{border-collapse:collapse}.border-transparent{border-color:transparent}.border-gray-100{--border-opacity:1;border-color:#f4f5f7;border-color:rgba(244,245,247,var(--border-opacity))}.border-gray-200{--border-opacity:1;border-color:#e5e7eb;border-color:rgba(229,231,235,var(--border-opacity))}.border-gray-300{--border-opacity:1;border-color:#d2d6dc;border-color:rgba(210,214,220,var(--border-opacity))}.border-gray-400{--border-opacity:1;border-color:#9fa6b2;border-color:rgba(159,166,178,var(--border-opacity))}.border-indigo-300{--border-opacity:1;border-color:#b4c6fc;border-color:rgba(180,198,252,var(--border-opacity))}.border-indigo-500{--border-opacity:1;border-color:#6875f5;border-color:rgba(104,117,245,var(--border-opacity))}.border-indigo-600{--border-opacity:1;border-color:#5850ec;border-color:rgba(88,80,236,var(--border-opacity))}.hover\:border-gray-200:hover{--border-opacity:1;border-color:#e5e7eb;border-color:rgba(229,231,235,var(--border-opacity))}.hover\:border-gray-500:hover{--border-opacity:1;border-color:#6b7280;border-color:rgba(107,114,128,var(--border-opacity))}.hover\:border-red-400:hover{--border-opacity:1;border-color:#f98080;border-color:rgba(249,128,128,var(--border-opacity))}.hover\:border-indigo-600:hover{--border-opacity:1;border-color:#5850ec;border-color:rgba(88,80,236,var(--border-opacity))}.focus\:border-blue-300:focus{--border-opacity:1;border-color:#a4cafe;border-color:rgba(164,202,254,var(--border-opacity))}.rounded{border-radius:.25rem}.rounded-md{border-radius:.375rem}.rounded-lg{border-radius:.5rem}.rounded-full{border-radius:9999px}.rounded-r-lg{border-top-right-radius:.5rem;border-bottom-right-radius:.5rem}.rounded-l-lg{border-top-left-radius:.5rem;border-bottom-left-radius:.5rem}.border-dashed{border-style:dashed}.border-dotted{border-style:dotted}.border-0{border-width:0}.border-2{border-width:2px}.border{border-width:1px}.border-t{border-top-width:1px}.border-r{border-right-width:1px}.border-b{border-bottom-width:1px}.cursor-default{cursor:default}.cursor-pointer{cursor:pointer}.cursor-not-allowed{cursor:not-allowed}.block{display:block}.inline-block{display:inline-block}.inline{display:inline}.flex{display:-webkit-box;display:-ms-flexbox;display:flex}.inline-flex{display:-webkit-inline-box;display:-ms-inline-flexbox;display:inline-flex}.table{display:table}.table-caption{display:table-caption}.table-cell{display:table-cell}.grid{display:grid}.contents{display:contents}.hidden{display:none}.flex-row{-webkit-box-orient:horizontal;-ms-flex-direction:row;flex-direction:row}.flex-col,.flex-row{-webkit-box-direction:normal}.flex-col{-webkit-box-orient:vertical;-ms-flex-direction:column;flex-direction:column}.flex-wrap{-ms-flex-wrap:wrap;flex-wrap:wrap}.items-start{-webkit-box-align:start;-ms-flex-align:start;align-items:flex-start}.items-center{-webkit-box-align:center;-ms-flex-align:center;align-items:center}.self-start{-ms-flex-item-align:start;align-self:flex-start}.justify-start{-webkit-box-pack:start;-ms-flex-pack:start;justify-content:flex-start}.justify-center{-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center}.justify-between{-webkit-box-pack:justify;-ms-flex-pack:justify;justify-content:space-between}.flex-1{-webkit-box-flex:1;-ms-flex:1 1 0%;flex:1 1 0%}.flex-auto{-webkit-box-flex:1;-ms-flex:1 1 auto;flex:1 1 auto}.flex-none{-webkit-box-flex:0;-ms-flex:none;flex:none}.flex-shrink-0{-ms-flex-negative:0;flex-shrink:0}.float-right{float:right}.float-left{float:left}.font-sans{font-family:system-ui,-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica Neue,Arial,Noto Sans,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol,Noto Color Emoji}.font-mono{font-family:Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace}.font-thin{font-weight:200}.font-normal{font-weight:400}.font-medium{font-weight:500}.font-semibold{font-weight:600}.font-bold{font-weight:700}.h-0{height:0}.h-2{height:.5rem}.h-3{height:.75rem}.h-4{height:1rem}.h-5{height:1.25rem}.h-6{height:1.5rem}.h-7{height:1.75rem}.h-8{height:2rem}.h-9{height:2.25rem}.h-10{height:2.5rem}.h-12{height:3rem}.h-15{height:3.75rem}.h-20{height:5rem}.h-48{height:12rem}.h-auto{height:auto}.h-1\.5{height:.375rem}.h-2\.5{height:.625rem}.h-full{height:100%}.text-xs{font-size:.75rem}.text-sm{font-size:.875rem}.text-base{font-size:1rem}.text-lg{font-size:1.125rem}.text-xl{font-size:1.25rem}.text-2xl{font-size:1.5rem}.text-3xl{font-size:1.875rem}.text-4xl{font-size:2.25rem}.leading-4{line-height:1rem}.leading-5{line-height:1.25rem}.leading-6{line-height:1.5rem}.leading-7{line-height:1.75rem}.leading-9{line-height:2.25rem}.leading-none{line-height:1}.leading-snug{line-height:1.375}.leading-normal{line-height:1.5}.leading-relaxed{line-height:1.625}.list-none{list-style-type:none}.list-disc{list-style-type:disc}.list-decimal{list-style-type:decimal}.m-4{margin:1rem}.my-0{margin-top:0;margin-bottom:0}.my-1{margin-top:.25rem;margin-bottom:.25rem}.mx-1{margin-left:.25rem;margin-right:.25rem}.my-2{margin-top:.5rem;margin-bottom:.5rem}.mx-2{margin-left:.5rem;margin-right:.5rem}.my-3{margin-top:.75rem;margin-bottom:.75rem}.my-4{margin-top:1rem;margin-bottom:1rem}.mx-4{margin-left:1rem;margin-right:1rem}.my-6{margin-top:1.5rem;margin-bottom:1.5rem}.mx-6{margin-left:1.5rem;margin-right:1.5rem}.my-8{margin-top:2rem;margin-bottom:2rem}.mx-8{margin-left:2rem;margin-right:2rem}.my-12{margin-top:3rem;margin-bottom:3rem}.mx-auto{margin-left:auto;margin-right:auto}.-my-4{margin-top:-1rem;margin-bottom:-1rem}.mt-0{margin-top:0}.mb-0{margin-bottom:0}.mt-1{margin-top:.25rem}.mr-1{margin-right:.25rem}.mb-1{margin-bottom:.25rem}.ml-1{margin-left:.25rem}.mt-2{margin-top:.5rem}.mr-2{margin-right:.5rem}.mb-2{margin-bottom:.5rem}.ml-2{margin-left:.5rem}.mt-3{margin-top:.75rem}.mr-3{margin-right:.75rem}.mb-3{margin-bottom:.75rem}.ml-3{margin-left:.75rem}.mt-4{margin-top:1rem}.mr-4{margin-right:1rem}.mb-4{margin-bottom:1rem}.ml-4{margin-left:1rem}.mt-5{margin-top:1.25rem}.ml-5{margin-left:1.25rem}.mt-6{margin-top:1.5rem}.mr-6{margin-right:1.5rem}.mb-6{margin-bottom:1.5rem}.ml-6{margin-left:1.5rem}.mt-7{margin-top:1.75rem}.mb-7{margin-bottom:1.75rem}.ml-7{margin-left:1.75rem}.mt-8{margin-top:2rem}.mr-8{margin-right:2rem}.ml-8{margin-left:2rem}.mr-10{margin-right:2.5rem}.mt-12{margin-top:3rem}.ml-12{margin-left:3rem}.ml-14{margin-left:3.5rem}.mt-16{margin-top:4rem}.mr-16{margin-right:4rem}.ml-16{margin-left:4rem}.mt-0\.5{margin-top:.125rem}.mt-1\.5{margin-top:.375rem}.mr-1\.5{margin-right:.375rem}.mt-2\.5{margin-top:.625rem}.-mt-1{margin-top:-.25rem}.-mr-1{margin-right:-.25rem}.-mb-1{margin-bottom:-.25rem}.-mb-2{margin-bottom:-.5rem}.-mt-3{margin-top:-.75rem}.-mt-5{margin-top:-1.25rem}.-ml-6{margin-left:-1.5rem}.-ml-8{margin-left:-2rem}.-mb-0\.5{margin-bottom:-.125rem}.-mt-1\.5{margin-top:-.375rem}.max-h-full{max-height:100%}.max-w-7xl{max-width:80rem}.max-w-full{max-width:100%}.min-h-screen{min-height:100vh}.min-w-0{min-width:0}.min-w-full{min-width:100%}.object-cover{-o-object-fit:cover;object-fit:cover}.opacity-0{opacity:0}.opacity-50{opacity:.5}.opacity-100{opacity:1}.focus\:outline-none:focus{outline:0}.overflow-hidden{overflow:hidden}.overflow-y-auto{overflow-y:auto}.overflow-x-hidden{overflow-x:hidden}.p-0{padding:0}.p-2{padding:.5rem}.p-3{padding:.75rem}.p-4{padding:1rem}.p-13{padding:3.25rem}.py-1{padding-top:.25rem;padding-bottom:.25rem}.px-1{padding-left:.25rem;padding-right:.25rem}.py-2{padding-top:.5rem;padding-bottom:.5rem}.px-2{padding-left:.5rem;padding-right:.5rem}.py-3{padding-top:.75rem;padding-bottom:.75rem}.px-3{padding-left:.75rem;padding-right:.75rem}.py-4{padding-top:1rem;padding-bottom:1rem}.px-4{padding-left:1rem;padding-right:1rem}.py-5{padding-top:1.25rem;padding-bottom:1.25rem}.px-5{padding-left:1.25rem;padding-right:1.25rem}.px-6{padding-left:1.5rem;padding-right:1.5rem}.py-8{padding-top:2rem;padding-bottom:2rem}.py-12{padding-top:3rem;padding-bottom:3rem}.px-12{padding-left:3rem;padding-right:3rem}.py-0\.5{padding-top:.125rem;padding-bottom:.125rem}.py-1\.5{padding-top:.375rem;padding-bottom:.375rem}.px-1\.5{padding-left:.375rem;padding-right:.375rem}.pt-1{padding-top:.25rem}.pr-1{padding-right:.25rem}.pb-1{padding-bottom:.25rem}.pl-1{padding-left:.25rem}.pt-2{padding-top:.5rem}.pr-2{padding-right:.5rem}.pb-2{padding-bottom:.5rem}.pl-2{padding-left:.5rem}.pt-3{padding-top:.75rem}.pr-3{padding-right:.75rem}.pb-3{padding-bottom:.75rem}.pl-3{padding-left:.75rem}.pt-4{padding-top:1rem}.pr-4{padding-right:1rem}.pb-4{padding-bottom:1rem}.pl-4{padding-left:1rem}.pt-5{padding-top:1.25rem}.pb-5{padding-bottom:1.25rem}.pl-5{padding-left:1.25rem}.pt-6{padding-top:1.5rem}.pr-6{padding-right:1.5rem}.pb-6{padding-bottom:1.5rem}.pl-6{padding-left:1.5rem}.pt-7{padding-top:1.75rem}.pt-8{padding-top:2rem}.pb-8{padding-bottom:2rem}.pl-8{padding-left:2rem}.pt-10{padding-top:2.5rem}.pl-10{padding-left:2.5rem}.pr-12{padding-right:3rem}.pb-12{padding-bottom:3rem}.pl-16{padding-left:4rem}.pt-0\.5{padding-top:.125rem}.pl-0\.5{padding-left:.125rem}.pt-1\.5{padding-top:.375rem}.pointer-events-none{pointer-events:none}.static{position:static}.fixed{position:fixed}.absolute{position:absolute}.relative{position:relative}.sticky{position:-webkit-sticky;position:sticky}.inset-0{right:0;left:0}.inset-0,.inset-y-0{top:0;bottom:0}.top-0{top:0}.right-0{right:0}.left-0{left:0}.bottom-2{bottom:.5rem}.top-8{top:2rem}.resize{resize:both}.shadow-xs{-webkit-box-shadow:0 0 0 1px rgba(0,0,0,.05);box-shadow:0 0 0 1px rgba(0,0,0,.05)}.shadow-sm{-webkit-box-shadow:0 1px 2px 0 rgba(0,0,0,.05);box-shadow:0 1px 2px 0 rgba(0,0,0,.05)}.shadow{-webkit-box-shadow:0 1px 3px 0 rgba(0,0,0,.1),0 1px 2px 0 rgba(0,0,0,.06);box-shadow:0 1px 3px 0 rgba(0,0,0,.1),0 1px 2px 0 rgba(0,0,0,.06)}.shadow-md{-webkit-box-shadow:0 4px 6px -1px rgba(0,0,0,.1),0 2px 4px -1px rgba(0,0,0,.06);box-shadow:0 4px 6px -1px rgba(0,0,0,.1),0 2px 4px -1px rgba(0,0,0,.06)}.shadow-lg{-webkit-box-shadow:0 10px 15px -3px rgba(0,0,0,.1),0 4px 6px -2px rgba(0,0,0,.05);box-shadow:0 10px 15px -3px rgba(0,0,0,.1),0 4px 6px -2px rgba(0,0,0,.05)}.shadow-xl{-webkit-box-shadow:0 20px 25px -5px rgba(0,0,0,.1),0 10px 10px -5px rgba(0,0,0,.04);box-shadow:0 20px 25px -5px rgba(0,0,0,.1),0 10px 10px -5px rgba(0,0,0,.04)}.shadow-inner{-webkit-box-shadow:inset 0 2px 4px 0 rgba(0,0,0,.06);box-shadow:inset 0 2px 4px 0 rgba(0,0,0,.06)}.hover\:shadow-md:hover{-webkit-box-shadow:0 4px 6px -1px rgba(0,0,0,.1),0 2px 4px -1px rgba(0,0,0,.06);box-shadow:0 4px 6px -1px rgba(0,0,0,.1),0 2px 4px -1px rgba(0,0,0,.06)}.focus\:shadow-lg:focus{-webkit-box-shadow:0 10px 15px -3px rgba(0,0,0,.1),0 4px 6px -2px rgba(0,0,0,.05);box-shadow:0 10px 15px -3px rgba(0,0,0,.1),0 4px 6px -2px rgba(0,0,0,.05)}.focus\:shadow-outline:focus{-webkit-box-shadow:0 0 0 3px rgba(118,169,250,.45);box-shadow:0 0 0 3px rgba(118,169,250,.45)}.focus\:shadow-outline-blue:focus{-webkit-box-shadow:0 0 0 3px rgba(164,202,254,.45);box-shadow:0 0 0 3px rgba(164,202,254,.45)}.focus\:shadow-outline-red:focus{-webkit-box-shadow:0 0 0 3px rgba(248,180,180,.45);box-shadow:0 0 0 3px rgba(248,180,180,.45)}.focus\:shadow-outline-indigo:focus{-webkit-box-shadow:0 0 0 3px rgba(180,198,252,.45);box-shadow:0 0 0 3px rgba(180,198,252,.45)}.fill-current{fill:currentColor}.table-fixed{table-layout:fixed}.text-left{text-align:left}.text-center{text-align:center}.text-right{text-align:right}.text-white{--text-opacity:1;color:#fff;color:rgba(255,255,255,var(--text-opacity))}.text-black{--text-opacity:1;color:#000;color:rgba(0,0,0,var(--text-opacity))}.text-gray-400{--text-opacity:1;color:#9fa6b2;color:rgba(159,166,178,var(--text-opacity))}.text-gray-500{--text-opacity:1;color:#6b7280;color:rgba(107,114,128,var(--text-opacity))}.text-gray-600{--text-opacity:1;color:#4b5563;color:rgba(75,85,99,var(--text-opacity))}.text-gray-700{--text-opacity:1;color:#374151;color:rgba(55,65,81,var(--text-opacity))}.text-gray-800{--text-opacity:1;color:#252f3f;color:rgba(37,47,63,var(--text-opacity))}.text-gray-900{--text-opacity:1;color:#161e2e;color:rgba(22,30,46,var(--text-opacity))}.text-red-400{--text-opacity:1;color:#f98080;color:rgba(249,128,128,var(--text-opacity))}.text-red-500{--text-opacity:1;color:#f05252;color:rgba(240,82,82,var(--text-opacity))}.text-red-600{--text-opacity:1;color:#e02424;color:rgba(224,36,36,var(--text-opacity))}.text-red-800{--text-opacity:1;color:#9b1c1c;color:rgba(155,28,28,var(--text-opacity))}.text-orange-400{--text-opacity:1;color:#ff8a4c;color:rgba(255,138,76,var(--text-opacity))}.text-orange-500{--text-opacity:1;color:#ff5a1f;color:rgba(255,90,31,var(--text-opacity))}.text-yellow-400{--text-opacity:1;color:#e3a008;color:rgba(227,160,8,var(--text-opacity))}.text-green-400{--text-opacity:1;color:#31c48d;color:rgba(49,196,141,var(--text-opacity))}.text-green-600{--text-opacity:1;color:#057a55;color:rgba(5,122,85,var(--text-opacity))}.text-green-800{--text-opacity:1;color:#03543f;color:rgba(3,84,63,var(--text-opacity))}.text-teal-400{--text-opacity:1;color:#16bdca;color:rgba(22,189,202,var(--text-opacity))}.text-teal-700{--text-opacity:1;color:#036672;color:rgba(3,102,114,var(--text-opacity))}.text-teal-800{--text-opacity:1;color:#05505c;color:rgba(5,80,92,var(--text-opacity))}.text-blue-400{--text-opacity:1;color:#76a9fa;color:rgba(118,169,250,var(--text-opacity))}.text-blue-500{--text-opacity:1;color:#3f83f8;color:rgba(63,131,248,var(--text-opacity))}.text-blue-700{--text-opacity:1;color:#1a56db;color:rgba(26,86,219,var(--text-opacity))}.text-blue-800{--text-opacity:1;color:#1e429f;color:rgba(30,66,159,var(--text-opacity))}.text-indigo-100{--text-opacity:1;color:#e5edff;color:rgba(229,237,255,var(--text-opacity))}.text-indigo-400{--text-opacity:1;color:#8da2fb;color:rgba(141,162,251,var(--text-opacity))}.text-indigo-500{--text-opacity:1;color:#6875f5;color:rgba(104,117,245,var(--text-opacity))}.text-indigo-600{--text-opacity:1;color:#5850ec;color:rgba(88,80,236,var(--text-opacity))}.text-indigo-700{--text-opacity:1;color:#5145cd;color:rgba(81,69,205,var(--text-opacity))}.text-indigo-800{--text-opacity:1;color:#42389d;color:rgba(66,56,157,var(--text-opacity))}.group:hover .group-hover\:text-gray-900{--text-opacity:1;color:#161e2e;color:rgba(22,30,46,var(--text-opacity))}.group:hover .group-hover\:text-indigo-800{--text-opacity:1;color:#42389d;color:rgba(66,56,157,var(--text-opacity))}.group:focus .group-focus\:text-gray-900{--text-opacity:1;color:#161e2e;color:rgba(22,30,46,var(--text-opacity))}.group:focus .group-focus\:text-indigo-800{--text-opacity:1;color:#42389d;color:rgba(66,56,157,var(--text-opacity))}.hover\:text-white:hover{--text-opacity:1;color:#fff;color:rgba(255,255,255,var(--text-opacity))}.hover\:text-gray-800:hover{--text-opacity:1;color:#252f3f;color:rgba(37,47,63,var(--text-opacity))}.hover\:text-gray-900:hover{--text-opacity:1;color:#161e2e;color:rgba(22,30,46,var(--text-opacity))}.hover\:text-blue-700:hover{--text-opacity:1;color:#1a56db;color:rgba(26,86,219,var(--text-opacity))}.hover\:text-indigo-500:hover{--text-opacity:1;color:#6875f5;color:rgba(104,117,245,var(--text-opacity))}.focus\:text-gray-900:focus{--text-opacity:1;color:#161e2e;color:rgba(22,30,46,var(--text-opacity))}.active\:text-indigo-600:active{--text-opacity:1;color:#5850ec;color:rgba(88,80,236,var(--text-opacity))}.text-opacity-75{--text-opacity:0.75}.italic{font-style:italic}.not-italic{font-style:normal}.uppercase{text-transform:uppercase}.lowercase{text-transform:lowercase}.underline{text-decoration:underline}.no-underline{text-decoration:none}.hover\:underline:hover{text-decoration:underline}.antialiased{-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.tracking-wide{letter-spacing:.025em}.tracking-wider{letter-spacing:.05em}.select-none{-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.select-all{-webkit-user-select:all;-moz-user-select:all;-ms-user-select:all;user-select:all}.align-middle{vertical-align:middle}.align-bottom{vertical-align:bottom}.visible{visibility:visible}.whitespace-no-wrap{white-space:nowrap}.break-words{overflow-wrap:break-word}.break-all{word-break:break-all}.truncate{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.w-0{width:0}.w-2{width:.5rem}.w-3{width:.75rem}.w-4{width:1rem}.w-5{width:1.25rem}.w-6{width:1.5rem}.w-7{width:1.75rem}.w-8{width:2rem}.w-12{width:3rem}.w-24{width:6rem}.w-40{width:10rem}.w-56{width:14rem}.w-auto{width:auto}.w-1\.5{width:.375rem}.w-2\.5{width:.625rem}.w-1\/2{width:50%}.w-1\/3{width:33.333333%}.w-2\/3{width:66.666667%}.w-1\/4{width:25%}.w-2\/4{width:50%}.w-3\/4{width:75%}.w-1\/5{width:20%}.w-2\/5{width:40%}.w-3\/5{width:60%}.w-4\/5{width:80%}.w-3\/6{width:50%}.w-4\/6{width:66.666667%}.w-5\/6{width:83.333333%}.w-1\/12{width:8.333333%}.w-2\/12{width:16.666667%}.w-3\/12{width:25%}.w-4\/12{width:33.333333%}.w-5\/12{width:41.666667%}.w-9\/12{width:75%}.w-11\/12{width:91.666667%}.w-full{width:100%}.z-20{z-index:20}.z-40{z-index:40}.z-50{z-index:50}.gap-8{grid-gap:2rem;gap:2rem}.grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}.transform{--transform-translate-x:0;--transform-translate-y:0;--transform-rotate:0;--transform-skew-x:0;--transform-skew-y:0;--transform-scale-x:1;--transform-scale-y:1;-webkit-transform:translateX(var(--transform-translate-x)) translateY(var(--transform-translate-y)) rotate(var(--transform-rotate)) skewX(var(--transform-skew-x)) skewY(var(--transform-skew-y)) scaleX(var(--transform-scale-x)) scaleY(var(--transform-scale-y));transform:translateX(var(--transform-translate-x)) translateY(var(--transform-translate-y)) rotate(var(--transform-rotate)) skewX(var(--transform-skew-x)) skewY(var(--transform-skew-y)) scaleX(var(--transform-scale-x)) scaleY(var(--transform-scale-y))}.origin-top-right{-webkit-transform-origin:top right;transform-origin:top right}.scale-95{--transform-scale-x:.95;--transform-scale-y:.95}.scale-100{--transform-scale-x:1;--transform-scale-y:1}.transition-all{-webkit-transition-property:all;transition-property:all}.transition{-webkit-transition-property:background-color,border-color,color,fill,stroke,opacity,-webkit-box-shadow,-webkit-transform;transition-property:background-color,border-color,color,fill,stroke,opacity,-webkit-box-shadow,-webkit-transform;transition-property:background-color,border-color,color,fill,stroke,opacity,box-shadow,transform;transition-property:background-color,border-color,color,fill,stroke,opacity,box-shadow,transform,-webkit-box-shadow,-webkit-transform}.ease-in{-webkit-transition-timing-function:cubic-bezier(.4,0,1,1);transition-timing-function:cubic-bezier(.4,0,1,1)}.ease-out{-webkit-transition-timing-function:cubic-bezier(0,0,.2,1);transition-timing-function:cubic-bezier(0,0,.2,1)}.ease-in-out{-webkit-transition-timing-function:cubic-bezier(.4,0,.2,1);transition-timing-function:cubic-bezier(.4,0,.2,1)}.duration-75{-webkit-transition-duration:75ms;transition-duration:75ms}.duration-100{-webkit-transition-duration:.1s;transition-duration:.1s}.duration-150{-webkit-transition-duration:.15s;transition-duration:.15s}.duration-300{-webkit-transition-duration:.3s;transition-duration:.3s}@-webkit-keyframes spin{to{-webkit-transform:rotate(1turn);transform:rotate(1turn)}}@keyframes spin{to{-webkit-transform:rotate(1turn);transform:rotate(1turn)}}@keyframes ping{75%,to{-webkit-transform:scale(2);transform:scale(2);opacity:0}}@keyframes pulse{50%{opacity:.5}}@keyframes bounce{0%,to{-webkit-transform:translateY(-25%);transform:translateY(-25%);-webkit-animation-timing-function:cubic-bezier(.8,0,1,1);animation-timing-function:cubic-bezier(.8,0,1,1)}50%{-webkit-transform:none;transform:none;-webkit-animation-timing-function:cubic-bezier(0,0,.2,1);animation-timing-function:cubic-bezier(0,0,.2,1)}}.animate-ping{-webkit-animation:ping 1s cubic-bezier(0,0,.2,1) infinite;animation:ping 1s cubic-bezier(0,0,.2,1) infinite}.animate-pulse{-webkit-animation:pulse 2s cubic-bezier(.4,0,.6,1) infinite;animation:pulse 2s cubic-bezier(.4,0,.6,1) infinite}@media (min-width:640px){.sm\:space-y-0>:not(template)~:not(template){--space-y-reverse:0;margin-top:calc(0px*(1 - var(--space-y-reverse)));margin-bottom:calc(0px*var(--space-y-reverse))}.sm\:space-y-3>:not(template)~:not(template){--space-y-reverse:0;margin-top:calc(0.75rem*(1 - var(--space-y-reverse)));margin-bottom:calc(0.75rem*var(--space-y-reverse))}.sm\:space-x-4>:not(template)~:not(template){--space-x-reverse:0;margin-right:calc(1rem*var(--space-x-reverse));margin-left:calc(1rem*(1 - var(--space-x-reverse)))}.sm\:rounded-md{border-radius:.375rem}.sm\:rounded-lg{border-radius:.5rem}.sm\:flex{display:-webkit-box;display:-ms-flexbox;display:flex}.sm\:grid{display:grid}.sm\:flex-row-reverse{-webkit-box-orient:horizontal;-webkit-box-direction:reverse;-ms-flex-direction:row-reverse;flex-direction:row-reverse}.sm\:items-start{-webkit-box-align:start;-ms-flex-align:start;align-items:flex-start}.sm\:items-center{-webkit-box-align:center;-ms-flex-align:center;align-items:center}.sm\:h-10{height:2.5rem}.sm\:text-sm{font-size:.875rem}.sm\:text-2xl{font-size:1.5rem}.sm\:text-3xl{font-size:1.875rem}.sm\:leading-5{line-height:1.25rem}.sm\:leading-7{line-height:1.75rem}.sm\:leading-9{line-height:2.25rem}.sm\:my-0{margin-top:0;margin-bottom:0}.sm\:mx-0{margin-left:0;margin-right:0}.sm\:my-7{margin-top:1.75rem;margin-bottom:1.75rem}.sm\:my-8{margin-top:2rem;margin-bottom:2rem}.sm\:my-12{margin-top:3rem;margin-bottom:3rem}.sm\:mt-0{margin-top:0}.sm\:ml-3{margin-left:.75rem}.sm\:ml-4{margin-left:1rem}.sm\:mt-5{margin-top:1.25rem}.sm\:max-w-lg{max-width:32rem}.sm\:p-6{padding:1.5rem}.sm\:px-0{padding-left:0;padding-right:0}.sm\:px-2{padding-left:.5rem;padding-right:.5rem}.sm\:px-4{padding-left:1rem;padding-right:1rem}.sm\:px-6{padding-left:1.5rem;padding-right:1.5rem}.sm\:pb-4{padding-bottom:1rem}.sm\:text-left{text-align:left}.sm\:align-middle{vertical-align:middle}.sm\:truncate{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.sm\:w-10{width:2.5rem}.sm\:w-32{width:8rem}.sm\:w-auto{width:auto}.sm\:w-1\/2{width:50%}.sm\:w-1\/3{width:33.333333%}.sm\:w-2\/3{width:66.666667%}.sm\:w-full{width:100%}.sm\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.sm\:grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}}@media (min-width:768px){.md\:rounded-lg{border-radius:.5rem}.md\:flex{display:-webkit-box;display:-ms-flexbox;display:flex}.md\:items-start{-webkit-box-align:start;-ms-flex-align:start;align-items:flex-start}.md\:items-center{-webkit-box-align:center;-ms-flex-align:center;align-items:center}.md\:justify-between{-webkit-box-pack:justify;-ms-flex-pack:justify;justify-content:space-between}.md\:text-base{font-size:1rem}.md\:mx-0{margin-left:0;margin-right:0}.md\:my-2{margin-top:.5rem;margin-bottom:.5rem}.md\:mx-auto{margin-left:auto;margin-right:auto}.md\:mt-0{margin-top:0}.md\:ml-2{margin-left:.5rem}.md\:ml-4{margin-left:1rem}.md\:ml-8{margin-left:2rem}.md\:-mr-8{margin-right:-2rem}.md\:max-w-xl{max-width:36rem}.md\:max-w-5xl{max-width:64rem}.md\:p-2{padding:.5rem}.md\:p-6{padding:1.5rem}.md\:py-0{padding-top:0;padding-bottom:0}.md\:px-1{padding-left:.25rem;padding-right:.25rem}.md\:px-2{padding-left:.5rem;padding-right:.5rem}.md\:py-5{padding-top:1.25rem;padding-bottom:1.25rem}.md\:px-8{padding-left:2rem;padding-right:2rem}.md\:pb-2{padding-bottom:.5rem}.md\:pr-4{padding-right:1rem}.md\:pt-6{padding-top:1.5rem}.md\:shadow-xl{-webkit-box-shadow:0 20px 25px -5px rgba(0,0,0,.1),0 10px 10px -5px rgba(0,0,0,.04);box-shadow:0 20px 25px -5px rgba(0,0,0,.1),0 10px 10px -5px rgba(0,0,0,.04)}.md\:w-3\/5{width:60%}}@media (min-width:1024px){.lg\:bg-transparent{background-color:transparent}.lg\:border-transparent{border-color:transparent}.lg\:rounded-full{border-radius:9999px}.lg\:block{display:block}.lg\:flex{display:-webkit-box;display:-ms-flexbox;display:flex}.lg\:inline-flex{display:-webkit-inline-box;display:-ms-inline-flexbox;display:inline-flex}.lg\:text-sm{font-size:.875rem}.lg\:text-lg{font-size:1.125rem}.lg\:my-0{margin-top:0;margin-bottom:0}.lg\:mx-5{margin-left:1.25rem;margin-right:1.25rem}.lg\:my-24{margin-top:6rem;margin-bottom:6rem}.lg\:mx-auto{margin-left:auto;margin-right:auto}.lg\:ml-16{margin-left:4rem}.lg\:-mr-16{margin-right:-4rem}.lg\:max-w-3xl{max-width:48rem}.lg\:p-6{padding:1.5rem}.lg\:p-8{padding:2rem}.lg\:px-3{padding-left:.75rem;padding-right:.75rem}.lg\:px-4{padding-left:1rem;padding-right:1rem}.lg\:px-8{padding-left:2rem;padding-right:2rem}.lg\:pt-2{padding-top:.5rem}.lg\:pb-2{padding-bottom:.5rem}.lg\:pl-2{padding-left:.5rem}.lg\:top-1\/2{top:50%}.lg\:shadow-none{-webkit-box-shadow:none;box-shadow:none}.lg\:w-40{width:10rem}.lg\:w-48{width:12rem}.lg\:w-1\/2{width:50%}.lg\:w-3\/5{width:60%}.lg\:w-3\/12{width:25%}.lg\:w-7\/12{width:58.333333%}}@media (min-width:1280px){.xl\:mx-7{margin-left:1.75rem;margin-right:1.75rem}.xl\:mr-0{margin-right:0}.xl\:ml-3{margin-left:.75rem}.xl\:ml-4{margin-left:1rem}.xl\:ml-20{margin-left:5rem}.xl\:max-w-4xl{max-width:56rem}.xl\:px-4{padding-left:1rem;padding-right:1rem}.xl\:pb-4{padding-bottom:1rem}.xl\:top-1\/3{top:33.333333%}.xl\:w-1\/4{width:25%}.xl\:w-2\/5{width:40%}.xl\:w-3\/5{width:60%}.xl\:w-2\/12{width:16.666667%}.xl\:w-7\/12{width:58.333333%}}
1
+ /*! normalize.css v8.0.1 | MIT License | github.com/necolas/normalize.css */html{line-height:1.15;-webkit-text-size-adjust:100%}body{margin:0}main{display:block}h1{font-size:2em;margin:.67em 0}hr{-webkit-box-sizing:content-box;box-sizing:content-box;height:0;overflow:visible}pre{font-family:monospace,monospace;font-size:1em}a{background-color:transparent}abbr[title]{border-bottom:none;text-decoration:underline;-webkit-text-decoration:underline dotted;text-decoration:underline dotted}b,strong{font-weight:bolder}code,kbd,samp{font-family:monospace,monospace;font-size:1em}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}img{border-style:none}button,input,optgroup,select,textarea{font-family:inherit;font-size:100%;line-height:1.15;margin:0}button,input{overflow:visible}button,select{text-transform:none}[type=button],[type=reset],[type=submit],button{-webkit-appearance:button}[type=button]::-moz-focus-inner,[type=reset]::-moz-focus-inner,[type=submit]::-moz-focus-inner,button::-moz-focus-inner{border-style:none;padding:0}[type=button]:-moz-focusring,[type=reset]:-moz-focusring,[type=submit]:-moz-focusring,button:-moz-focusring{outline:1px dotted ButtonText}fieldset{padding:.35em .75em .625em}legend{-webkit-box-sizing:border-box;box-sizing:border-box;color:inherit;display:table;max-width:100%;padding:0;white-space:normal}progress{vertical-align:baseline}textarea{overflow:auto}[type=checkbox],[type=radio]{-webkit-box-sizing:border-box;box-sizing:border-box;padding:0}[type=number]::-webkit-inner-spin-button,[type=number]::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}[type=search]::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}details{display:block}summary{display:list-item}[hidden],template{display:none}blockquote,dd,dl,figure,h1,h2,h3,h4,h5,h6,hr,p,pre{margin:0}button{background-color:transparent;background-image:none}button:focus{outline:1px dotted;outline:5px auto -webkit-focus-ring-color}fieldset,ol,ul{margin:0;padding:0}ol,ul{list-style:none}html{font-family:system-ui,-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica Neue,Arial,Noto Sans,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol,Noto Color Emoji;line-height:1.5}*,:after,:before{-webkit-box-sizing:border-box;box-sizing:border-box;border:0 solid #d2d6dc}hr{border-top-width:1px}img{border-style:solid}textarea{resize:vertical}input::-webkit-input-placeholder,textarea::-webkit-input-placeholder{color:#a0aec0}input::-moz-placeholder,textarea::-moz-placeholder{color:#a0aec0}input::-ms-input-placeholder,textarea::-ms-input-placeholder{color:#a0aec0}input::placeholder,textarea::placeholder{color:#a0aec0}[role=button],button{cursor:pointer}table{border-collapse:collapse}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;text-decoration:inherit}button,input,optgroup,select,textarea{padding:0;line-height:inherit;color:inherit}code,kbd,pre,samp{font-family:Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace}audio,canvas,embed,iframe,img,object,svg,video{display:block;vertical-align:middle}img,video{max-width:100%;height:auto}a{--text-opacity:1;color:#5850ec;color:rgba(88,80,236,var(--text-opacity))}img{border-width:0}.container{width:100%}@media (min-width:640px){.container{max-width:640px}}@media (min-width:768px){.container{max-width:768px}}@media (min-width:1024px){.container{max-width:1024px}}@media (min-width:1280px){.container{max-width:1280px}}.form-input{-webkit-appearance:none;-moz-appearance:none;appearance:none;background-color:#fff;border-color:#d2d6dc;border-width:1px;border-radius:.375rem;padding:.5rem .75rem;font-size:1rem;line-height:1.5}.form-input::-webkit-input-placeholder{color:#9fa6b2;opacity:1}.form-input::-moz-placeholder{color:#9fa6b2;opacity:1}.form-input::-ms-input-placeholder{color:#9fa6b2;opacity:1}.form-input::placeholder{color:#9fa6b2;opacity:1}.form-input:focus{outline:none;-webkit-box-shadow:0 0 0 3px rgba(164,202,254,.45);box-shadow:0 0 0 3px rgba(164,202,254,.45);border-color:#a4cafe}.form-textarea{-webkit-appearance:none;-moz-appearance:none;appearance:none;background-color:#fff;border-color:#d2d6dc;border-width:1px;border-radius:.375rem;padding:.5rem .75rem;font-size:1rem;line-height:1.5}.form-textarea::-webkit-input-placeholder{color:#9fa6b2;opacity:1}.form-textarea::-moz-placeholder{color:#9fa6b2;opacity:1}.form-textarea::-ms-input-placeholder{color:#9fa6b2;opacity:1}.form-textarea::placeholder{color:#9fa6b2;opacity:1}.form-textarea:focus{outline:none;-webkit-box-shadow:0 0 0 3px rgba(164,202,254,.45);box-shadow:0 0 0 3px rgba(164,202,254,.45);border-color:#a4cafe}.form-multiselect{-webkit-appearance:none;-moz-appearance:none;appearance:none;background-color:#fff;border-color:#d2d6dc;border-width:1px;border-radius:.375rem;padding:.5rem .75rem;font-size:1rem;line-height:1.5}.form-multiselect:focus{outline:none;-webkit-box-shadow:0 0 0 3px rgba(164,202,254,.45);box-shadow:0 0 0 3px rgba(164,202,254,.45);border-color:#a4cafe}.form-select{background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20' fill='none'%3E%3Cpath d='M7 7l3-3 3 3m0 6l-3 3-3-3' stroke='%239fa6b2' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");-webkit-appearance:none;-moz-appearance:none;appearance:none;-webkit-print-color-adjust:exact;color-adjust:exact;background-repeat:no-repeat;background-color:#fff;border-color:#d2d6dc;border-width:1px;border-radius:.375rem;padding:.5rem 2.5rem .5rem .75rem;font-size:1rem;line-height:1.5;background-position:right .5rem center;background-size:1.5em 1.5em}.form-select::-ms-expand{color:#9fa6b2;border:none}@media not print{.form-select::-ms-expand{display:none}}@media print and (-ms-high-contrast:active),print and (-ms-high-contrast:none){.form-select{padding-right:.75rem}}.form-select:focus{outline:none;-webkit-box-shadow:0 0 0 3px rgba(164,202,254,.45);box-shadow:0 0 0 3px rgba(164,202,254,.45);border-color:#a4cafe}.form-checkbox:checked{background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg viewBox='0 0 16 16' fill='%23fff' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M5.707 7.293a1 1 0 00-1.414 1.414l2 2a1 1 0 001.414 0l4-4a1 1 0 00-1.414-1.414L7 8.586 5.707 7.293z'/%3E%3C/svg%3E");border-color:transparent;background-color:currentColor;background-size:100% 100%;background-position:50%;background-repeat:no-repeat}@media not print{.form-checkbox::-ms-check{border-width:1px;color:transparent;background:inherit;border-color:inherit;border-radius:inherit}}.form-checkbox{-webkit-appearance:none;-moz-appearance:none;appearance:none;-webkit-print-color-adjust:exact;color-adjust:exact;display:inline-block;vertical-align:middle;background-origin:border-box;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;-ms-flex-negative:0;flex-shrink:0;height:1rem;width:1rem;color:#3f83f8;background-color:#fff;border-color:#d2d6dc;border-width:1px;border-radius:.25rem}.form-checkbox:focus{outline:none;-webkit-box-shadow:0 0 0 3px rgba(164,202,254,.45);box-shadow:0 0 0 3px rgba(164,202,254,.45);border-color:#a4cafe}.form-checkbox:checked:focus,.form-radio:checked{border-color:transparent}.form-radio:checked{background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg viewBox='0 0 16 16' fill='%23fff' xmlns='http://www.w3.org/2000/svg'%3E%3Ccircle cx='8' cy='8' r='3'/%3E%3C/svg%3E");background-color:currentColor;background-size:100% 100%;background-position:50%;background-repeat:no-repeat}@media not print{.form-radio::-ms-check{border-width:1px;color:transparent;background:inherit;border-color:inherit;border-radius:inherit}}.form-radio{-webkit-appearance:none;-moz-appearance:none;appearance:none;-webkit-print-color-adjust:exact;color-adjust:exact;display:inline-block;vertical-align:middle;background-origin:border-box;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;-ms-flex-negative:0;flex-shrink:0;border-radius:100%;height:1rem;width:1rem;color:#3f83f8;background-color:#fff;border-color:#d2d6dc;border-width:1px}.form-radio:focus{outline:none;-webkit-box-shadow:0 0 0 3px rgba(164,202,254,.45);box-shadow:0 0 0 3px rgba(164,202,254,.45);border-color:#a4cafe}.form-radio:checked:focus{border-color:transparent}.ig-es-primary-button,.ig-es-send-queue-emails{border-color:transparent;padding:.5rem 1rem;background-color:#fff;background-color:rgba(255,255,255,var(--bg-opacity));color:#fff;color:rgba(255,255,255,var(--text-opacity));background-color:#5850ec;background-color:rgba(88,80,236,var(--bg-opacity))}.ig-es-primary-button,.ig-es-send-queue-emails,.ig-es-title-button,.wp-heading-inline+.page-title-action{display:-webkit-inline-box;display:-ms-inline-flexbox;display:inline-flex;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center;border-radius:.375rem;border-width:1px;font-size:.875rem;line-height:1.25rem;font-weight:500;--text-opacity:1;--bg-opacity:1;-webkit-transition-property:background-color,border-color,color,fill,stroke,opacity,-webkit-box-shadow,-webkit-transform;transition-property:background-color,border-color,color,fill,stroke,opacity,-webkit-box-shadow,-webkit-transform;transition-property:background-color,border-color,color,fill,stroke,opacity,box-shadow,transform;transition-property:background-color,border-color,color,fill,stroke,opacity,box-shadow,transform,-webkit-box-shadow,-webkit-transform;-webkit-transition-timing-function:cubic-bezier(.4,0,.2,1);transition-timing-function:cubic-bezier(.4,0,.2,1);-webkit-transition-duration:.15s;transition-duration:.15s}.ig-es-title-button,.wp-heading-inline+.page-title-action{--border-opacity:1;border-color:#d2d6dc;border-color:rgba(210,214,220,var(--border-opacity));color:#374151;color:rgba(55,65,81,var(--text-opacity));background-color:#fff;background-color:rgba(255,255,255,var(--bg-opacity));padding:.25rem .75rem}.wrap .wp-heading-inline+.page-title-action{margin-left:.5rem}.ig-es-title-button:hover,.wp-heading-inline+.page-title-action:hover{--bg-opacity:1;background-color:#f9fafb;background-color:rgba(249,250,251,var(--bg-opacity));--text-opacity:1;color:#374151;color:rgba(55,65,81,var(--text-opacity))}.ig-es-title-button:focus,.wp-heading-inline+.page-title-action:focus{outline:2px solid transparent;outline-offset:2px;-webkit-box-shadow:0 0 0 3px rgba(118,169,250,.45);box-shadow:0 0 0 3px rgba(118,169,250,.45);--border-opacity:1;border-color:#a4cafe;border-color:rgba(164,202,254,var(--border-opacity))}.ig-es-primary-button:hover{--bg-opacity:1;background-color:#6875f5;background-color:rgba(104,117,245,var(--bg-opacity));--text-opacity:1;color:#fff;color:rgba(255,255,255,var(--text-opacity))}.ig-es-primary-button:focus{outline:2px solid transparent;outline-offset:2px;-webkit-box-shadow:0 0 0 3px rgba(164,202,254,.45);box-shadow:0 0 0 3px rgba(164,202,254,.45)}.ig-es-imp-button{display:-webkit-inline-box!important;display:-ms-inline-flexbox!important;display:inline-flex!important;-webkit-box-pack:center!important;-ms-flex-pack:center!important;justify-content:center!important;border-radius:.375rem!important;border-width:1px!important;border-color:transparent!important;background-color:#fff!important;background-color:rgba(255,255,255,var(--bg-opacity))!important;font-size:.875rem!important;line-height:1.25rem!important;font-weight:500!important;background-color:#0e9f6e!important;background-color:rgba(14,159,110,var(--bg-opacity))!important;-webkit-transition-property:background-color,border-color,color,fill,stroke,opacity,-webkit-box-shadow,-webkit-transform!important;transition-property:background-color,border-color,color,fill,stroke,opacity,-webkit-box-shadow,-webkit-transform!important;transition-property:background-color,border-color,color,fill,stroke,opacity,box-shadow,transform!important;transition-property:background-color,border-color,color,fill,stroke,opacity,box-shadow,transform,-webkit-box-shadow,-webkit-transform!important;-webkit-transition-timing-function:cubic-bezier(.4,0,.2,1)!important;transition-timing-function:cubic-bezier(.4,0,.2,1)!important;-webkit-transition-duration:.15s!important;transition-duration:.15s!important}.ig-es-imp-button,.ig-es-imp-button:hover{--text-opacity:1!important;color:#fff!important;color:rgba(255,255,255,var(--text-opacity))!important;--bg-opacity:1!important}.ig-es-imp-button:hover{background-color:#31c48d!important;background-color:rgba(49,196,141,var(--bg-opacity))!important}.ig-es-imp-button:focus{outline:2px solid transparent!important;outline-offset:2px!important;-webkit-box-shadow:0 0 0 3px rgba(132,225,188,.45)!important;box-shadow:0 0 0 3px rgba(132,225,188,.45)!important}.ig-es-link-button{display:-webkit-inline-box;display:-ms-inline-flexbox;display:inline-flex;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center;border-radius:.375rem;border-width:1px;border-color:transparent;background-color:#fff;background-color:rgba(255,255,255,var(--bg-opacity));font-size:.875rem;line-height:1.25rem;font-weight:500;background-color:#ff5a1f;background-color:rgba(255,90,31,var(--bg-opacity));-webkit-transition-property:background-color,border-color,color,fill,stroke,opacity,-webkit-box-shadow,-webkit-transform;transition-property:background-color,border-color,color,fill,stroke,opacity,-webkit-box-shadow,-webkit-transform;transition-property:background-color,border-color,color,fill,stroke,opacity,box-shadow,transform;transition-property:background-color,border-color,color,fill,stroke,opacity,box-shadow,transform,-webkit-box-shadow,-webkit-transform;-webkit-transition-timing-function:cubic-bezier(.4,0,.2,1);transition-timing-function:cubic-bezier(.4,0,.2,1);-webkit-transition-duration:.15s;transition-duration:.15s}.ig-es-link-button,.ig-es-link-button:hover{--text-opacity:1;color:#fff;color:rgba(255,255,255,var(--text-opacity));--bg-opacity:1}.ig-es-link-button:hover{background-color:#ff8a4c;background-color:rgba(255,138,76,var(--bg-opacity))}.ig-es-link-button:focus{outline:2px solid transparent;outline-offset:2px;-webkit-box-shadow:0 0 0 3px rgba(253,186,140,.45);box-shadow:0 0 0 3px rgba(253,186,140,.45)}.ig-es-action.js-open .ig-es-action__header{--bg-opacity:1;background-color:#d2d6dc;background-color:rgba(210,214,220,var(--bg-opacity));--text-opacity:1;color:#374151;color:rgba(55,65,81,var(--text-opacity));--border-opacity:1;border-color:#d2d6dc;border-color:rgba(210,214,220,var(--border-opacity))}.form-input{--bg-opacity:1!important;background-color:#fff!important;background-color:rgba(255,255,255,var(--bg-opacity))!important;border-width:1px!important;border-radius:.375rem!important;-webkit-box-shadow:0 1px 2px 0 rgba(0,0,0,.05)!important;box-shadow:0 1px 2px 0 rgba(0,0,0,.05)!important;--border-opacity:1!important;border-color:#d2d6dc!important;border-color:rgba(210,214,220,var(--border-opacity))!important}.form-input:focus{outline:2px solid transparent!important;outline-offset:2px!important;-webkit-box-shadow:0 0 0 3px rgba(164,202,254,.45)!important;box-shadow:0 0 0 3px rgba(164,202,254,.45)!important}.form-checkbox{content:url("data:image/svg+xml;charset=utf-8,%3Csvg viewBox='0 0 16 16' fill='%23fff' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M5.707 7.293a1 1 0 00-1.414 1.414l2 2a1 1 0 001.414 0l4-4a1 1 0 00-1.414-1.414L7 8.586 5.707 7.293z'/%3E%3C/svg%3E")}.form-radio{content:url("data:image/svg+xml;charset=utf-8,%3Csvg viewBox='0 0 16 16' fill='%23fff' xmlns='http://www.w3.org/2000/svg'%3E%3Ccircle cx='8' cy='8' r='3'/%3E%3C/svg%3E")}.form-checkbox:checked,.form-radio:checked{--text-opacity:1!important;color:#5850ec!important;color:rgba(88,80,236,var(--text-opacity))!important}.form-select{font-size:.875rem!important;--border-opacity:1!important;border-color:#9fa6b2!important;border-color:rgba(159,166,178,var(--border-opacity))!important;background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20' fill='none'%3E%3Cpath d='M7 7l3-3 3 3m0 6l-3 3-3-3' stroke='%239fa6b2' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E")!important}.form-select:focus,input[type=number]:focus{outline:2px solid transparent!important;outline-offset:2px!important;-webkit-box-shadow:0 0 0 3px rgba(164,202,254,.45)!important;box-shadow:0 0 0 3px rgba(164,202,254,.45)!important;--border-opacity:1!important;border-color:#a4cafe!important;border-color:rgba(164,202,254,var(--border-opacity))!important}.es-check-toggle:checked~.es-mail-toggle-line{--bg-opacity:1;background-color:#5850ec;background-color:rgba(88,80,236,var(--bg-opacity))}.es-check-toggle:checked~.es-mail-toggle-dot{--transform-translate-x:0;--transform-translate-y:0;--transform-rotate:0;--transform-skew-x:0;--transform-skew-y:0;--transform-scale-x:1;--transform-scale-y:1;-webkit-transform:translateX(var(--transform-translate-x)) translateY(var(--transform-translate-y)) rotate(var(--transform-rotate)) skewX(var(--transform-skew-x)) skewY(var(--transform-skew-y)) scaleX(var(--transform-scale-x)) scaleY(var(--transform-scale-y));transform:translateX(var(--transform-translate-x)) translateY(var(--transform-translate-y)) rotate(var(--transform-rotate)) skewX(var(--transform-skew-x)) skewY(var(--transform-skew-y)) scaleX(var(--transform-scale-x)) scaleY(var(--transform-scale-y));--transform-translate-x:100%}.es-mail-toggle-line{width:2.25rem;height:1.25rem;background-color:#d2d6dc;background-color:rgba(210,214,220,var(--bg-opacity));-webkit-box-shadow:inset 0 2px 4px 0 rgba(0,0,0,.06);box-shadow:inset 0 2px 4px 0 rgba(0,0,0,.06)}.es-mail-toggle-dot,.es-mail-toggle-line{display:block;--bg-opacity:1;border-radius:9999px}.es-mail-toggle-dot{width:.875rem;height:.875rem;margin-left:.25rem;position:absolute;top:0;bottom:0;-webkit-transition-property:all;transition-property:all;-webkit-transition-duration:.3s;transition-duration:.3s;-webkit-transition-timing-function:cubic-bezier(.4,0,.2,1);transition-timing-function:cubic-bezier(.4,0,.2,1);background-color:#fff;background-color:rgba(255,255,255,var(--bg-opacity));-webkit-box-shadow:0 1px 3px 0 rgba(0,0,0,.1),0 1px 2px 0 rgba(0,0,0,.06);box-shadow:0 1px 3px 0 rgba(0,0,0,.1),0 1px 2px 0 rgba(0,0,0,.06)}.es-mail-toggle-dot:focus-within{-webkit-box-shadow:0 0 0 3px rgba(118,169,250,.45);box-shadow:0 0 0 3px rgba(118,169,250,.45)}[type=radio]:checked+.es-mailer-logo{-webkit-transition-property:all;transition-property:all;-webkit-transition-duration:.1s;transition-duration:.1s;-webkit-transition-timing-function:cubic-bezier(.4,0,.2,1);transition-timing-function:cubic-bezier(.4,0,.2,1);--transform-translate-x:0;--transform-translate-y:0;--transform-rotate:0;--transform-skew-x:0;--transform-skew-y:0;--transform-scale-x:1;--transform-scale-y:1;-webkit-transform:translateX(var(--transform-translate-x)) translateY(var(--transform-translate-y)) rotate(var(--transform-rotate)) skewX(var(--transform-skew-x)) skewY(var(--transform-skew-y)) scaleX(var(--transform-scale-x)) scaleY(var(--transform-scale-y));transform:translateX(var(--transform-translate-x)) translateY(var(--transform-translate-y)) rotate(var(--transform-rotate)) skewX(var(--transform-skew-x)) skewY(var(--transform-skew-y)) scaleX(var(--transform-scale-x)) scaleY(var(--transform-scale-y));--transform-scale-x:1.1;--transform-scale-y:1.1;-webkit-box-shadow:0 0 3px 1px #5a67d8;box-shadow:0 0 3px 1px #5a67d8}[type=radio]:checked+.es-mailer-logo:hover{border-width:1px;--border-opacity:1;border-color:#e5e7eb;border-color:rgba(229,231,235,var(--border-opacity))}.wp-core-ui .button,.wp-core-ui .button-secondary{--border-opacity:1;border-color:#5850ec;border-color:rgba(88,80,236,var(--border-opacity));color:#5850ec;color:rgba(88,80,236,var(--text-opacity))}.wp-core-ui .button,.wp-core-ui .button-primary,.wp-core-ui .button-secondary{font-size:.875rem;border-radius:.375rem;border-width:1px;line-height:1.25rem;font-weight:500;--text-opacity:1}.wp-core-ui .button-primary{--bg-opacity:1;background-color:#5850ec;background-color:rgba(88,80,236,var(--bg-opacity));color:#fff;color:rgba(255,255,255,var(--text-opacity));-webkit-transition-property:background-color,border-color,color,fill,stroke,opacity,-webkit-box-shadow,-webkit-transform;transition-property:background-color,border-color,color,fill,stroke,opacity,-webkit-box-shadow,-webkit-transform;transition-property:background-color,border-color,color,fill,stroke,opacity,box-shadow,transform;transition-property:background-color,border-color,color,fill,stroke,opacity,box-shadow,transform,-webkit-box-shadow,-webkit-transform;-webkit-transition-timing-function:cubic-bezier(.4,0,.2,1);transition-timing-function:cubic-bezier(.4,0,.2,1);-webkit-transition-duration:.15s;transition-duration:.15s}.wp-core-ui .button-primary:hover,.wp-core-ui .button:hover{--border-opacity:1;border-color:#5850ec;border-color:rgba(88,80,236,var(--border-opacity));--text-opacity:1;color:#6875f5;color:rgba(104,117,245,var(--text-opacity))}.wp-core-ui .search-box input[name=s],.wp-core-ui select{border-radius:.375rem}.wp-core-ui #bulk-action-selector-top,.wp-core-ui #doaction,.wp-core-ui #doaction2,.wp-core-ui #filter-by-date,.wp-core-ui #post-query-submit,.wp-core-ui #poststuff select,.wp-core-ui #search-submit{cursor:pointer;line-height:1.25rem;--text-opacity:1;color:#4b5563;color:rgba(75,85,99,var(--text-opacity));background-color:transparent;font-size:.875rem}.wp-core-ui #search-submit{margin-left:.375rem}.wp-core-ui #doaction2:hover .wp-core-ui #post-query-submit:hover,.wp-core-ui #doaction:hover,.wp-core-ui #search-submit:hover{--bg-opacity:1;background-color:#f4f5f7;background-color:rgba(244,245,247,var(--bg-opacity));--border-opacity:1;border-color:#6b7280;border-color:rgba(107,114,128,var(--border-opacity))}.wp-core-ui #doaction2:focus .wp-core-ui #post-query-submit:focus,.wp-core-ui #doaction:focus,.wp-core-ui #search-submit:focus{outline:2px solid transparent;outline-offset:2px;-webkit-box-shadow:0 0 0 3px rgba(159,166,178,.45);box-shadow:0 0 0 3px rgba(159,166,178,.45)}.es-items-lists table.fixed,.post-type-es_template table.fixed{margin-top:1rem;margin-bottom:1rem;-webkit-box-shadow:0 1px 3px 0 rgba(0,0,0,.1),0 1px 2px 0 rgba(0,0,0,.06);box-shadow:0 1px 3px 0 rgba(0,0,0,.1),0 1px 2px 0 rgba(0,0,0,.06);border-radius:.5rem;overflow:hidden}.es-items-lists table.fixed tfoot td,.es-items-lists table.fixed tfoot th,.es-items-lists table.fixed thead td,.es-items-lists table.fixed thead th,.post-type-es_template table.fixed tfoot th,.post-type-es_template table.fixed thead td,.post-type-es_template table.fixed thead th{--bg-opacity:1;background-color:#f4f5f7;background-color:rgba(244,245,247,var(--bg-opacity));border-bottom-width:1px;--border-opacity:1;border-color:#e5e7eb;border-color:rgba(229,231,235,var(--border-opacity));--text-opacity:1;color:#6b7280;color:rgba(107,114,128,var(--text-opacity));font-weight:500;letter-spacing:.05em}.es-items-lists table.fixed tfoot th,.es-items-lists table.fixed thead th,.post-type-es_template table.fixed tfoot th,.post-type-es_template table.fixed thead th{padding-top:.5rem;padding-bottom:.5rem}.es-items-lists .widefat thead td input,.post-type-es_template .widefat thead td input{margin-right:1.5rem}.post-type-es_template .wrap{padding-top:1rem;font-family:system-ui,-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica Neue,Arial,Noto Sans,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol,Noto Color Emoji}.post-type-es_template .wrap>h1{padding-top:0;font-weight:600;--text-opacity:1;color:#374151;color:rgba(55,65,81,var(--text-opacity));line-height:2.25rem}.es-items-lists .striped>tbody tr,.post-type-es_template .striped>tbody tr{border-bottom-width:1px;--border-opacity:1;border-color:#e5e7eb;border-color:rgba(229,231,235,var(--border-opacity));padding-top:.5rem;padding-bottom:.5rem}.es-items-lists .striped>tbody>:nth-child(odd),.post-type-es_template .striped>tbody>:nth-child(odd){--bg-opacity:1;background-color:#fff;background-color:rgba(255,255,255,var(--bg-opacity))}.es_onboard_email{padding:.25rem .75rem!important}.es_reports_table_header{border-bottom-width:1px;--border-opacity:1;border-color:#e5e7eb;border-color:rgba(229,231,235,var(--border-opacity));--bg-opacity:1;background-color:#f4f5f7;background-color:rgba(244,245,247,var(--bg-opacity));text-align:left;font-size:.875rem;line-height:1rem;font-weight:500;--text-opacity:1;color:#6b7280;color:rgba(107,114,128,var(--text-opacity));letter-spacing:.05em}.importing-progress,.progress{width:100%;height:2rem;--bg-opacity:1;background-color:#e5e7eb;background-color:rgba(229,231,235,var(--bg-opacity));overflow:hidden;position:relative;text-align:right;line-height:1rem;margin-top:.375rem;border-radius:.25rem}.importing-progress span.bar,.progress span.bar{display:block;position:absolute;line-height:2.5rem;padding-top:.25rem;padding-bottom:.25rem;top:0;bottom:0;left:0;border-radius:.25rem;overflow:hidden;background-image:-webkit-gradient(linear,left top,right top,from(var(--gradient-color-stops)));background-image:linear-gradient(90deg,var(--gradient-color-stops));--gradient-from-color:#42389d;--gradient-color-stops:var(--gradient-from-color),var(--gradient-to-color,rgba(66,56,157,0));--gradient-to-color:#6875f5;--bg-opacity:1;background-color:#8da2fb;background-color:rgba(141,162,251,var(--bg-opacity))}.space-y-1>:not(template)~:not(template){--space-y-reverse:0;margin-top:calc(0.25rem*(1 - var(--space-y-reverse)));margin-bottom:calc(0.25rem*var(--space-y-reverse))}.space-y-2>:not(template)~:not(template){--space-y-reverse:0;margin-top:calc(0.5rem*(1 - var(--space-y-reverse)));margin-bottom:calc(0.5rem*var(--space-y-reverse))}.space-y-3>:not(template)~:not(template){--space-y-reverse:0;margin-top:calc(0.75rem*(1 - var(--space-y-reverse)));margin-bottom:calc(0.75rem*var(--space-y-reverse))}.space-x-3>:not(template)~:not(template){--space-x-reverse:0;margin-right:calc(0.75rem*var(--space-x-reverse));margin-left:calc(0.75rem*(1 - var(--space-x-reverse)))}.space-y-4>:not(template)~:not(template){--space-y-reverse:0;margin-top:calc(1rem*(1 - var(--space-y-reverse)));margin-bottom:calc(1rem*var(--space-y-reverse))}.space-y-5>:not(template)~:not(template){--space-y-reverse:0;margin-top:calc(1.25rem*(1 - var(--space-y-reverse)));margin-bottom:calc(1.25rem*var(--space-y-reverse))}.bg-white{--bg-opacity:1;background-color:#fff;background-color:rgba(255,255,255,var(--bg-opacity))}.bg-gray-50{--bg-opacity:1;background-color:#f9fafb;background-color:rgba(249,250,251,var(--bg-opacity))}.bg-gray-100{--bg-opacity:1;background-color:#f4f5f7;background-color:rgba(244,245,247,var(--bg-opacity))}.bg-gray-200{--bg-opacity:1;background-color:#e5e7eb;background-color:rgba(229,231,235,var(--bg-opacity))}.bg-gray-300{--bg-opacity:1;background-color:#d2d6dc;background-color:rgba(210,214,220,var(--bg-opacity))}.bg-red-50{--bg-opacity:1;background-color:#fdf2f2;background-color:rgba(253,242,242,var(--bg-opacity))}.bg-red-100{--bg-opacity:1;background-color:#fde8e8;background-color:rgba(253,232,232,var(--bg-opacity))}.bg-yellow-100{--bg-opacity:1;background-color:#fdf6b2;background-color:rgba(253,246,178,var(--bg-opacity))}.bg-green-100{--bg-opacity:1;background-color:#def7ec;background-color:rgba(222,247,236,var(--bg-opacity))}.bg-green-300{--bg-opacity:1;background-color:#84e1bc;background-color:rgba(132,225,188,var(--bg-opacity))}.bg-green-600{--bg-opacity:1;background-color:#057a55;background-color:rgba(5,122,85,var(--bg-opacity))}.bg-teal-50{--bg-opacity:1;background-color:#edfafa;background-color:rgba(237,250,250,var(--bg-opacity))}.bg-blue-50{--bg-opacity:1;background-color:#ebf5ff;background-color:rgba(235,245,255,var(--bg-opacity))}.bg-blue-300{--bg-opacity:1;background-color:#a4cafe;background-color:rgba(164,202,254,var(--bg-opacity))}.bg-indigo-200{--bg-opacity:1;background-color:#cddbfe;background-color:rgba(205,219,254,var(--bg-opacity))}.bg-indigo-500{--bg-opacity:1;background-color:#6875f5;background-color:rgba(104,117,245,var(--bg-opacity))}.bg-indigo-600{--bg-opacity:1;background-color:#5850ec;background-color:rgba(88,80,236,var(--bg-opacity))}.bg-indigo-700{--bg-opacity:1;background-color:#5145cd;background-color:rgba(81,69,205,var(--bg-opacity))}.bg-indigo-800{--bg-opacity:1;background-color:#42389d;background-color:rgba(66,56,157,var(--bg-opacity))}.bg-pink-200{--bg-opacity:1;background-color:#fad1e8;background-color:rgba(250,209,232,var(--bg-opacity))}.group:focus .group-focus\:bg-gray-400,.group:hover .group-hover\:bg-gray-400{--bg-opacity:1;background-color:#9fa6b2;background-color:rgba(159,166,178,var(--bg-opacity))}.hover\:bg-gray-50:hover{--bg-opacity:1;background-color:#f9fafb;background-color:rgba(249,250,251,var(--bg-opacity))}.hover\:bg-gray-100:hover{--bg-opacity:1;background-color:#f4f5f7;background-color:rgba(244,245,247,var(--bg-opacity))}.hover\:bg-green-500:hover{--bg-opacity:1;background-color:#0e9f6e;background-color:rgba(14,159,110,var(--bg-opacity))}.hover\:bg-indigo-500:hover{--bg-opacity:1;background-color:#6875f5;background-color:rgba(104,117,245,var(--bg-opacity))}.hover\:bg-indigo-600:hover{--bg-opacity:1;background-color:#5850ec;background-color:rgba(88,80,236,var(--bg-opacity))}.focus\:bg-gray-50:focus{--bg-opacity:1;background-color:#f9fafb;background-color:rgba(249,250,251,var(--bg-opacity))}.focus\:bg-gray-100:focus{--bg-opacity:1;background-color:#f4f5f7;background-color:rgba(244,245,247,var(--bg-opacity))}.border-collapse{border-collapse:collapse}.border-transparent{border-color:transparent}.border-gray-100{--border-opacity:1;border-color:#f4f5f7;border-color:rgba(244,245,247,var(--border-opacity))}.border-gray-200{--border-opacity:1;border-color:#e5e7eb;border-color:rgba(229,231,235,var(--border-opacity))}.border-gray-300{--border-opacity:1;border-color:#d2d6dc;border-color:rgba(210,214,220,var(--border-opacity))}.border-gray-400{--border-opacity:1;border-color:#9fa6b2;border-color:rgba(159,166,178,var(--border-opacity))}.border-indigo-300{--border-opacity:1;border-color:#b4c6fc;border-color:rgba(180,198,252,var(--border-opacity))}.border-indigo-500{--border-opacity:1;border-color:#6875f5;border-color:rgba(104,117,245,var(--border-opacity))}.border-indigo-600{--border-opacity:1;border-color:#5850ec;border-color:rgba(88,80,236,var(--border-opacity))}.hover\:border-gray-200:hover{--border-opacity:1;border-color:#e5e7eb;border-color:rgba(229,231,235,var(--border-opacity))}.hover\:border-gray-500:hover{--border-opacity:1;border-color:#6b7280;border-color:rgba(107,114,128,var(--border-opacity))}.hover\:border-red-400:hover{--border-opacity:1;border-color:#f98080;border-color:rgba(249,128,128,var(--border-opacity))}.hover\:border-indigo-600:hover{--border-opacity:1;border-color:#5850ec;border-color:rgba(88,80,236,var(--border-opacity))}.focus\:border-blue-300:focus{--border-opacity:1;border-color:#a4cafe;border-color:rgba(164,202,254,var(--border-opacity))}.rounded{border-radius:.25rem}.rounded-md{border-radius:.375rem}.rounded-lg{border-radius:.5rem}.rounded-full{border-radius:9999px}.rounded-r-lg{border-top-right-radius:.5rem;border-bottom-right-radius:.5rem}.rounded-l-lg{border-top-left-radius:.5rem;border-bottom-left-radius:.5rem}.border-dashed{border-style:dashed}.border-dotted{border-style:dotted}.border-0{border-width:0}.border-2{border-width:2px}.border{border-width:1px}.border-t{border-top-width:1px}.border-r{border-right-width:1px}.border-b{border-bottom-width:1px}.cursor-default{cursor:default}.cursor-pointer{cursor:pointer}.cursor-not-allowed{cursor:not-allowed}.block{display:block}.inline-block{display:inline-block}.inline{display:inline}.flex{display:-webkit-box;display:-ms-flexbox;display:flex}.inline-flex{display:-webkit-inline-box;display:-ms-inline-flexbox;display:inline-flex}.table{display:table}.table-caption{display:table-caption}.table-cell{display:table-cell}.grid{display:grid}.contents{display:contents}.hidden{display:none}.flex-row{-webkit-box-orient:horizontal;-ms-flex-direction:row;flex-direction:row}.flex-col,.flex-row{-webkit-box-direction:normal}.flex-col{-webkit-box-orient:vertical;-ms-flex-direction:column;flex-direction:column}.flex-wrap{-ms-flex-wrap:wrap;flex-wrap:wrap}.items-start{-webkit-box-align:start;-ms-flex-align:start;align-items:flex-start}.items-center{-webkit-box-align:center;-ms-flex-align:center;align-items:center}.self-start{-ms-flex-item-align:start;align-self:flex-start}.justify-start{-webkit-box-pack:start;-ms-flex-pack:start;justify-content:flex-start}.justify-center{-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center}.justify-between{-webkit-box-pack:justify;-ms-flex-pack:justify;justify-content:space-between}.flex-1{-webkit-box-flex:1;-ms-flex:1 1 0%;flex:1 1 0%}.flex-auto{-webkit-box-flex:1;-ms-flex:1 1 auto;flex:1 1 auto}.flex-none{-webkit-box-flex:0;-ms-flex:none;flex:none}.flex-shrink-0{-ms-flex-negative:0;flex-shrink:0}.float-right{float:right}.float-left{float:left}.font-sans{font-family:system-ui,-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica Neue,Arial,Noto Sans,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol,Noto Color Emoji}.font-mono{font-family:Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace}.font-thin{font-weight:200}.font-normal{font-weight:400}.font-medium{font-weight:500}.font-semibold{font-weight:600}.font-bold{font-weight:700}.h-0{height:0}.h-2{height:.5rem}.h-3{height:.75rem}.h-4{height:1rem}.h-5{height:1.25rem}.h-6{height:1.5rem}.h-7{height:1.75rem}.h-8{height:2rem}.h-9{height:2.25rem}.h-10{height:2.5rem}.h-12{height:3rem}.h-15{height:3.75rem}.h-20{height:5rem}.h-48{height:12rem}.h-auto{height:auto}.h-1\.5{height:.375rem}.h-2\.5{height:.625rem}.h-full{height:100%}.text-xs{font-size:.75rem}.text-sm{font-size:.875rem}.text-base{font-size:1rem}.text-lg{font-size:1.125rem}.text-xl{font-size:1.25rem}.text-2xl{font-size:1.5rem}.text-3xl{font-size:1.875rem}.text-4xl{font-size:2.25rem}.leading-4{line-height:1rem}.leading-5{line-height:1.25rem}.leading-6{line-height:1.5rem}.leading-7{line-height:1.75rem}.leading-9{line-height:2.25rem}.leading-none{line-height:1}.leading-snug{line-height:1.375}.leading-normal{line-height:1.5}.leading-relaxed{line-height:1.625}.list-none{list-style-type:none}.list-disc{list-style-type:disc}.list-decimal{list-style-type:decimal}.m-4{margin:1rem}.my-0{margin-top:0;margin-bottom:0}.my-1{margin-top:.25rem;margin-bottom:.25rem}.mx-1{margin-left:.25rem;margin-right:.25rem}.my-2{margin-top:.5rem;margin-bottom:.5rem}.mx-2{margin-left:.5rem;margin-right:.5rem}.my-3{margin-top:.75rem;margin-bottom:.75rem}.my-4{margin-top:1rem;margin-bottom:1rem}.mx-4{margin-left:1rem;margin-right:1rem}.my-6{margin-top:1.5rem;margin-bottom:1.5rem}.mx-6{margin-left:1.5rem;margin-right:1.5rem}.my-8{margin-top:2rem;margin-bottom:2rem}.mx-8{margin-left:2rem;margin-right:2rem}.my-12{margin-top:3rem;margin-bottom:3rem}.mx-auto{margin-left:auto;margin-right:auto}.-my-4{margin-top:-1rem;margin-bottom:-1rem}.mt-0{margin-top:0}.mb-0{margin-bottom:0}.mt-1{margin-top:.25rem}.mr-1{margin-right:.25rem}.mb-1{margin-bottom:.25rem}.ml-1{margin-left:.25rem}.mt-2{margin-top:.5rem}.mr-2{margin-right:.5rem}.mb-2{margin-bottom:.5rem}.ml-2{margin-left:.5rem}.mt-3{margin-top:.75rem}.mr-3{margin-right:.75rem}.mb-3{margin-bottom:.75rem}.ml-3{margin-left:.75rem}.mt-4{margin-top:1rem}.mr-4{margin-right:1rem}.mb-4{margin-bottom:1rem}.ml-4{margin-left:1rem}.mt-5{margin-top:1.25rem}.ml-5{margin-left:1.25rem}.mt-6{margin-top:1.5rem}.mr-6{margin-right:1.5rem}.mb-6{margin-bottom:1.5rem}.ml-6{margin-left:1.5rem}.mt-7{margin-top:1.75rem}.mb-7{margin-bottom:1.75rem}.ml-7{margin-left:1.75rem}.mt-8{margin-top:2rem}.mr-8{margin-right:2rem}.ml-8{margin-left:2rem}.mr-10{margin-right:2.5rem}.mt-12{margin-top:3rem}.ml-12{margin-left:3rem}.ml-14{margin-left:3.5rem}.mt-16{margin-top:4rem}.mr-16{margin-right:4rem}.ml-16{margin-left:4rem}.mt-0\.5{margin-top:.125rem}.mt-1\.5{margin-top:.375rem}.mr-1\.5{margin-right:.375rem}.mt-2\.5{margin-top:.625rem}.-mt-1{margin-top:-.25rem}.-mr-1{margin-right:-.25rem}.-mb-1{margin-bottom:-.25rem}.-mb-2{margin-bottom:-.5rem}.-mt-3{margin-top:-.75rem}.-mt-5{margin-top:-1.25rem}.-ml-6{margin-left:-1.5rem}.-ml-8{margin-left:-2rem}.-mb-0\.5{margin-bottom:-.125rem}.-mt-1\.5{margin-top:-.375rem}.max-h-full{max-height:100%}.max-w-7xl{max-width:80rem}.max-w-full{max-width:100%}.min-h-screen{min-height:100vh}.min-w-0{min-width:0}.min-w-full{min-width:100%}.object-cover{-o-object-fit:cover;object-fit:cover}.opacity-0{opacity:0}.opacity-50{opacity:.5}.opacity-100{opacity:1}.focus\:outline-none:focus{outline:2px solid transparent;outline-offset:2px}.overflow-auto{overflow:auto}.overflow-hidden{overflow:hidden}.overflow-y-auto{overflow-y:auto}.overflow-x-hidden{overflow-x:hidden}.p-0{padding:0}.p-2{padding:.5rem}.p-3{padding:.75rem}.p-4{padding:1rem}.p-13{padding:3.25rem}.py-1{padding-top:.25rem;padding-bottom:.25rem}.px-1{padding-left:.25rem;padding-right:.25rem}.py-2{padding-top:.5rem;padding-bottom:.5rem}.px-2{padding-left:.5rem;padding-right:.5rem}.py-3{padding-top:.75rem;padding-bottom:.75rem}.px-3{padding-left:.75rem;padding-right:.75rem}.py-4{padding-top:1rem;padding-bottom:1rem}.px-4{padding-left:1rem;padding-right:1rem}.py-5{padding-top:1.25rem;padding-bottom:1.25rem}.px-5{padding-left:1.25rem;padding-right:1.25rem}.px-6{padding-left:1.5rem;padding-right:1.5rem}.py-8{padding-top:2rem;padding-bottom:2rem}.py-12{padding-top:3rem;padding-bottom:3rem}.px-12{padding-left:3rem;padding-right:3rem}.py-0\.5{padding-top:.125rem;padding-bottom:.125rem}.py-1\.5{padding-top:.375rem;padding-bottom:.375rem}.px-1\.5{padding-left:.375rem;padding-right:.375rem}.pt-1{padding-top:.25rem}.pr-1{padding-right:.25rem}.pb-1{padding-bottom:.25rem}.pl-1{padding-left:.25rem}.pt-2{padding-top:.5rem}.pr-2{padding-right:.5rem}.pb-2{padding-bottom:.5rem}.pl-2{padding-left:.5rem}.pt-3{padding-top:.75rem}.pr-3{padding-right:.75rem}.pb-3{padding-bottom:.75rem}.pl-3{padding-left:.75rem}.pt-4{padding-top:1rem}.pr-4{padding-right:1rem}.pb-4{padding-bottom:1rem}.pl-4{padding-left:1rem}.pt-5{padding-top:1.25rem}.pb-5{padding-bottom:1.25rem}.pl-5{padding-left:1.25rem}.pt-6{padding-top:1.5rem}.pr-6{padding-right:1.5rem}.pb-6{padding-bottom:1.5rem}.pl-6{padding-left:1.5rem}.pt-7{padding-top:1.75rem}.pt-8{padding-top:2rem}.pb-8{padding-bottom:2rem}.pl-8{padding-left:2rem}.pt-10{padding-top:2.5rem}.pl-10{padding-left:2.5rem}.pr-12{padding-right:3rem}.pb-12{padding-bottom:3rem}.pl-16{padding-left:4rem}.pt-0\.5{padding-top:.125rem}.pl-0\.5{padding-left:.125rem}.pt-1\.5{padding-top:.375rem}.pb-1\.5{padding-bottom:.375rem}.pointer-events-none{pointer-events:none}.static{position:static}.fixed{position:fixed}.absolute{position:absolute}.relative{position:relative}.sticky{position:-webkit-sticky;position:sticky}.inset-0{right:0;left:0}.inset-0,.inset-y-0{top:0;bottom:0}.top-0{top:0}.right-0{right:0}.left-0{left:0}.bottom-2{bottom:.5rem}.top-8{top:2rem}.resize{resize:both}.shadow-xs{-webkit-box-shadow:0 0 0 1px rgba(0,0,0,.05);box-shadow:0 0 0 1px rgba(0,0,0,.05)}.shadow-sm{-webkit-box-shadow:0 1px 2px 0 rgba(0,0,0,.05);box-shadow:0 1px 2px 0 rgba(0,0,0,.05)}.shadow{-webkit-box-shadow:0 1px 3px 0 rgba(0,0,0,.1),0 1px 2px 0 rgba(0,0,0,.06);box-shadow:0 1px 3px 0 rgba(0,0,0,.1),0 1px 2px 0 rgba(0,0,0,.06)}.shadow-md{-webkit-box-shadow:0 4px 6px -1px rgba(0,0,0,.1),0 2px 4px -1px rgba(0,0,0,.06);box-shadow:0 4px 6px -1px rgba(0,0,0,.1),0 2px 4px -1px rgba(0,0,0,.06)}.shadow-lg{-webkit-box-shadow:0 10px 15px -3px rgba(0,0,0,.1),0 4px 6px -2px rgba(0,0,0,.05);box-shadow:0 10px 15px -3px rgba(0,0,0,.1),0 4px 6px -2px rgba(0,0,0,.05)}.shadow-xl{-webkit-box-shadow:0 20px 25px -5px rgba(0,0,0,.1),0 10px 10px -5px rgba(0,0,0,.04);box-shadow:0 20px 25px -5px rgba(0,0,0,.1),0 10px 10px -5px rgba(0,0,0,.04)}.shadow-inner{-webkit-box-shadow:inset 0 2px 4px 0 rgba(0,0,0,.06);box-shadow:inset 0 2px 4px 0 rgba(0,0,0,.06)}.hover\:shadow-md:hover{-webkit-box-shadow:0 4px 6px -1px rgba(0,0,0,.1),0 2px 4px -1px rgba(0,0,0,.06);box-shadow:0 4px 6px -1px rgba(0,0,0,.1),0 2px 4px -1px rgba(0,0,0,.06)}.focus\:shadow-lg:focus{-webkit-box-shadow:0 10px 15px -3px rgba(0,0,0,.1),0 4px 6px -2px rgba(0,0,0,.05);box-shadow:0 10px 15px -3px rgba(0,0,0,.1),0 4px 6px -2px rgba(0,0,0,.05)}.focus\:shadow-outline:focus{-webkit-box-shadow:0 0 0 3px rgba(118,169,250,.45);box-shadow:0 0 0 3px rgba(118,169,250,.45)}.focus\:shadow-outline-blue:focus{-webkit-box-shadow:0 0 0 3px rgba(164,202,254,.45);box-shadow:0 0 0 3px rgba(164,202,254,.45)}.focus\:shadow-outline-red:focus{-webkit-box-shadow:0 0 0 3px rgba(248,180,180,.45);box-shadow:0 0 0 3px rgba(248,180,180,.45)}.focus\:shadow-outline-indigo:focus{-webkit-box-shadow:0 0 0 3px rgba(180,198,252,.45);box-shadow:0 0 0 3px rgba(180,198,252,.45)}.fill-current{fill:currentColor}.table-fixed{table-layout:fixed}.text-left{text-align:left}.text-center{text-align:center}.text-right{text-align:right}.text-white{--text-opacity:1;color:#fff;color:rgba(255,255,255,var(--text-opacity))}.text-black{--text-opacity:1;color:#000;color:rgba(0,0,0,var(--text-opacity))}.text-gray-400{--text-opacity:1;color:#9fa6b2;color:rgba(159,166,178,var(--text-opacity))}.text-gray-500{--text-opacity:1;color:#6b7280;color:rgba(107,114,128,var(--text-opacity))}.text-gray-600{--text-opacity:1;color:#4b5563;color:rgba(75,85,99,var(--text-opacity))}.text-gray-700{--text-opacity:1;color:#374151;color:rgba(55,65,81,var(--text-opacity))}.text-gray-800{--text-opacity:1;color:#252f3f;color:rgba(37,47,63,var(--text-opacity))}.text-gray-900{--text-opacity:1;color:#161e2e;color:rgba(22,30,46,var(--text-opacity))}.text-red-400{--text-opacity:1;color:#f98080;color:rgba(249,128,128,var(--text-opacity))}.text-red-500{--text-opacity:1;color:#f05252;color:rgba(240,82,82,var(--text-opacity))}.text-red-600{--text-opacity:1;color:#e02424;color:rgba(224,36,36,var(--text-opacity))}.text-red-800{--text-opacity:1;color:#9b1c1c;color:rgba(155,28,28,var(--text-opacity))}.text-orange-400{--text-opacity:1;color:#ff8a4c;color:rgba(255,138,76,var(--text-opacity))}.text-orange-500{--text-opacity:1;color:#ff5a1f;color:rgba(255,90,31,var(--text-opacity))}.text-yellow-400{--text-opacity:1;color:#e3a008;color:rgba(227,160,8,var(--text-opacity))}.text-yellow-600{--text-opacity:1;color:#9f580a;color:rgba(159,88,10,var(--text-opacity))}.text-green-400{--text-opacity:1;color:#31c48d;color:rgba(49,196,141,var(--text-opacity))}.text-green-600{--text-opacity:1;color:#057a55;color:rgba(5,122,85,var(--text-opacity))}.text-green-800{--text-opacity:1;color:#03543f;color:rgba(3,84,63,var(--text-opacity))}.text-teal-400{--text-opacity:1;color:#16bdca;color:rgba(22,189,202,var(--text-opacity))}.text-teal-700{--text-opacity:1;color:#036672;color:rgba(3,102,114,var(--text-opacity))}.text-teal-800{--text-opacity:1;color:#05505c;color:rgba(5,80,92,var(--text-opacity))}.text-blue-400{--text-opacity:1;color:#76a9fa;color:rgba(118,169,250,var(--text-opacity))}.text-blue-500{--text-opacity:1;color:#3f83f8;color:rgba(63,131,248,var(--text-opacity))}.text-blue-700{--text-opacity:1;color:#1a56db;color:rgba(26,86,219,var(--text-opacity))}.text-blue-800{--text-opacity:1;color:#1e429f;color:rgba(30,66,159,var(--text-opacity))}.text-indigo-100{--text-opacity:1;color:#e5edff;color:rgba(229,237,255,var(--text-opacity))}.text-indigo-400{--text-opacity:1;color:#8da2fb;color:rgba(141,162,251,var(--text-opacity))}.text-indigo-500{--text-opacity:1;color:#6875f5;color:rgba(104,117,245,var(--text-opacity))}.text-indigo-600{--text-opacity:1;color:#5850ec;color:rgba(88,80,236,var(--text-opacity))}.text-indigo-700{--text-opacity:1;color:#5145cd;color:rgba(81,69,205,var(--text-opacity))}.text-indigo-800{--text-opacity:1;color:#42389d;color:rgba(66,56,157,var(--text-opacity))}.group:hover .group-hover\:text-gray-900{--text-opacity:1;color:#161e2e;color:rgba(22,30,46,var(--text-opacity))}.group:hover .group-hover\:text-indigo-800{--text-opacity:1;color:#42389d;color:rgba(66,56,157,var(--text-opacity))}.group:focus .group-focus\:text-gray-900{--text-opacity:1;color:#161e2e;color:rgba(22,30,46,var(--text-opacity))}.group:focus .group-focus\:text-indigo-800{--text-opacity:1;color:#42389d;color:rgba(66,56,157,var(--text-opacity))}.hover\:text-white:hover{--text-opacity:1;color:#fff;color:rgba(255,255,255,var(--text-opacity))}.hover\:text-gray-800:hover{--text-opacity:1;color:#252f3f;color:rgba(37,47,63,var(--text-opacity))}.hover\:text-gray-900:hover{--text-opacity:1;color:#161e2e;color:rgba(22,30,46,var(--text-opacity))}.hover\:text-blue-700:hover{--text-opacity:1;color:#1a56db;color:rgba(26,86,219,var(--text-opacity))}.hover\:text-indigo-500:hover{--text-opacity:1;color:#6875f5;color:rgba(104,117,245,var(--text-opacity))}.focus\:text-gray-900:focus{--text-opacity:1;color:#161e2e;color:rgba(22,30,46,var(--text-opacity))}.active\:text-indigo-600:active{--text-opacity:1;color:#5850ec;color:rgba(88,80,236,var(--text-opacity))}.text-opacity-75{--text-opacity:0.75}.italic{font-style:italic}.not-italic{font-style:normal}.uppercase{text-transform:uppercase}.lowercase{text-transform:lowercase}.underline{text-decoration:underline}.no-underline{text-decoration:none}.hover\:underline:hover{text-decoration:underline}.antialiased{-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.tracking-wide{letter-spacing:.025em}.tracking-wider{letter-spacing:.05em}.select-none{-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.select-all{-webkit-user-select:all;-moz-user-select:all;-ms-user-select:all;user-select:all}.align-middle{vertical-align:middle}.align-bottom{vertical-align:bottom}.visible{visibility:visible}.whitespace-no-wrap{white-space:nowrap}.break-words{word-wrap:break-word;overflow-wrap:break-word}.break-all{word-break:break-all}.truncate{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.w-0{width:0}.w-2{width:.5rem}.w-3{width:.75rem}.w-4{width:1rem}.w-5{width:1.25rem}.w-6{width:1.5rem}.w-7{width:1.75rem}.w-8{width:2rem}.w-12{width:3rem}.w-24{width:6rem}.w-40{width:10rem}.w-56{width:14rem}.w-auto{width:auto}.w-1\.5{width:.375rem}.w-2\.5{width:.625rem}.w-1\/2{width:50%}.w-1\/3{width:33.333333%}.w-2\/3{width:66.666667%}.w-1\/4{width:25%}.w-2\/4{width:50%}.w-3\/4{width:75%}.w-1\/5{width:20%}.w-2\/5{width:40%}.w-3\/5{width:60%}.w-4\/5{width:80%}.w-3\/6{width:50%}.w-4\/6{width:66.666667%}.w-5\/6{width:83.333333%}.w-1\/12{width:8.333333%}.w-2\/12{width:16.666667%}.w-3\/12{width:25%}.w-4\/12{width:33.333333%}.w-5\/12{width:41.666667%}.w-9\/12{width:75%}.w-10\/12{width:83.333333%}.w-11\/12{width:91.666667%}.w-full{width:100%}.z-20{z-index:20}.z-40{z-index:40}.z-50{z-index:50}.gap-8{grid-gap:2rem;gap:2rem}.grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}.transform{--transform-translate-x:0;--transform-translate-y:0;--transform-rotate:0;--transform-skew-x:0;--transform-skew-y:0;--transform-scale-x:1;--transform-scale-y:1;-webkit-transform:translateX(var(--transform-translate-x)) translateY(var(--transform-translate-y)) rotate(var(--transform-rotate)) skewX(var(--transform-skew-x)) skewY(var(--transform-skew-y)) scaleX(var(--transform-scale-x)) scaleY(var(--transform-scale-y));transform:translateX(var(--transform-translate-x)) translateY(var(--transform-translate-y)) rotate(var(--transform-rotate)) skewX(var(--transform-skew-x)) skewY(var(--transform-skew-y)) scaleX(var(--transform-scale-x)) scaleY(var(--transform-scale-y))}.origin-top-right{-webkit-transform-origin:top right;transform-origin:top right}.scale-95{--transform-scale-x:.95;--transform-scale-y:.95}.scale-100{--transform-scale-x:1;--transform-scale-y:1}.transition-all{-webkit-transition-property:all;transition-property:all}.transition{-webkit-transition-property:background-color,border-color,color,fill,stroke,opacity,-webkit-box-shadow,-webkit-transform;transition-property:background-color,border-color,color,fill,stroke,opacity,-webkit-box-shadow,-webkit-transform;transition-property:background-color,border-color,color,fill,stroke,opacity,box-shadow,transform;transition-property:background-color,border-color,color,fill,stroke,opacity,box-shadow,transform,-webkit-box-shadow,-webkit-transform}.ease-in{-webkit-transition-timing-function:cubic-bezier(.4,0,1,1);transition-timing-function:cubic-bezier(.4,0,1,1)}.ease-out{-webkit-transition-timing-function:cubic-bezier(0,0,.2,1);transition-timing-function:cubic-bezier(0,0,.2,1)}.ease-in-out{-webkit-transition-timing-function:cubic-bezier(.4,0,.2,1);transition-timing-function:cubic-bezier(.4,0,.2,1)}.duration-75{-webkit-transition-duration:75ms;transition-duration:75ms}.duration-100{-webkit-transition-duration:.1s;transition-duration:.1s}.duration-150{-webkit-transition-duration:.15s;transition-duration:.15s}.duration-300{-webkit-transition-duration:.3s;transition-duration:.3s}@-webkit-keyframes spin{to{-webkit-transform:rotate(1turn);transform:rotate(1turn)}}@keyframes spin{to{-webkit-transform:rotate(1turn);transform:rotate(1turn)}}@keyframes ping{75%,to{-webkit-transform:scale(2);transform:scale(2);opacity:0}}@keyframes pulse{50%{opacity:.5}}@keyframes bounce{0%,to{-webkit-transform:translateY(-25%);transform:translateY(-25%);-webkit-animation-timing-function:cubic-bezier(.8,0,1,1);animation-timing-function:cubic-bezier(.8,0,1,1)}50%{-webkit-transform:none;transform:none;-webkit-animation-timing-function:cubic-bezier(0,0,.2,1);animation-timing-function:cubic-bezier(0,0,.2,1)}}.animate-ping{-webkit-animation:ping 1s cubic-bezier(0,0,.2,1) infinite;animation:ping 1s cubic-bezier(0,0,.2,1) infinite}.animate-pulse{-webkit-animation:pulse 2s cubic-bezier(.4,0,.6,1) infinite;animation:pulse 2s cubic-bezier(.4,0,.6,1) infinite}@media (min-width:640px){.sm\:space-y-0>:not(template)~:not(template){--space-y-reverse:0;margin-top:calc(0px*(1 - var(--space-y-reverse)));margin-bottom:calc(0px*var(--space-y-reverse))}.sm\:space-y-3>:not(template)~:not(template){--space-y-reverse:0;margin-top:calc(0.75rem*(1 - var(--space-y-reverse)));margin-bottom:calc(0.75rem*var(--space-y-reverse))}.sm\:space-x-4>:not(template)~:not(template){--space-x-reverse:0;margin-right:calc(1rem*var(--space-x-reverse));margin-left:calc(1rem*(1 - var(--space-x-reverse)))}.sm\:rounded-md{border-radius:.375rem}.sm\:rounded-lg{border-radius:.5rem}.sm\:flex{display:-webkit-box;display:-ms-flexbox;display:flex}.sm\:grid{display:grid}.sm\:flex-row-reverse{-webkit-box-orient:horizontal;-webkit-box-direction:reverse;-ms-flex-direction:row-reverse;flex-direction:row-reverse}.sm\:items-start{-webkit-box-align:start;-ms-flex-align:start;align-items:flex-start}.sm\:items-center{-webkit-box-align:center;-ms-flex-align:center;align-items:center}.sm\:h-10{height:2.5rem}.sm\:text-sm{font-size:.875rem}.sm\:text-2xl{font-size:1.5rem}.sm\:text-3xl{font-size:1.875rem}.sm\:leading-5{line-height:1.25rem}.sm\:leading-7{line-height:1.75rem}.sm\:leading-9{line-height:2.25rem}.sm\:my-0{margin-top:0;margin-bottom:0}.sm\:mx-0{margin-left:0;margin-right:0}.sm\:my-7{margin-top:1.75rem;margin-bottom:1.75rem}.sm\:my-8{margin-top:2rem;margin-bottom:2rem}.sm\:my-12{margin-top:3rem;margin-bottom:3rem}.sm\:mt-0{margin-top:0}.sm\:ml-3{margin-left:.75rem}.sm\:ml-4{margin-left:1rem}.sm\:mt-5{margin-top:1.25rem}.sm\:max-w-lg{max-width:32rem}.sm\:p-6{padding:1.5rem}.sm\:px-0{padding-left:0;padding-right:0}.sm\:px-2{padding-left:.5rem;padding-right:.5rem}.sm\:px-4{padding-left:1rem;padding-right:1rem}.sm\:px-6{padding-left:1.5rem;padding-right:1.5rem}.sm\:pb-4{padding-bottom:1rem}.sm\:text-left{text-align:left}.sm\:align-middle{vertical-align:middle}.sm\:truncate{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.sm\:w-10{width:2.5rem}.sm\:w-32{width:8rem}.sm\:w-auto{width:auto}.sm\:w-1\/2{width:50%}.sm\:w-1\/3{width:33.333333%}.sm\:w-2\/3{width:66.666667%}.sm\:w-full{width:100%}.sm\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.sm\:grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}}@media (min-width:768px){.md\:rounded-lg{border-radius:.5rem}.md\:flex{display:-webkit-box;display:-ms-flexbox;display:flex}.md\:items-start{-webkit-box-align:start;-ms-flex-align:start;align-items:flex-start}.md\:items-center{-webkit-box-align:center;-ms-flex-align:center;align-items:center}.md\:justify-between{-webkit-box-pack:justify;-ms-flex-pack:justify;justify-content:space-between}.md\:text-base{font-size:1rem}.md\:mx-0{margin-left:0;margin-right:0}.md\:my-2{margin-top:.5rem;margin-bottom:.5rem}.md\:mx-auto{margin-left:auto;margin-right:auto}.md\:mt-0{margin-top:0}.md\:ml-2{margin-left:.5rem}.md\:ml-4{margin-left:1rem}.md\:ml-8{margin-left:2rem}.md\:-mr-8{margin-right:-2rem}.md\:max-w-xl{max-width:36rem}.md\:max-w-5xl{max-width:64rem}.md\:p-2{padding:.5rem}.md\:p-6{padding:1.5rem}.md\:py-0{padding-top:0;padding-bottom:0}.md\:px-1{padding-left:.25rem;padding-right:.25rem}.md\:px-2{padding-left:.5rem;padding-right:.5rem}.md\:py-5{padding-top:1.25rem;padding-bottom:1.25rem}.md\:px-8{padding-left:2rem;padding-right:2rem}.md\:pb-2{padding-bottom:.5rem}.md\:pr-4{padding-right:1rem}.md\:pt-6{padding-top:1.5rem}.md\:shadow-xl{-webkit-box-shadow:0 20px 25px -5px rgba(0,0,0,.1),0 10px 10px -5px rgba(0,0,0,.04);box-shadow:0 20px 25px -5px rgba(0,0,0,.1),0 10px 10px -5px rgba(0,0,0,.04)}.md\:w-3\/5{width:60%}}@media (min-width:1024px){.lg\:bg-transparent{background-color:transparent}.lg\:border-transparent{border-color:transparent}.lg\:rounded-full{border-radius:9999px}.lg\:block{display:block}.lg\:flex{display:-webkit-box;display:-ms-flexbox;display:flex}.lg\:inline-flex{display:-webkit-inline-box;display:-ms-inline-flexbox;display:inline-flex}.lg\:text-sm{font-size:.875rem}.lg\:text-lg{font-size:1.125rem}.lg\:my-0{margin-top:0;margin-bottom:0}.lg\:mx-5{margin-left:1.25rem;margin-right:1.25rem}.lg\:my-24{margin-top:6rem;margin-bottom:6rem}.lg\:mx-auto{margin-left:auto;margin-right:auto}.lg\:ml-16{margin-left:4rem}.lg\:-mr-16{margin-right:-4rem}.lg\:max-w-3xl{max-width:48rem}.lg\:p-6{padding:1.5rem}.lg\:p-8{padding:2rem}.lg\:px-3{padding-left:.75rem;padding-right:.75rem}.lg\:px-4{padding-left:1rem;padding-right:1rem}.lg\:px-8{padding-left:2rem;padding-right:2rem}.lg\:pt-2{padding-top:.5rem}.lg\:pb-2{padding-bottom:.5rem}.lg\:pl-2{padding-left:.5rem}.lg\:top-1\/2{top:50%}.lg\:shadow-none{-webkit-box-shadow:none;box-shadow:none}.lg\:w-40{width:10rem}.lg\:w-48{width:12rem}.lg\:w-1\/2{width:50%}.lg\:w-3\/5{width:60%}.lg\:w-3\/12{width:25%}.lg\:w-7\/12{width:58.333333%}}@media (min-width:1280px){.xl\:mx-7{margin-left:1.75rem;margin-right:1.75rem}.xl\:mr-0{margin-right:0}.xl\:ml-3{margin-left:.75rem}.xl\:ml-4{margin-left:1rem}.xl\:ml-20{margin-left:5rem}.xl\:max-w-4xl{max-width:56rem}.xl\:px-4{padding-left:1rem;padding-right:1rem}.xl\:pb-4{padding-bottom:1rem}.xl\:top-1\/3{top:33.333333%}.xl\:w-1\/4{width:25%}.xl\:w-2\/5{width:40%}.xl\:w-3\/5{width:60%}.xl\:w-2\/12{width:16.666667%}.xl\:w-7\/12{width:58.333333%}}
lite/admin/dist/main.js CHANGED
@@ -1 +1 @@
1
- !function(r){var n={};function o(e){if(n[e])return n[e].exports;var t=n[e]={i:e,l:!1,exports:{}};return r[e].call(t.exports,t,t.exports,o),t.l=!0,t.exports}o.m=r,o.c=n,o.d=function(e,t,r){o.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:r})},o.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},o.t=function(t,e){if(1&e&&(t=o(t)),8&e)return t;if(4&e&&"object"==typeof t&&t&&t.__esModule)return t;var r=Object.create(null);if(o.r(r),Object.defineProperty(r,"default",{enumerable:!0,value:t}),2&e&&"string"!=typeof t)for(var n in t)o.d(r,n,function(e){return t[e]}.bind(null,n));return r},o.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return o.d(t,"a",t),t},o.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},o.p="",o(o.s=0)}([function(e,t,r){"use strict";r.r(t);r(1)},function(e,t,r){}]);
1
+ !function(r){var n={};function o(e){if(n[e])return n[e].exports;var t=n[e]={i:e,l:!1,exports:{}};return r[e].call(t.exports,t,t.exports,o),t.l=!0,t.exports}o.m=r,o.c=n,o.d=function(e,t,r){o.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:r})},o.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},o.t=function(t,e){if(1&e&&(t=o(t)),8&e)return t;if(4&e&&"object"==typeof t&&t&&t.__esModule)return t;var r=Object.create(null);if(o.r(r),Object.defineProperty(r,"default",{enumerable:!0,value:t}),2&e&&"string"!=typeof t)for(var n in t)o.d(r,n,function(e){return t[e]}.bind(null,n));return r},o.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return o.d(t,"a",t),t},o.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},o.p="",o(o.s=0)}([function(e,t,r){"use strict";r.r(t);t=r(1)},function(e,t,r){}]);
lite/admin/js/email-subscribers-admin.js CHANGED
@@ -96,8 +96,8 @@
96
  jQuery(".es-audience-view .bulkactions #bulk-action-selector-top").after(statusselect);
97
  jQuery(".es-audience-view .bulkactions #bulk-action-selector-top").after(groupselect);
98
 
99
- //jQuery(".es-audience-view .bulkactions #bulk-action-selector-bottom").after(statusselect);
100
- // jQuery(".es-audience-view .bulkactions #bulk-action-selector-bottom").after(groupselect);
101
 
102
  jQuery("#bulk-action-selector-top").change(function () {
103
  if (jQuery('option:selected', this).attr('value') == 'bulk_list_update' || jQuery('option:selected', this).attr('value') == 'bulk_list_add') {
96
  jQuery(".es-audience-view .bulkactions #bulk-action-selector-top").after(statusselect);
97
  jQuery(".es-audience-view .bulkactions #bulk-action-selector-top").after(groupselect);
98
 
99
+ jQuery('.groupsselect').hide();
100
+ jQuery('.statusesselect').hide();
101
 
102
  jQuery("#bulk-action-selector-top").change(function () {
103
  if (jQuery('option:selected', this).attr('value') == 'bulk_list_update' || jQuery('option:selected', this).attr('value') == 'bulk_list_add') {
lite/admin/js/subscribers.js ADDED
@@ -0,0 +1,280 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ jQuery(document).ready(function ($) {
2
+ "use strict"
3
+
4
+ let importstatus = $('.step1 .import-status'),
5
+ progress = $('#progress'),
6
+ progressbar = progress.find('.bar'),
7
+ importprogress = $('#importing-progress'),
8
+ importprogressbar = importprogress.find('.bar'),
9
+ import_percentage = importprogress.find('.import_percentage'),
10
+ wpnonce = ig_es_subscribers_data.security,
11
+ importerrors = 0,
12
+ importstarttime,
13
+ importidentifier,
14
+
15
+ uploader_init = function () {
16
+ let uploader = new plupload.Uploader(wpUploaderInit);
17
+
18
+ uploader.bind('Init', function (up) {
19
+ let uploaddiv = $('#plupload-upload-ui');
20
+
21
+ if (up.features.dragdrop && !$(document.body).hasClass('mobile')) {
22
+ uploaddiv.addClass('drag-drop');
23
+ $('#drag-drop-area').bind('dragover.wp-uploader', function () { // dragenter doesn't fire right :(
24
+ uploaddiv.addClass('drag-over');
25
+ }).bind('dragleave.wp-uploader, drop.wp-uploader', function () {
26
+ uploaddiv.removeClass('drag-over');
27
+ });
28
+ } else {
29
+ uploaddiv.removeClass('drag-drop');
30
+ $('#drag-drop-area').unbind('.wp-uploader');
31
+ }
32
+
33
+ });
34
+
35
+ uploader.bind('FilesAdded', function (up, files) {
36
+ $('#media-upload-error').html('');
37
+
38
+ setTimeout(function () {
39
+ up.refresh();
40
+ up.start();
41
+ }, 1);
42
+
43
+ });
44
+
45
+ uploader.bind('BeforeUpload', function (up, file) {
46
+ progress.removeClass('finished error hidden');
47
+ importstatus.show().removeClass('text-red-600');
48
+ importstatus.html('Uploading');
49
+ });
50
+
51
+ uploader.bind('UploadFile', function (up, file) {});
52
+
53
+ uploader.bind('UploadProgress', function (up, file) {
54
+ importstatus.show().removeClass('text-red-600');
55
+ importstatus.html(sprintf(ig_es_subscribers_data.i18n.uploading, file.percent + '%'));
56
+ progressbar.stop().animate({
57
+ 'width': file.percent + '%'
58
+ }, 100);
59
+ });
60
+
61
+ uploader.bind('Error', function (up, err) {
62
+ importstatus.show().addClass('text-red-600 text-base font-medium');
63
+ importstatus.html(err.message);
64
+ progress.addClass('error');
65
+ up.refresh();
66
+ });
67
+
68
+ uploader.bind('FileUploaded', function (up, file, response) {
69
+ response = $.parseJSON(response.response);
70
+ importidentifier = response.identifier;
71
+ if (!response.success) {
72
+ importstatus.html(response.message);
73
+ progress.addClass('error');
74
+ up.refresh();
75
+ uploader.unbind('UploadComplete');
76
+ }
77
+ });
78
+
79
+ uploader.bind('UploadComplete', function (up, files) {
80
+ importstatus.removeClass('text-red-600').html(ig_es_subscribers_data.i18n.prepare_data);
81
+ progress.addClass('finished');
82
+ get_import_data();
83
+ });
84
+
85
+ uploader.init();
86
+ }
87
+
88
+ let get_import_data = function () {
89
+
90
+ progress.removeClass('finished error');
91
+
92
+ $.post( ajaxurl, {
93
+ action: 'ig_es_get_import_data',
94
+ identifier: importidentifier,
95
+ security: wpnonce,
96
+ dataType: 'json'
97
+ }, function( response ) {
98
+ progress.addClass('hidden');
99
+
100
+ $('.step1').slideUp();
101
+ $('.step2-body').html(response.html).parent().show();
102
+ $('.step2-status,.step2-list').show();
103
+
104
+ importstatus.html('');
105
+ });
106
+ }
107
+
108
+ let start_import = function(e) {
109
+
110
+ e.preventDefault();
111
+
112
+ let is_email_field_set = false;
113
+ let mapping_order = [];
114
+ $('select[name="mapping_order[]"').each(function(){
115
+ let mapped_field = $(this).val();
116
+ mapping_order.push(mapped_field);
117
+ if ( 'email' === mapped_field ) {
118
+ is_email_field_set = true;
119
+ }
120
+ });
121
+
122
+
123
+ if ( ! is_email_field_set ) {
124
+ alert(ig_es_subscribers_data.i18n.select_emailcolumn);
125
+ return false;
126
+ }
127
+
128
+ let status = $('#es_email_status').val();
129
+ if ( '' === status || '0' === status ) {
130
+ alert(ig_es_subscribers_data.i18n.select_status);
131
+ return false;
132
+ }
133
+
134
+ let list_id = $('#list_id').val();
135
+
136
+ if ( ! confirm(ig_es_subscribers_data.i18n.confirm_import) ) {
137
+ return false;
138
+ }
139
+
140
+ let _this = $('.start-import').prop('disabled', true),
141
+ loader = $('#import-ajax-loading').css({
142
+ 'display': 'inline-block'
143
+ }),
144
+ identifier = $('#identifier').val(),
145
+ performance = $('#performance').is(':checked') ? 'yes' : 'no';
146
+
147
+ progress.removeClass('hidden');
148
+ progressbar.stop().width(0);
149
+ $('.step1').slideUp();
150
+ $('.step2-body').html('<br><br>').parent().show();
151
+ $('.step2-status,.step2-list, .es-import-processing ').hide();
152
+
153
+ importstarttime = new Date();
154
+
155
+ do_import(0, {
156
+ identifier: identifier,
157
+ mapping_order: mapping_order,
158
+ list_id: list_id,
159
+ status: status,
160
+ performance: performance
161
+ });
162
+
163
+ importstatus = $('.step2 .import-status');
164
+
165
+ importstatus.html(ig_es_subscribers_data.i18n.prepare_import);
166
+
167
+ window.onbeforeunload = function () {
168
+ return ig_es_subscribers_data.i18n.onbeforeunloadimport;
169
+ };
170
+ }
171
+
172
+ let do_import = function(id, options) {
173
+ let percentage = 0;
174
+ importprogress.removeClass('hidden');
175
+ $.ajax({
176
+ type: 'POST',
177
+ url: ajaxurl,
178
+ dataType: 'json',
179
+ data: {
180
+ action: 'ig_es_do_import',
181
+ id: id,
182
+ options: options,
183
+ security: wpnonce,
184
+ },
185
+ success: function( response ) {
186
+ percentage = (Math.min(1, (response.imported + response.errors) / response.total) * 100);
187
+
188
+ $('.step2-body').html('<p class="pt-3 pb-2 text-sm text-gray-600">' + get_stats(response.f_imported, response.f_errors, response.f_total, percentage, response.memoryusage) + '</p>');
189
+ $('.step2-status,.step2-list, .es-import-processing').hide();
190
+ importerrors = 0;
191
+ let finished = percentage >= 100;
192
+
193
+ if (response.success) {
194
+
195
+ if (!finished) do_import(id + 1, options);
196
+
197
+ importprogressbar.animate({
198
+ 'width': (percentage) + '%'
199
+ }, {
200
+ duration: 1000,
201
+ easing: 'swing',
202
+ queue: false,
203
+ step: function (percentage) {
204
+ importstatus.show().addClass('text-lg').html( sprintf(ig_es_subscribers_data.i18n.import_contacts, '' ) );
205
+ $('.import-instruction').html( ig_es_subscribers_data.i18n.no_windowclose );
206
+ import_percentage.html( Math.ceil(percentage) + '%' );
207
+ },
208
+ complete: function () {
209
+ if (finished) {
210
+ window.onbeforeunload = null;
211
+ $('.import-instruction').hide();
212
+ importprogress.addClass('finished');
213
+ $('.step2-body').html(response.html).slideDown();
214
+ $('.step2-status,.step2-list,.es-import-processing').hide();
215
+ importstatus.addClass('text-xl');
216
+ importstatus.html(sprintf(ig_es_subscribers_data.i18n.import_complete,'<svg class=" w-6 h-6 inline-block text-indigo-600" fill="currentColor" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zm3.707-9.293a1 1 0 00-1.414-1.414L9 10.586 7.707 9.293a1 1 0 00-1.414 1.414l2 2a1 1 0 001.414 0l4-4z" clip-rule="evenodd"></path></svg>'));
217
+ }
218
+ }
219
+ });
220
+ } else {
221
+ import_error_handler(percentage, id, options);
222
+ }
223
+ },
224
+ error: function(jqXHR, textStatus, errorThrown) {
225
+ import_error_handler(percentage, id, options);
226
+ }
227
+ });
228
+ }
229
+
230
+ let get_stats = function(imported, errors, total, percentage, memoryusage) {
231
+ let timepast = new Date().getTime() - importstarttime.getTime(),
232
+ timeleft = Math.ceil(((100 - percentage) * (timepast / percentage)) / 60000);
233
+
234
+ return sprintf(ig_es_subscribers_data.i18n.current_stats, '<span class="font-medium">' + imported + '</span>', '<span class="font-medium">' + total + '</span>', '<span class="font-medium">' + errors + '</span>', '<span class="font-medium">' + memoryusage + '</span>') + '<br>' +
235
+ sprintf(ig_es_subscribers_data.i18n.estimate_time, timeleft);
236
+ }
237
+
238
+ let import_error_handler = function(percentage, id, options) {
239
+ importerrors++;
240
+ if (importerrors >= 5) {
241
+
242
+ alert(ig_es_subscribers_data.i18n.error_importing);
243
+ importstatus.html(sprintf(ig_es_subscribers_data.i18n.import_failed, '<svg class=" w-6 h-6 inline-block text-red-600" fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10 14l2-2m0 0l2-2m-2 2l-2-2m2 2l2 2m7-2a9 9 0 11-18 0 9 9 0 0118 0z"></path></svg>'));
244
+ window.onbeforeunload = null;
245
+ return;
246
+ }
247
+
248
+ let i = importerrors * 5,
249
+ str = '',
250
+ errorint = setInterval(function () {
251
+ if (i <= 0) {
252
+ clearInterval(errorint);
253
+ progress.removeClass('paused');
254
+ do_import(id, options);
255
+ } else {
256
+ progress.addClass('paused');
257
+ str = '<span class="error">' + sprintf(ig_es_subscribers_data.i18n.continues_in, (i--)) + '</span>';
258
+ }
259
+ importstatus.html(sprintf(ig_es_subscribers_data.i18n.import_contacts, str));
260
+ }, 1000);
261
+ }
262
+
263
+ let sprintf = function() {
264
+ let a = Array.prototype.slice.call(arguments),
265
+ str = a.shift(),
266
+ total = a.length,
267
+ reg;
268
+ for (let i = 0; i < total; i++) {
269
+ reg = new RegExp('%(' + (i + 1) + '\\$)?(s|d|f)');
270
+ str = str.replace(reg, a[i]);
271
+ }
272
+ return str;
273
+ }
274
+
275
+ if ( 'object' === typeof (wpUploaderInit) ) {
276
+ uploader_init();
277
+ }
278
+
279
+ $('#form_import_subscribers').on('submit', start_import );
280
+ });
lite/includes/class-email-subscribers.php CHANGED
@@ -246,6 +246,24 @@ if ( ! class_exists( 'Email_Subscribers' ) ) {
246
  */
247
  public $mailer;
248
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
249
  /**
250
  * The loader that's responsible for maintaining and registering all hooks that power
251
  * the plugin.
@@ -620,6 +638,8 @@ if ( ! class_exists( 'Email_Subscribers' ) ) {
620
  'lite/includes/class-email-subscribers-loader.php',
621
  'lite/includes/class-email-subscribers-i18n.php',
622
 
 
 
623
  // Logs
624
  'lite/includes/logs/class-ig-logger-interface.php',
625
  'lite/includes/logs/class-ig-log-handler-interface.php',
@@ -952,6 +972,17 @@ if ( ! class_exists( 'Email_Subscribers' ) ) {
952
  }
953
  }
954
 
 
 
 
 
 
 
 
 
 
 
 
955
  /**
956
  * Method to get if trial has expired or not.
957
  *
@@ -993,9 +1024,7 @@ if ( ! class_exists( 'Email_Subscribers' ) ) {
993
  public function is_trial_valid() {
994
 
995
  // Check if user has opted for trial and it has not yet expired.
996
- $is_trial_valid = $this->is_trial() && ! $this->is_trial_expired() ? true : false;
997
-
998
- return $is_trial_valid;
999
  }
1000
 
1001
  /**
246
  */
247
  public $mailer;
248
 
249
+ /**
250
+ * IG_ES_Trail object
251
+ *
252
+ * @var object|IG_ES_Trial
253
+ *
254
+ * @since 4.6.6
255
+ */
256
+ public $trial;
257
+
258
+ /**
259
+ * IG_ES_DB_WC_Cart object
260
+ *
261
+ * @var object|IG_ES_DB_WC_Cart
262
+ *
263
+ * @since 4.6.6
264
+ */
265
+ public $carts_db;
266
+
267
  /**
268
  * The loader that's responsible for maintaining and registering all hooks that power
269
  * the plugin.
638
  'lite/includes/class-email-subscribers-loader.php',
639
  'lite/includes/class-email-subscribers-i18n.php',
640
 
641
+ 'lite/includes/classes/class-es-list-table.php',
642
+
643
  // Logs
644
  'lite/includes/logs/class-ig-logger-interface.php',
645
  'lite/includes/logs/class-ig-log-handler-interface.php',
972
  }
973
  }
974
 
975
+ /**
976
+ * Get trial start date
977
+ *
978
+ * @return false|mixed|void
979
+ *
980
+ * @since 4.6.6
981
+ */
982
+ public function get_trial_start_date() {
983
+ return get_option( 'ig_es_trial_started_at', '' );
984
+ }
985
+
986
  /**
987
  * Method to get if trial has expired or not.
988
  *
1024
  public function is_trial_valid() {
1025
 
1026
  // Check if user has opted for trial and it has not yet expired.
1027
+ return $this->is_trial() && ! $this->is_trial_expired();
 
 
1028
  }
1029
 
1030
  /**
lite/includes/class-es-common.php CHANGED
@@ -119,61 +119,54 @@ class ES_Common {
119
  // Convert URL HTML back to URL itself if it a current post URL.
120
  $html = $url;
121
  } else {
 
122
  if ( ! class_exists( 'WP_oEmbed' ) ) {
123
  require_once ABSPATH . 'wp-includes/class-wp-oembed.php';
124
  }
125
 
126
- // Increase http response size to allow fetching of youtube pages which has large page size.
127
- add_filter( 'http_request_args', 'ig_es_increase_http_response_size' );
128
-
129
  $oembed = new WP_oEmbed();
130
- $provider = $oembed->discover( $url );
131
-
132
  if ( ! empty( $provider ) ) {
133
  $oembed_response = $oembed->fetch( $provider, $url, $attr );
134
- if ( is_object( $oembed_response ) && ! empty( $oembed_response->type ) && 'video' === $oembed_response->type ) {
135
  $thumbnail_url = $oembed_response->thumbnail_url;
136
- if ( ! empty( $thumbnail_url ) ) {
137
- $title = $oembed_response->title;
138
- $provider_name = $oembed_response->provider_name;
139
- $play_icon_url = '';
140
-
141
- switch ( $provider_name ) {
142
- case 'YouTube':
143
- $play_icon_url = ES_PLUGIN_URL . 'lite/public/images/youtube-play-button.png';
144
- break;
145
-
146
- case 'Vimeo':
147
- $play_icon_url = ES_PLUGIN_URL . 'lite/public/images/vimeo-play-button.png';
148
- break;
149
-
150
- default:
151
- $play_icon_url = ES_PLUGIN_URL . 'lite/public/images/default-play-button.png';
152
- break;
153
- }
154
-
155
- ob_start();
156
- $thumbnail_width = ! empty( $oembed_response->width ) ? $oembed_response->width . 'px' : 'auto';
157
- $thumbnail_height = ! empty( $oembed_response->height ) ? $oembed_response->height . 'px' : 'auto';
158
- ?>
159
- <table style="margin-bottom: 1em;">
160
- <tbody>
161
- <tr>
162
- <td style="background-image: url('<?php echo esc_url( $thumbnail_url ); ?>');height:<?php echo esc_attr( $thumbnail_height ); ?>;width:<?php echo esc_attr( $thumbnail_width ); ?>;background-size: 100% 100%;background-repeat: no-repeat;text-align:center;">
163
- <a href="<?php echo esc_url( $url ); ?>" title="<?php echo esc_attr( $title ); ?>" target="_blank">
164
- <img src="<?php echo esc_url( $play_icon_url ); ?>" style="height: 75px; margin: auto;">
165
- </a>
166
- </td>
167
- </tr>
168
- </tbody>
169
- </table>
170
- <?php
171
- $html = ob_get_clean();
172
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
173
  }
174
  }
175
-
176
- remove_filter( 'http_request_args', 'ig_es_increase_http_response_size' );
177
  }
178
 
179
  return $html;
@@ -1163,6 +1156,68 @@ class ES_Common {
1163
 
1164
  }
1165
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1166
  /**
1167
  * Get all ES settings
1168
  *
@@ -1179,7 +1234,13 @@ class ES_Common {
1179
 
1180
  $options_name_value_map = array();
1181
  if ( count( $results ) > 0 ) {
 
1182
  foreach ( $results as $result ) {
 
 
 
 
 
1183
  $options_name_value_map[ $result['option_name'] ] = $result['option_value'];
1184
  }
1185
  }
@@ -1198,18 +1259,26 @@ class ES_Common {
1198
 
1199
  $total_contacts = ES()->contacts_db->count();
1200
  $total_lists = ES()->lists_db->count_lists();
 
1201
  $total_newsletters = ES()->campaigns_db->get_total_newsletters();
1202
  $total_post_notifications = ES()->campaigns_db->get_total_post_notifications();
1203
-
1204
- $meta_info = array(
 
 
 
 
 
 
 
1205
  'total_contacts' => $total_contacts,
1206
  'total_lists' => $total_lists,
 
1207
  'total_newsletters' => $total_newsletters,
1208
- 'total_post_notifications' => $total_post_notifications,
 
1209
  'settings' => self::get_all_settings()
1210
  );
1211
-
1212
- return $meta_info;
1213
  }
1214
 
1215
  /**
@@ -1719,17 +1788,17 @@ class ES_Common {
1719
  $blog_url = get_bloginfo( 'url' );
1720
 
1721
  // If URI is like, eg. www.way2tutorial.com/
1722
- $blog_url = trim($blog_url, '/');
1723
 
1724
  // If not have http:// or https:// then prepend it
1725
- if (!preg_match('#^http(s)?://#', $blog_url)) {
1726
  $blog_url = 'http://' . $blog_url;
1727
  }
1728
 
1729
- $url_parts = parse_url($blog_url);
1730
 
1731
  // Remove www.
1732
- $domain = preg_replace('/^www\./', '', $url_parts['host']);
1733
 
1734
  $hash = self::generate_hash( 5 );
1735
 
@@ -1744,11 +1813,11 @@ class ES_Common {
1744
  * @since 4.6.0
1745
  */
1746
  public static function get_test_email() {
1747
- $mailbox_user = get_option('ig_es_test_mailbox_user', '');
1748
 
1749
- if (empty($mailbox_user)) {
1750
  $mailbox_user = self::generate_test_mailbox_user();
1751
- update_option('ig_es_test_mailbox_user', $mailbox_user);
1752
  }
1753
 
1754
  return $mailbox_user . '@box.icegram.com';
@@ -1759,7 +1828,7 @@ class ES_Common {
1759
  *
1760
  * @since 4.6.2
1761
  */
1762
- public static function upsell_description_message_box( $upsell_info = array(), $echo = true ) {
1763
  ob_start();
1764
  ?>
1765
  <div class="inline-flex rounded-md shadow bg-teal-50 px-2 pt-1 my-2 w-full font-sans">
@@ -1772,53 +1841,58 @@ class ES_Common {
1772
  </div>
1773
  <div class="ml-3">
1774
  <h3 class="text-sm leading-5 font-medium text-blue-800 hover:underline">
1775
- <?php
1776
  /* translators: 1: Anchor opening tag with href attribute 2: Target attribute 3: Anchor closing tag */
1777
- echo sprintf( esc_html__('%1$s' . esc_url( $upsell_info[ 'pricing_url' ] ) . '%2$s' . esc_html( $upsell_info['upgrade_title'] ) . '%3$s', 'email-subscribers' ) , '<a href="', '" target="_blank">', '</a>' );
1778
  ?>
1779
  </h3>
1780
  </div>
1781
  </div>
1782
  <div class="mt-2 ml-8 text-sm leading-5 text-teal-700">
1783
  <p>
1784
- <?php
1785
- $allowed_html_tags = ig_es_allowed_html_tags_in_esc();
1786
- if ( ! empty( $upsell_info[ 'upsell_message' ] ) ) {
1787
- echo wp_kses( $upsell_info[ 'upsell_message' ] , $allowed_html_tags );
1788
  }
1789
 
1790
- $timezone_format = _x( 'Y-m-d', 'timezone date format' );
1791
- $ig_current_date = strtotime( date_i18n( $timezone_format ) ) ;
1792
- if ( ( ( $ig_current_date < strtotime( '2020-11-24' ) ) || ( $ig_current_date > strtotime( '2020-12-02' ) ) ) && self::can_show_coupon('PREMIUM10')) {
1793
  ?>
1794
- <p class="mb-1 mt-3">
1795
- <?php
1796
- echo wp_kses_post( 'Upgrade now & get <b> 10% discount!</b> <br/><br/>Use coupon code:');
1797
  ?>
1798
-
1799
- <span class="ml-2 px-1.5 py-1 font-medium bg-yellow-100 rounded-md border-2 border-dotted border-indigo-300 select-all"><?php esc_html_e( 'PREMIUM10', 'email-subscribers' ); ?> </span>
1800
- </p>
1801
- <?php
1802
- }
1803
- if ( $upsell_info[ 'cta_html' ] ) {
1804
  ?>
1805
- <div class="pt-6 text-center -ml-6 pb-2">
1806
- <a href="<?php echo esc_url( $upsell_info[ 'pricing_url' ] ); ?>" target="_blank" class="rounded-md border border-transparent px-3 py-2 bg-white text-sm leading-7 font-medium text-white bg-indigo-600 hover:text-white hover:bg-indigo-500 transition ease-in-out duration-150 mt-2"><?php esc_html_e('Upgrade', 'email-subscribers'); ?></a>
1807
- </div>
1808
- <?php
1809
- }
 
 
 
 
 
1810
  ?>
1811
  </div>
1812
  </div>
1813
  </div>
1814
-
1815
- <?php
1816
- $message_html = ob_get_clean();
1817
- if ( $echo ) {
1818
- echo wp_kses( $message_html , $allowed_html_tags );
1819
- } else {
1820
- return $message_html;
1821
- }
1822
  }
1823
 
1824
  /**
@@ -1833,10 +1907,10 @@ class ES_Common {
1833
  */
1834
  public static function prepare_campaign_report_statuses_dropdown_options( $selected = '', $default_label = '' ) {
1835
 
1836
- $statuses = array(
1837
- 'Sent' => __( 'Completed', 'email-subscribers' ),
1838
  'In Queue' => __( 'In Queue', 'email-subscribers' ),
1839
- 'Sending' => __( 'Sending', 'email-subscribers' ),
1840
  );
1841
 
1842
  $dropdown = '<option class="text-sm" value="">' . esc_html__( 'All Status', 'email-subscribers' ) . '</option>';
119
  // Convert URL HTML back to URL itself if it a current post URL.
120
  $html = $url;
121
  } else {
122
+
123
  if ( ! class_exists( 'WP_oEmbed' ) ) {
124
  require_once ABSPATH . 'wp-includes/class-wp-oembed.php';
125
  }
126
 
 
 
 
127
  $oembed = new WP_oEmbed();
128
+ $provider = $oembed->get_provider( $url );
 
129
  if ( ! empty( $provider ) ) {
130
  $oembed_response = $oembed->fetch( $provider, $url, $attr );
131
+ if ( is_object( $oembed_response ) && ! empty( $oembed_response->type ) && 'video' === $oembed_response->type && ! empty( $oembed_response->thumbnail_url ) ) {
132
  $thumbnail_url = $oembed_response->thumbnail_url;
133
+ $title = $oembed_response->title;
134
+ $provider_name = $oembed_response->provider_name;
135
+ $play_icon_url = '';
136
+
137
+ switch ( $provider_name ) {
138
+ case 'YouTube':
139
+ $play_icon_url = ES_PLUGIN_URL . 'lite/public/images/youtube-play-button.png';
140
+ break;
141
+
142
+ case 'Vimeo':
143
+ $play_icon_url = ES_PLUGIN_URL . 'lite/public/images/vimeo-play-button.png';
144
+ break;
145
+
146
+ default:
147
+ $play_icon_url = ES_PLUGIN_URL . 'lite/public/images/default-play-button.png';
148
+ break;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
149
  }
150
+
151
+ ob_start();
152
+ $thumbnail_width = ! empty( $oembed_response->width ) ? $oembed_response->width . 'px' : 'auto';
153
+ $thumbnail_height = ! empty( $oembed_response->height ) ? $oembed_response->height . 'px' : 'auto';
154
+ ?>
155
+ <table style="margin-bottom: 1em;">
156
+ <tbody>
157
+ <tr>
158
+ <td style="background-image: url('<?php echo esc_url( $thumbnail_url ); ?>');height:<?php echo esc_attr( $thumbnail_height ); ?>;width:<?php echo esc_attr( $thumbnail_width ); ?>;background-size: 100% 100%;background-repeat: no-repeat;text-align:center;">
159
+ <a href="<?php echo esc_url( $url ); ?>" title="<?php echo esc_attr( $title ); ?>" target="_blank">
160
+ <img src="<?php echo esc_url( $play_icon_url ); ?>" style="height: 75px; margin: auto;">
161
+ </a>
162
+ </td>
163
+ </tr>
164
+ </tbody>
165
+ </table>
166
+ <?php
167
+ $html = ob_get_clean();
168
  }
169
  }
 
 
170
  }
171
 
172
  return $html;
1156
 
1157
  }
1158
 
1159
+ /**
1160
+ * Get all restricted settings which we can't share
1161
+ * @return array
1162
+ *
1163
+ * @since 4.6.6
1164
+ */
1165
+ public static function get_restricted_settings() {
1166
+
1167
+ return array(
1168
+ 'ig_es_admin_new_contact_email_content',
1169
+ 'ig_es_admin_emails',
1170
+ 'ig_es_admin_new_contact_email_subject',
1171
+ 'ig_es_admin_notices',
1172
+ 'ig_es_confirmation_mail_content',
1173
+ 'ig_es_confirmation_mail_subject',
1174
+ 'ig_es_coupons',
1175
+ 'ig_es_cron_admin_email',
1176
+ 'ig_es_cron_admin_email_subject',
1177
+ 'ig_es_cronurl',
1178
+ 'ig_es_current_version_date_details',
1179
+ 'ig_es_custom_admin_notice_bfcm_2019',
1180
+ 'ig_es_custom_admin_notice_covid_19',
1181
+ 'ig_es_custom_admin_notice_halloween_offer_2020',
1182
+ 'ig_es_db_update_history',
1183
+ 'ig_es_default_subscriber_imported',
1184
+ 'ig_es_feedback_data',
1185
+ 'ig_es_form_submission_success_message',
1186
+ 'ig_es_last_cron_run',
1187
+ 'ig_es_last_updated_blocked_domains',
1188
+ 'ig_es_mailer_settings',
1189
+ 'ig_es_ob_skip_email_receive_error',
1190
+ 'ig_es_offer_bfcm_done_2019',
1191
+ 'ig_es_offer_covid_19',
1192
+ 'ig_es_onboarding_test_campaign_error',
1193
+ 'ig_es_opt_in_consent_text',
1194
+ 'ig_es_optin_link',
1195
+ 'ig_es_optin_page',
1196
+ 'ig_es_send_email_action_response',
1197
+ 'ig_es_roles_and_capabilities',
1198
+ 'ig_es_send_email_action_response',
1199
+ 'ig_es_sent_report_content',
1200
+ 'ig_es_sent_report_subject',
1201
+ 'ig_es_set_widget',
1202
+ 'ig_es_show_opt_in_consent',
1203
+ 'ig_es_show_sync_tab',
1204
+ 'ig_es_subscription_error_messsage',
1205
+ 'ig_es_subscription_success_message',
1206
+ 'ig_es_sync_wp_users',
1207
+ 'ig_es_unsubscribe_error_message',
1208
+ 'ig_es_unsubscribe_link',
1209
+ 'ig_es_unsubscribe_link_content',
1210
+ 'ig_es_unsubscribe_page',
1211
+ 'ig_es_unsubscribe_success_message',
1212
+ 'ig_es_update_processed_tasks',
1213
+ 'ig_es_update_tasks_to_process',
1214
+ 'ig_es_welcome_email_content',
1215
+ 'ig_es_welcome_email_subject',
1216
+ 'ig_es_email_sent_data'
1217
+ );
1218
+
1219
+ }
1220
+
1221
  /**
1222
  * Get all ES settings
1223
  *
1234
 
1235
  $options_name_value_map = array();
1236
  if ( count( $results ) > 0 ) {
1237
+ $restricted_settings = self::get_restricted_settings();
1238
  foreach ( $results as $result ) {
1239
+
1240
+ if ( in_array( $result['option_name'], $restricted_settings ) ) {
1241
+ continue;
1242
+ }
1243
+
1244
  $options_name_value_map[ $result['option_name'] ] = $result['option_value'];
1245
  }
1246
  }
1259
 
1260
  $total_contacts = ES()->contacts_db->count();
1261
  $total_lists = ES()->lists_db->count_lists();
1262
+ $total_forms = ES()->forms_db->count_forms();
1263
  $total_newsletters = ES()->campaigns_db->get_total_newsletters();
1264
  $total_post_notifications = ES()->campaigns_db->get_total_post_notifications();
1265
+ $total_sequences = ES()->campaigns_db->get_total_sequences();
1266
+
1267
+ return array(
1268
+ 'version' => ES_PLUGIN_VERSION,
1269
+ 'is_premium' => ES()->is_premium() ? 'yes' : 'no',
1270
+ 'plan' => ES()->get_plan(),
1271
+ 'is_trial' => ES()->is_trial() ? 'yes' : 'no',
1272
+ 'is_trial_expired' => ES()->is_trial_expired() ? 'yes' : 'no',
1273
+ 'trial_start_at' => ES()->get_trial_start_date(),
1274
  'total_contacts' => $total_contacts,
1275
  'total_lists' => $total_lists,
1276
+ 'total_forms' => $total_forms,
1277
  'total_newsletters' => $total_newsletters,
1278
+ 'total_post_notifications' => $total_post_notifications,
1279
+ 'total_sequences' => $total_sequences,
1280
  'settings' => self::get_all_settings()
1281
  );
 
 
1282
  }
1283
 
1284
  /**
1788
  $blog_url = get_bloginfo( 'url' );
1789
 
1790
  // If URI is like, eg. www.way2tutorial.com/
1791
+ $blog_url = trim( $blog_url, '/' );
1792
 
1793
  // If not have http:// or https:// then prepend it
1794
+ if ( ! preg_match( '#^http(s)?://#', $blog_url ) ) {
1795
  $blog_url = 'http://' . $blog_url;
1796
  }
1797
 
1798
+ $url_parts = parse_url( $blog_url );
1799
 
1800
  // Remove www.
1801
+ $domain = preg_replace( '/^www\./', '', $url_parts['host'] );
1802
 
1803
  $hash = self::generate_hash( 5 );
1804
 
1813
  * @since 4.6.0
1814
  */
1815
  public static function get_test_email() {
1816
+ $mailbox_user = get_option( 'ig_es_test_mailbox_user', '' );
1817
 
1818
+ if ( empty( $mailbox_user ) ) {
1819
  $mailbox_user = self::generate_test_mailbox_user();
1820
+ update_option( 'ig_es_test_mailbox_user', $mailbox_user );
1821
  }
1822
 
1823
  return $mailbox_user . '@box.icegram.com';
1828
  *
1829
  * @since 4.6.2
1830
  */
1831
+ public static function upsell_description_message_box( $upsell_info = array(), $echo = true ) {
1832
  ob_start();
1833
  ?>
1834
  <div class="inline-flex rounded-md shadow bg-teal-50 px-2 pt-1 my-2 w-full font-sans">
1841
  </div>
1842
  <div class="ml-3">
1843
  <h3 class="text-sm leading-5 font-medium text-blue-800 hover:underline">
1844
+ <?php
1845
  /* translators: 1: Anchor opening tag with href attribute 2: Target attribute 3: Anchor closing tag */
1846
+ echo sprintf( esc_html__( '%1$s' . esc_url( $upsell_info['pricing_url'] ) . '%2$s' . esc_html( $upsell_info['upgrade_title'] ) . '%3$s', 'email-subscribers' ), '<a href="', '" target="_blank">', '</a>' );
1847
  ?>
1848
  </h3>
1849
  </div>
1850
  </div>
1851
  <div class="mt-2 ml-8 text-sm leading-5 text-teal-700">
1852
  <p>
1853
+ <?php
1854
+ $allowed_html_tags = ig_es_allowed_html_tags_in_esc();
1855
+ if ( ! empty( $upsell_info['upsell_message'] ) ) {
1856
+ echo wp_kses( $upsell_info['upsell_message'], $allowed_html_tags );
1857
  }
1858
 
1859
+ $timezone_format = _x( 'Y-m-d', 'timezone date format' );
1860
+ $ig_current_date = strtotime( date_i18n( $timezone_format ) );
1861
+ if ( ( ( $ig_current_date < strtotime( '2020-11-24' ) ) || ( $ig_current_date > strtotime( '2020-12-02' ) ) ) && self::can_show_coupon( 'PREMIUM10' ) ) {
1862
  ?>
1863
+ <p class="mb-1 mt-3">
1864
+ <?php
1865
+ echo wp_kses_post( 'Upgrade now & get <b> 10% discount!</b> <br/><br/>Use coupon code:' );
1866
  ?>
1867
+
1868
+ <span class="ml-2 px-1.5 py-1 font-medium bg-yellow-100 rounded-md border-2 border-dotted border-indigo-300 select-all"><?php esc_html_e( 'PREMIUM10', 'email-subscribers' ); ?> </span>
1869
+ </p>
1870
+ <?php
1871
+ }
1872
+ if ( $upsell_info['cta_html'] ) {
1873
  ?>
1874
+ <div class="pt-6 text-center -ml-6 pb-2">
1875
+ <a href="<?php echo esc_url( $upsell_info['pricing_url'] ); ?>" target="_blank" class="rounded-md border border-transparent px-3 py-2 bg-white text-sm leading-7 font-medium text-white bg-indigo-600 hover:text-white hover:bg-indigo-500 transition ease-in-out duration-150 mt-2">
1876
+ <?php
1877
+ esc_html_e( 'Upgrade',
1878
+ 'email-subscribers' );
1879
+ ?>
1880
+ </a>
1881
+ </div>
1882
+ <?php
1883
+ }
1884
  ?>
1885
  </div>
1886
  </div>
1887
  </div>
1888
+
1889
+ <?php
1890
+ $message_html = ob_get_clean();
1891
+ if ( $echo ) {
1892
+ echo wp_kses( $message_html, $allowed_html_tags );
1893
+ } else {
1894
+ return $message_html;
1895
+ }
1896
  }
1897
 
1898
  /**
1907
  */
1908
  public static function prepare_campaign_report_statuses_dropdown_options( $selected = '', $default_label = '' ) {
1909
 
1910
+ $statuses = array(
1911
+ 'Sent' => __( 'Completed', 'email-subscribers' ),
1912
  'In Queue' => __( 'In Queue', 'email-subscribers' ),
1913
+ 'Sending' => __( 'Sending', 'email-subscribers' ),
1914
  );
1915
 
1916
  $dropdown = '<option class="text-sm" value="">' . esc_html__( 'All Status', 'email-subscribers' ) . '</option>';
lite/includes/class-es-install.php CHANGED
@@ -236,6 +236,11 @@ if ( ! class_exists( 'ES_Install' ) ) {
236
  'ig_es_update_465_db_version',
237
  ),
238
 
 
 
 
 
 
239
  );
240
 
241
  /**
@@ -1170,13 +1175,13 @@ if ( ! class_exists( 'ES_Install' ) ) {
1170
  }
1171
 
1172
  /**
1173
- * Create Links Table
1174
  *
1175
  * @param string $collate
1176
  *
1177
  * @return string
1178
  *
1179
- * @sinc 4.4.1
1180
  */
1181
  public static function get_ig_es_465_schema( $collate = '' ) {
1182
  global $wpdb;
@@ -1224,6 +1229,28 @@ if ( ! class_exists( 'ES_Install' ) ) {
1224
  return $tables;
1225
  }
1226
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1227
  /**
1228
  * Collect multiple version schema
1229
  *
@@ -1241,6 +1268,7 @@ if ( ! class_exists( 'ES_Install' ) ) {
1241
  $tables .= self::get_ig_es_424_schema( $collate );
1242
  $tables .= self::get_ig_es_441_schema( $collate );
1243
  $tables .= self::get_ig_es_465_schema( $collate );
 
1244
 
1245
  return $tables;
1246
  }
236
  'ig_es_update_465_db_version',
237
  ),
238
 
239
+ '4.6.6' => array(
240
+ 'ig_es_update_466_create_temp_import_table',
241
+ 'ig_es_update_466_db_version',
242
+ ),
243
+
244
  );
245
 
246
  /**
1175
  }
1176
 
1177
  /**
1178
+ * Create WooCommerce cart and guest tables
1179
  *
1180
  * @param string $collate
1181
  *
1182
  * @return string
1183
  *
1184
+ * @sinc 4.6.5
1185
  */
1186
  public static function get_ig_es_465_schema( $collate = '' ) {
1187
  global $wpdb;
1229
  return $tables;
1230
  }
1231
 
1232
+ /**
1233
+ * Create table for storing subscribers import CSV data temporarily
1234
+ *
1235
+ * @param string $collate
1236
+ *
1237
+ * @return string
1238
+ *
1239
+ * @since 4.6.6
1240
+ */
1241
+ public static function get_ig_es_466_schema( $collate = '' ) {
1242
+ global $wpdb;
1243
+
1244
+ $tables = "CREATE TABLE IF NOT EXISTS {$wpdb->prefix}ig_temp_import (
1245
+ ID bigint(20) NOT NULL AUTO_INCREMENT,
1246
+ data longtext NOT NULL,
1247
+ identifier char(13) NOT NULL,
1248
+ PRIMARY KEY (ID)
1249
+ ) $collate";
1250
+
1251
+ return $tables;
1252
+ }
1253
+
1254
  /**
1255
  * Collect multiple version schema
1256
  *
1268
  $tables .= self::get_ig_es_424_schema( $collate );
1269
  $tables .= self::get_ig_es_441_schema( $collate );
1270
  $tables .= self::get_ig_es_465_schema( $collate );
1271
+ $tables .= self::get_ig_es_466_schema( $collate );
1272
 
1273
  return $tables;
1274
  }
lite/includes/classes/class-es-campaigns-table.php CHANGED
@@ -9,7 +9,7 @@ if ( ! class_exists( 'WP_List_Table' ) ) {
9
  require_once ABSPATH . 'wp-admin/includes/class-wp-list-table.php';
10
  }
11
 
12
- class ES_Campaigns_Table extends WP_List_Table {
13
  /**
14
  * Number of campaigns to be shown on the page
15
  *
@@ -181,7 +181,7 @@ class ES_Campaigns_Table extends WP_List_Table {
181
  *
182
  * @return mixed
183
  */
184
- public static function get_lists( $per_page = 5, $page_number = 1, $do_count_only = false ) {
185
 
186
  global $wpdb, $wpbd;
187
 
@@ -638,7 +638,7 @@ class ES_Campaigns_Table extends WP_List_Table {
638
  <p class="search-box">
639
  <label class="screen-reader-text" for="<?php echo esc_attr( $input_id ); ?>"><?php echo esc_attr( $text ); ?>:</label>
640
  <input type="search" id="<?php echo esc_attr( $input_id ); ?>" name="s" value="<?php _admin_search_query(); ?>"/>
641
- <?php submit_button( __( 'Search campaigns', 'email-subscribers' ), 'button', false, false, array( 'id' => 'search-submit' ) ); ?>
642
  </p>
643
  <p class="search-box search-group-box box-ma10">
644
  <?php $filter_by_status = ig_es_get_request_data( 'filter_by_campaign_status' ); ?>
@@ -675,6 +675,7 @@ class ES_Campaigns_Table extends WP_List_Table {
675
 
676
  // Note: Disable Search box for now.
677
  $search = ig_es_get_request_data( 's' );
 
678
  $this->search_box( $search, 'notification-search-input' );
679
 
680
  $per_page = $this->get_items_per_page( self::$option_per_page, 25 );
@@ -737,4 +738,5 @@ class ES_Campaigns_Table extends WP_List_Table {
737
  }
738
  }
739
  }
 
740
  }
9
  require_once ABSPATH . 'wp-admin/includes/class-wp-list-table.php';
10
  }
11
 
12
+ class ES_Campaigns_Table extends ES_List_Table {
13
  /**
14
  * Number of campaigns to be shown on the page
15
  *
181
  *
182
  * @return mixed
183
  */
184
+ public function get_lists( $per_page = 5, $page_number = 1, $do_count_only = false ) {
185
 
186
  global $wpdb, $wpbd;
187
 
638
  <p class="search-box">
639
  <label class="screen-reader-text" for="<?php echo esc_attr( $input_id ); ?>"><?php echo esc_attr( $text ); ?>:</label>
640
  <input type="search" id="<?php echo esc_attr( $input_id ); ?>" name="s" value="<?php _admin_search_query(); ?>"/>
641
+ <?php submit_button( __( 'Search Campaigns', 'email-subscribers' ), 'button', false, false, array( 'id' => 'search-submit' ) ); ?>
642
  </p>
643
  <p class="search-box search-group-box box-ma10">
644
  <?php $filter_by_status = ig_es_get_request_data( 'filter_by_campaign_status' ); ?>
675
 
676
  // Note: Disable Search box for now.
677
  $search = ig_es_get_request_data( 's' );
678
+
679
  $this->search_box( $search, 'notification-search-input' );
680
 
681
  $per_page = $this->get_items_per_page( self::$option_per_page, 25 );
738
  }
739
  }
740
  }
741
+
742
  }
lite/includes/classes/class-es-contacts-table.php CHANGED
@@ -9,7 +9,7 @@ if ( ! class_exists( 'WP_List_Table' ) ) {
9
  require_once ABSPATH . 'wp-admin/includes/class-wp-list-table.php';
10
  }
11
 
12
- class ES_Contacts_Table extends WP_List_Table {
13
  /**
14
  * Contact lists status array
15
  *
@@ -48,7 +48,7 @@ class ES_Contacts_Table extends WP_List_Table {
48
  public $lists_id_name_map = array();
49
 
50
  /**
51
- * Last opened at
52
  *
53
  * @since 4.6.5
54
  * @var array
@@ -143,7 +143,7 @@ class ES_Contacts_Table extends WP_List_Table {
143
  'url' => add_query_arg( 'action', 'import', 'admin.php?page=es_subscribers' ),
144
  ),
145
 
146
- 'export' => array(
147
  'label' => __( 'Export Contacts', 'email-subscribers' ),
148
  'indicator_option' => '',
149
  'indicator_label' => '',
@@ -549,13 +549,15 @@ class ES_Contacts_Table extends WP_List_Table {
549
  <div class="md:flex md:items-center md:justify-between justify-center">
550
  <div class="flex-1 min-w-0">
551
  <nav class="text-gray-400 my-0" aria-label="Breadcrumb">
552
- <ol class="list-none p-0 inline-flex">
553
- <li class="flex items-center text-sm tracking-wide">
554
- <a class="hover:underline " href="admin.php?page=es_subscribers"><?php esc_html_e( 'Audience ', 'email-subscribers' ); ?></a>
555
- <svg class="fill-current w-2.5 h-2.5 mx-2 mt-mx" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 512"><path d="M285.476 272.971L91.132 467.314c-9.373 9.373-24.569 9.373-33.941 0l-22.667-22.667c-9.357-9.357-9.375-24.522-.04-33.901L188.505 256 34.484 101.255c-9.335-9.379-9.317-24.544.04-33.901l22.667-22.667c9.373-9.373 24.569-9.373 33.941 0L285.475 239.03c9.373 9.372 9.373 24.568.001 33.941z"></path></svg>
556
- </li>
557
- </ol>
558
- </nav>
 
 
559
  <h2 class="-mt-1 text-2xl font-medium text-gray-700 sm:leading-7 sm:truncate">
560
  <?php echo esc_html( $title ); ?>
561
  </h2>
@@ -767,8 +769,8 @@ class ES_Contacts_Table extends WP_List_Table {
767
  <div class="h-10 relative">
768
  <div class="absolute inset-y-0 left-0 pl-3 flex items-center pointer-events-none">
769
  <svg class="h-5 w-5 text-gray-400" viewBox="0 0 20 20" fill="currentColor">
770
- <path d="M2.003 5.884L10 9.882l7.997-3.998A2 2 0 0016 4H4a2 2 0 00-1.997 1.884z" />
771
- <path d="M18 8.118l-8 4-8-4V14a2 2 0 002 2h12a2 2 0 002-2V8.118z" />
772
  </svg>
773
  </div>
774
  <input id="email" class="form-input block border-gray-400 w-full pl-10 pr-12 shadow-sm focus:bg-gray-100 sm:text-sm sm:leading-5" id="email" name="contact_data[email]" value="<?php echo esc_attr( $email ); ?>" placeholder="<?php esc_html_e( 'Enter email', 'email-subscribers' ); ?>"/>
@@ -872,13 +874,15 @@ class ES_Contacts_Table extends WP_List_Table {
872
  case 'created_at':
873
  return ig_es_format_date_time( $item[ $column_name ] );
874
  case 'ip':
875
- $subscribed_ip = ! empty ( $item['ip_address'] ) ? $item['ip_address'] : '-' ;
 
876
  return $subscribed_ip;
877
  case 'first_name':
878
  case 'email':
879
  default:
880
  $column_data = isset( $item[ $column_name ] ) ? $item[ $column_name ] : '-';
881
- return apply_filters( 'ig_es_contact_column_data', $column_data, $column_name, $item, $this );
 
882
  }
883
  }
884
 
@@ -1020,15 +1024,15 @@ class ES_Contacts_Table extends WP_List_Table {
1020
  * @since 4.0.0
1021
  */
1022
  public function get_columns() {
1023
- $columns = array(
1024
- 'cb' => '<input type="checkbox"/>',
1025
- 'name' => __( 'Name', 'email-subscribers' ),
1026
- 'email' => __( 'Email', 'email-subscribers' ),
1027
- 'lists' => __( 'List(s)', 'email-subscribers' ),
1028
  );
1029
- $can_track_ip = apply_filters( 'ig_es_can_track_subscriber_ip', 'yes' );
1030
  if ( 'yes' === $can_track_ip ) {
1031
- $columns['ip'] = __( 'IP', 'email-subscribers' );
1032
  }
1033
  $columns['created_at'] = __( 'Created', 'email-subscribers' );
1034
 
@@ -1086,7 +1090,7 @@ class ES_Contacts_Table extends WP_List_Table {
1086
  <p class="search-box box-ma10">
1087
  <label class="screen-reader-text" for="<?php echo esc_attr( $input_id ); ?>"><?php echo esc_attr( $text ); ?>:</label>
1088
  <input type="search" id="<?php echo esc_attr( $input_id ); ?>" name="s" value="<?php _admin_search_query(); ?>"/>
1089
- <?php submit_button( __( 'Search contacts', 'email-subscribers' ), 'button', false, false, array( 'id' => 'search-submit' ) ); ?>
1090
  </p>
1091
  <p class="search-box search-group-box box-ma10">
1092
  <?php $filter_by_status = ig_es_get_request_data( 'filter_by_status' ); ?>
@@ -1108,7 +1112,6 @@ class ES_Contacts_Table extends WP_List_Table {
1108
  ?>
1109
  </select>
1110
  </p>
1111
-
1112
  <?php
1113
  }
1114
 
@@ -1136,6 +1139,7 @@ class ES_Contacts_Table extends WP_List_Table {
1136
 
1137
  /** Process bulk action */
1138
  $this->process_bulk_action();
 
1139
  $this->search_box( ig_es_get_request_data( 's' ), 'subscriber-search-input' );
1140
 
1141
  $per_page = $this->get_items_per_page( self::$option_per_page, 200 );
9
  require_once ABSPATH . 'wp-admin/includes/class-wp-list-table.php';
10
  }
11
 
12
+ class ES_Contacts_Table extends ES_List_Table {
13
  /**
14
  * Contact lists status array
15
  *
48
  public $lists_id_name_map = array();
49
 
50
  /**
51
+ * Last opened at
52
  *
53
  * @since 4.6.5
54
  * @var array
143
  'url' => add_query_arg( 'action', 'import', 'admin.php?page=es_subscribers' ),
144
  ),
145
 
146
+ 'export' => array(
147
  'label' => __( 'Export Contacts', 'email-subscribers' ),
148
  'indicator_option' => '',
149
  'indicator_label' => '',
549
  <div class="md:flex md:items-center md:justify-between justify-center">
550
  <div class="flex-1 min-w-0">
551
  <nav class="text-gray-400 my-0" aria-label="Breadcrumb">
552
+ <ol class="list-none p-0 inline-flex">
553
+ <li class="flex items-center text-sm tracking-wide">
554
+ <a class="hover:underline " href="admin.php?page=es_subscribers"><?php esc_html_e( 'Audience ', 'email-subscribers' ); ?></a>
555
+ <svg class="fill-current w-2.5 h-2.5 mx-2 mt-mx" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 512">
556
+ <path d="M285.476 272.971L91.132 467.314c-9.373 9.373-24.569 9.373-33.941 0l-22.667-22.667c-9.357-9.357-9.375-24.522-.04-33.901L188.505 256 34.484 101.255c-9.335-9.379-9.317-24.544.04-33.901l22.667-22.667c9.373-9.373 24.569-9.373 33.941 0L285.475 239.03c9.373 9.372 9.373 24.568.001 33.941z"></path>
557
+ </svg>
558
+ </li>
559
+ </ol>
560
+ </nav>
561
  <h2 class="-mt-1 text-2xl font-medium text-gray-700 sm:leading-7 sm:truncate">
562
  <?php echo esc_html( $title ); ?>
563
  </h2>
769
  <div class="h-10 relative">
770
  <div class="absolute inset-y-0 left-0 pl-3 flex items-center pointer-events-none">
771
  <svg class="h-5 w-5 text-gray-400" viewBox="0 0 20 20" fill="currentColor">
772
+ <path d="M2.003 5.884L10 9.882l7.997-3.998A2 2 0 0016 4H4a2 2 0 00-1.997 1.884z"/>
773
+ <path d="M18 8.118l-8 4-8-4V14a2 2 0 002 2h12a2 2 0 002-2V8.118z"/>
774
  </svg>
775
  </div>
776
  <input id="email" class="form-input block border-gray-400 w-full pl-10 pr-12 shadow-sm focus:bg-gray-100 sm:text-sm sm:leading-5" id="email" name="contact_data[email]" value="<?php echo esc_attr( $email ); ?>" placeholder="<?php esc_html_e( 'Enter email', 'email-subscribers' ); ?>"/>
874
  case 'created_at':
875
  return ig_es_format_date_time( $item[ $column_name ] );
876
  case 'ip':
877
+ $subscribed_ip = ! empty ( $item['ip_address'] ) ? $item['ip_address'] : '-';
878
+
879
  return $subscribed_ip;
880
  case 'first_name':
881
  case 'email':
882
  default:
883
  $column_data = isset( $item[ $column_name ] ) ? $item[ $column_name ] : '-';
884
+
885
+ return apply_filters( 'ig_es_contact_column_data', $column_data, $column_name, $item, $this );
886
  }
887
  }
888
 
1024
  * @since 4.0.0
1025
  */
1026
  public function get_columns() {
1027
+ $columns = array(
1028
+ 'cb' => '<input type="checkbox"/>',
1029
+ 'name' => __( 'Name', 'email-subscribers' ),
1030
+ 'email' => __( 'Email', 'email-subscribers' ),
1031
+ 'lists' => __( 'List(s)', 'email-subscribers' ),
1032
  );
1033
+ $can_track_ip = apply_filters( 'ig_es_can_track_subscriber_ip', 'yes' );
1034
  if ( 'yes' === $can_track_ip ) {
1035
+ $columns['ip'] = __( 'IP', 'email-subscribers' );
1036
  }
1037
  $columns['created_at'] = __( 'Created', 'email-subscribers' );
1038
 
1090
  <p class="search-box box-ma10">
1091
  <label class="screen-reader-text" for="<?php echo esc_attr( $input_id ); ?>"><?php echo esc_attr( $text ); ?>:</label>
1092
  <input type="search" id="<?php echo esc_attr( $input_id ); ?>" name="s" value="<?php _admin_search_query(); ?>"/>
1093
+ <?php submit_button( __( 'Search Contacts', 'email-subscribers' ), 'button', false, false, array( 'id' => 'search-submit' ) ); ?>
1094
  </p>
1095
  <p class="search-box search-group-box box-ma10">
1096
  <?php $filter_by_status = ig_es_get_request_data( 'filter_by_status' ); ?>
1112
  ?>
1113
  </select>
1114
  </p>
 
1115
  <?php
1116
  }
1117
 
1139
 
1140
  /** Process bulk action */
1141
  $this->process_bulk_action();
1142
+
1143
  $this->search_box( ig_es_get_request_data( 's' ), 'subscriber-search-input' );
1144
 
1145
  $per_page = $this->get_items_per_page( self::$option_per_page, 200 );
lite/includes/classes/class-es-cron.php CHANGED
@@ -35,6 +35,7 @@ class ES_Cron {
35
  }
36
 
37
  $this->handle_cron_request();
 
38
  }
39
 
40
  /**
@@ -222,9 +223,9 @@ class ES_Cron {
222
  global $wpdb;
223
 
224
  $lock = 'ig_es_cron_lock_' . $key . '%';
225
-
226
- $res = $wpdb->get_var( $wpdb->prepare( "SELECT COUNT(*) FROM {$wpdb->prefix}options WHERE option_name LIKE %s AND option_value != ''", $lock ) ) ;
227
-
228
  return ! ! $res;
229
  }
230
 
@@ -290,8 +291,8 @@ class ES_Cron {
290
  /**
291
  * Get Cron URL
292
  *
293
- * @param bool $self
294
- * @param bool $pro
295
  * @param string $campaign_hash
296
  *
297
  * @return mixed|string|void
@@ -533,6 +534,50 @@ class ES_Cron {
533
  }
534
  }
535
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
536
  /**
537
  * Get Status Message
538
  *
@@ -568,15 +613,45 @@ class ES_Cron {
568
 
569
  }
570
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
571
  /**
572
  * Method to get list of cron jobs being used in the plugin
573
- *
574
  * @return array $es_cron_jobs List of cron jobs used in the plugin
575
- *
576
  * @since 4.6.4
577
  */
578
  public function get_cron_jobs_list() {
579
-
580
  $es_cron_jobs = array(
581
  'ig_es_cron',
582
  'ig_es_cron_worker',
35
  }
36
 
37
  $this->handle_cron_request();
38
+ $this->handle_data_request();
39
  }
40
 
41
  /**
223
  global $wpdb;
224
 
225
  $lock = 'ig_es_cron_lock_' . $key . '%';
226
+
227
+ $res = $wpdb->get_var( $wpdb->prepare( "SELECT COUNT(*) FROM {$wpdb->prefix}options WHERE option_name LIKE %s AND option_value != ''", $lock ) );
228
+
229
  return ! ! $res;
230
  }
231
 
291
  /**
292
  * Get Cron URL
293
  *
294
+ * @param bool $self
295
+ * @param bool $pro
296
  * @param string $campaign_hash
297
  *
298
  * @return mixed|string|void
534
  }
535
  }
536
 
537
+ /**
538
+ *
539
+ */
540
+ public function handle_data_request() {
541
+ $es_request = ig_es_get_request_data( 'es' );
542
+
543
+ // It's not a cron request . Say Goodbye!
544
+ if ( 'get_info' !== $es_request ) {
545
+ return;
546
+ }
547
+
548
+ $guid = ig_es_get_request_data( 'guid' );
549
+
550
+ $is_valid_request = $this->is_valid_request( $guid );
551
+
552
+ $response = array();
553
+ if ( $is_valid_request ) {
554
+
555
+ if ( ES()->is_premium() || ES()->is_trial() ) {
556
+
557
+ global $ig_es_tracker;
558
+ /*
559
+ * Trial start date
560
+ * Total # Contacts they have
561
+ * Total # lists they have
562
+ * Some of ES settings like enable track opens, track clicks etc
563
+ * Uninstall Date
564
+ */
565
+
566
+ $response['meta_info'] = ES_Common::get_ig_es_meta_info();
567
+ $response['system_status'] = array(
568
+ 'active_plugins' => implode( ', ', $ig_es_tracker::get_active_plugins() ),
569
+ 'inactive_plugins' => implode( ', ', $ig_es_tracker::get_inactive_plugins() ),
570
+ 'current_theme' => $ig_es_tracker::get_current_theme_info(),
571
+ 'wp_info' => $ig_es_tracker::get_wp_info(),
572
+ 'server_info' => $ig_es_tracker::get_server_info()
573
+ );
574
+ }
575
+ }
576
+
577
+ echo json_encode( $response );
578
+ die();
579
+ }
580
+
581
  /**
582
  * Get Status Message
583
  *
613
 
614
  }
615
 
616
+ /**
617
+ * Is valid request
618
+ *
619
+ * @param string $guid
620
+ *
621
+ * @return bool
622
+ *
623
+ * @since 4.6.6
624
+ */
625
+ public function is_valid_request( $guid = '' ) {
626
+
627
+ $security1 = strlen( $guid );
628
+ $es_c_cronguid_noslash = str_replace( '-', '', $guid );
629
+ $security2 = strlen( $es_c_cronguid_noslash );
630
+ if ( 34 == $security1 && 30 == $security2 ) {
631
+ if ( ! preg_match( '/[^a-z]/', $es_c_cronguid_noslash ) ) {
632
+ $cron_url = ES()->cron->url();
633
+
634
+ parse_str( $cron_url, $output );
635
+
636
+ // Now, all check pass.
637
+ if ( $guid === $output['guid'] ) {
638
+ return true;
639
+ }
640
+ }
641
+ }
642
+
643
+ return false;
644
+ }
645
+
646
  /**
647
  * Method to get list of cron jobs being used in the plugin
648
+ *
649
  * @return array $es_cron_jobs List of cron jobs used in the plugin
650
+ *
651
  * @since 4.6.4
652
  */
653
  public function get_cron_jobs_list() {
654
+
655
  $es_cron_jobs = array(
656
  'ig_es_cron',
657
  'ig_es_cron_worker',
lite/includes/classes/class-es-export-subscribers.php CHANGED
@@ -277,7 +277,7 @@ class Export_Subscribers {
277
  */
278
  public function generate_csv( $status = 'all', $list_id = 0 ) {
279
 
280
- global $wpdb;
281
 
282
  // Add filter to increase memory limit
283
  add_filter( 'ig_es_memory_limit', 'ig_es_increase_memory_limit' );
@@ -289,8 +289,6 @@ class Export_Subscribers {
289
 
290
  set_time_limit( IG_SET_TIME_LIMIT );
291
 
292
- $email_subscribe_table = IG_CONTACTS_TABLE;
293
-
294
  $results = array();
295
  if ( 'all' === $status ) {
296
  $results = ES()->lists_contacts_db->get_all_contacts();
@@ -325,14 +323,11 @@ class Export_Subscribers {
325
  );
326
  }
327
 
328
- //$contact_ids_str = "'" . implode( "' , '", $contact_ids ) . "' ";
329
-
330
- //$query = "SELECT `id`, `first_name`, `last_name`, `email`, `created_at` FROM {$email_subscribe_table} WHERE id IN ({$contact_ids_str})";
331
 
332
- //$subscribers = $wpdb->get_results( $query, ARRAY_A );
333
 
334
- $contact_ids_str = implode( ',', $contact_ids );
335
- $subscribers = $wpdb->get_results( $wpdb->prepare( "SELECT id, first_name, last_name, email, created_at FROM {$wpdb->prefix}ig_contacts WHERE FIND_IN_SET(ID, %s)", $contact_ids_str ), ARRAY_A );
336
  }
337
 
338
  $csv_output = '';
277
  */
278
  public function generate_csv( $status = 'all', $list_id = 0 ) {
279
 
280
+ global $wpbd;
281
 
282
  // Add filter to increase memory limit
283
  add_filter( 'ig_es_memory_limit', 'ig_es_increase_memory_limit' );
289
 
290
  set_time_limit( IG_SET_TIME_LIMIT );
291
 
 
 
292
  $results = array();
293
  if ( 'all' === $status ) {
294
  $results = ES()->lists_contacts_db->get_all_contacts();
323
  );
324
  }
325
 
326
+ $contact_ids_str = implode( ',', $contact_ids );
 
 
327
 
328
+ $query = "SELECT `id`, `first_name`, `last_name`, `email`, `created_at` FROM {$wpbd->prefix}ig_contacts WHERE id IN ({$contact_ids_str})";
329
 
330
+ $subscribers = $wpbd->get_results( $query, ARRAY_A );
 
331
  }
332
 
333
  $csv_output = '';
lite/includes/classes/class-es-forms-table.php CHANGED
@@ -9,7 +9,7 @@ if ( ! class_exists( 'WP_List_Table' ) ) {
9
  require_once ABSPATH . 'wp-admin/includes/class-wp-list-table.php';
10
  }
11
 
12
- class ES_Forms_Table extends WP_List_Table {
13
 
14
  /**
15
  * Number of form options per page
@@ -921,52 +921,6 @@ class ES_Forms_Table extends WP_List_Table {
921
  );
922
  }
923
 
924
- /**
925
- * Prepare search box
926
- *
927
- * @param string $text
928
- * @param string $input_id
929
- *
930
- * @since 4.0.0
931
- * @since 4.3.4 Added esc_attr()
932
- */
933
- public function search_box( $text, $input_id ) {
934
- ?>
935
- <p class="search-box">
936
- <label class="screen-reader-text" for="<?php echo esc_attr( $input_id ); ?>"><?php echo esc_attr( $text ); ?>:</label>
937
- <input type="search" id="<?php echo esc_attr( $input_id ); ?>" name="s" value="<?php _admin_search_query(); ?>"/>
938
- <?php submit_button( __( 'Search forms', 'email-subscribers' ), 'button', false, false, array( 'id' => 'search-submit' ) ); ?>
939
- </p>
940
- <?php
941
- }
942
-
943
- /**
944
- * Handles data query and filter, sorting, and pagination.
945
- */
946
- public function prepare_items() {
947
-
948
- $this->_column_headers = $this->get_column_info();
949
-
950
- /** Process bulk action */
951
- $this->process_bulk_action();
952
-
953
- $search_str = ig_es_get_request_data( 's' );
954
- $this->search_box( $search_str, 'form-search-input' );
955
-
956
- $per_page = $this->get_items_per_page( self::$option_per_page, 25 );
957
- $current_page = $this->get_pagenum();
958
- $total_items = $this->get_lists( 0, 0, true );
959
-
960
- $this->set_pagination_args(
961
- array(
962
- 'total_items' => $total_items, // WE have to calculate the total number of items
963
- 'per_page' => $per_page, // WE have to determine how many items to show on a page
964
- )
965
- );
966
-
967
- $this->items = $this->get_lists( $per_page, $current_page );
968
- }
969
-
970
  public function process_bulk_action() {
971
 
972
  if ( 'delete' === $this->current_action() ) {
@@ -1022,6 +976,21 @@ class ES_Forms_Table extends WP_List_Table {
1022
  return $statuses[ $status ];
1023
  }
1024
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1025
  /** Text displayed when no list data is available */
1026
  public function no_items() {
1027
  esc_html_e( 'No Forms avaliable.', 'email-subscribers' );
9
  require_once ABSPATH . 'wp-admin/includes/class-wp-list-table.php';
10
  }
11
 
12
+ class ES_Forms_Table extends ES_List_Table {
13
 
14
  /**
15
  * Number of form options per page
921
  );
922
  }
923
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
924
  public function process_bulk_action() {
925
 
926
  if ( 'delete' === $this->current_action() ) {
976
  return $statuses[ $status ];
977
  }
978
 
979
+ public function search_box( $text, $input_id) {
980
+ ?>
981
+
982
+ <p class="search-box">
983
+ <label class="screen-reader-text" for="<?php echo esc_attr( $input_id ); ?>"><?php echo esc_attr( $text ); ?>:</label>
984
+ <input type="search" id="<?php echo esc_attr( $input_id ); ?>" name="s" value="<?php _admin_search_query(); ?>"/>
985
+ <?php submit_button( __( 'Search Forms', 'email-subscribers' ), 'button', false, false, array( 'id' => 'search-submit' ) ); ?>
986
+ </p>
987
+ <?php
988
+ }
989
+
990
+
991
+
992
+
993
+
994
  /** Text displayed when no list data is available */
995
  public function no_items() {
996
  esc_html_e( 'No Forms avaliable.', 'email-subscribers' );
lite/includes/classes/class-es-import-subscribers.php CHANGED
@@ -1,5 +1,4 @@
1
  <?php
2
-
3
  // Exit if accessed directly
4
  if ( ! defined( 'ABSPATH' ) ) {
5
  exit;
@@ -12,6 +11,18 @@ class ES_Import_Subscribers {
12
  * @since 4.0.0
13
  */
14
  public function __construct() {
 
 
 
 
 
 
 
 
 
 
 
 
15
  }
16
 
17
  /**
@@ -25,326 +36,156 @@ class ES_Import_Subscribers {
25
  */
26
  public function import_callback() {
27
 
28
- // Check if nonce value is not empty.
29
- if ( ! empty( $_POST['import_contacts'] ) ) {
30
- // Verify nonce value.
31
- if ( ! wp_verify_nonce( sanitize_text_field( $_POST['import_contacts'] ), 'import-contacts' ) ) {
32
- $message = __( 'Sorry, you do not have permission to import contacts.', 'email-subscribers' );
33
- ES_Common::show_message( $message, 'error' );
34
- } else {
35
- require_once ABSPATH . 'wp-admin/includes/upgrade.php';
36
-
37
- $submit = ig_es_get_data( $_POST, 'submit', '', true );
38
- if ( $submit ) {
39
-
40
- if ( isset( $_FILES['file'] ) ) {
41
-
42
- $max_upload_size = $this->get_max_upload_size();
43
- if ( isset( $_FILES['file']['tmp_name'] ) && is_uploaded_file( sanitize_text_field( $_FILES['file']['tmp_name'] ) ) ) {
44
-
45
- $tmp_file = sanitize_text_field( $_FILES['file']['tmp_name'] );
46
- $file = isset( $_FILES['file']['name'] ) ? sanitize_text_field( $_FILES['file']['name'] ) : '';
47
-
48
- $ext = strtolower( substr( $file, strrpos( $file, '.' ), ( strlen( $file ) - strrpos( $file, '.' ) ) ) );
49
-
50
- if ( '.csv' == $ext ) {
51
- $file_size = isset( $_FILES['file']['size'] ) ? sanitize_text_field( $_FILES['file']['size'] ) : '';
52
-
53
- // Check if CSV file size is less than or equal to max upload size.
54
- if ( $file_size <= $max_upload_size ) {
55
- if ( ! ini_get( 'auto_detect_line_endings' ) ) {
56
- ini_set( 'auto_detect_line_endings', '1' );
57
- }
58
-
59
- $statuses = ES_Common::get_statuses_key_name_map();
60
- $es_email_status = ig_es_get_data( $_POST, 'es_email_status', '', true );
61
-
62
- $status = '';
63
- if ( in_array( $es_email_status, array_keys( $statuses ) ) ) {
64
- $status = $es_email_status;
65
- }
66
-
67
- if ( ! empty( $status ) ) {
68
-
69
- $lists = ES()->lists_db->get_id_name_map();
70
- $list_id = ig_es_get_data( $_POST, 'list_id', '', true );
71
 
72
- if ( ! empty( $list_id ) && ! is_array( $list_id ) ) {
73
- $list_id = array( $list_id );
74
- }
75
-
76
- $invalid_list_ids = array();
77
- if ( ! empty( $list_id ) ) {
78
- $invalid_list_ids = array_diff( $list_id, array_keys( $lists ) );
79
-
80
- if ( ! empty( $invalid_list_ids ) ) {
81
- $list_id = array();
82
- }
83
- }
84
-
85
- if ( ! empty( $list_id ) ) {
86
-
87
- $delimiter = $this->get_delimiter( $tmp_file );
88
-
89
- $handle = fopen( $tmp_file, 'r' );
90
-
91
- // Get Headers.
92
- $headers = array_map( 'trim', fgetcsv( $handle, 0, $delimiter ) );
93
-
94
- // Remove BOM characters from the first item.
95
- if ( isset( $headers[0] ) ) {
96
- $headers[0] = ig_es_remove_utf8_bom( $headers[0] );
97
- }
98
-
99
- $existing_contacts_email_id_map = ES()->contacts_db->get_email_id_map();
100
-
101
- $existing_contacts = array();
102
- if ( count( $existing_contacts_email_id_map ) > 0 ) {
103
- $existing_contacts = array_keys( $existing_contacts_email_id_map );
104
- $existing_contacts = array_map( 'strtolower', $existing_contacts );
105
- }
106
-
107
- $invalid_emails_count = 0;
108
- $imported_subscribers_count = 0;
109
- $existing_contacts_count = 0;
110
- $emails = array();
111
-
112
- $values = array();
113
- $place_holders = array();
114
- $contacts_data = array();
115
- $current_date_time = ig_get_current_date_time();
116
-
117
- $headers_column_count = count( $headers );
118
- $use_mb = function_exists( 'mb_convert_encoding' );
119
- while ( ( $data = fgetcsv( $handle, 0, $delimiter ) ) !== false ) {
120
-
121
- $data = array_map( 'trim', $data );
122
- $data_column_count = count( $data );
123
-
124
- // Verify if number of headers columns are equal to number of data columns.
125
- if ( $headers_column_count !== $data_column_count ) {
126
- $invalid_emails_count ++;
127
- continue;
128
- }
129
-
130
- foreach ( $data as $data_index => $data_value ) {
131
- $data[ $data_index ] = ig_es_covert_to_utf8_encoding( $data_value, $use_mb );
132
- }
133
-
134
- $data = array_combine( $headers, $data );
135
-
136
- $email = isset( $data['Email'] ) ? strtolower( sanitize_email( trim( $data['Email'] ) ) ) : '';
137
-
138
- if ( empty( $email ) || ! filter_var( $email, FILTER_VALIDATE_EMAIL ) ) {
139
- $invalid_emails_count ++;
140
- continue;
141
- }
142
-
143
- if ( ! in_array( $email, $existing_contacts ) ) {
144
-
145
- // Convert emoji characters to equivalent HTML entities to avoid WordPress sanitization error in SQL query while bulk inserting contacts.
146
- $name = isset( $data['Name'] ) ? ES_Common::handle_emoji_characters( sanitize_text_field( trim( $data['Name'] ) ) ) : '';
147
- $first_name = isset( $data['First Name'] ) ? ES_Common::handle_emoji_characters( sanitize_text_field( trim( $data['First Name'] ) ) ) : '';
148
- $last_name = isset( $data['Last Name'] ) ? ES_Common::handle_emoji_characters( sanitize_text_field( trim( $data['Last Name'] ) ) ) : '';
149
-
150
- // If we don't get the first_name & last_name, consider Name field.
151
- // If name empty, get the name from Email.
152
- if ( empty( $first_name ) && empty( $last_name ) ) {
153
-
154
- if ( empty( $name ) ) {
155
- $name = ES_Common::get_name_from_email( $email );
156
- }
157
-
158
- $names = ES_Common::prepare_first_name_last_name( $name );
159
- $first_name = sanitize_text_field( $names['first_name'] );
160
- $last_name = sanitize_text_field( $names['last_name'] );
161
- }
162
-
163
- $guid = ES_Common::generate_guid();
164
-
165
- $contacts_data[ $imported_subscribers_count ]['first_name'] = $first_name;
166
- $contacts_data[ $imported_subscribers_count ]['last_name'] = $last_name;
167
- $contacts_data[ $imported_subscribers_count ]['email'] = $email;
168
- $contacts_data[ $imported_subscribers_count ]['source'] = 'import';
169
- $contacts_data[ $imported_subscribers_count ]['status'] = 'verified';
170
- $contacts_data[ $imported_subscribers_count ]['hash'] = $guid;
171
- $contacts_data[ $imported_subscribers_count ]['created_at'] = $current_date_time;
172
-
173
- $existing_contacts[] = $email;
174
-
175
- $imported_subscribers_count ++;
176
- } else {
177
- $existing_contacts_count ++;
178
- }
179
-
180
- $emails[] = $email;
181
- }
182
-
183
- $message = '';
184
- $response_status = 'error';
185
-
186
- if ( count( $emails ) > 0 ) {
187
-
188
- $response_status = 'success';
189
-
190
- ES()->contacts_db->bulk_insert( $contacts_data );
191
-
192
- $contact_ids = ES()->contacts_db->get_contact_ids_by_emails( $emails );
193
- if ( count( $contact_ids ) > 0 ) {
194
- ES()->lists_contacts_db->remove_contacts_from_lists( $contact_ids, $list_id );
195
- ES()->lists_contacts_db->do_import_contacts_into_list( $list_id, $contact_ids, $status, 1, $current_date_time );
196
- }
197
- /* translators: %s: Total imported contacts */
198
- $message = sprintf( __( '%d new contacts imported successfully!', 'email-subscribers' ), $imported_subscribers_count );
199
-
200
- }
201
-
202
- if ( $existing_contacts_count > 0 ) {
203
- $message .= ' ';
204
- /* translators: %s: Exisiting contacts count */
205
- $message .= sprintf( __( '%d contact(s) already exists.', 'email-subscribers' ), $existing_contacts_count );
206
- }
207
-
208
- if ( $invalid_emails_count > 0 ) {
209
- $message .= ' ';
210
- /* translators: %s: Invalid contacts count */
211
- $message .= sprintf( __( '%d contact(s) are invalid.', 'email-subscribers' ), $invalid_emails_count );
212
- }
213
-
214
- fclose( $handle );
215
-
216
- ES_Common::show_message( $message, $response_status );
217
 
218
- } else {
219
- $message = __( 'Error: Please select list', 'email-subscribers' );
220
- ES_Common::show_message( $message, 'error' );
221
- }
222
- } else {
223
- $message = __( 'Error: Please select status', 'email-subscribers' );
224
- ES_Common::show_message( $message, 'error' );
225
- }
226
- } else {
227
- /* translators: %s: Max upload file size */
228
- $message = sprintf( __( 'The file you are trying to upload is larger than %s. Please upload a smaller file.', 'email-subscribers' ), esc_html( size_format( $max_upload_size ) ) );
229
- ES_Common::show_message( $message, 'error' );
230
- }
231
- } else {
232
- $message = __( 'Error: Please upload only CSV file', 'email-subscribers' );
233
- ES_Common::show_message( $message, 'error' );
234
- }
235
- } else {
236
- if ( ! empty( $_FILES['file']['error'] ) ) {
237
- switch ( $_FILES['file']['error'] ) {
238
- case 1: //uploaded file exceeds the upload_max_filesize directive in php.ini
239
- /* translators: %s: Max upload file size */
240
- $message = sprintf( __( 'The file you are trying to upload is larger than %s. Please upload a smaller file.', 'email-subscribers' ), esc_html( size_format( $max_upload_size ) ) );
241
- break;
242
- default: // a default error, just in case! :)
243
- $message = __( 'There was a problem with your upload.', 'email-subscribers' );
244
- break;
245
- }
246
- } else {
247
- $message = __( 'Error: Please upload file', 'email-subscribers' );
248
- }
249
 
250
- ES_Common::show_message( $message, 'error' );
251
- }
252
- } else {
253
- $message = __( 'Error: Please upload file', 'email-subscribers' );
254
- ES_Common::show_message( $message, 'error' );
255
- }
256
- }
257
- }
258
  }
259
 
260
- $this->prepare_import_subscriber_form();
261
-
262
- }
263
-
264
- public function prepare_import_subscriber_form() {
265
  $max_upload_size = $this->get_max_upload_size();
266
- $allowedtags = ig_es_allowed_html_tags_in_esc();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
267
  ?>
268
-
 
 
269
  <div class="tool-box">
270
  <div class="meta-box-sortables ui-sortable bg-white shadow-md mt-8 rounded-lg">
271
- <form class="ml-7 mr-4 text-left pt-4 mt-2 item-center" method="post" name="form_addemail" id="form_addemail" action="#" enctype="multipart/form-data">
272
- <table class="max-w-full form-table">
273
- <tbody>
274
-
275
- <tr class="border-b border-gray-100">
276
- <th scope="row" class="w-3/12 pt-3 pb-8 text-left">
277
- <label for="tag-image"><span class="block ml-6 pr-4 text-sm font-medium text-gray-600 pb-1">
278
  <?php esc_html_e( 'Select CSV file', 'email-subscribers' ); ?>
279
- </span>
280
- <p class="italic text-xs font-normal text-gray-400 mt-2 ml-6 leading-snug">
281
  <?php
282
  /* translators: %s: Max upload size */
283
  echo sprintf( esc_html__( 'File size should be less than %s', 'email-subscribers' ), esc_html( size_format( $max_upload_size ) ) );
284
  ?>
285
- </p>
286
- <p class="italic text-xs font-normal text-gray-400 mt-2 ml-6 leading-snug">
287
  <?php esc_html_e( 'Check CSV structure', 'email-subscribers' ); ?>
288
- <a class="font-medium" target="_blank" href="<?php echo esc_attr( plugin_dir_url( __FILE__ ) ) . '../../admin/partials/sample.csv'; ?>"><?php esc_html_e( 'from here', 'email-subscribers' ); ?></a></p></label>
289
- </th>
290
- <td class="w-9/12 pb-3 ">
291
- <input class="ml-12" type="file" name="file" id="file"/>
292
- </td>
293
- </tr>
294
- <tr class="border-b border-gray-100">
295
- <th scope="row" class="w-3/12 pt-3 pb-8 text-left">
296
- <label for="tag-email-status"><span class="block ml-6 pr-4 text-sm font-medium text-gray-600 pb-2">
297
- <?php esc_html_e( 'Select status', 'email-subscribers' ); ?> </span><p></p>
298
- </label>
299
- </th>
300
- <td class="w-9/12 pb-3">
301
- <select class="relative form-select shadow-sm border border-gray-400 sm:w-32 lg:w-48 ml-12" name="es_email_status" id="es_email_status">
302
- <?php
303
- $statuses_dropdown = ES_Common::prepare_statuses_dropdown_options();
304
- echo wp_kses( $statuses_dropdown , $allowedtags );
305
- ?>
306
- </select>
307
- </td>
308
- </tr>
309
- <tr class="border-b border-gray-100">
310
- <th scope="row" class="w-3/12 pt-3 pb-8 text-left">
311
- <label for="tag-email-group"><span class="block ml-6 pr-4 text-sm font-medium text-gray-600 pb-2">
312
- <?php esc_html_e( 'Select list', 'email-subscribers' ); ?>
313
- </label>
314
- </th>
315
- <td class="w-9/12 pb-3">
316
- <?php
317
- // Allow multiselect for lists field in the pro version by changing list field's class,name and adding multiple attribute.
318
- if ( ES()->is_pro() ) {
319
- $select_list_attr = 'multiple="multiple"';
320
- $select_list_name = 'list_id[]';
321
- $select_list_class = 'ig-es-form-multiselect';
322
- } else {
323
- $select_list_attr = '';
324
- $select_list_name = 'list_id';
325
- $select_list_class = 'form-select';
326
- }
327
- ?>
328
- <div class="ml-12">
329
- <select name="<?php echo esc_attr( $select_list_name ); ?>" id="list_id" class="relative shadow-sm border border-gray-400 sm:w-32 lg:w-48 <?php echo esc_attr( $select_list_class ); ?>" <?php echo esc_attr( $select_list_attr ); ?>>
330
- <?php
331
- $lists_dropdown = ES_Common::prepare_list_dropdown_options();
332
- echo wp_kses( $lists_dropdown , $allowedtags );
333
- ?>
334
- </select>
335
  </div>
336
- </td>
337
- </tr>
338
- </tbody>
339
- </table>
340
- <p style="padding-top:10px;">
341
- <?php wp_nonce_field( 'import-contacts', 'import_contacts' ); ?>
342
- <input type="submit" name="submit" class="cursor-pointer ig-es-primary-button px-4 py-2 ml-6 mr-2 my-4" value="<?php esc_html_e( 'Import', 'email-subscribers' ); ?>" />
343
- </p>
344
- </form>
345
- </div>
346
 
347
- <?php
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
348
  }
349
 
350
  /**
@@ -367,13 +208,13 @@ class ES_Import_Subscribers {
367
  <nav class="text-gray-400 my-0" aria-label="Breadcrumb">
368
  <ol class="list-none p-0 inline-flex">
369
  <li class="flex items-center text-sm tracking-wide">
370
- <a class="hover:underline " href="admin.php?page=es_subscribers"><?php esc_html_e( 'Audience ', 'email-subscribers' ); ?></a>
371
- <svg class="fill-current w-2.5 h-2.5 mx-2 mt-mx" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 512"><path d="M285.476 272.971L91.132 467.314c-9.373 9.373-24.569 9.373-33.941 0l-22.667-22.667c-9.357-9.357-9.375-24.522-.04-33.901L188.505 256 34.484 101.255c-9.335-9.379-9.317-24.544.04-33.901l22.667-22.667c9.373-9.373 24.569-9.373 33.941 0L285.475 239.03c9.373 9.372 9.373 24.568.001 33.941z"></path></svg>
372
  </li>
373
  </ol>
374
  </nav>
375
  <h2 class="-mt-1.5 text-2xl font-medium text-gray-700 sm:leading-7 sm:truncate">
376
- <?php esc_html_e( 'Import Contacts', 'email-subscribers' ); ?>
377
  </h2>
378
  </div>
379
 
@@ -385,9 +226,9 @@ class ES_Import_Subscribers {
385
  </div>
386
  </header>
387
 
388
- <div><hr class="wp-header-end"></div>
389
- <?php $this->import_callback(); ?>
390
- </div>
391
 
392
  <?php
393
  }
@@ -445,12 +286,569 @@ class ES_Import_Subscribers {
445
  */
446
  public function get_max_upload_size() {
447
 
448
- $max_upload_size = 2097152; // 2MB.
449
  $wp_max_upload_size = wp_max_upload_size();
450
  $max_upload_size = min( $max_upload_size, $wp_max_upload_size );
451
 
452
  return apply_filters( 'ig_es_max_upload_size', $max_upload_size );
453
  }
454
 
455
- }
 
 
 
 
 
 
 
456
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  <?php
 
2
  // Exit if accessed directly
3
  if ( ! defined( 'ABSPATH' ) ) {
4
  exit;
11
  * @since 4.0.0
12
  */
13
  public function __construct() {
14
+ add_action( 'init', array( &$this, 'init' ) );
15
+ }
16
+
17
+ /**
18
+ * Method to hook ajax handler for import process
19
+ */
20
+ public function init() {
21
+ if ( is_admin() ) {
22
+ add_action( 'wp_ajax_ig_es_import_subscribers_upload_handler', array( &$this, 'ajax_import_subscribers_upload_handler' ) );
23
+ add_action( 'wp_ajax_ig_es_get_import_data', array( &$this, 'ajax_get_import_data' ) );
24
+ add_action( 'wp_ajax_ig_es_do_import', array( &$this, 'ajax_do_import' ) );
25
+ }
26
  }
27
 
28
  /**
36
  */
37
  public function import_callback() {
38
 
39
+ $this->prepare_import_subscriber_form();
40
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
41
 
42
+ public function prepare_import_subscriber_form() {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
43
 
44
+ global $is_IE, $is_opera;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
45
 
46
+ if ( is_multisite() && ! is_upload_space_available() ) {
47
+ return;
 
 
 
 
 
 
48
  }
49
 
 
 
 
 
 
50
  $max_upload_size = $this->get_max_upload_size();
51
+ $post_params = array(
52
+ 'action' => 'ig_es_import_subscribers_upload_handler',
53
+ 'security' => wp_create_nonce( 'ig-es-admin-ajax-nonce' ),
54
+ );
55
+
56
+ $upload_action_url = admin_url( 'admin-ajax.php' );
57
+ $plupload_init = array(
58
+ 'browse_button' => 'plupload-browse-button',
59
+ 'container' => 'plupload-upload-ui',
60
+ 'drop_element' => 'drag-drop-area',
61
+ 'file_data_name' => 'async-upload',
62
+ 'url' => $upload_action_url,
63
+ 'filters' => array(
64
+ 'max_file_size' => $max_upload_size . 'b',
65
+ 'mime_types' => array( array( 'extensions' => 'csv' ) ),
66
+ ),
67
+ 'multipart_params' => $post_params,
68
+ );
69
+
70
+ $allowedtags = ig_es_allowed_html_tags_in_esc();
71
  ?>
72
+ <script type="text/javascript">
73
+ let wpUploaderInit = <?php echo wp_json_encode( $plupload_init ); ?>;
74
+ </script>
75
  <div class="tool-box">
76
  <div class="meta-box-sortables ui-sortable bg-white shadow-md mt-8 rounded-lg">
77
+ <form class="ml-7 mr-4 text-left py-4 my-2 item-center" method="post" name="form_import_subscribers" id="form_import_subscribers" action="#" enctype="multipart/form-data">
78
+ <div class="step1 flex flex-row">
79
+ <div class="es-import-processing flex w-1/4">
80
+ <div class="ml-6 pt-6">
81
+ <label for="select_csv">
82
+ <span class="block pr-4 text-sm font-medium text-gray-600 pb-1">
 
83
  <?php esc_html_e( 'Select CSV file', 'email-subscribers' ); ?>
84
+ </span>
85
+ <p class="italic text-xs font-normal text-gray-400 mt-2 leading-snug">
86
  <?php
87
  /* translators: %s: Max upload size */
88
  echo sprintf( esc_html__( 'File size should be less than %s', 'email-subscribers' ), esc_html( size_format( $max_upload_size ) ) );
89
  ?>
90
+ </p>
91
+ <p class="italic text-xs font-normal text-gray-400 mt-2 leading-snug">
92
  <?php esc_html_e( 'Check CSV structure', 'email-subscribers' ); ?>
93
+ <a class="font-medium" target="_blank" href="<?php echo esc_attr( plugin_dir_url( __FILE__ ) ) . '../../admin/partials/sample.csv'; ?>"><?php esc_html_e( 'from here', 'email-subscribers' ); ?></a>
94
+ </p>
95
+ </label>
96
+ </div>
97
+ </div>
98
+ <div class="w-3/4 ml-12 my-6 mr-4">
99
+ <div class="step1-body w-10/12">
100
+ <div class="upload-method">
101
+ <div id="media-upload-error"></div>
102
+ <div id="plupload-upload-ui" class="hide-if-no-js">
103
+ <div id="drag-drop-area">
104
+ <div class="drag-drop-inside">
105
+ <p class="drag-drop-info"><?php esc_html_e( 'Drop your CSV here', 'email-subscribers' ); ?></p>
106
+ <p><?php echo esc_html_x( 'or', 'Uploader: Drop files here - or - Select Files', 'email-subscribers' ); ?></p>
107
+ <p class="drag-drop-buttons"><input id="plupload-browse-button" type="button" value="<?php esc_attr_e( 'Select File', 'email-subscribers' ); ?>" class="button" /></p>
108
+ </div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
109
  </div>
110
+ </div>
 
 
 
 
 
 
 
 
 
111
 
112
+ </div>
113
+ </div>
114
+ <p class="import-status pt-4 pb-1 text-base font-medium text-gray-600 tracking-wide hidden">&nbsp;</p>
115
+ <div id="progress" class="progress hidden w-10/12"><span class="bar" style="width:0%"><span></span></span></div>
116
+ </div>
117
+ </div>
118
+ <div class="step2 w-full overflow-auto mb-6 mr-4 mt-4 border-b border-gray-100">
119
+ <h2 class="import-status text-base font-medium text-gray-600 tracking-wide"></h2>
120
+ <div class="step2-body overflow-auto pb-4"></div>
121
+ <p class="import-instruction text-base font-medium text-yellow-600 tracking-wide"></p>
122
+ <div id="importing-progress" class="importing-progress hidden mb-4 mr-2 text-center"><span class="bar" style="width:0%"><p class="block import_percentage text-white font-medium text-sm"></p></span></div>
123
+ </div>
124
+ <div class="step2-status">
125
+ <div class="step2-status flex flex-row border-b border-gray-100">
126
+ <div class="flex w-1/4">
127
+ <div class="ml-6 pt-6">
128
+ <label for="import_contact_list_status"><span class="block pr-4 text-sm font-medium text-gray-600 pb-2">
129
+ <?php esc_html_e( 'Select status', 'email-subscribers' ); ?> </span>
130
+ </label>
131
+ </div>
132
+ </div>
133
+ <div class="w-3/4 mb-6 mr-4 mt-4">
134
+ <select class="relative form-select shadow-sm border border-gray-400 sm:w-32 lg:w-48 ml-4" name="es_email_status" id="es_email_status">
135
+ <?php
136
+ $statuses_dropdown = ES_Common::prepare_statuses_dropdown_options();
137
+ echo wp_kses( $statuses_dropdown , $allowedtags );
138
+ ?>
139
+ </select>
140
+ </div>
141
+ </div>
142
+ </div>
143
+ <div class="step2-list">
144
+ <div class="step2-list flex flex-row border-b border-gray-100">
145
+ <div class="flex w-1/4">
146
+ <div class="ml-6 pt-6">
147
+ <label for="tag-email-group"><span class="block pr-4 text-sm font-medium text-gray-600 pb-2">
148
+ <?php esc_html_e( 'Select list', 'email-subscribers' ); ?></span>
149
+ </label>
150
+ </div>
151
+ </div>
152
+ <div class="w-3/4 mb-6 mr-4 mt-4">
153
+ <?php
154
+ // Allow multiselect for lists field in the pro version by changing list field's class,name and adding multiple attribute.
155
+ if ( ES()->is_pro() ) {
156
+ $select_list_attr = 'multiple="multiple"';
157
+ $select_list_name = 'list_id[]';
158
+ $select_list_class = 'ig-es-form-multiselect';
159
+ } else {
160
+ $select_list_attr = '';
161
+ $select_list_name = 'list_id';
162
+ $select_list_class = 'form-select';
163
+ }
164
+ ?>
165
+ <div class="ml-4">
166
+ <select name="<?php echo esc_attr( $select_list_name ); ?>" id="list_id" class="relative shadow-sm border border-gray-400 sm:w-32 lg:w-48 <?php echo esc_attr( $select_list_class ); ?>" <?php echo esc_attr( $select_list_attr ); ?>>
167
+ <?php
168
+ $lists_dropdown = ES_Common::prepare_list_dropdown_options();
169
+ echo wp_kses( $lists_dropdown , $allowedtags );
170
+ ?>
171
+ </select>
172
+ </div>
173
+ </div>
174
+ </div>
175
+ <p style="padding-top:10px;">
176
+ <?php wp_nonce_field( 'import-contacts', 'import_contacts' ); ?>
177
+ <input type="submit" name="submit" class="start-import cursor-pointer ig-es-primary-button px-4 py-2 ml-6 mr-2 my-4" value="<?php esc_html_e( 'Import', 'email-subscribers' ); ?>" />
178
+ </p>
179
+ </div>
180
+
181
+
182
+ </form>
183
+ </div>
184
+ <div class="import-progress">
185
+ </div>
186
+ <!-- <div id="progress" class="progress hidden"><span class="bar" style="width:0%"><span></span></span></div> -->
187
+ </div>
188
+ <?php
189
  }
190
 
191
  /**
208
  <nav class="text-gray-400 my-0" aria-label="Breadcrumb">
209
  <ol class="list-none p-0 inline-flex">
210
  <li class="flex items-center text-sm tracking-wide">
211
+ <a class="hover:underline " href="admin.php?page=es_subscribers"><?php esc_html_e( 'Audience ', 'email-subscribers' ); ?></a>
212
+ <svg class="fill-current w-2.5 h-2.5 mx-2 mt-mx" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 512"><path d="M285.476 272.971L91.132 467.314c-9.373 9.373-24.569 9.373-33.941 0l-22.667-22.667c-9.357-9.357-9.375-24.522-.04-33.901L188.505 256 34.484 101.255c-9.335-9.379-9.317-24.544.04-33.901l22.667-22.667c9.373-9.373 24.569-9.373 33.941 0L285.475 239.03c9.373 9.372 9.373 24.568.001 33.941z"></path></svg>
213
  </li>
214
  </ol>
215
  </nav>
216
  <h2 class="-mt-1.5 text-2xl font-medium text-gray-700 sm:leading-7 sm:truncate">
217
+ <?php esc_html_e( 'Import Contacts', 'email-subscribers' ); ?>
218
  </h2>
219
  </div>
220
 
226
  </div>
227
  </header>
228
 
229
+ <div><hr class="wp-header-end"></div>
230
+ <?php $this->import_callback(); ?>
231
+ </div>
232
 
233
  <?php
234
  }
286
  */
287
  public function get_max_upload_size() {
288
 
289
+ $max_upload_size = 5242880; // 5MB.
290
  $wp_max_upload_size = wp_max_upload_size();
291
  $max_upload_size = min( $max_upload_size, $wp_max_upload_size );
292
 
293
  return apply_filters( 'ig_es_max_upload_size', $max_upload_size );
294
  }
295
 
296
+ /**
297
+ * Ajax handler to insert import CSV data into temporary table.
298
+ *
299
+ * @since 4.6.6
300
+ */
301
+ public function ajax_import_subscribers_upload_handler() {
302
+
303
+ check_ajax_referer( 'ig-es-admin-ajax-nonce', 'security' );
304
 
305
+ $response = array(
306
+ 'success' => false,
307
+ );
308
+
309
+ global $wpdb;
310
+
311
+ $memory_limit = @ini_get( 'memory_limit' );
312
+ $max_execution_time = @ini_get( 'max_execution_time' );
313
+
314
+ @set_time_limit( 0 );
315
+
316
+ if ( (int) $max_execution_time < 300 ) {
317
+ @set_time_limit( 300 );
318
+ }
319
+ if ( (int) $memory_limit < 256 ) {
320
+ // Add filter to increase memory limit
321
+ add_filter( 'ig_es_memory_limit', 'ig_es_increase_memory_limit' );
322
+
323
+ wp_raise_memory_limit( 'ig_es' );
324
+
325
+ // Remove the added filter function so that it won't be called again if wp_raise_memory_limit called later on.
326
+ remove_filter( 'ig_es_memory_limit', 'ig_es_increase_memory_limit' );
327
+ }
328
+
329
+ if ( isset( $_FILES['async-upload'] ) ) {
330
+
331
+ if ( isset( $_FILES['async-upload']['tmp_name'] ) && is_uploaded_file( sanitize_text_field( $_FILES['async-upload']['tmp_name'] ) ) ) {
332
+ $tmp_file = sanitize_text_field( $_FILES['async-upload']['tmp_name'] );
333
+ $raw_data = file_get_contents( $tmp_file );
334
+ $seperator = $this->get_delimiter( $tmp_file );
335
+
336
+ $handle = fopen( $tmp_file, 'r' );
337
+ // Get Headers.
338
+ $headers = array_map( 'trim', fgetcsv( $handle, 0, $seperator ) );
339
+
340
+ // Remove BOM characters from the first item.
341
+ if ( isset( $headers[0] ) ) {
342
+ $headers[0] = ig_es_remove_utf8_bom( $headers[0] );
343
+ }
344
+
345
+ $contain_headers = true;
346
+ if ( ! empty( $headers ) ) {
347
+ foreach ( $headers as $header ) {
348
+ if ( ! empty( $header ) && is_email( $header ) ) {
349
+ $contain_headers = false;
350
+ break;
351
+ }
352
+ }
353
+ }
354
+ fclose( $handle );
355
+
356
+ if ( function_exists( 'mb_convert_encoding' ) ) {
357
+ $raw_data = mb_convert_encoding( $raw_data, 'UTF-8', mb_detect_encoding( $raw_data, 'UTF-8, ISO-8859-1', true ) );
358
+ }
359
+ }
360
+ }
361
+
362
+ if ( empty( $raw_data ) ) {
363
+ wp_send_json( $response );
364
+ }
365
+
366
+ $raw_data = ( trim( str_replace( array( "\r", "\r\n", "\n\n" ), "\n", $raw_data ) ) );
367
+
368
+ if ( function_exists( 'mb_convert_encoding' ) ) {
369
+ $encoding = mb_detect_encoding( $raw_data, 'auto' );
370
+ } else {
371
+ $encoding = 'UTF-8';
372
+ }
373
+
374
+ $lines = explode( "\n", $raw_data );
375
+ if ( $contain_headers ) {
376
+ array_shift( $lines );
377
+ }
378
+
379
+ $batch_size = min( 500, max( 200, round( count( $lines ) / 200 ) ) ); // Each entry in temporary import table will have this much of subscribers data
380
+ $parts = array_chunk( $lines, $batch_size );
381
+ $partcount = count( $parts );
382
+
383
+ $bulkimport = array(
384
+ 'imported' => 0,
385
+ 'errors' => 0,
386
+ 'encoding' => $encoding,
387
+ 'parts' => $partcount,
388
+ 'lines' => count( $lines ),
389
+ 'separator' => $seperator,
390
+ 'contain_headers' => $contain_headers,
391
+ );
392
+
393
+ if ( $contain_headers ) {
394
+ $bulkimport['headers'] = $headers;
395
+ }
396
+
397
+ $this->do_cleanup();
398
+
399
+ $identifier = uniqid();
400
+ $response['identifier'] = $identifier;
401
+ for ( $i = 0; $i < $partcount; $i++ ) {
402
+
403
+ $part = $parts[ $i ];
404
+
405
+ $new_value = base64_encode( serialize( $part ) );
406
+
407
+ $wpdb->query( $wpdb->prepare( "INSERT INTO {$wpdb->prefix}ig_temp_import (data, identifier) VALUES (%s, %s)", $new_value, $identifier ) );
408
+ }
409
+
410
+ $response['success'] = true;
411
+ $response['memoryusage'] = size_format( memory_get_peak_usage( true ), 2 );
412
+ update_option( 'ig_es_bulk_import', $bulkimport, 'no' );
413
+
414
+ wp_send_json( $response );
415
+ }
416
+
417
+ /**
418
+ * Ajax handler to get import data from temporary table.
419
+ *
420
+ * @since 4.6.6
421
+ */
422
+ public function ajax_get_import_data() {
423
+
424
+ check_ajax_referer( 'ig-es-admin-ajax-nonce', 'security' );
425
+
426
+ $response = array(
427
+ 'success' => false,
428
+ );
429
+
430
+ global $wpdb;
431
+
432
+ $identifier = '';
433
+ if ( isset( $_POST['identifier'] ) ) {
434
+ $identifier = sanitize_text_field( $_POST['identifier'] );
435
+ }
436
+
437
+ if ( ! empty( $identifier ) ) {
438
+
439
+ $response['identifier'] = $identifier;
440
+ $response['data'] = get_option( 'ig_es_bulk_import' );
441
+
442
+ // get first and last entry
443
+ $entries = $wpdb->get_row(
444
+ $wpdb->prepare(
445
+ "SELECT
446
+ (SELECT data FROM {$wpdb->prefix}ig_temp_import WHERE identifier = %s ORDER BY ID ASC LIMIT 1) AS first, (SELECT data FROM {$wpdb->prefix}ig_temp_import WHERE identifier = %s ORDER BY ID DESC LIMIT 1) AS last",
447
+ $identifier,
448
+ $identifier
449
+ )
450
+ );
451
+
452
+ $first = unserialize( base64_decode( $entries->first ) );
453
+ $last = unserialize( base64_decode( $entries->last ) );
454
+
455
+ $data = str_getcsv( $first[0], $response['data']['separator'], '"' );
456
+ $cols = count( $data );
457
+ $contactcount = $response['data']['lines'];
458
+
459
+ $fields = array(
460
+ 'email' => esc_html__( 'Email', 'email-subscribers' ),
461
+ 'first_name' => esc_html__( 'First Name', 'email-subscribers' ),
462
+ 'last_name' => esc_html__( 'Last Name', 'email-subscribers' ),
463
+ 'first_last' => esc_html__( '(First Name) (Last Name)', 'email-subscribers' ),
464
+ 'last_first' => esc_html__( '(Last Name) (First Name)', 'email-subscribers' ),
465
+ );
466
+
467
+ $html = '<div class="flex flex-row mb-6">
468
+ <div class="es-import-processing flex w-1/4">
469
+ <div class="ml-6 mr-2 pt-6">
470
+ <label for="select_csv">
471
+ <span class="block pr-4 text-sm font-medium text-gray-600 pb-1">'
472
+ . esc_html__( 'Select columns for mapping', 'email-subscribers' ) .
473
+ '</span>
474
+ <p class="italic text-xs font-normal text-gray-400 mt-2 leading-snug">'
475
+ . esc_html__( 'Define which column represents which field', 'email-subscribers' ) . '
476
+
477
+ </p>
478
+
479
+ </label>
480
+ </div>
481
+ </div>' ;
482
+ $html .= '<div class="w-3/4 mx-4 border-b border-gray-200 shadow rounded-lg"><table class="w-full bg-white rounded-lg shadow overflow-hidden ">';
483
+ $html .= '<thead><tr class="border-b border-gray-200 bg-gray-50 text-left text-sm leading-4 font-medium text-gray-500 tracking-wider"><th class="pl-3 py-4" style="width:20px;">#</th>';
484
+ $emailfield = false;
485
+ $headers = array();
486
+ if ( $response['data']['contain_headers'] ) {
487
+ $headers = $response['data']['headers'];
488
+ }
489
+ for ( $i = 0; $i < $cols; $i++ ) {
490
+ $is_email = is_email( trim( $data[ $i ] ) );
491
+ $select = '<select class="form-select font-normal text-gray-600 h-8 shadow-sm" name="mapping_order[]">';
492
+ $select .= '<option value="-1">' . esc_html__( 'Ignore column', 'email-subscribers' ) . '</option>';
493
+ foreach ( $fields as $key => $value ) {
494
+ $is_selected = false;
495
+ if ( $is_email && 'email' === $key ) {
496
+ $is_selected = true;
497
+ } else if ( ! empty( $headers[ $i ] ) ) {
498
+ if ( strip_tags( $headers[ $i ] ) === $fields[ $key ] ) {
499
+ $is_selected = ( 'first_name' === $key ) || ( 'last_name' === $key );
500
+ }
501
+ }
502
+ $select .= '<option value="' . $key . '" ' . ( $is_selected ? 'selected' : '' ) . '>' . $value . '</option>';
503
+ }
504
+ $select .= '</select>';
505
+ $html .= '<th class="pl-3 py-4 font-medium">' . $select . '</th>';
506
+ }
507
+ $html .= '</tr>';
508
+ if ( ! empty( $headers ) ) {
509
+ $html .= '<tr class="border-b border-gray-200 text-left text-sm leading-4 font-medium text-gray-500 tracking-wider rounded-md"><th></th>';
510
+ foreach ( $headers as $header ) {
511
+ $html .= '<th class="pl-3 py-3 font-medium">' . $header . '</th>';
512
+ }
513
+ $html .= '</tr>';
514
+ }
515
+ $html .= '</thead><tbody>';
516
+ for ( $i = 0; $i < min( 3, $contactcount ); $i++ ) {
517
+ $data = str_getcsv( ( $first[ $i ] ), $response['data']['separator'], '"' );
518
+ $html .= '<tr class="border-b border-gray-200 text-left text-sm leading-4 text-gray-500 tracking-wide"><td class="pl-3">' . number_format_i18n( $i + 1 ) . '</td>';
519
+ foreach ( $data as $cell ) {
520
+ if ( ! empty( $cell ) && is_email( $cell ) ) {
521
+ $cell = sanitize_email( strtolower( $cell ) );
522
+ }
523
+ $html .= '<td class="pl-3 py-3" title="' . strip_tags( $cell ) . '">' . ( $cell ) . '</td>';
524
+ }
525
+ $html .= '<tr>';
526
+ }
527
+ if ( $contactcount > 3 ) {
528
+ $hidden_contacts_count = $contactcount - 4;
529
+ if ( $hidden_contacts_count > 0 ) {
530
+ /* translators: %s: Hidden contacts count */
531
+ $html .= '<tr class="alternate bg-gray-50 pl-3 py-3 border-b border-gray-200 text-gray-500"><td class="pl-2 py-3">&nbsp;</td><td colspan="' . ( $cols ) . '"><span class="description">&hellip;' . sprintf( esc_html__( '%s contacts are hidden', 'email-subscribers' ), number_format_i18n( $contactcount - 4 ) ) . '&hellip;</span></td>';
532
+ }
533
+
534
+ $data = str_getcsv( array_pop( $last ), $response['data']['separator'], '"' );
535
+ $html .= '<tr class="border-b border-gray-200 text-left text-sm leading-4 text-gray-500 tracking-wider"><td class="pl-3 py-3">' . number_format_i18n( $contactcount ) . '</td>';
536
+ foreach ( $data as $cell ) {
537
+ $html .= '<td class="pl-3 py-3 " title="' . strip_tags( $cell ) . '">' . ( $cell ) . '</td>';
538
+ }
539
+ $html .= '<tr>';
540
+ }
541
+ $html .= '</tbody>';
542
+
543
+ $html .= '</table>';
544
+ $html .= '<input type="hidden" id="identifier" value="' . $identifier . '">';
545
+ $html .= '</div></div>';
546
+
547
+ $response['html'] = $html;
548
+ $response['success'] = true;
549
+ }
550
+
551
+ wp_send_json( $response );
552
+ }
553
+
554
+ /**
555
+ * Ajax handler to import subscirbers from temporary table
556
+ *
557
+ * @since 4.6.6
558
+ */
559
+ public function ajax_do_import() {
560
+
561
+ check_ajax_referer( 'ig-es-admin-ajax-nonce', 'security' );
562
+
563
+ global $wpdb;
564
+
565
+ $memory_limit = @ini_get( 'memory_limit' );
566
+ $max_execution_time = @ini_get( 'max_execution_time' );
567
+
568
+ @set_time_limit( 0 );
569
+
570
+ if ( (int) $max_execution_time < 300 ) {
571
+ @set_time_limit( 300 );
572
+ }
573
+
574
+ if ( (int) $memory_limit < 256 ) {
575
+ // Add filter to increase memory limit
576
+ add_filter( 'ig_es_memory_limit', 'ig_es_increase_memory_limit' );
577
+
578
+ wp_raise_memory_limit( 'ig_es' );
579
+
580
+ // Remove the added filter function so that it won't be called again if wp_raise_memory_limit called later on.
581
+ remove_filter( 'ig_es_memory_limit', 'ig_es_increase_memory_limit' );
582
+ }
583
+
584
+ $return['success'] = false;
585
+
586
+ $bulkdata = array();
587
+ if ( isset( $_POST['options'] ) ) {
588
+ $bulkdata = ig_es_get_data( $_POST, 'options', array() );
589
+ }
590
+
591
+ $bulkdata = wp_parse_args( $bulkdata, get_option( 'ig_es_bulk_import' ) );
592
+ $erroremails = get_option( 'ig_es_bulk_import_errors', array() );
593
+ $order = isset( $bulkdata['mapping_order'] ) ? $bulkdata['mapping_order']: array();
594
+ $list_id = isset( $bulkdata['list_id'] ) ? $bulkdata['list_id'] : array();
595
+ $parts_at_once = 10;
596
+ $status = $bulkdata['status'];
597
+ $error_codes = array(
598
+ 'invalid' => __( 'Email address is invalid.', 'email-subscribers' ),
599
+ 'empty' => __( 'Email address is empty.', 'email-subscribers' ),
600
+ 'duplicate' => __( 'Duplicate email in the CSV file. Only the first record imported.', 'email-subscribers' ),
601
+ );
602
+
603
+ if ( ! empty( $list_id ) && ! is_array( $list_id ) ) {
604
+ $list_id = array( $list_id );
605
+ }
606
+
607
+ if ( isset( $_POST['id'] ) ) {
608
+
609
+ $bulkdata['current'] = (int) sanitize_text_field( $_POST['id'] );
610
+ $raw_list_data = $wpdb->get_col(
611
+ $wpdb->prepare(
612
+ "SELECT data FROM {$wpdb->prefix}ig_temp_import
613
+ WHERE identifier = %s ORDER BY ID ASC LIMIT %d, %d",
614
+ $bulkdata['identifier'],
615
+ $bulkdata['current'] * $parts_at_once,
616
+ $parts_at_once
617
+ )
618
+ );
619
+ if ( $raw_list_data ) {
620
+
621
+ $contacts_data = array();
622
+ $current_date_time = ig_get_current_date_time();
623
+ $contact_emails = array();
624
+ $processed_emails = array();
625
+ foreach ( $raw_list_data as $raw_list ) {
626
+ $raw_list = unserialize( base64_decode( $raw_list ) );
627
+ // each entry
628
+ foreach ( $raw_list as $line ) {
629
+ if ( ! trim( $line ) ) {
630
+ $bulkdata['lines']--;
631
+ continue;
632
+ }
633
+ $data = str_getcsv( $line, $bulkdata['separator'], '"' );
634
+ $cols_count = count( $data );
635
+ $insert = array();
636
+ for ( $col = 0; $col < $cols_count; $col++ ) {
637
+ $d = trim( $data[ $col ] );
638
+ if ( ! isset( $order[ $col ] ) ) {
639
+ continue;
640
+ }
641
+ switch ( $order[ $col ] ) {
642
+ case 'first_last':
643
+ $name = explode( ' ', $d );
644
+ if ( ! empty( $name[0] ) ) {
645
+ $insert['first_name'] = $name[0];
646
+ }
647
+ if ( ! empty( $name[1] ) ) {
648
+ $insert['last_name'] = $name[1];
649
+ }
650
+ break;
651
+ case 'last_first':
652
+ $name = explode( ' ', $d );
653
+ if ( ! empty( $name[1] ) ) {
654
+ $insert['first_name'] = $name[1];
655
+ }
656
+ if ( ! empty( $name[0] ) ) {
657
+ $insert['last_name'] = $name[0];
658
+ }
659
+ break;
660
+ case '-1':
661
+ // ignored column
662
+ break;
663
+ default:
664
+ $insert[ $order[ $col ] ] = $d;
665
+ }
666
+ }
667
+
668
+ if ( empty( $insert['email'] ) || ! is_email( $insert['email'] ) ) {
669
+ $error_data = array();
670
+ if ( empty( $insert['email'] ) ) {
671
+ $error_data['error_code'] = 'empty';
672
+ } else if ( ! is_email( $insert['email'] ) ) {
673
+ $error_data['error_code'] = 'invalid';
674
+ $error_data['email'] = $insert['email'];
675
+ }
676
+ if ( ! empty( $insert['first_name'] ) ) {
677
+ $error_data['first_name'] = $insert['first_name'];
678
+ }
679
+ if ( ! empty( $insert['last_name'] ) ) {
680
+ $error_data['last_name'] = $insert['last_name'];
681
+ }
682
+ $bulkdata['errors']++;
683
+ $erroremails[] = $error_data;
684
+ continue;
685
+ }
686
+
687
+ $email = sanitize_email( strtolower( $insert['email'] ) );
688
+
689
+ if ( ! in_array( $email, $processed_emails, true ) ) {
690
+ $first_name = isset( $insert['first_name'] ) ? ES_Common::handle_emoji_characters( sanitize_text_field( trim( $insert['first_name'] ) ) ) : '';
691
+ $last_name = isset( $insert['last_name'] ) ? ES_Common::handle_emoji_characters( sanitize_text_field( trim( $insert['last_name'] ) ) ) : '';
692
+
693
+ // If name empty, get the name from Email.
694
+ if ( empty( $first_name ) && empty( $last_name ) ) {
695
+ $name = ES_Common::get_name_from_email( $email );
696
+ $names = ES_Common::prepare_first_name_last_name( $name );
697
+ $first_name = sanitize_text_field( $names['first_name'] );
698
+ $last_name = sanitize_text_field( $names['last_name'] );
699
+ }
700
+
701
+ $guid = ES_Common::generate_guid();
702
+
703
+ $contacts_data[$email]['first_name'] = $first_name;
704
+ $contacts_data[$email]['last_name'] = $last_name;
705
+ $contacts_data[$email]['email'] = $email;
706
+ $contacts_data[$email]['source'] = 'import';
707
+ $contacts_data[$email]['status'] = 'verified';
708
+ $contacts_data[$email]['hash'] = $guid;
709
+ $contacts_data[$email]['created_at'] = $current_date_time;
710
+
711
+ $processed_emails[] = $email;
712
+ $bulkdata['imported']++;
713
+ } else {
714
+ $error_data = array(
715
+ 'email' => $email,
716
+ 'error_code' => 'duplicate',
717
+ );
718
+ if ( ! empty( $insert['first_name'] ) ) {
719
+ $error_data['first_name'] = $insert['first_name'];
720
+ }
721
+ if ( ! empty( $insert['last_name'] ) ) {
722
+ $error_data['last_name'] = $insert['last_name'];
723
+ }
724
+ $erroremails[] = $error_data;
725
+ $bulkdata['errors']++;
726
+ }
727
+ $contact_emails[] = $email;
728
+ }
729
+ }
730
+
731
+ if ( count( $contact_emails ) > 0 ) {
732
+
733
+ $contact_emails = array_unique( $contact_emails );
734
+
735
+ $existing_contacts_email_id_map = ES()->contacts_db->get_email_id_map( $processed_emails );
736
+ $existing_contacts_count = count( $existing_contacts_email_id_map );
737
+ if ( ! empty( $existing_contacts_email_id_map ) ) {
738
+ $contacts_data = array_diff_key( $contacts_data, $existing_contacts_email_id_map );
739
+ }
740
+
741
+ if ( ! empty( $contacts_data ) ) {
742
+ ES()->contacts_db->bulk_insert( $contacts_data );
743
+ }
744
+
745
+ $contact_ids = ES()->contacts_db->get_contact_ids_by_emails( $contact_emails );
746
+ if ( count( $contact_ids ) > 0 ) {
747
+ ES()->lists_contacts_db->remove_contacts_from_lists( $contact_ids, $list_id );
748
+ ES()->lists_contacts_db->do_import_contacts_into_list( $list_id, $contact_ids, $status, 1, $current_date_time );
749
+ }
750
+ }
751
+ }
752
+
753
+ $return['memoryusage'] = size_format( memory_get_peak_usage( true ), 2 );
754
+ $return['errors'] = isset( $bulkdata['errors'] ) ? $bulkdata['errors'] : 0;
755
+ $return['imported'] = ( $bulkdata['imported'] );
756
+ $return['total'] = ( $bulkdata['lines'] );
757
+ $return['f_errors'] = number_format_i18n( $bulkdata['errors'] );
758
+ $return['f_imported'] = number_format_i18n( $bulkdata['imported'] );
759
+ $return['f_total'] = number_format_i18n( $bulkdata['lines'] );
760
+
761
+ $return['html'] = '';
762
+
763
+ if ( $bulkdata['imported'] + $bulkdata['errors'] >= $bulkdata['lines'] ) {
764
+ /* translators: 1. Total imported contacts 2. Total contacts */
765
+ $return['html'] .= '<p class="text-base text-gray-600 pt-2 pb-1.5">' . sprintf( esc_html__( '%1$s of %2$s contacts imported', 'email-subscribers' ), '<span class="font-medium">' . number_format_i18n( $bulkdata['imported'] ) . '</span>', '<span class="font-medium">' . number_format_i18n( $bulkdata['lines'] ) . '</span>' ) . '<p>';
766
+
767
+ if ( $bulkdata['errors'] ) {
768
+ $i = 0;
769
+ $table = '<p class="text-sm text-gray-600 pt-2 pb-1.5">' . esc_html__( 'The following contacts were skipped', 'email-subscribers' ) . ':</p>';
770
+ $table .= '<table class="w-full bg-white rounded-lg shadow overflow-hidden mt-1.5">';
771
+ $table .= '<thead class="rounded-md"><tr class="border-b border-gray-200 bg-gray-50 text-left text-sm leading-4 font-medium text-gray-500 tracking-wider"><th class="pl-4 py-4" width="5%">#</th>';
772
+
773
+ $first_name_column_choosen = in_array( 'first_name', $order, true );
774
+ if ( $first_name_column_choosen ) {
775
+ $table .= '<th class="pl-3 py-3 font-medium">' . esc_html__( 'First Name', 'email-subscribers' ) . '</th>';
776
+ }
777
+
778
+ $last_name_column_choosen = in_array( 'last_name', $order, true );
779
+ if ( $last_name_column_choosen ) {
780
+ $table .= '<th class="pl-3 py-3 font-medium">' . esc_html__( 'Last Name', 'email-subscribers' ) . '</th>';
781
+ }
782
+
783
+ $table .= '<th class="pl-3 py-3 font-medium">' . esc_html__( 'Email', 'email-subscribers' ) . '</th>';
784
+ $table .= '<th class="pl-3 pr-1 py-3 font-medium">' . esc_html__( 'Reason', 'email-subscribers' ) . '</th>';
785
+ $table .= '</tr></thead><tbody>';
786
+ foreach ( $erroremails as $error_data ) {
787
+ $table .= '<tr class="border-b border-gray-200 text-left leading-4 text-gray-800 tracking-wide">';
788
+ $table .= '<td class="pl-4">' . ( ++$i ) . '</td>';
789
+ $email = ! empty( $error_data['email'] ) ? $error_data['email'] : '-';
790
+ if ( $first_name_column_choosen ) {
791
+ $first_name = ! empty( $error_data['first_name'] ) ? $error_data['first_name'] : '-';
792
+ $table .= '<td class="pl-3 py-3">' . esc_html( $first_name ) . '</td>';
793
+ }
794
+ if ( $last_name_column_choosen ) {
795
+ $last_name = ! empty( $error_data['last_name'] ) ? $error_data['last_name'] : '-';
796
+ $table .= '<td class="pl-3 py-3">' . esc_html( $last_name ) . '</td>';
797
+ }
798
+ $error_code = ! empty( $error_data['error_code'] ) ? $error_data['error_code'] : '-';
799
+ $reason = ! empty( $error_codes[$error_code] ) ? $error_codes[$error_code] : '-';
800
+ $table .= '<td class="pl-3 py-3">' . esc_html( $email ) . '</td><td class="pl-3 py-3">' . esc_html( $reason ) . '</td></tr>';
801
+ }
802
+ $table .= '</tbody></table>';
803
+ $return['html'] .= $table;
804
+ }
805
+ $this->do_cleanup();
806
+ } else {
807
+ update_option( 'ig_es_bulk_import', $bulkdata );
808
+ update_option( 'ig_es_bulk_import_errors', $erroremails );
809
+ }
810
+ $return['success'] = true;
811
+ }
812
+
813
+ wp_send_json( $return );
814
+ }
815
+
816
+ /**
817
+ * Method to create temporary table if not already exists
818
+ *
819
+ * @since 4.6.6
820
+ */
821
+ public function maybe_create_temporary_import_table() {
822
+
823
+ global $wpdb;
824
+
825
+ require_once ABSPATH . 'wp-admin/includes/upgrade.php';
826
+
827
+ $charset_collate = $wpdb->get_charset_collate();
828
+ $create_table_query = "CREATE TABLE IF NOT EXISTS {$wpdb->prefix}ig_temp_import (
829
+ ID bigint(20) NOT NULL AUTO_INCREMENT,
830
+ data longtext NOT NULL,
831
+ identifier char(13) NOT NULL,
832
+ PRIMARY KEY (ID)
833
+ ) $charset_collate";
834
+
835
+ dbDelta( $create_table_query );
836
+ }
837
+
838
+ /**
839
+ * Method to truncate table and options used during import process
840
+ *
841
+ * @since 4.6.6
842
+ */
843
+ public function do_cleanup() {
844
+
845
+ global $wpdb;
846
+
847
+ // Delete options used during import.
848
+ delete_option( 'ig_es_bulk_import' );
849
+ delete_option( 'ig_es_bulk_import_errors' );
850
+
851
+ // We are trancating table so that primary key is reset to 1 otherwise ID column's value will increase on every insert and at some point ID column's data type may not be able to accomodate its value resulting in insert to fail.
852
+ $wpdb->query( "TRUNCATE TABLE {$wpdb->prefix}ig_temp_import" );
853
+ }
854
+ }
lite/includes/classes/class-es-list-table.php ADDED
@@ -0,0 +1,128 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ if ( ! class_exists( 'WP_List_Table' ) ) {
4
+ require_once( ABSPATH . 'wp-admin/includes/class-wp-list-table.php' );
5
+ }
6
+
7
+ class ES_List_Table extends WP_List_Table {
8
+
9
+ /**
10
+ * Perpage items
11
+ *
12
+ * @since 4.6.6
13
+ * @var int
14
+ *
15
+ */
16
+ public $per_page = 10;
17
+
18
+ /**
19
+ * Prepare Items
20
+ *
21
+ * @since 4.6.6
22
+ */
23
+ public function prepare_items() {
24
+
25
+ $this->_column_headers = $this->get_column_info();
26
+
27
+ /** Process bulk action */
28
+ $this->process_bulk_action();
29
+
30
+ $search_str = ig_es_get_request_data( 's' );
31
+ $this->search_box( $search_str, 'form-search-input' );
32
+
33
+ $per_page = $this->get_items_per_page( static::$option_per_page, 25 );
34
+ //$per_page = $this->per_page; // Show Max 10 records per page
35
+
36
+ $current_page = $this->get_pagenum();
37
+ $total_items = $this->get_lists( 0, 0, true );
38
+
39
+ $this->set_pagination_args( array(
40
+ 'total_items' => $total_items, //WE have to calculate the total number of items
41
+ 'per_page' => $per_page //WE have to determine how many items to show on a page
42
+ ) );
43
+
44
+ $this->items = $this->get_lists( $per_page, $current_page );
45
+ }
46
+
47
+ /**
48
+ * Get Lists
49
+ *
50
+ * @param int $per_page
51
+ * @param int $current_page
52
+ * @param false $do_count_only
53
+ *
54
+ * @since 4.6.6
55
+ */
56
+ public function get_lists( $per_page = 10, $current_page = 1, $do_count_only = false ) {
57
+
58
+ }
59
+
60
+ /**
61
+ * For Bulk actions
62
+ *
63
+ * @since 1.0.0
64
+ */
65
+ public function process_bulk_action() {
66
+
67
+ }
68
+
69
+ /**
70
+ * Hide default search box
71
+ *
72
+ * @param string $text
73
+ * @param string $input_id
74
+ *
75
+ * @since 4.6.6
76
+ */
77
+ public function search_box( $text, $input_id ) {
78
+ }
79
+
80
+
81
+ /**
82
+ * Hide top pagination
83
+ *
84
+ * @param string $which
85
+ *
86
+ * @since 4.6.6
87
+ */
88
+ public function pagination( $which ) {
89
+
90
+ if ( 'bottom' == $which ) {
91
+ parent::pagination( $which );
92
+ }
93
+ }
94
+
95
+ /**
96
+ * Add Row action
97
+ *
98
+ * @param string[] $actions
99
+ * @param bool $always_visible
100
+ * @param string $class
101
+ *
102
+ * @return string
103
+ *
104
+ * @since 4.6.6
105
+ *
106
+ */
107
+ protected function row_actions( $actions, $always_visible = false, $class = '' ) {
108
+ $action_count = count( $actions );
109
+ $i = 0;
110
+
111
+ if ( ! $action_count ) {
112
+ return '';
113
+ }
114
+
115
+ $out = '<div class="' . ( $always_visible ? 'row-actions visible' : 'row-actions ' . $class ) . '">';
116
+ foreach ( $actions as $action => $link ) {
117
+ ++ $i;
118
+ ( $i == $action_count ) ? $sep = '' : $sep = ' | ';
119
+ $out .= "<span class='$action'>$link$sep</span>";
120
+ }
121
+ $out .= '</div>';
122
+
123
+ $out .= '<button type="button" class="toggle-row"><span class="screen-reader-text">' . __( 'Show more details', 'email-subscribers' ) . '</span></button>';
124
+
125
+ return $out;
126
+ }
127
+
128
+ }
lite/includes/classes/class-es-lists-table.php CHANGED
@@ -5,11 +5,7 @@ if ( ! defined( 'ABSPATH' ) ) {
5
  exit;
6
  }
7
 
8
- if ( ! class_exists( 'WP_List_Table' ) ) {
9
- require_once ABSPATH . 'wp-admin/includes/class-wp-list-table.php';
10
- }
11
-
12
- class ES_Lists_Table extends WP_List_Table {
13
  /**
14
  * ES_DB_Lists object
15
  *
@@ -600,6 +596,7 @@ class ES_Lists_Table extends WP_List_Table {
600
  return $actions;
601
  }
602
 
 
603
  /**
604
  * Prepare search box
605
  *
@@ -609,7 +606,7 @@ class ES_Lists_Table extends WP_List_Table {
609
  * @since 4.0.0
610
  * @since 4.3.4 Added esc_attr()
611
  */
612
- public function search_box( $text = '', $input_id = '' ) {
613
  ?>
614
  <p class="search-box">
615
  <label class="screen-reader-text" for="<?php echo esc_attr( $input_id ); ?>"><?php echo esc_attr( $text ); ?>:</label>
@@ -628,6 +625,7 @@ class ES_Lists_Table extends WP_List_Table {
628
 
629
  /** Process bulk action */
630
  $this->process_bulk_action();
 
631
  $this->search_box( ig_es_get_request_data( 's' ), 'list-search-input' );
632
 
633
  $per_page = $this->get_items_per_page( self::$option_per_page, 25 );
5
  exit;
6
  }
7
 
8
+ class ES_Lists_Table extends ES_List_Table {
 
 
 
 
9
  /**
10
  * ES_DB_Lists object
11
  *
596
  return $actions;
597
  }
598
 
599
+
600
  /**
601
  * Prepare search box
602
  *
606
  * @since 4.0.0
607
  * @since 4.3.4 Added esc_attr()
608
  */
609
+ public function search_box( $text = '', $input_id = '' ) {
610
  ?>
611
  <p class="search-box">
612
  <label class="screen-reader-text" for="<?php echo esc_attr( $input_id ); ?>"><?php echo esc_attr( $text ); ?>:</label>
625
 
626
  /** Process bulk action */
627
  $this->process_bulk_action();
628
+
629
  $this->search_box( ig_es_get_request_data( 's' ), 'list-search-input' );
630
 
631
  $per_page = $this->get_items_per_page( self::$option_per_page, 25 );
lite/includes/classes/class-es-queue.php CHANGED
@@ -898,10 +898,10 @@ if ( ! class_exists( 'ES_Queue' ) ) {
898
 
899
  if ( ! empty( $active_subscribers ) ) {
900
  $subscribers_batch_size = 5000;
901
-
902
  // Create batches of subscribers each containing maximum subscribers equal to $subscribers_batch_size.
903
  $subscribers_batches = array_chunk( $active_subscribers, $subscribers_batch_size );
904
-
905
  foreach ( $subscribers_batches as $key => $subscribers ) {
906
 
907
  $delivery_data = array();
898
 
899
  if ( ! empty( $active_subscribers ) ) {
900
  $subscribers_batch_size = 5000;
901
+
902
  // Create batches of subscribers each containing maximum subscribers equal to $subscribers_batch_size.
903
  $subscribers_batches = array_chunk( $active_subscribers, $subscribers_batch_size );
904
+
905
  foreach ( $subscribers_batches as $key => $subscribers ) {
906
 
907
  $delivery_data = array();
lite/includes/classes/class-es-reports-table.php CHANGED
@@ -5,12 +5,7 @@ if ( ! defined( 'ABSPATH' ) ) {
5
  exit;
6
  }
7
 
8
-
9
- if ( ! class_exists( 'WP_List_Table' ) ) {
10
- require_once ABSPATH . 'wp-admin/includes/class-wp-list-table.php';
11
- }
12
-
13
- class ES_Reports_Table extends WP_List_Table {
14
 
15
  public static $instance;
16
 
@@ -36,10 +31,10 @@ class ES_Reports_Table extends WP_List_Table {
36
  $campaign_type = ES()->campaigns_db->get_campaign_type_by_id( $campaign_id );
37
  }
38
 
39
- $campaign_types = array('sequence', 'sequence_message');
40
  //Only if it is sequence then control will transfer to Sequence Reports class.
41
  if ( ! empty ( $campaign_type ) && in_array( $campaign_type, $campaign_types ) ) {
42
- if ( ES()->is_pro() ) {
43
  $reports = ES_Pro_Sequence_Reports::get_instance();
44
  $reports->es_sequence_reports_callback();
45
  } else {
@@ -66,7 +61,7 @@ class ES_Reports_Table extends WP_List_Table {
66
  /* translators: %s: Cron url */
67
  $content = sprintf( __( "<a href='%s' class='px-3 py-2 ig-es-imp-button'>Send Queued Emails Now</a>", 'email-subscribers' ), $cron_url );
68
  } else {
69
- $content = sprintf( __( "<span class='ig-es-send-queue-emails px-3 button-disabled'>Send Queued Emails Now</span>", 'email-subscribers' ) );
70
  $content .= sprintf( __( "<br /><span class='es-helper pl-6'>No emails found in queue</span>", 'email-subscribers' ) );
71
  }
72
  ?>
@@ -77,13 +72,15 @@ class ES_Reports_Table extends WP_List_Table {
77
  </div>
78
  </div>
79
  </header>
80
- <div><hr class="wp-header-end"></div>
 
 
81
  <div id="poststuff" class="es-items-lists">
82
  <div id="post-body" class="metabox-holder column-1">
83
  <div id="post-body-content">
84
  <div class="meta-box-sortables ui-sortable">
85
  <form method="get">
86
- <input type="hidden" name="page" value="es_reports" />
87
  <?php
88
  // Display search field and other available filter fields.
89
  $this->prepare_items();
@@ -101,7 +98,7 @@ class ES_Reports_Table extends WP_List_Table {
101
  <br class="clear">
102
  </div>
103
  </div>
104
- <?php
105
  }
106
  }
107
  }
@@ -159,7 +156,7 @@ class ES_Reports_Table extends WP_List_Table {
159
  </div>
160
 
161
  <div class="mt-2 mb-2 block">
162
- <span class="pt-3 pb-4 leading-5 tracking-wide text-gray-600"><?php echo esc_html('Viewed ' . $email_viewed_count . '/' . $total_email_sent ); ?>
163
  </span>
164
  </div>
165
 
@@ -210,12 +207,12 @@ class ES_Reports_Table extends WP_List_Table {
210
  <td class="pl-6 pr-2 py-2 border-b border-gray-200 text-sm leading-5 text-gray-500"><span style="color:#03a025;font-weight:bold;"><?php echo esc_html( $status ); ?></span></td>
211
  <td class="pl-2 pr-2 py-2 border-b border-gray-200 text-sm leading-5 text-gray-500"><?php echo wp_kses_post( ig_es_format_date_time( $sent_at ) ); ?></td>
212
  <td class="pl-6 pr-2 py-2 border-b border-gray-200 text-sm leading-5 text-gray-600"><span>
213
- <?php
214
  /* translators: 1: Italic tag 2: Class attribute */
215
- echo ! empty( $opened ) && 1 == $opened ? esc_html__( 'Viewed', 'email-subscribers' ) : wp_kses_post( '<i title="Not yet viewed" class="dashicons dashicons-es dashicons-minus"/>' );
216
  ?>
217
  </span></td>
218
- <td class="pl-6 pr-1 py-2 border-b border-gray-200 text-sm leading-5 text-gray-500"><?php echo wp_kses_post(ig_es_format_date_time( $opened_at ) ); ?></td>
219
  </tr>
220
 
221
  <?php
@@ -233,7 +230,7 @@ class ES_Reports_Table extends WP_List_Table {
233
  /**
234
  * Render a column when no column specific method exist.
235
  *
236
- * @param array $item
237
  * @param string $column_name
238
  *
239
  * @return mixed
@@ -343,7 +340,7 @@ class ES_Reports_Table extends WP_List_Table {
343
 
344
  $campaign_hash = $item['hash'];
345
 
346
- $total_emails_sent = $item['count'];
347
  $total_emails_to_be_sent = $item['count'];
348
  // if ( ! empty( $campaign_hash ) ) {
349
  // $total_emails_sent = ES_DB_Sending_Queue::get_total_emails_sent_by_hash( $campaign_hash );
@@ -415,6 +412,7 @@ class ES_Reports_Table extends WP_List_Table {
415
 
416
  // Search box
417
  $search = ig_es_get_request_data( 's' );
 
418
  $this->search_box( $search, 'reports-search-input' );
419
 
420
  $per_page = $this->get_items_per_page( 'reports_per_page', 20 );
@@ -432,14 +430,14 @@ class ES_Reports_Table extends WP_List_Table {
432
  }
433
 
434
  public function get_notifications( $per_page = 5, $page_number = 1, $do_count_only = false ) {
435
- global $wpdb,$wpbd;
436
 
437
- $order_by = sanitize_sql_orderby( ig_es_get_request_data( 'orderby' ) );
438
- $order = ig_es_get_request_data( 'order' );
439
- $campaign_id = ig_es_get_request_data( 'campaign_id' );
440
- $search = ig_es_get_request_data( 's' );
441
- $filter_reports_by_campaign_status = ig_es_get_request_data( 'filter_reports_by_status' );
442
- $filter_reports_by_campaign_type = ig_es_get_request_data( 'filter_reports_by_campaign_type' );
443
 
444
  $ig_mailing_queue_table = IG_MAILING_QUEUE_TABLE;
445
 
@@ -449,8 +447,8 @@ class ES_Reports_Table extends WP_List_Table {
449
  $sql = "SELECT * FROM {$ig_mailing_queue_table}";
450
  }
451
 
452
- $where_columns = array();
453
- $where_args = array();
454
  $add_where_clause = true;
455
 
456
  if ( ! empty( $campaign_id ) && is_numeric( $campaign_id ) ) {
@@ -465,7 +463,7 @@ class ES_Reports_Table extends WP_List_Table {
465
  }
466
 
467
  if ( ! empty( $where_query ) ) {
468
- $sql .= ' WHERE ' . $where_query;
469
  $add_where_clause = false;
470
  }
471
 
@@ -473,7 +471,7 @@ class ES_Reports_Table extends WP_List_Table {
473
  if ( ! $add_where_clause ) {
474
  $sql .= $wpdb->prepare( ' AND status = %s', $filter_reports_by_campaign_status );
475
  } else {
476
- $sql .= $wpdb->prepare( ' WHERE status = %s', $filter_reports_by_campaign_status );
477
  $add_where_clause = false;
478
  }
479
  }
@@ -507,9 +505,9 @@ class ES_Reports_Table extends WP_List_Table {
507
  $order_by_clause = " ORDER BY {$order_by} {$order}, {$default_order_by} DESC";
508
  }
509
 
510
- $sql .= $order_by_clause;
511
- $sql .= " LIMIT $per_page";
512
- $sql .= ' OFFSET ' . ( $page_number - 1 ) * $per_page;
513
  $result = $wpbd->get_results( $sql, 'ARRAY_A' );
514
 
515
  } else {
@@ -520,7 +518,7 @@ class ES_Reports_Table extends WP_List_Table {
520
  }
521
 
522
  public function process_bulk_action() {
523
- $allowedtags = ig_es_allowed_html_tags_in_esc();
524
  // Detect when a bulk action is being triggered...
525
  if ( 'view' === $this->current_action() ) {
526
 
@@ -579,8 +577,8 @@ class ES_Reports_Table extends WP_List_Table {
579
 
580
  public function preview_email( $report_id ) {
581
  ob_start();
582
- $allowedtags = ig_es_allowed_html_tags_in_esc();
583
- add_filter( 'safe_style_css', 'ig_es_allowed_css_style' );
584
  ?>
585
  <div class="wrap">
586
  <h2 style="margin-bottom:1em;">
@@ -624,7 +622,7 @@ class ES_Reports_Table extends WP_List_Table {
624
  *
625
  * @since 4.6.5
626
  */
627
- public function search_box( $text = '', $input_id = '' ) {
628
  ?>
629
  <p class="search-box">
630
  <label class="screen-reader-text" for="<?php echo esc_attr( $input_id ); ?>"><?php echo esc_attr( $text ); ?>:</label>
@@ -632,28 +630,28 @@ class ES_Reports_Table extends WP_List_Table {
632
  <?php submit_button( __( 'Search Reports', 'email-subscribers' ), 'button', false, false, array( 'id' => 'search-submit' ) ); ?>
633
  </p>
634
  <p class="search-box search-group-box box-ma10">
635
- <?php
636
- $filter_by_status = ig_es_get_request_data( 'filter_reports_by_status' );
637
  ?>
638
  <select name="filter_reports_by_status" id="ig_es_filter_report_by_status">
639
- <?php
640
- $allowedtags = ig_es_allowed_html_tags_in_esc();
641
  add_filter( 'safe_style_css', 'ig_es_allowed_css_style' );
642
- $campaign_report_status = ES_Common::prepare_campaign_report_statuses_dropdown_options( $filter_by_status, __( 'All Status', 'email-subscribers' ) );
643
- echo wp_kses( $campaign_report_status , $allowedtags );
644
  ?>
645
  </select>
646
  </p>
647
  <p class="search-box search-group-box box-ma10">
648
  <?php $filter_by_campaign_type = ig_es_get_request_data( 'filter_reports_by_campaign_type' ); ?>
649
  <select name="filter_reports_by_campaign_type" id="ig_es_filter_reports_by_campaign_type">
650
- <?php
651
  $campaign_report_type = ES_Common::prepare_campaign_type_dropdown_options( $filter_by_campaign_type, __( 'All Type', 'email-subscribers' ) );
652
- echo wp_kses( $campaign_report_type , $allowedtags );
653
  ?>
654
  </select>
655
  </p>
656
- <?php
657
  }
658
 
659
  public static function get_instance() {
@@ -663,4 +661,5 @@ class ES_Reports_Table extends WP_List_Table {
663
 
664
  return self::$instance;
665
  }
 
666
  }
5
  exit;
6
  }
7
 
8
+ class ES_Reports_Table extends ES_List_Table {
 
 
 
 
 
9
 
10
  public static $instance;
11
 
31
  $campaign_type = ES()->campaigns_db->get_campaign_type_by_id( $campaign_id );
32
  }
33
 
34
+ $campaign_types = array( 'sequence', 'sequence_message' );
35
  //Only if it is sequence then control will transfer to Sequence Reports class.
36
  if ( ! empty ( $campaign_type ) && in_array( $campaign_type, $campaign_types ) ) {
37
+ if ( ES()->is_pro() ) {
38
  $reports = ES_Pro_Sequence_Reports::get_instance();
39
  $reports->es_sequence_reports_callback();
40
  } else {
61
  /* translators: %s: Cron url */
62
  $content = sprintf( __( "<a href='%s' class='px-3 py-2 ig-es-imp-button'>Send Queued Emails Now</a>", 'email-subscribers' ), $cron_url );
63
  } else {
64
+ $content = sprintf( __( "<span class='ig-es-send-queue-emails px-3 button-disabled'>Send Queued Emails Now</span>", 'email-subscribers' ) );
65
  $content .= sprintf( __( "<br /><span class='es-helper pl-6'>No emails found in queue</span>", 'email-subscribers' ) );
66
  }
67
  ?>
72
  </div>
73
  </div>
74
  </header>
75
+ <div>
76
+ <hr class="wp-header-end">
77
+ </div>
78
  <div id="poststuff" class="es-items-lists">
79
  <div id="post-body" class="metabox-holder column-1">
80
  <div id="post-body-content">
81
  <div class="meta-box-sortables ui-sortable">
82
  <form method="get">
83
+ <input type="hidden" name="page" value="es_reports"/>
84
  <?php
85
  // Display search field and other available filter fields.
86
  $this->prepare_items();
98
  <br class="clear">
99
  </div>
100
  </div>
101
+ <?php
102
  }
103
  }
104
  }
156
  </div>
157
 
158
  <div class="mt-2 mb-2 block">
159
+ <span class="pt-3 pb-4 leading-5 tracking-wide text-gray-600"><?php echo esc_html( 'Viewed ' . $email_viewed_count . '/' . $total_email_sent ); ?>
160
  </span>
161
  </div>
162
 
207
  <td class="pl-6 pr-2 py-2 border-b border-gray-200 text-sm leading-5 text-gray-500"><span style="color:#03a025;font-weight:bold;"><?php echo esc_html( $status ); ?></span></td>
208
  <td class="pl-2 pr-2 py-2 border-b border-gray-200 text-sm leading-5 text-gray-500"><?php echo wp_kses_post( ig_es_format_date_time( $sent_at ) ); ?></td>
209
  <td class="pl-6 pr-2 py-2 border-b border-gray-200 text-sm leading-5 text-gray-600"><span>
210
+ <?php
211
  /* translators: 1: Italic tag 2: Class attribute */
212
+ echo ! empty( $opened ) && 1 == $opened ? esc_html__( 'Viewed', 'email-subscribers' ) : wp_kses_post( '<i title="Not yet viewed" class="dashicons dashicons-es dashicons-minus"/>' );
213
  ?>
214
  </span></td>
215
+ <td class="pl-6 pr-1 py-2 border-b border-gray-200 text-sm leading-5 text-gray-500"><?php echo wp_kses_post( ig_es_format_date_time( $opened_at ) ); ?></td>
216
  </tr>
217
 
218
  <?php
230
  /**
231
  * Render a column when no column specific method exist.
232
  *
233
+ * @param array $item
234
  * @param string $column_name
235
  *
236
  * @return mixed
340
 
341
  $campaign_hash = $item['hash'];
342
 
343
+ $total_emails_sent = $item['count'];
344
  $total_emails_to_be_sent = $item['count'];
345
  // if ( ! empty( $campaign_hash ) ) {
346
  // $total_emails_sent = ES_DB_Sending_Queue::get_total_emails_sent_by_hash( $campaign_hash );
412
 
413
  // Search box
414
  $search = ig_es_get_request_data( 's' );
415
+
416
  $this->search_box( $search, 'reports-search-input' );
417
 
418
  $per_page = $this->get_items_per_page( 'reports_per_page', 20 );
430
  }
431
 
432
  public function get_notifications( $per_page = 5, $page_number = 1, $do_count_only = false ) {
433
+ global $wpdb, $wpbd;
434
 
435
+ $order_by = sanitize_sql_orderby( ig_es_get_request_data( 'orderby' ) );
436
+ $order = ig_es_get_request_data( 'order' );
437
+ $campaign_id = ig_es_get_request_data( 'campaign_id' );
438
+ $search = ig_es_get_request_data( 's' );
439
+ $filter_reports_by_campaign_status = ig_es_get_request_data( 'filter_reports_by_status' );
440
+ $filter_reports_by_campaign_type = ig_es_get_request_data( 'filter_reports_by_campaign_type' );
441
 
442
  $ig_mailing_queue_table = IG_MAILING_QUEUE_TABLE;
443
 
447
  $sql = "SELECT * FROM {$ig_mailing_queue_table}";
448
  }
449
 
450
+ $where_columns = array();
451
+ $where_args = array();
452
  $add_where_clause = true;
453
 
454
  if ( ! empty( $campaign_id ) && is_numeric( $campaign_id ) ) {
463
  }
464
 
465
  if ( ! empty( $where_query ) ) {
466
+ $sql .= ' WHERE ' . $where_query;
467
  $add_where_clause = false;
468
  }
469
 
471
  if ( ! $add_where_clause ) {
472
  $sql .= $wpdb->prepare( ' AND status = %s', $filter_reports_by_campaign_status );
473
  } else {
474
+ $sql .= $wpdb->prepare( ' WHERE status = %s', $filter_reports_by_campaign_status );
475
  $add_where_clause = false;
476
  }
477
  }
505
  $order_by_clause = " ORDER BY {$order_by} {$order}, {$default_order_by} DESC";
506
  }
507
 
508
+ $sql .= $order_by_clause;
509
+ $sql .= " LIMIT $per_page";
510
+ $sql .= ' OFFSET ' . ( $page_number - 1 ) * $per_page;
511
  $result = $wpbd->get_results( $sql, 'ARRAY_A' );
512
 
513
  } else {
518
  }
519
 
520
  public function process_bulk_action() {
521
+ $allowedtags = ig_es_allowed_html_tags_in_esc();
522
  // Detect when a bulk action is being triggered...
523
  if ( 'view' === $this->current_action() ) {
524
 
577
 
578
  public function preview_email( $report_id ) {
579
  ob_start();
580
+ $allowedtags = ig_es_allowed_html_tags_in_esc();
581
+ add_filter( 'safe_style_css', 'ig_es_allowed_css_style' );
582
  ?>
583
  <div class="wrap">
584
  <h2 style="margin-bottom:1em;">
622
  *
623
  * @since 4.6.5
624
  */
625
+ public function search_box( $text = '', $input_id = '' ) {
626
  ?>
627
  <p class="search-box">
628
  <label class="screen-reader-text" for="<?php echo esc_attr( $input_id ); ?>"><?php echo esc_attr( $text ); ?>:</label>
630
  <?php submit_button( __( 'Search Reports', 'email-subscribers' ), 'button', false, false, array( 'id' => 'search-submit' ) ); ?>
631
  </p>
632
  <p class="search-box search-group-box box-ma10">
633
+ <?php
634
+ $filter_by_status = ig_es_get_request_data( 'filter_reports_by_status' );
635
  ?>
636
  <select name="filter_reports_by_status" id="ig_es_filter_report_by_status">
637
+ <?php
638
+ $allowedtags = ig_es_allowed_html_tags_in_esc();
639
  add_filter( 'safe_style_css', 'ig_es_allowed_css_style' );
640
+ $campaign_report_status = ES_Common::prepare_campaign_report_statuses_dropdown_options( $filter_by_status, __( 'All Status', 'email-subscribers' ) );
641
+ echo wp_kses( $campaign_report_status, $allowedtags );
642
  ?>
643
  </select>
644
  </p>
645
  <p class="search-box search-group-box box-ma10">
646
  <?php $filter_by_campaign_type = ig_es_get_request_data( 'filter_reports_by_campaign_type' ); ?>
647
  <select name="filter_reports_by_campaign_type" id="ig_es_filter_reports_by_campaign_type">
648
+ <?php
649
  $campaign_report_type = ES_Common::prepare_campaign_type_dropdown_options( $filter_by_campaign_type, __( 'All Type', 'email-subscribers' ) );
650
+ echo wp_kses( $campaign_report_type, $allowedtags );
651
  ?>
652
  </select>
653
  </p>
654
+ <?php
655
  }
656
 
657
  public static function get_instance() {
661
 
662
  return self::$instance;
663
  }
664
+
665
  }
lite/includes/classes/class-ig-es-background-process-helper.php CHANGED
@@ -247,7 +247,9 @@ if ( ! class_exists( 'IG_ES_Background_Process_Helper' ) ) {
247
  'cookies' => $_COOKIE,
248
  'sslverify' => apply_filters( 'https_local_ssl_verify', false ),
249
  );
250
-
 
 
251
  // Make a asynchronous request.
252
  $response = wp_remote_get( esc_url_raw( $admin_ajax_url ), $args );
253
 
247
  'cookies' => $_COOKIE,
248
  'sslverify' => apply_filters( 'https_local_ssl_verify', false ),
249
  );
250
+
251
+ $args = apply_filters( 'ig_es_async_request_args', $args );
252
+
253
  // Make a asynchronous request.
254
  $response = wp_remote_get( esc_url_raw( $admin_ajax_url ), $args );
255
 
lite/includes/classes/class-ig-es-wc-session-tracker.php CHANGED
@@ -20,6 +20,7 @@ class IG_ES_WC_Session_Tracker {
20
 
21
  /**
22
  * Tracking cookie name
 
23
  * @var string - cookie name
24
  **/
25
  private static $tracking_key_cookie_name;
20
 
21
  /**
22
  * Tracking cookie name
23
+ *
24
  * @var string - cookie name
25
  **/
26
  private static $tracking_key_cookie_name;
lite/includes/classes/ig-es-wc-cookies.php CHANGED
@@ -6,6 +6,7 @@ if ( ! defined( 'ABSPATH' ) ) {
6
 
7
  /**
8
  * Class IG_ES_WC_Cookies
 
9
  * @since 4.6.5
10
  */
11
  class IG_ES_WC_Cookies {
@@ -40,6 +41,7 @@ class IG_ES_WC_Cookies {
40
 
41
  /**
42
  * Clear a cookie and also updates the $_COOKIE array.
 
43
  * @param $name
44
  */
45
  public static function clear( $name ) {
6
 
7
  /**
8
  * Class IG_ES_WC_Cookies
9
+ *
10
  * @since 4.6.5
11
  */
12
  class IG_ES_WC_Cookies {
41
 
42
  /**
43
  * Clear a cookie and also updates the $_COOKIE array.
44
+ *
45
  * @param $name
46
  */
47
  public static function clear( $name ) {
lite/includes/db/class-es-db-actions.php CHANGED
@@ -417,7 +417,7 @@ class ES_DB_Actions extends ES_DB {
417
  */
418
  public function get_last_opened_of_contact_ids( $contact_ids = '', $filter = false ) {
419
 
420
- global $wpdb;
421
 
422
  if ( empty( $contact_ids ) ) {
423
  return array();
@@ -425,7 +425,7 @@ class ES_DB_Actions extends ES_DB {
425
 
426
  $contact_ids_str = implode( ',', $contact_ids );
427
 
428
- $result = $wpdb->get_results( $wpdb->prepare( "SELECT contact_id, MAX(created_at) as last_opened_at FROM {$wpdb->prefix}ig_actions WHERE FIND_IN_SET( contact_id, %s ) AND type = %d GROUP BY contact_id", $contact_ids_str, IG_MESSAGE_OPEN ), ARRAY_A );
429
 
430
  if ( $filter ) {
431
  $last_opened_at = array_column($result, 'last_opened_at', 'contact_id');
417
  */
418
  public function get_last_opened_of_contact_ids( $contact_ids = '', $filter = false ) {
419
 
420
+ global $wpbd;
421
 
422
  if ( empty( $contact_ids ) ) {
423
  return array();
425
 
426
  $contact_ids_str = implode( ',', $contact_ids );
427
 
428
+ $result = $wpbd->get_results( $wpbd->prepare( "SELECT contact_id, MAX(created_at) as last_opened_at FROM {$wpbd->prefix}ig_actions WHERE contact_id IN ({$contact_ids_str}) AND type = %d GROUP BY contact_id", IG_MESSAGE_OPEN ), ARRAY_A );
429
 
430
  if ( $filter ) {
431
  $last_opened_at = array_column($result, 'last_opened_at', 'contact_id');
lite/includes/db/class-es-db-campaigns.php CHANGED
@@ -179,7 +179,7 @@ class ES_DB_Campaigns extends ES_DB {
179
  * @since 4.0.0
180
  */
181
  public function migrate_post_notifications() {
182
- global $wpdb;
183
 
184
  $campaigns_data = array();
185
  $template_ids = array();
@@ -190,7 +190,7 @@ class ES_DB_Campaigns extends ES_DB {
190
 
191
  $es_notification_table = EMAIL_SUBSCRIBERS_NOTIFICATION_TABLE;
192
 
193
- $total = $wpdb->get_var( $wpdb->prepare( "SELECT count(*) as total FROM {$wpdb->prefix}es_notification WHERE %d", 1 ) );
194
 
195
  if ( $total > 0 ) {
196
  $batch_size = IG_DEFAULT_BATCH_SIZE;
@@ -200,8 +200,8 @@ class ES_DB_Campaigns extends ES_DB {
200
  for ( $i = 0; $i < $total_batches; $i ++ ) {
201
  $batch_start = $i * $batch_size;
202
  //$query = 'SELECT * FROM ' . EMAIL_SUBSCRIBERS_NOTIFICATION_TABLE . " LIMIT {$batch_start}, {$batch_size}";
203
- //$notifications = $wpdb->get_results( $query, ARRAY_A ); // WPCS: cache ok, DB call ok, unprepared SQL ok.
204
- $notifications = $wpdb->get_results( $wpdb->prepare( "SELECT * FROM {$wpdb->prefix}es_notification LIMIT %d, %d", $batch_start, $batch_size ), ARRAY_A );
205
  if ( count( $notifications ) > 0 ) {
206
  foreach ( $notifications as $key => $notification ) {
207
  $categories = ! empty( $notification['es_note_cat'] ) ? $notification['es_note_cat'] : '';
@@ -239,13 +239,10 @@ class ES_DB_Campaigns extends ES_DB {
239
  $templates_data = array();
240
  // Get Template Name & Slug
241
  if ( count( $template_ids ) > 0 ) {
242
- //$template_ids_str = implode( "', '", $template_ids );
243
- //$query = "SELECT ID, post_name, post_title FROM {$wpdb->prefix}posts WHERE id IN ({$template_ids_str})";
244
- //$templates = $wpdb->get_results( $query, ARRAY_A );
245
- $template_ids_str = implode( ',', $template_ids );
246
 
247
- // We can use IN query only but to make WooCommerce standard compatible, we have used FIND_IN_SET.
248
- $templates = $wpdb->get_results( $wpdb->prepare( "SELECT ID, post_name, post_title FROM {$wpdb->prefix}posts WHERE FIND_IN_SET(ID, %s)", $template_ids_str ), ARRAY_A );
249
  foreach ( $templates as $template ) {
250
  $templates_data[ $template['ID'] ] = $template;
251
  }
@@ -430,7 +427,18 @@ class ES_DB_Campaigns extends ES_DB {
430
  * @since 4.2.1
431
  */
432
  public function get_total_newsletters() {
433
- return $this->get_total_campaigns_by_type( 'newsletter' );
 
 
 
 
 
 
 
 
 
 
 
434
  }
435
 
436
  /**
@@ -697,7 +705,7 @@ class ES_DB_Campaigns extends ES_DB {
697
  * @since 4.4.4
698
  */
699
  public function update_status( $campaign_ids = array(), $status = 0 ) {
700
- global $wpdb;
701
 
702
  $updated = false;
703
  if ( empty( $campaign_ids ) ) {
@@ -706,7 +714,6 @@ class ES_DB_Campaigns extends ES_DB {
706
 
707
  $id_str = '';
708
  $campaign_ids = esc_sql( $campaign_ids );
709
-
710
  if ( is_array( $campaign_ids ) && count( $campaign_ids ) > 0 ) {
711
  $id_str = implode( ',', $campaign_ids );
712
  } elseif ( is_numeric( $campaign_ids ) ) {
@@ -715,10 +722,10 @@ class ES_DB_Campaigns extends ES_DB {
715
 
716
  if ( ! empty( $id_str ) ) {
717
 
718
- $updated = $wpdb->query( $wpdb->prepare("UPDATE {$wpdb->prefix}ig_campaigns SET status = %d WHERE FIND_IN_SET(id, %s)", $status, $id_str) );
719
 
720
  //Changing status of child campaigns along with its parent campaign id
721
- $wpdb->query( $wpdb->prepare("UPDATE {$wpdb->prefix}ig_campaigns SET status = %d WHERE FIND_IN_SET(parent_id, %s)", $status, $id_str) );
722
  }
723
 
724
  return $updated;
179
  * @since 4.0.0
180
  */
181
  public function migrate_post_notifications() {
182
+ global $wpbd;
183
 
184
  $campaigns_data = array();
185
  $template_ids = array();
190
 
191
  $es_notification_table = EMAIL_SUBSCRIBERS_NOTIFICATION_TABLE;
192
 
193
+ $total = $wpbd->get_var( $wpbd->prepare( "SELECT count(*) as total FROM {$wpbd->prefix}es_notification WHERE %d", 1 ) );
194
 
195
  if ( $total > 0 ) {
196
  $batch_size = IG_DEFAULT_BATCH_SIZE;
200
  for ( $i = 0; $i < $total_batches; $i ++ ) {
201
  $batch_start = $i * $batch_size;
202
  //$query = 'SELECT * FROM ' . EMAIL_SUBSCRIBERS_NOTIFICATION_TABLE . " LIMIT {$batch_start}, {$batch_size}";
203
+ //$notifications = $wpbd->get_results( $query, ARRAY_A ); // WPCS: cache ok, DB call ok, unprepared SQL ok.
204
+ $notifications = $wpbd->get_results( $wpbd->prepare( "SELECT * FROM {$wpbd->prefix}es_notification LIMIT %d, %d", $batch_start, $batch_size ), ARRAY_A );
205
  if ( count( $notifications ) > 0 ) {
206
  foreach ( $notifications as $key => $notification ) {
207
  $categories = ! empty( $notification['es_note_cat'] ) ? $notification['es_note_cat'] : '';
239
  $templates_data = array();
240
  // Get Template Name & Slug
241
  if ( count( $template_ids ) > 0 ) {
242
+ $template_ids_str = implode( "', '", $template_ids );
243
+ $query = "SELECT ID, post_name, post_title FROM {$wpbd->prefix}posts WHERE id IN ({$template_ids_str})";
244
+ $templates = $wpbd->get_results( $query, ARRAY_A );
 
245
 
 
 
246
  foreach ( $templates as $template ) {
247
  $templates_data[ $template['ID'] ] = $template;
248
  }
427
  * @since 4.2.1
428
  */
429
  public function get_total_newsletters() {
430
+ return $this->get_total_campaigns_by_type();
431
+ }
432
+
433
+ /**
434
+ * Get total sequence
435
+ *
436
+ * @return string|null
437
+ *
438
+ * @since 4.6.6
439
+ */
440
+ public function get_total_sequences() {
441
+ return $this->get_total_campaigns_by_type( 'sequence' );
442
  }
443
 
444
  /**
705
  * @since 4.4.4
706
  */
707
  public function update_status( $campaign_ids = array(), $status = 0 ) {
708
+ global $wpbd;
709
 
710
  $updated = false;
711
  if ( empty( $campaign_ids ) ) {
714
 
715
  $id_str = '';
716
  $campaign_ids = esc_sql( $campaign_ids );
 
717
  if ( is_array( $campaign_ids ) && count( $campaign_ids ) > 0 ) {
718
  $id_str = implode( ',', $campaign_ids );
719
  } elseif ( is_numeric( $campaign_ids ) ) {
722
 
723
  if ( ! empty( $id_str ) ) {
724
 
725
+ $updated = $wpbd->query( $wpbd->prepare("UPDATE {$wpbd->prefix}ig_campaigns SET status = %d WHERE id IN({$id_str})", $status ) );
726
 
727
  //Changing status of child campaigns along with its parent campaign id
728
+ $wpbd->query( $wpbd->prepare("UPDATE {$wpbd->prefix}ig_campaigns SET status = %d WHERE parent_id IN({$id_str})", $status ) );
729
  }
730
 
731
  return $updated;
lite/includes/db/class-es-db-contacts.php CHANGED
@@ -135,18 +135,15 @@ class ES_DB_Contacts extends ES_DB {
135
  */
136
  public function get_contacts_email_name_map( $emails = array() ) {
137
 
138
- global $wpdb;
139
 
140
  $subscriber_email_name_map = array();
141
  if ( count( $emails ) > 0 ) {
142
 
143
- $emails_str = implode( ',', $emails );
144
 
145
- $subscribers = $wpdb->get_results(
146
- $wpdb->prepare(
147
- "SELECT email, first_name, last_name FROM {$wpdb->prefix}ig_contacts WHERE FIND_IN_SET( email, %s )",
148
- $emails_str
149
- ),
150
  ARRAY_A
151
  );
152
 
@@ -266,14 +263,12 @@ class ES_DB_Contacts extends ES_DB {
266
  // Check if we have got array of list ids.
267
  if ( is_array( $list_id ) ) {
268
  $list_ids_str = implode( ',', $list_id );
269
- $where = $wpdb->prepare(
270
- "id IN (SELECT contact_id FROM {$wpdb->prefix}ig_lists_contacts WHERE FIND_IN_SET( list_id, %s ) AND status IN ('subscribed', 'confirmed'))",
271
- $list_ids_str
272
- );
273
  } else {
274
- $where = $wpdb->prepare( "id IN (SELECT contact_id FROM {$wpdb->prefix}ig_lists_contacts WHERE list_id = %d AND status IN ('subscribed', 'confirmed'))", $list_id );
275
  }
276
 
 
 
277
  return $this->get_by_conditions( $where );
278
 
279
  }
@@ -423,15 +418,14 @@ class ES_DB_Contacts extends ES_DB {
423
  * @since 4.3.4 Use prepare_for_in_query instead of array_to_str
424
  */
425
  public function edit_contact_global_status( $ids = array(), $unsubscribed = 0 ) {
426
- global $wpdb;
427
 
428
- $ids = implode( ',', $ids );
429
 
430
- return $wpdb->query(
431
- $wpdb->prepare(
432
- "UPDATE {$wpdb->prefix}ig_contacts SET unsubscribed = %d WHERE FIND_IN_SET( id, %s )",
433
- $unsubscribed,
434
- $ids
435
  )
436
  );
437
  }
@@ -448,7 +442,7 @@ class ES_DB_Contacts extends ES_DB {
448
  * @since 4.3.4 Used prepare_for_in_query instead of array_to_str
449
  */
450
  public function is_contact_exist_in_list( $email, $list_id ) {
451
- global $wpdb;
452
 
453
  $contact_id = $this->get_column_by( 'id', 'email', $email );
454
 
@@ -462,10 +456,9 @@ class ES_DB_Contacts extends ES_DB {
462
 
463
  $list_ids_str = implode( ',', $list_id );
464
 
465
- $list_contact_count = $wpdb->get_var(
466
- $wpdb->prepare(
467
- "SELECT count(*) as count FROM {$wpdb->prefix}ig_lists_contacts WHERE FIND_IN_SET(list_id,%s) AND contact_id = %d",
468
- $list_ids_str,
469
  $contact_id
470
  )
471
  );
@@ -542,18 +535,17 @@ class ES_DB_Contacts extends ES_DB {
542
  * @since 4.3.4 Used prepare_for_in_query instead of array_to_str
543
  */
544
  public function get_contact_ids_by_emails( $emails = array() ) {
545
- global $wpdb;
546
 
547
  if ( count( $emails ) > 0 ) {
548
- $emails_str = implode( ',', $emails );
549
- $ids = $wpdb->get_col(
550
- $wpdb->prepare(
551
- "SELECT id FROM {$wpdb->prefix}ig_contacts WHERE FIND_IN_SET( email, %s ) ",
552
- $emails_str
553
- )
554
- );
555
  } else {
556
- $ids = $wpdb->get_col( "SELECT id FROM {$wpdb->prefix}ig_contacts" );
557
  }
558
 
559
  return $ids;
@@ -570,19 +562,20 @@ class ES_DB_Contacts extends ES_DB {
570
  * @since 4.3.4 Used prepare_for_in_query instead of array_to_str
571
  */
572
  public function get_email_id_map( $emails = array() ) {
573
- global $wpdb;
574
 
575
  if ( count( $emails ) > 0 ) {
576
- $emails_str = implode( ',', $emails );
577
- $results = $wpdb->get_results(
578
- $wpdb->prepare(
579
- "SELECT id, email FROM {$wpdb->prefix}ig_contacts WHERE FIND_IN_SET( email, %s )",
580
- $emails_str
 
581
  ),
582
  ARRAY_A
583
  );
584
  } else {
585
- $results = $wpdb->get_results( "SELECT id, email FROM {$wpdb->prefix}ig_contacts", ARRAY_A );
586
  }
587
 
588
  $map = array();
@@ -722,7 +715,7 @@ class ES_DB_Contacts extends ES_DB {
722
  * @since 4.3.4 Used prepare_for_in_query instead of array_to_str
723
  */
724
  public function edit_list_contact_status( $contact_ids, $list_ids, $status ) {
725
- global $wpdb;
726
 
727
  $contact_ids = implode( ',', $contact_ids );
728
  $list_ids = implode( ',', $list_ids );
@@ -730,38 +723,32 @@ class ES_DB_Contacts extends ES_DB {
730
 
731
  $query_result = array();
732
  if ( 'subscribed' === $status ) {
733
- $query_result = $wpdb->query(
734
- $wpdb->prepare(
735
- "UPDATE {$wpdb->prefix}ig_lists_contacts SET status = %s, subscribed_at = %s WHERE FIND_IN_SET( contact_id, %s ) AND FIND_IN_SET( list_id, %s )",
736
  array(
737
  $status,
738
  $current_date,
739
- $contact_ids,
740
- $list_ids
741
  )
742
  )
743
  );
744
  } elseif ( 'unsubscribed' === $status ) {
745
- $query_result = $wpdb->query(
746
- $wpdb->prepare(
747
- "UPDATE {$wpdb->prefix}ig_lists_contacts SET status = %s, unsubscribed_at = %s WHERE FIND_IN_SET( contact_id, %s ) AND FIND_IN_SET( list_id, %s )",
748
  array(
749
  $status,
750
  $current_date,
751
- $contact_ids,
752
- $list_ids
753
  )
754
  )
755
  );
756
  } elseif ( 'unconfirmed' === $status ) {
757
- $query_result = $wpdb->query(
758
- $wpdb->prepare(
759
- "UPDATE {$wpdb->prefix}ig_lists_contacts SET status = %s, optin_type = %d, subscribed_at = NULL, unsubscribed_at = NULL WHERE FIND_IN_SET( contact_id, %s ) AND FIND_IN_SET( list_id, %s )",
760
  array(
761
  $status,
762
  IG_DOUBLE_OPTIN,
763
- $contact_ids,
764
- $list_ids
765
  )
766
  )
767
  );
135
  */
136
  public function get_contacts_email_name_map( $emails = array() ) {
137
 
138
+ global $wpbd;
139
 
140
  $subscriber_email_name_map = array();
141
  if ( count( $emails ) > 0 ) {
142
 
143
+ $emails_str = "'" . implode( "','", $emails ) . "'";
144
 
145
+ $subscribers = $wpbd->get_results(
146
+ "SELECT email, first_name, last_name FROM {$wpbd->prefix}ig_contacts WHERE email IN({$emails_str})",
 
 
 
147
  ARRAY_A
148
  );
149
 
263
  // Check if we have got array of list ids.
264
  if ( is_array( $list_id ) ) {
265
  $list_ids_str = implode( ',', $list_id );
 
 
 
 
266
  } else {
267
+ $list_ids_str = $list_id;
268
  }
269
 
270
+ $where = "id IN (SELECT contact_id FROM {$wpdb->prefix}ig_lists_contacts WHERE list_id IN({$list_ids_str}) AND status IN ('subscribed', 'confirmed'))";
271
+
272
  return $this->get_by_conditions( $where );
273
 
274
  }
418
  * @since 4.3.4 Use prepare_for_in_query instead of array_to_str
419
  */
420
  public function edit_contact_global_status( $ids = array(), $unsubscribed = 0 ) {
421
+ global $wpbd;
422
 
423
+ $ids_str = implode( ',', $ids );
424
 
425
+ return $wpbd->query(
426
+ $wpbd->prepare(
427
+ "UPDATE {$wpbd->prefix}ig_contacts SET unsubscribed = %d WHERE id IN({$ids_str})",
428
+ $unsubscribed
 
429
  )
430
  );
431
  }
442
  * @since 4.3.4 Used prepare_for_in_query instead of array_to_str
443
  */
444
  public function is_contact_exist_in_list( $email, $list_id ) {
445
+ global $wpbd;
446
 
447
  $contact_id = $this->get_column_by( 'id', 'email', $email );
448
 
456
 
457
  $list_ids_str = implode( ',', $list_id );
458
 
459
+ $list_contact_count = $wpbd->get_var(
460
+ $wpbd->prepare(
461
+ "SELECT count(*) as count FROM {$wpbd->prefix}ig_lists_contacts WHERE list_id IN ($list_ids_str) AND contact_id = %d",
 
462
  $contact_id
463
  )
464
  );
535
  * @since 4.3.4 Used prepare_for_in_query instead of array_to_str
536
  */
537
  public function get_contact_ids_by_emails( $emails = array() ) {
538
+ global $wpbd;
539
 
540
  if ( count( $emails ) > 0 ) {
541
+ $ids_count = count( $emails );
542
+ $ids_placeholders = array_fill( 0, $ids_count, '%s' );
543
+ $ids = $wpbd->get_col( $wpbd->prepare(
544
+ "SELECT id FROM {$wpbd->prefix}ig_contacts WHERE email IN( " . implode( ',', $ids_placeholders ) . ' )',
545
+ $emails
546
+ ) );
 
547
  } else {
548
+ $ids = $wpbd->get_col( "SELECT id FROM {$wpbd->prefix}ig_contacts" );
549
  }
550
 
551
  return $ids;
562
  * @since 4.3.4 Used prepare_for_in_query instead of array_to_str
563
  */
564
  public function get_email_id_map( $emails = array() ) {
565
+ global $wpbd;
566
 
567
  if ( count( $emails ) > 0 ) {
568
+ $email_count = count( $emails );
569
+ $placeholders = array_fill( 0, $email_count, '%s' );
570
+ $results = $wpbd->get_results(
571
+ $wpbd->prepare(
572
+ "SELECT id, email FROM {$wpbd->prefix}ig_contacts WHERE email IN( " . implode( ',', $placeholders ) . ' )',
573
+ $emails
574
  ),
575
  ARRAY_A
576
  );
577
  } else {
578
+ $results = $wpbd->get_results( "SELECT id, email FROM {$wpbd->prefix}ig_contacts", ARRAY_A );
579
  }
580
 
581
  $map = array();
715
  * @since 4.3.4 Used prepare_for_in_query instead of array_to_str
716
  */
717
  public function edit_list_contact_status( $contact_ids, $list_ids, $status ) {
718
+ global $wpbd;
719
 
720
  $contact_ids = implode( ',', $contact_ids );
721
  $list_ids = implode( ',', $list_ids );
723
 
724
  $query_result = array();
725
  if ( 'subscribed' === $status ) {
726
+ $query_result = $wpbd->query(
727
+ $wpbd->prepare(
728
+ "UPDATE {$wpbd->prefix}ig_lists_contacts SET status = %s, subscribed_at = %s WHERE contact_id IN( {$contact_ids} ) AND list_id IN( {$list_ids} )",
729
  array(
730
  $status,
731
  $current_date,
 
 
732
  )
733
  )
734
  );
735
  } elseif ( 'unsubscribed' === $status ) {
736
+ $query_result = $wpbd->query(
737
+ $wpbd->prepare(
738
+ "UPDATE {$wpbd->prefix}ig_lists_contacts SET status = %s, unsubscribed_at = %s WHERE contact_id IN( {$contact_ids} ) AND list_id IN( {$list_ids} )",
739
  array(
740
  $status,
741
  $current_date,
 
 
742
  )
743
  )
744
  );
745
  } elseif ( 'unconfirmed' === $status ) {
746
+ $query_result = $wpbd->query(
747
+ $wpbd->prepare(
748
+ "UPDATE {$wpbd->prefix}ig_lists_contacts SET status = %s, optin_type = %d, subscribed_at = NULL, unsubscribed_at = NULL WHERE contact_id IN( {$contact_ids} ) AND list_id IN( {$list_ids} )",
749
  array(
750
  $status,
751
  IG_DOUBLE_OPTIN,
 
 
752
  )
753
  )
754
  );
lite/includes/db/class-es-db-lists-contacts.php CHANGED
@@ -137,7 +137,7 @@ class ES_DB_Lists_Contacts extends ES_DB {
137
  *
138
  * @since 4.3.5
139
  */
140
- public function prepare_contact_data( $contact_ids = array(), $list_id ) {
141
 
142
  if ( empty( $contact_ids ) || empty( $list_id ) ) {
143
  return array();
@@ -602,7 +602,7 @@ class ES_DB_Lists_Contacts extends ES_DB {
602
  * @since 4.3.5 Removed static call
603
  */
604
  public function edit_subscriber_status( $ids = array(), $status = '', $list_ids = array() ) {
605
- global $wpdb;
606
 
607
  if ( ! is_array( $ids ) ) {
608
  $ids = array( $ids );
@@ -623,49 +623,44 @@ class ES_DB_Lists_Contacts extends ES_DB {
623
  if ( ! empty ( $list_ids ) ) {
624
 
625
  $list_ids_str = implode( ',', $list_ids );
626
- $result = $wpdb->query(
627
- $wpdb->prepare(
628
- "UPDATE {$wpdb->prefix}ig_lists_contacts SET status = %s, subscribed_at = %s WHERE FIND_IN_SET(contact_id, %s) AND FIND_IN_SET(list_id, %s)",
629
  array(
630
  $status,
631
  $current_date,
632
- $ids_str,
633
- $list_ids_str,
634
  )
635
  )
636
  );
637
  } else {
638
- $result = $wpdb->query(
639
- $wpdb->prepare(
640
- "UPDATE {$wpdb->prefix}ig_lists_contacts SET status = %s, subscribed_at = %s WHERE FIND_IN_SET(contact_id, %s)",
641
  array(
642
  $status,
643
  $current_date,
644
- $ids_str
645
  )
646
  )
647
  );
648
  }
649
  return $result;
650
  } elseif ( 'unsubscribed' === $status ) {
651
- return $wpdb->query(
652
- $wpdb->prepare(
653
- "UPDATE {$wpdb->prefix}ig_lists_contacts SET status = %s, unsubscribed_at = %s WHERE FIND_IN_SET(contact_id, %s)",
654
  array(
655
  $status,
656
  $current_date,
657
- $ids_str
658
  )
659
  )
660
  );
661
  } elseif ( 'unconfirmed' === $status ) {
662
- return $wpdb->query(
663
- $wpdb->prepare(
664
- "UPDATE {$wpdb->prefix}ig_lists_contacts SET status = %s, optin_type = %d, subscribed_at = NULL, unsubscribed_at = NULL WHERE FIND_IN_SET(contact_id, %s)",
665
  array(
666
  $status,
667
  IG_DOUBLE_OPTIN,
668
- $ids_str
669
  )
670
  )
671
  );
@@ -687,7 +682,7 @@ class ES_DB_Lists_Contacts extends ES_DB {
687
  * @since 4.3.5 Removed static call
688
  */
689
  public function is_status_update_required( $ids = array(), $status = '' ) {
690
- global $wpdb;
691
 
692
  if ( ! is_array( $ids ) ) {
693
  $ids = array( $ids );
@@ -696,7 +691,7 @@ class ES_DB_Lists_Contacts extends ES_DB {
696
  $ids = array_map( 'absint', $ids );
697
  $ids_str = implode( ',', $ids );
698
 
699
- $where = $wpdb->prepare( 'FIND_IN_SET(contact_id, %s) && status != %s', $ids_str, $status );
700
 
701
  if ( $this->count( $where ) ) {
702
  return true;
137
  *
138
  * @since 4.3.5
139
  */
140
+ public function prepare_contact_data( $contact_ids, $list_id ) {
141
 
142
  if ( empty( $contact_ids ) || empty( $list_id ) ) {
143
  return array();
602
  * @since 4.3.5 Removed static call
603
  */
604
  public function edit_subscriber_status( $ids = array(), $status = '', $list_ids = array() ) {
605
+ global $wpbd;
606
 
607
  if ( ! is_array( $ids ) ) {
608
  $ids = array( $ids );
623
  if ( ! empty ( $list_ids ) ) {
624
 
625
  $list_ids_str = implode( ',', $list_ids );
626
+ $result = $wpbd->query(
627
+ $wpbd->prepare(
628
+ "UPDATE {$wpbd->prefix}ig_lists_contacts SET status = %s, subscribed_at = %s WHERE contact_id IN( {$ids_str} ) AND list_id IN( {$list_ids_str} )",
629
  array(
630
  $status,
631
  $current_date,
 
 
632
  )
633
  )
634
  );
635
  } else {
636
+ $result = $wpbd->query(
637
+ $wpbd->prepare(
638
+ "UPDATE {$wpbd->prefix}ig_lists_contacts SET status = %s, subscribed_at = %s WHERE contact_id IN( {$ids_str} )",
639
  array(
640
  $status,
641
  $current_date,
 
642
  )
643
  )
644
  );
645
  }
646
  return $result;
647
  } elseif ( 'unsubscribed' === $status ) {
648
+ return $wpbd->query(
649
+ $wpbd->prepare(
650
+ "UPDATE {$wpbd->prefix}ig_lists_contacts SET status = %s, unsubscribed_at = %s WHERE contact_id IN( {$ids_str} )",
651
  array(
652
  $status,
653
  $current_date,
 
654
  )
655
  )
656
  );
657
  } elseif ( 'unconfirmed' === $status ) {
658
+ return $wpbd->query(
659
+ $wpbd->prepare(
660
+ "UPDATE {$wpbd->prefix}ig_lists_contacts SET status = %s, optin_type = %d, subscribed_at = NULL, unsubscribed_at = NULL WHERE contact_id IN( {$ids_str} )",
661
  array(
662
  $status,
663
  IG_DOUBLE_OPTIN,
 
664
  )
665
  )
666
  );
682
  * @since 4.3.5 Removed static call
683
  */
684
  public function is_status_update_required( $ids = array(), $status = '' ) {
685
+ global $wpbd;
686
 
687
  if ( ! is_array( $ids ) ) {
688
  $ids = array( $ids );
691
  $ids = array_map( 'absint', $ids );
692
  $ids_str = implode( ',', $ids );
693
 
694
+ $where = $wpbd->prepare( "contact_id IN($ids_str) && status != %s", $status );
695
 
696
  if ( $this->count( $where ) ) {
697
  return true;
lite/includes/db/class-es-db-lists.php CHANGED
@@ -327,7 +327,7 @@ class ES_DB_Lists extends ES_DB {
327
  *
328
  * @since 4.2.1
329
  */
330
- public function update_list( $row_id = 0, $name ) {
331
 
332
  if ( empty( $row_id ) ) {
333
  return;
327
  *
328
  * @since 4.2.1
329
  */
330
+ public function update_list( $row_id, $name ) {
331
 
332
  if ( empty( $row_id ) ) {
333
  return;
lite/includes/db/class-es-db-mailing-queue.php CHANGED
@@ -250,17 +250,14 @@ class ES_DB_Mailing_Queue {
250
  }
251
 
252
  public static function delete_notifications( $ids ) {
253
- global $wpdb;
254
 
255
  $ids = esc_sql( $ids );
256
 
257
  $ids = implode( ',', array_map( 'absint', $ids ) );
258
 
259
- $wpdb->query(
260
- $wpdb->prepare(
261
- "DELETE FROM {$wpdb->prefix}ig_mailing_queue WHERE FIND_IN_SET(id, %s)",
262
- $ids
263
- )
264
  );
265
  }
266
 
250
  }
251
 
252
  public static function delete_notifications( $ids ) {
253
+ global $wpbd;
254
 
255
  $ids = esc_sql( $ids );
256
 
257
  $ids = implode( ',', array_map( 'absint', $ids ) );
258
 
259
+ $wpbd->query(
260
+ "DELETE FROM {$wpbd->prefix}ig_mailing_queue WHERE id IN($ids)"
 
 
 
261
  );
262
  }
263
 
lite/includes/db/class-es-db-sending-queue.php CHANGED
@@ -69,7 +69,7 @@ class ES_DB_Sending_Queue {
69
  }
70
 
71
  public static function update_sent_status( $contact_ids, $message_id = 0, $status = 'Sent' ) {
72
- global $wpdb;
73
 
74
  $updated = false;
75
  if ( 0 == $message_id ) {
@@ -86,22 +86,20 @@ class ES_DB_Sending_Queue {
86
  if ( ! empty( $id_str ) ) {
87
  if ( 'Sent' === $status ) {
88
  $current_time = ig_get_current_date_time();
89
- $updated = $wpdb->query(
90
- $wpdb->prepare(
91
- "UPDATE {$wpdb->prefix}ig_sending_queue SET status = %s, sent_at = %s WHERE mailing_queue_id = %d AND FIND_IN_SET(contact_id, %s)",
92
  $status,
93
  $current_time,
94
- $message_id,
95
- $id_str
96
  )
97
  );
98
  } else {
99
- $updated = $wpdb->query(
100
- $wpdb->prepare(
101
- "UPDATE {$wpdb->prefix}ig_sending_queue SET status = %s WHERE mailing_queue_id = %d AND FIND_IN_SET(contact_id, %s)",
102
  $status,
103
- $message_id,
104
- $id_str
105
  )
106
  );
107
  }
@@ -467,16 +465,13 @@ class ES_DB_Sending_Queue {
467
  }
468
 
469
  public static function delete_sending_queue_by_mailing_id( $mailing_queue_ids ) {
470
- global $wpdb;
471
 
472
  $mailing_queue_ids = esc_sql( $mailing_queue_ids );
473
  $mailing_queue_ids = implode( ',', array_map( 'absint', $mailing_queue_ids ) );
474
 
475
- $wpdb->query(
476
- $wpdb->prepare(
477
- "DELETE FROM {$wpdb->prefix}ig_sending_queue WHERE FIND_IN_SET (mailing_queue_id, %s)",
478
- $mailing_queue_ids
479
- )
480
  );
481
  }
482
 
@@ -585,7 +580,7 @@ class ES_DB_Sending_Queue {
585
  * @since 4.3.7
586
  */
587
  public static function get_emails_id_map_by_campaign( $campaign_id = 0, $emails = array() ) {
588
- global $wpdb;
589
 
590
  $emails = esc_sql( $emails );
591
  $campaign_id = esc_sql( absint( $campaign_id ) );
@@ -594,14 +589,12 @@ class ES_DB_Sending_Queue {
594
  return array();
595
  }
596
 
597
- $emails_str = implode( ',', $emails );
598
 
599
- $results = $wpdb->get_results(
600
- $wpdb->prepare(
601
- // We are using FIND_IN_SET since IN clause requires emails to be seperated by single quotes(') which get escaped when passed as a placeholder value in $wp->prepare.
602
- "SELECT contact_id, email FROM {$wpdb->prefix}ig_sending_queue WHERE campaign_id = %d AND FIND_IN_SET( email, %s)",
603
- $campaign_id,
604
- $emails_str
605
  ),
606
  ARRAY_A
607
  );
69
  }
70
 
71
  public static function update_sent_status( $contact_ids, $message_id = 0, $status = 'Sent' ) {
72
+ global $wpbd;
73
 
74
  $updated = false;
75
  if ( 0 == $message_id ) {
86
  if ( ! empty( $id_str ) ) {
87
  if ( 'Sent' === $status ) {
88
  $current_time = ig_get_current_date_time();
89
+ $updated = $wpbd->query(
90
+ $wpbd->prepare(
91
+ "UPDATE {$wpbd->prefix}ig_sending_queue SET status = %s, sent_at = %s WHERE mailing_queue_id = %d AND contact_id IN($id_str)",
92
  $status,
93
  $current_time,
94
+ $message_id
 
95
  )
96
  );
97
  } else {
98
+ $updated = $wpbd->query(
99
+ $wpbd->prepare(
100
+ "UPDATE {$wpbd->prefix}ig_sending_queue SET status = %s WHERE mailing_queue_id = %d AND contact_id IN($id_str)",
101
  $status,
102
+ $message_id
 
103
  )
104
  );
105
  }
465
  }
466
 
467
  public static function delete_sending_queue_by_mailing_id( $mailing_queue_ids ) {
468
+ global $wpbd;
469
 
470
  $mailing_queue_ids = esc_sql( $mailing_queue_ids );
471
  $mailing_queue_ids = implode( ',', array_map( 'absint', $mailing_queue_ids ) );
472
 
473
+ $wpbd->query(
474
+ "DELETE FROM {$wpbd->prefix}ig_sending_queue WHERE mailing_queue_id IN ($mailing_queue_ids)"
 
 
 
475
  );
476
  }
477
 
580
  * @since 4.3.7
581
  */
582
  public static function get_emails_id_map_by_campaign( $campaign_id = 0, $emails = array() ) {
583
+ global $wpbd;
584
 
585
  $emails = esc_sql( $emails );
586
  $campaign_id = esc_sql( absint( $campaign_id ) );
589
  return array();
590
  }
591
 
592
+ $emails_str = "'" . implode( "','", $emails ) . "'";
593
 
594
+ $results = $wpbd->get_results(
595
+ $wpbd->prepare(
596
+ "SELECT contact_id, email FROM {$wpbd->prefix}ig_sending_queue WHERE campaign_id = %d AND email IN($emails_str)",
597
+ $campaign_id
 
 
598
  ),
599
  ARRAY_A
600
  );
lite/includes/es-core-functions.php CHANGED
@@ -979,22 +979,3 @@ if ( ! function_exists( 'ig_es_insert_widget_in_sidebar' ) ) {
979
  }
980
  }
981
 
982
- /**
983
- * Method to increase response size while making http request.
984
- *
985
- * @param array $args Request arguements.
986
- *
987
- * @return array $args Request arguements.
988
- *
989
- * @since 4.6.5
990
- */
991
- if ( ! function_exists( 'ig_es_increase_http_response_size') ) {
992
-
993
- function ig_es_increase_http_response_size( $args = array() ) {
994
-
995
- // Increase the reponse size to 1500 KB.
996
- $args['limit_response_size'] = 1536000; // 1500 KB
997
-
998
- return $args;
999
- }
1000
- }
979
  }
980
  }
981
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
lite/includes/feedback.php CHANGED
@@ -6,7 +6,7 @@
6
  */
7
  if ( ! function_exists( 'ig_es_get_additional_info' ) ) {
8
 
9
- function ig_es_get_additional_info( $additional_info, $system_info = false ) {
10
  global $ig_es_tracker;
11
 
12
  $additional_info['version'] = ES_PLUGIN_VERSION;
6
  */
7
  if ( ! function_exists( 'ig_es_get_additional_info' ) ) {
8
 
9
+ function ig_es_get_additional_info( $additional_info = array(), $system_info = false ) {
10
  global $ig_es_tracker;
11
 
12
  $additional_info['version'] = ES_PLUGIN_VERSION;
lite/includes/feedback/class-ig-feedback.php CHANGED
@@ -4,20 +4,20 @@ if ( ! defined( 'ABSPATH' ) ) {
4
  exit; // Exit if accessed directly.
5
  }
6
 
7
- if ( ! class_exists( 'IG_Feedback_V_1_2_4' ) ) {
8
  /**
9
  * IG Feedback
10
  *
11
  * The IG Feedback class adds functionality to get quick interactive feedback from users.
12
  * There are different types of feedabck widget like Stars, Emoji, Thubms Up/ Down, Number etc.
13
  *
14
- * @class IG_Feedback_V_1_2_4
15
  * @since 1.0.0
16
  * @copyright Copyright (c) 2019, Icegram
17
  * @license https://opensource.org/licenses/gpl-license GNU Public License
18
  * @package feedback
19
  */
20
- class IG_Feedback_V_1_2_4 {
21
 
22
  /**
23
  * Version of Feedback Library
@@ -26,7 +26,7 @@ if ( ! class_exists( 'IG_Feedback_V_1_2_4' ) ) {
26
  * @var string
27
  *
28
  */
29
- public $version = '1.2.4';
30
  /**
31
  * The API URL where we will send feedback data.
32
  *
4
  exit; // Exit if accessed directly.
5
  }
6
 
7
+ if ( ! class_exists( 'IG_Feedback_V_1_2_5' ) ) {
8
  /**
9
  * IG Feedback
10
  *
11
  * The IG Feedback class adds functionality to get quick interactive feedback from users.
12
  * There are different types of feedabck widget like Stars, Emoji, Thubms Up/ Down, Number etc.
13
  *
14
+ * @class IG_Feedback_V_1_2_5
15
  * @since 1.0.0
16
  * @copyright Copyright (c) 2019, Icegram
17
  * @license https://opensource.org/licenses/gpl-license GNU Public License
18
  * @package feedback
19
  */
20
+ class IG_Feedback_V_1_2_5 {
21
 
22
  /**
23
  * Version of Feedback Library
26
  * @var string
27
  *
28
  */
29
+ public $version = '1.2.5';
30
  /**
31
  * The API URL where we will send feedback data.
32
  *
lite/includes/feedback/class-ig-tracker.php CHANGED
@@ -4,20 +4,20 @@ if ( ! defined( 'ABSPATH' ) ) {
4
  exit; // Exit if accessed directly.
5
  }
6
 
7
- if ( ! class_exists( 'IG_Tracker_V_1_2_4' ) ) {
8
 
9
  /**
10
- * Class IG_Tracker_V_1_2_4
11
  *
12
  * Icegram tracker handler class is responsible for sending anonymous plugin
13
  * data to Icegram servers for users that actively allowed data tracking.
14
  *
15
- * @class IG_Tracker_V_1_2_4
16
  * @since 1.0.0
17
  *
18
  * @package feedback
19
  */
20
- class IG_Tracker_V_1_2_4 {
21
 
22
  /**
23
  * Get Active, Inactive or all plugins info
@@ -180,7 +180,7 @@ if ( ! class_exists( 'IG_Tracker_V_1_2_4' ) ) {
180
  'author' => $theme_data->get( 'Author' ),
181
  'author_uri' => $theme_data->get( 'AuthorURI' )
182
  );
183
- }
184
 
185
  return $current_theme;
186
  }
@@ -239,7 +239,7 @@ if ( ! class_exists( 'IG_Tracker_V_1_2_4' ) ) {
239
  'wp_db_charset_Collate' => $wpdb->get_charset_collate(),
240
  'wp_memory_limit' => ( size_format( (int) WP_MEMORY_LIMIT * 1048576 ) ),
241
  'wp_upload_size' => ( size_format( wp_max_upload_size() ) ),
242
- 'filesystem_method' => get_filesystem_method(),
243
  );
244
 
245
  return $wp_info;
4
  exit; // Exit if accessed directly.
5
  }
6
 
7
+ if ( ! class_exists( 'IG_Tracker_V_1_2_5' ) ) {
8
 
9
  /**
10
+ * Class IG_Tracker_V_1_2_5
11
  *
12
  * Icegram tracker handler class is responsible for sending anonymous plugin
13
  * data to Icegram servers for users that actively allowed data tracking.
14
  *
15
+ * @class IG_Tracker_V_1_2_5
16
  * @since 1.0.0
17
  *
18
  * @package feedback
19
  */
20
+ class IG_Tracker_V_1_2_5 {
21
 
22
  /**
23
  * Get Active, Inactive or all plugins info
180
  'author' => $theme_data->get( 'Author' ),
181
  'author_uri' => $theme_data->get( 'AuthorURI' )
182
  );
183
+ }
184
 
185
  return $current_theme;
186
  }
239
  'wp_db_charset_Collate' => $wpdb->get_charset_collate(),
240
  'wp_memory_limit' => ( size_format( (int) WP_MEMORY_LIMIT * 1048576 ) ),
241
  'wp_upload_size' => ( size_format( wp_max_upload_size() ) ),
242
+ 'filesystem_method' => function_exists('get_filesystem_method') ? get_filesystem_method() : ''
243
  );
244
 
245
  return $wp_info;
lite/includes/upgrade/es-update-functions.php CHANGED
@@ -997,7 +997,7 @@ function ig_es_update_431_permanently_delete_forms() {
997
  * @since 4.3.1
998
  */
999
  function ig_es_update_431_delete_options() {
1000
- global $wpdb;
1001
 
1002
  $options_to_delete = array(
1003
  'ig_es_smtp_host',
@@ -1011,13 +1011,10 @@ function ig_es_update_431_delete_options() {
1011
  'ig_es_unsubcontent',
1012
  );
1013
 
1014
- $options_str = implode( ',', $options_to_delete );
1015
 
1016
- $wpdb->query(
1017
- $wpdb->prepare(
1018
- "DELETE FROM {$wpdb->prefix}options WHERE FIND_IN_SET (option_name, %s)",
1019
- $options_str
1020
- )
1021
  );
1022
  }
1023
 
@@ -1326,3 +1323,23 @@ function ig_es_update_465_db_version() {
1326
  ES_Install::update_db_version( '4.6.5' );
1327
  }
1328
  /* --------------------- ES 4.6.5(End)--------------------------- */
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
997
  * @since 4.3.1
998
  */
999
  function ig_es_update_431_delete_options() {
1000
+ global $wpbd;
1001
 
1002
  $options_to_delete = array(
1003
  'ig_es_smtp_host',
1011
  'ig_es_unsubcontent',
1012
  );
1013
 
1014
+ $options_str = "'" . implode( "','", $options_to_delete ) . "'";
1015
 
1016
+ $wpbd->query(
1017
+ "DELETE FROM {$wpbd->prefix}options WHERE option_name IN($options_str, %s)"
 
 
 
1018
  );
1019
  }
1020
 
1323
  ES_Install::update_db_version( '4.6.5' );
1324
  }
1325
  /* --------------------- ES 4.6.5(End)--------------------------- */
1326
+
1327
+ /* --------------------- ES 4.6.6(Start)--------------------------- */
1328
+ /**
1329
+ * Create table for storing subscribers import CSV data temporarily
1330
+ *
1331
+ * @since 4.6.6
1332
+ */
1333
+ function ig_es_update_466_create_temp_import_table() {
1334
+ ES_Install::create_tables( '4.6.6' );
1335
+ }
1336
+
1337
+ /**
1338
+ * Update DB version
1339
+ *
1340
+ * @since 4.6.6
1341
+ */
1342
+ function ig_es_update_466_db_version() {
1343
+ ES_Install::update_db_version( '4.6.6' );
1344
+ }
1345
+ /* --------------------- ES 4.6.6(End)--------------------------- */
lite/includes/workflows/class-es-workflows-table.php CHANGED
@@ -23,7 +23,7 @@ if ( ! class_exists( 'WP_List_Table' ) ) {
23
  *
24
  * @since 4.4.1
25
  */
26
- class ES_Workflows_Table extends WP_List_Table {
27
 
28
  /**
29
  * Number of workflows to show at once.
@@ -197,7 +197,7 @@ class ES_Workflows_Table extends WP_List_Table {
197
  *
198
  * @return mixed
199
  */
200
- public static function get_lists( $per_page = 5, $page_number = 1, $do_count_only = false ) {
201
 
202
  $order_by = sanitize_sql_orderby( ig_es_get_request_data( 'orderby' ) );
203
  $order = ig_es_get_request_data( 'order' );
@@ -358,7 +358,7 @@ class ES_Workflows_Table extends WP_List_Table {
358
  <label class="screen-reader-text"
359
  for="<?php echo esc_attr( $input_id ); ?>"><?php echo esc_attr( $text ); ?>:</label>
360
  <input type="search" id="<?php echo esc_attr( $input_id ); ?>" name="s" value="<?php _admin_search_query(); ?>" />
361
- <?php submit_button( __( 'Search workflows', 'email-subscribers' ), 'button', false, false, array( 'id' => 'search-submit' ) ); ?>
362
  </p>
363
  <?php
364
  }
@@ -375,6 +375,7 @@ class ES_Workflows_Table extends WP_List_Table {
375
 
376
  // Note: Disable Search box for now.
377
  $search = ig_es_get_request_data( 's' );
 
378
  $this->search_box( $search, 'workflow-search-input' );
379
 
380
  $per_page = $this->get_items_per_page( self::$option_per_page, 25 );
@@ -461,4 +462,5 @@ class ES_Workflows_Table extends WP_List_Table {
461
  }
462
  }
463
  }
 
464
  }
23
  *
24
  * @since 4.4.1
25
  */
26
+ class ES_Workflows_Table extends ES_List_Table {
27
 
28
  /**
29
  * Number of workflows to show at once.
197
  *
198
  * @return mixed
199
  */
200
+ public function get_lists( $per_page = 5, $page_number = 1, $do_count_only = false ) {
201
 
202
  $order_by = sanitize_sql_orderby( ig_es_get_request_data( 'orderby' ) );
203
  $order = ig_es_get_request_data( 'order' );
358
  <label class="screen-reader-text"
359
  for="<?php echo esc_attr( $input_id ); ?>"><?php echo esc_attr( $text ); ?>:</label>
360
  <input type="search" id="<?php echo esc_attr( $input_id ); ?>" name="s" value="<?php _admin_search_query(); ?>" />
361
+ <?php submit_button( __( 'Search Workflows', 'email-subscribers' ), 'button', false, false, array( 'id' => 'search-submit' ) ); ?>
362
  </p>
363
  <?php
364
  }
375
 
376
  // Note: Disable Search box for now.
377
  $search = ig_es_get_request_data( 's' );
378
+
379
  $this->search_box( $search, 'workflow-search-input' );
380
 
381
  $per_page = $this->get_items_per_page( self::$option_per_page, 25 );
462
  }
463
  }
464
  }
465
+
466
  }
lite/includes/workflows/db/class-es-db-workflows.php CHANGED
@@ -331,7 +331,7 @@ class ES_DB_Workflows extends ES_DB {
331
  * @since 4.4.1
332
  */
333
  public function update_status( $workflow_ids = array(), $status = 0 ) {
334
- global $wpdb;
335
 
336
  $updated = false;
337
  if ( empty( $workflow_ids ) ) {
@@ -349,8 +349,7 @@ class ES_DB_Workflows extends ES_DB {
349
  }
350
 
351
  if ( ! empty( $workflow_ids_str ) ) {
352
- // Required in WooCommerce Coding Standards when preparing dynamic query.
353
- $updated = $wpdb->query( $wpdb->prepare( "UPDATE {$wpdb->prefix}ig_workflows SET status = %d WHERE FIND_IN_SET(id, %s)", $status, $workflow_ids_str ) );
354
  }
355
 
356
  do_action( 'ig_es_workflow_status_changed', $workflow_ids );
331
  * @since 4.4.1
332
  */
333
  public function update_status( $workflow_ids = array(), $status = 0 ) {
334
+ global $wpbd;
335
 
336
  $updated = false;
337
  if ( empty( $workflow_ids ) ) {
349
  }
350
 
351
  if ( ! empty( $workflow_ids_str ) ) {
352
+ $updated = $wpbd->query( $wpbd->prepare( "UPDATE {$wpbd->prefix}ig_workflows SET status = %d WHERE id IN ($workflow_ids_str)", $status ) );
 
353
  }
354
 
355
  do_action( 'ig_es_workflow_status_changed', $workflow_ids );
readme.txt CHANGED
@@ -6,7 +6,7 @@ Tags: email marketing, subscription, autoresponder, post notification, welcome e
6
  Requires at least: 3.9
7
  Tested up to: 5.6
8
  Requires PHP: 5.6
9
- Stable tag: 4.6.5
10
  License: GPLv3
11
  License URI: http://www.gnu.org/licenses
12
 
@@ -304,6 +304,12 @@ Refer [here](https://www.icegram.com/documentation/es-faq/).
304
 
305
  == Changelog ==
306
 
 
 
 
 
 
 
307
  **4.6.5 (22.12.2020)**
308
 
309
  * New: WooCommerce Abandoned Cart [PRO]
6
  Requires at least: 3.9
7
  Tested up to: 5.6
8
  Requires PHP: 5.6
9
+ Stable tag: 4.6.6
10
  License: GPLv3
11
  License URI: http://www.gnu.org/licenses
12
 
304
 
305
  == Changelog ==
306
 
307
+ **4.6.6 (14.01.2021)**
308
+
309
+ * New: Now, able to map fields while importing
310
+ * Update: Improved UI
311
+ * Fix: YouTube video embedding issue
312
+
313
  **4.6.5 (22.12.2020)**
314
 
315
  * New: WooCommerce Abandoned Cart [PRO]