Email Subscribers & Newsletters - Version 4.3.4

Version Description

Download this release

Release Info

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

Code changes from version 4.3.3 to 4.3.4

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.3.3
7
  * Author: Icegram
8
  * Author URI: https://www.icegram.com/
9
  * Requires at least: 3.9
@@ -36,7 +36,7 @@ if ( ! defined( 'IG_ES_FEEDBACK_TRACKER_VERSION' ) ) {
36
  global $ig_es_tracker;
37
  /* ***************************** Initial Compatibility Work (Start) ******************* */
38
 
39
- /* ===========Do not edit this code unless you know what you are doing ========= */
40
 
41
  /*
42
  * Note: We are not using ES_PLUGIN_DIR constant at this moment because there are chances
@@ -48,8 +48,8 @@ $ig_es_tracker = 'IG_Tracker_V_' . str_replace( '.', '_', IG_ES_FEEDBACK_TRACKER
48
  if ( ! function_exists( 'ig_es_show_upgrade_pro_notice' ) ) {
49
  /**
50
  * Show ES Premium Upgrade Notice
51
- *
52
- * @since 4.3.0
53
  */
54
  function ig_es_show_upgrade_pro_notice() {
55
  $url = admin_url( "plugins.php?plugin_status=upgrade" );
@@ -67,7 +67,7 @@ if ( ! function_exists( 'deactivate_plugins' ) ) {
67
  }
68
 
69
  $is_premium = false;
70
- if ( 'email-subscribers-premium.php' === basename(__FILE__) ) {
71
  $is_premium = true;
72
  }
73
 
@@ -100,11 +100,7 @@ if ( $is_premium ) {
100
 
101
  // Show Upgrade Notice if It's Admin Screen.
102
  if ( is_admin() ) {
103
- add_action('admin_head', 'ig_es_show_upgrade_pro_notice', PHP_INT_MAX);
104
-
105
- if ( $is_pro_active ) {
106
- //deactivate_plugins( 'email-subscribers-premium/email-subscribers-premium.php', true );
107
- }
108
  }
109
 
110
  } elseif ( $is_pro_active && version_compare( $es_pro_plugin_version, 4.3, '>=' ) ) {
@@ -115,7 +111,7 @@ if ( $is_premium ) {
115
  /* ***************************** Initial Compatibility Work (End) ******************* */
116
 
117
  if ( ! defined( 'ES_PLUGIN_VERSION' ) ) {
118
- define( 'ES_PLUGIN_VERSION', '4.3.3' );
119
  }
120
 
121
  // Plugin Folder Path.
@@ -210,5 +206,4 @@ if ( ! function_exists( 'ES' ) ) {
210
  }
211
 
212
  // Start ES
213
- ES()->run();
214
-
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.3.4
7
  * Author: Icegram
8
  * Author URI: https://www.icegram.com/
9
  * Requires at least: 3.9
36
  global $ig_es_tracker;
37
  /* ***************************** Initial Compatibility Work (Start) ******************* */
38
 
39
+ /* =========== Do not edit this code unless you know what you are doing ========= */
40
 
41
  /*
42
  * Note: We are not using ES_PLUGIN_DIR constant at this moment because there are chances
48
  if ( ! function_exists( 'ig_es_show_upgrade_pro_notice' ) ) {
49
  /**
50
  * Show ES Premium Upgrade Notice
51
+ *
52
+ * @since 4.3.0
53
  */
54
  function ig_es_show_upgrade_pro_notice() {
55
  $url = admin_url( "plugins.php?plugin_status=upgrade" );
67
  }
68
 
69
  $is_premium = false;
70
+ if ( 'email-subscribers-premium.php' === basename( __FILE__ ) ) {
71
  $is_premium = true;
72
  }
73
 
100
 
101
  // Show Upgrade Notice if It's Admin Screen.
102
  if ( is_admin() ) {
103
+ add_action( 'admin_head', 'ig_es_show_upgrade_pro_notice', PHP_INT_MAX );
 
 
 
 
104
  }
105
 
106
  } elseif ( $is_pro_active && version_compare( $es_pro_plugin_version, 4.3, '>=' ) ) {
111
  /* ***************************** Initial Compatibility Work (End) ******************* */
112
 
113
  if ( ! defined( 'ES_PLUGIN_VERSION' ) ) {
114
+ define( 'ES_PLUGIN_VERSION', '4.3.4' );
115
  }
116
 
117
  // Plugin Folder Path.
206
  }
207
 
208
  // Start ES
209
+ ES()->run();
 
lite/admin/class-email-subscribers-admin.php CHANGED
@@ -212,11 +212,11 @@ class Email_Subscribers_Admin {
212
  }
213
 
214
  /**
215
- * Add Other Submenu Pages
216
- *
217
  * @since 4.3.0
218
  */
219
- do_action('ig_es_add_submenu_page', $accessible_sub_menus);
220
 
221
  }
222
 
@@ -321,7 +321,7 @@ class Email_Subscribers_Admin {
321
  }
322
 
323
  /**
324
- * Render Post Notifications
325
  * @since 4.2.1
326
  */
327
  public function load_post_notifications() {
@@ -330,8 +330,8 @@ class Email_Subscribers_Admin {
330
  }
331
 
332
  /**
333
- * Render Newsletters
334
- *
335
  * @since 4.2.1
336
  */
337
  public function load_newsletters() {
@@ -340,8 +340,8 @@ class Email_Subscribers_Admin {
340
  }
341
 
342
  /**
343
- * Render Reports
344
- *
345
  * @since 4.2.1
346
  */
347
  public function load_reports() {
@@ -350,8 +350,8 @@ class Email_Subscribers_Admin {
350
  }
351
 
352
  /**
353
- * Render Settings
354
- *
355
  * @since 4.2.1
356
  */
357
  public function load_settings() {
@@ -360,8 +360,8 @@ class Email_Subscribers_Admin {
360
  }
361
 
362
  /**
363
- * Render Preview
364
- *
365
  * @since 4.2.1
366
  */
367
  public function load_preview() {
@@ -442,7 +442,6 @@ class Email_Subscribers_Admin {
442
 
443
 
444
  function send_test_email() {
445
- $message = array();
446
  $message = array(
447
  'status' => 'ERROR',
448
  'message' => __( 'Something went wrong', 'email-subscribers' )
@@ -480,13 +479,20 @@ class Email_Subscribers_Admin {
480
  }
481
  $res = ES_Install::create_and_send_default_broadcast();
482
  $res = ES_Install::create_and_send_default_post_notification();
483
- if ( $res['status'] === 'SUCCESS' ) {
484
- update_option( 'ig_es_onboarding_test_campaign_success', 'yes' );
485
- } else {
486
- update_option( 'ig_es_onboarding_test_campaign_error', 'yes' );
 
 
 
487
  }
 
488
  update_option( 'ig_es_onboarding_complete', 'yes' );
489
- $res['dashboard_url'] = admin_url( 'admin.php?page=es_dashboard' );
 
 
 
490
  echo json_encode( $res );
491
  exit;
492
 
@@ -499,6 +505,7 @@ class Email_Subscribers_Admin {
499
  $es_skip = ig_es_get_request_data( 'es_skip' );
500
  $option_name = ig_es_get_request_data( 'option_name' );
501
 
 
502
  if ( $es_skip == '1' && ! empty( $option_name ) ) {
503
  /**
504
  * If user logged in then only save option.
@@ -507,7 +514,9 @@ class Email_Subscribers_Admin {
507
  if ( $can_access_settings ) {
508
  update_option( 'ig_es_ob_skip_' . $option_name, 'yes' );
509
  }
 
510
  $referer = wp_get_referer();
 
511
  wp_safe_redirect( $referer );
512
  exit();
513
  }
212
  }
213
 
214
  /**
215
+ * Add Other Submenu Pages
216
+ *
217
  * @since 4.3.0
218
  */
219
+ do_action( 'ig_es_add_submenu_page', $accessible_sub_menus );
220
 
221
  }
222
 
321
  }
322
 
323
  /**
324
+ * Render Post Notifications
325
  * @since 4.2.1
326
  */
327
  public function load_post_notifications() {
330
  }
331
 
332
  /**
333
+ * Render Newsletters
334
+ *
335
  * @since 4.2.1
336
  */
337
  public function load_newsletters() {
340
  }
341
 
342
  /**
343
+ * Render Reports
344
+ *
345
  * @since 4.2.1
346
  */
347
  public function load_reports() {
350
  }
351
 
352
  /**
353
+ * Render Settings
354
+ *
355
  * @since 4.2.1
356
  */
357
  public function load_settings() {
360
  }
361
 
362
  /**
363
+ * Render Preview
364
+ *
365
  * @since 4.2.1
366
  */
367
  public function load_preview() {
442
 
443
 
444
  function send_test_email() {
 
445
  $message = array(
446
  'status' => 'ERROR',
447
  'message' => __( 'Something went wrong', 'email-subscribers' )
479
  }
480
  $res = ES_Install::create_and_send_default_broadcast();
481
  $res = ES_Install::create_and_send_default_post_notification();
482
+
483
+ if ( $res && is_array( $res ) && ! empty( $res['status'] ) ) {
484
+ if ( 'SUCCESS' === $res['status'] ) {
485
+ update_option( 'ig_es_onboarding_test_campaign_success', 'yes' );
486
+ } else {
487
+ update_option( 'ig_es_onboarding_test_campaign_error', 'yes' );
488
+ }
489
  }
490
+
491
  update_option( 'ig_es_onboarding_complete', 'yes' );
492
+
493
+ $response = array();
494
+ $response['dashboard_url'] = admin_url( 'admin.php?page=es_dashboard' );
495
+ $response['status'] = 'SUCCESS';
496
  echo json_encode( $res );
497
  exit;
498
 
505
  $es_skip = ig_es_get_request_data( 'es_skip' );
506
  $option_name = ig_es_get_request_data( 'option_name' );
507
 
508
+
509
  if ( $es_skip == '1' && ! empty( $option_name ) ) {
510
  /**
511
  * If user logged in then only save option.
514
  if ( $can_access_settings ) {
515
  update_option( 'ig_es_ob_skip_' . $option_name, 'yes' );
516
  }
517
+
518
  $referer = wp_get_referer();
519
+
520
  wp_safe_redirect( $referer );
521
  exit();
522
  }
lite/admin/js/es-onboarding.js CHANGED
@@ -25,6 +25,7 @@ jQuery(document).ready(function() {
25
  },
26
  dataType: 'json',
27
  success: function(data, status, xhr) {
 
28
  jQuery('.es-send-email-screen .es-loader').find('img').hide();
29
  jQuery('.active').fadeOut('fast').removeClass('active');
30
  jQuery('#button-send').hide();
@@ -41,7 +42,7 @@ jQuery(document).ready(function() {
41
 
42
  jQuery.ajax(params);
43
  } else {
44
- jQuery(".es_email").addClass('error')
45
  jQuery("#es-send-email-form")[0].reportValidity();
46
  }
47
 
25
  },
26
  dataType: 'json',
27
  success: function(data, status, xhr) {
28
+
29
  jQuery('.es-send-email-screen .es-loader').find('img').hide();
30
  jQuery('.active').fadeOut('fast').removeClass('active');
31
  jQuery('#button-send').hide();
42
 
43
  jQuery.ajax(params);
44
  } else {
45
+ jQuery(".es_email").addClass('error');
46
  jQuery("#es-send-email-form")[0].reportValidity();
47
  }
48
 
lite/includes/class-es-common.php CHANGED
@@ -62,14 +62,14 @@ Class ES_Common {
62
  // site url
63
  $site_url = home_url( '/' );
64
  $content = str_replace( "{{SITEURL}}", $site_url, $content );
65
- //add pre header if available
66
- $meta = ES()->campaigns_db->get_campaign_meta_by_id( $campaign_id );
67
 
 
 
68
  $meta['pre_header'] = !empty($meta['pre_header']) ? $meta['pre_header'] : '';
69
-
70
  if( !empty( $meta['pre_header'] )){
71
- //$content = '<span class="es_preheader" style="display: none !important; visibility: hidden; opacity: 0; color: transparent; height: 0; width: 0;">'.$meta['pre_header'].'</span>'.$content;
72
  }
 
73
 
74
  return $content;
75
  }
62
  // site url
63
  $site_url = home_url( '/' );
64
  $content = str_replace( "{{SITEURL}}", $site_url, $content );
 
 
65
 
66
+ /*TODO: Enable it once Pre header issue fix
67
+ $meta = ES()->campaigns_db->get_campaign_meta_by_id( $campaign_id );
68
  $meta['pre_header'] = !empty($meta['pre_header']) ? $meta['pre_header'] : '';
 
69
  if( !empty( $meta['pre_header'] )){
70
+ $content = '<span class="es_preheader" style="display: none !important; visibility: hidden; opacity: 0; color: transparent; height: 0; width: 0;">'.$meta['pre_header'].'</span>'.$content;
71
  }
72
+ */
73
 
74
  return $content;
75
  }
lite/includes/class-es-install.php CHANGED
@@ -182,9 +182,15 @@ if ( ! class_exists( 'ES_Install' ) ) {
182
  'ig_es_update_431_disable_autoload_options',
183
  'ig_es_update_431_db_version'
184
  ),
 
185
  '4.3.2' => array(
186
  'ig_es_update_432_import_bfcm_templates',
187
  'ig_es_update_432_db_version'
 
 
 
 
 
188
  )
189
 
190
  );
182
  'ig_es_update_431_disable_autoload_options',
183
  'ig_es_update_431_db_version'
184
  ),
185
+
186
  '4.3.2' => array(
187
  'ig_es_update_432_import_bfcm_templates',
188
  'ig_es_update_432_db_version'
189
+ ),
190
+
191
+ '4.3.4' => array(
192
+ 'ig_es_update_434_permanently_delete_campaigns',
193
+ 'ig_es_update_434_db_version'
194
  )
195
 
196
  );
lite/includes/classes/class-es-actions.php CHANGED
@@ -101,7 +101,6 @@ if ( ! class_exists( 'ES_Actions' ) ) {
101
  ) );
102
 
103
  return $this->db->add( $args, $explicit );
104
-
105
  }
106
 
107
  /**
101
  ) );
102
 
103
  return $this->db->add( $args, $explicit );
 
104
  }
105
 
106
  /**
lite/includes/classes/class-es-admin-settings.php CHANGED
@@ -23,10 +23,6 @@ class ES_Admin_Settings {
23
  public function __construct() {
24
  }
25
 
26
- public static function set_screen( $status, $option, $value ) {
27
- return $value;
28
- }
29
-
30
  public function es_settings_callback() {
31
 
32
  $submitted = ig_es_get_request_data( 'submitted' );
@@ -156,15 +152,6 @@ class ES_Admin_Settings {
156
 
157
  }
158
 
159
- public function es_roles_sanitize_options( $input ) {
160
- $input['option_display_mode'] = wp_filter_nohtml_kses( $input['option_display_mode'] );
161
- $input['option_font_size'] = sanitize_text_field( absint( $input['option_font_size'] ) );
162
- $input['option_font_color'] = sanitize_text_field( $input['option_font_color'] );
163
- $input['option_custom_css'] = esc_textarea( $input['option_custom_css'] );
164
-
165
- return $input;
166
- }
167
-
168
  public static function get_registered_settings() {
169
 
170
  $general_settings = array(
@@ -631,10 +618,9 @@ class ES_Admin_Settings {
631
  case 'text': // If it is a text field
632
  $field_html = sprintf( '<input name="%1$s" id="%2$s" type="%3$s" placeholder="%4$s" value="%5$s" %6$s class="%7$s"/>', $uid, $id_key, $type, $placeholder, $value, $readonly, $class );
633
  break;
 
634
  case 'number': // If it is a number field
635
  $field_html = sprintf( '<input name="%1$s" id="%1$s" type="%2$s" placeholder="%3$s" value="%4$s" %5$s min="0"/>', $uid, $type, $placeholder, $value, $readonly );
636
- case 'password': // If it is a text field
637
- $field_html = sprintf( '<input name="%1$s" id="%2$s" type="%3$s" placeholder="%4$s" value="%5$s" %6$s class="%7$s" />', $uid, $id_key, $type, $placeholder, $value, $readonly, $class );
638
  break;
639
 
640
  case 'email':
@@ -642,12 +628,13 @@ class ES_Admin_Settings {
642
  break;
643
 
644
  case 'textarea':
645
- $field_html = sprintf( '<textarea name="%1$s" id="%2$s" placeholder="%3$s" size="100" rows="12" cols="58" class="%5$s">%4$s</textarea>',
646
- $uid, $id_key, $placeholder, $value, $class );
647
  break;
 
648
  case 'file':
649
  $field_html = '<input type="text" id="logo_url" name="' . $uid . '" value="' . $value . '" class="' . $class . '"/> <input id="upload_logo_button" type="button" class="button" value="Upload Logo" />';
650
  break;
 
651
  case 'checkbox' :
652
  $field_html = '<input id="' . $id_key . '" type="checkbox" name="' . $uid . '" value="yes" ' . checked( $value, 'yes', false ) . ' class="' . $class . '" />' . $placeholder . '</input>';
653
  break;
@@ -662,6 +649,7 @@ class ES_Admin_Settings {
662
  $field_html = sprintf( '<select name="%1$s" id="%2$s" class="%4$s">%3$s</select>', $uid, $id_key, $options_markup, $class );
663
  }
664
  break;
 
665
  case 'html' :
666
  default:
667
  $field_html = $html;
@@ -760,8 +748,10 @@ class ES_Admin_Settings {
760
  'phpmail' => array( 'name' => 'PHP mail', 'logo' => ES_PLUGIN_URL . 'lite/admin/images/phpmail.png' ),
761
  'pepipost' => array( 'name' => 'Pepipost', 'logo' => ES_PLUGIN_URL . 'lite/admin/images/pepipost.png', 'docblock' => $pepipost_doc_block ),
762
  );
763
- $mailers = apply_filters( 'ig_es_mailers', $mailers );
764
- $default_mailer = ( array_key_exists( $default_mailer, $mailers ) ) ? $default_mailer : 'wpmail';
 
 
765
  foreach ( $mailers as $key => $mailer ) {
766
  $class = ( $key === 'pepipost' ) ? 'es_recommended' : '';
767
  $html .= '<label><div class="es-mailer-logo ' . $class . '"><div class="es-logo-wrapper"><img src="' . $mailer['logo'] . '" alt="Default (none)"></div>';
23
  public function __construct() {
24
  }
25
 
 
 
 
 
26
  public function es_settings_callback() {
27
 
28
  $submitted = ig_es_get_request_data( 'submitted' );
152
 
153
  }
154
 
 
 
 
 
 
 
 
 
 
155
  public static function get_registered_settings() {
156
 
157
  $general_settings = array(
618
  case 'text': // If it is a text field
619
  $field_html = sprintf( '<input name="%1$s" id="%2$s" type="%3$s" placeholder="%4$s" value="%5$s" %6$s class="%7$s"/>', $uid, $id_key, $type, $placeholder, $value, $readonly, $class );
620
  break;
621
+
622
  case 'number': // If it is a number field
623
  $field_html = sprintf( '<input name="%1$s" id="%1$s" type="%2$s" placeholder="%3$s" value="%4$s" %5$s min="0"/>', $uid, $type, $placeholder, $value, $readonly );
 
 
624
  break;
625
 
626
  case 'email':
628
  break;
629
 
630
  case 'textarea':
631
+ $field_html = sprintf( '<textarea name="%1$s" id="%2$s" placeholder="%3$s" size="100" rows="12" cols="58" class="%5$s">%4$s</textarea>', $uid, $id_key, $placeholder, $value, $class );
 
632
  break;
633
+
634
  case 'file':
635
  $field_html = '<input type="text" id="logo_url" name="' . $uid . '" value="' . $value . '" class="' . $class . '"/> <input id="upload_logo_button" type="button" class="button" value="Upload Logo" />';
636
  break;
637
+
638
  case 'checkbox' :
639
  $field_html = '<input id="' . $id_key . '" type="checkbox" name="' . $uid . '" value="yes" ' . checked( $value, 'yes', false ) . ' class="' . $class . '" />' . $placeholder . '</input>';
640
  break;
649
  $field_html = sprintf( '<select name="%1$s" id="%2$s" class="%4$s">%3$s</select>', $uid, $id_key, $options_markup, $class );
650
  }
651
  break;
652
+
653
  case 'html' :
654
  default:
655
  $field_html = $html;
748
  'phpmail' => array( 'name' => 'PHP mail', 'logo' => ES_PLUGIN_URL . 'lite/admin/images/phpmail.png' ),
749
  'pepipost' => array( 'name' => 'Pepipost', 'logo' => ES_PLUGIN_URL . 'lite/admin/images/pepipost.png', 'docblock' => $pepipost_doc_block ),
750
  );
751
+
752
+ $mailers = apply_filters( 'ig_es_mailers', $mailers );
753
+ $default_mailer = ( array_key_exists( $default_mailer, $mailers ) ) ? $default_mailer : 'wpmail';
754
+
755
  foreach ( $mailers as $key => $mailer ) {
756
  $class = ( $key === 'pepipost' ) ? 'es_recommended' : '';
757
  $html .= '<label><div class="es-mailer-logo ' . $class . '"><div class="es-logo-wrapper"><img src="' . $mailer['logo'] . '" alt="Default (none)"></div>';
lite/includes/classes/class-es-campaigns-table.php CHANGED
@@ -17,6 +17,15 @@ class ES_Campaigns_Table extends WP_List_Table {
17
  */
18
  public static $option_per_page = 'es_campaigns_per_page';
19
 
 
 
 
 
 
 
 
 
 
20
  /**
21
  * ES_Campaigns_Table constructor.
22
  *
@@ -29,6 +38,10 @@ class ES_Campaigns_Table extends WP_List_Table {
29
  'ajax' => false, //does this table support ajax?
30
  'screen' => 'es_campaigns'
31
  ) );
 
 
 
 
32
  }
33
 
34
  /**
@@ -49,6 +62,21 @@ class ES_Campaigns_Table extends WP_List_Table {
49
 
50
  }
51
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
52
  /**
53
  * Render Campaigns table
54
  *
@@ -119,7 +147,6 @@ class ES_Campaigns_Table extends WP_List_Table {
119
 
120
  $query[] = "( deleted_at IS NULL OR deleted_at = '0000-00-00 00:00:00' )";
121
 
122
-
123
  if ( ! empty( $search ) ) {
124
  $query[] = " name LIKE %s ";
125
  $args[] = "%" . $wpdb->esc_like( $search ) . "%";
@@ -322,9 +349,18 @@ class ES_Campaigns_Table extends WP_List_Table {
322
  return $actions;
323
  }
324
 
325
- public function search_box( $text, $input_id ) { ?>
 
 
 
 
 
 
 
 
 
326
  <p class="search-box">
327
- <label class="screen-reader-text" for="<?php echo $input_id ?>"><?php echo $text; ?>:</label>
328
  <input type="search" id="<?php echo $input_id ?>" name="s" value="<?php _admin_search_query(); ?>"/>
329
  <?php submit_button( __( 'Search Campaigns', 'email-subscribers' ), 'button', false, false, array( 'id' => 'search-submit' ) ); ?>
330
  </p>
@@ -368,8 +404,9 @@ class ES_Campaigns_Table extends WP_List_Table {
368
  $message = __( 'You are not allowed to delete campaign.', 'email-subscribers' );
369
  $status = 'error';
370
  } else {
371
- $list = ig_es_get_request_data( 'list' );
372
- $this->delete_list( array( $list ) );
 
373
  $message = __( 'Campaign has been deleted successfully!', 'email-subscribers' );
374
  $status = 'success';
375
  }
@@ -385,13 +422,11 @@ class ES_Campaigns_Table extends WP_List_Table {
385
  $ids = ig_es_get_request_data( 'campaigns' );
386
 
387
  if ( is_array( $ids ) && count( $ids ) > 0 ) {
 
 
388
 
389
- $deleted = $this->delete_list( $ids );
390
-
391
- if ( $deleted ) {
392
- $message = __( 'Campaign(s) have been deleted successfully!', 'email-subscribers' );
393
- ES_Common::show_message( $message );
394
- }
395
  } else {
396
 
397
  $message = __( 'Please check campaign(s) to delete.', 'email-subscribers' );
@@ -401,32 +436,4 @@ class ES_Campaigns_Table extends WP_List_Table {
401
 
402
  }
403
  }
404
-
405
- /**
406
- * Delete a list record.
407
- *
408
- * @param int $id list ID
409
- */
410
- public function delete_list( $ids ) {
411
- global $wpdb;
412
-
413
- if ( is_array( $ids ) && count( $ids ) > 0 ) {
414
-
415
- $campaigns_table = IG_CAMPAIGNS_TABLE;
416
-
417
- $ids = implode( ',', array_map( 'absint', $ids ) );
418
-
419
- $current_date = gmdate( 'Y-m-d G:i:s' );
420
- $query = "UPDATE {$campaigns_table} SET deleted_at = %s WHERE id IN ($ids)";
421
- $query = $wpdb->prepare( $query, array( $current_date ) );
422
- $result = $wpdb->query( $query );
423
-
424
- if ( $result ) {
425
- return true;
426
- }
427
- }
428
-
429
- return false;
430
- }
431
-
432
  }
17
  */
18
  public static $option_per_page = 'es_campaigns_per_page';
19
 
20
+ /**
21
+ * ES_DB_Campaigns object
22
+ *
23
+ * @since 4.3.4
24
+ * @var $db
25
+ *
26
+ */
27
+ protected $db;
28
+
29
  /**
30
  * ES_Campaigns_Table constructor.
31
  *
38
  'ajax' => false, //does this table support ajax?
39
  'screen' => 'es_campaigns'
40
  ) );
41
+
42
+ $this->db = new ES_DB_Campaigns();
43
+
44
+ add_action('ig_es_campaign_deleted', array($this, 'delete_child_campaigns'), 10, 1);
45
  }
46
 
47
  /**
62
 
63
  }
64
 
65
+ /**
66
+ * Delete all child campaigns based on $parent_campaign_id
67
+ *
68
+ * @param int $parent_campaign_id
69
+ *
70
+ * @since 4.3.4
71
+ */
72
+ public function delete_child_campaigns( $parent_campaign_id = 0) {
73
+
74
+ $child_campaign_ids = $this->db->get_campaigns_by_parent_id($parent_campaign_id);
75
+
76
+ //Delete All Child Campaigns
77
+ $this->db->delete_campaigns($child_campaign_ids);
78
+ }
79
+
80
  /**
81
  * Render Campaigns table
82
  *
147
 
148
  $query[] = "( deleted_at IS NULL OR deleted_at = '0000-00-00 00:00:00' )";
149
 
 
150
  if ( ! empty( $search ) ) {
151
  $query[] = " name LIKE %s ";
152
  $args[] = "%" . $wpdb->esc_like( $search ) . "%";
349
  return $actions;
350
  }
351
 
352
+ /**
353
+ * Prepare search box
354
+ *
355
+ * @param string $text
356
+ * @param string $input_id
357
+ *
358
+ * @since 4.0.0
359
+ * @since 4.3.4 Added esc_attr()
360
+ */
361
+ public function search_box( $text = '', $input_id = '') { ?>
362
  <p class="search-box">
363
+ <label class="screen-reader-text" for="<?php echo esc_attr($input_id); ?>"><?php echo esc_attr($text); ?>:</label>
364
  <input type="search" id="<?php echo $input_id ?>" name="s" value="<?php _admin_search_query(); ?>"/>
365
  <?php submit_button( __( 'Search Campaigns', 'email-subscribers' ), 'button', false, false, array( 'id' => 'search-submit' ) ); ?>
366
  </p>
404
  $message = __( 'You are not allowed to delete campaign.', 'email-subscribers' );
405
  $status = 'error';
406
  } else {
407
+ $campaign_id = ig_es_get_request_data( 'list' );
408
+
409
+ $this->db->delete_campaigns( $campaign_id );
410
  $message = __( 'Campaign has been deleted successfully!', 'email-subscribers' );
411
  $status = 'success';
412
  }
422
  $ids = ig_es_get_request_data( 'campaigns' );
423
 
424
  if ( is_array( $ids ) && count( $ids ) > 0 ) {
425
+ // Delete multiple Campaigns
426
+ $this->db->delete_campaigns( $ids );
427
 
428
+ $message = __( 'Campaign(s) have been deleted successfully!', 'email-subscribers' );
429
+ ES_Common::show_message( $message );
 
 
 
 
430
  } else {
431
 
432
  $message = __( 'Please check campaign(s) to delete.', 'email-subscribers' );
436
 
437
  }
438
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
439
  }
lite/includes/classes/class-es-contacts-table.php CHANGED
@@ -92,22 +92,22 @@ class ES_Contacts_Table extends WP_List_Table {
92
  'url' => add_query_arg( 'action', 'new', 'admin.php?page=es_subscribers' )
93
  ),
94
 
95
- 'export' => array(
96
- 'label' => __( 'Export Contacts', 'email-subscribers' ),
97
  'indicator_option' => '',
98
  'indicator_label' => '',
99
  'indicator_type' => '',
100
- 'action' => 'export',
101
- 'url' => add_query_arg( 'action', 'export', 'admin.php?page=es_subscribers' )
102
  ),
103
 
104
- 'import' => array(
105
- 'label' => __( 'Import Contacts', 'email-subscribers' ),
106
  'indicator_option' => '',
107
  'indicator_label' => '',
108
  'indicator_type' => '',
109
- 'action' => 'import',
110
- 'url' => add_query_arg( 'action', 'import', 'admin.php?page=es_subscribers' )
111
  ),
112
 
113
  'sync' => array(
@@ -176,8 +176,9 @@ class ES_Contacts_Table extends WP_List_Table {
176
  ES_Common::prepare_main_header_navigation( $audience_tab_main_navigation );
177
  ?>
178
  </h1>
 
179
  <div class="es-contact-reports">
180
- <?php $this->get_contacts_reports()?>
181
  </div>
182
 
183
  <?php Email_Subscribers_Admin::es_feedback(); ?>
@@ -215,32 +216,37 @@ class ES_Contacts_Table extends WP_List_Table {
215
  $sync->prepare_sync_user();
216
  }
217
 
218
- public function get_contacts_reports(){
219
- $es_total_contact = ES_Reports_Data::get_total_contacts();
220
- $es_total_subscribed_contacts = ES_Reports_Data::get_total_subscribed_contacts( 60 );
221
- $es_total_unsubscribed_contacts = ES_Reports_Data::get_total_unsubscribed_contacts( 60 );
 
 
 
 
 
222
  $es_total_contacts_opened_emails = ES_Reports_Data::get_total_contacts_opened_emails( 60 );
223
  ?>
224
- <div class="es_total_contact">
225
- <h2 class="es_contact_kpi_text"><?php _e('Contacts', 'email-subscribers'); ?></h2>
226
- <span class="es_contact_kpi_no"><?php echo $es_total_contact; ?></span></br>
227
- </div>
228
- <div class="es_last_60_days">
229
- <h2><?php _e('Last 60 Days', 'email-subscribers'); ?></h2>
230
- <div class="es_contact_kpi">
231
- <span class="es_contact_kpi_no" style="color: #009e00"><?php echo $es_total_subscribed_contacts; ?></span></br>
232
- <span class="es_contact_kpi_text"><?php _e('Subscribed', 'email-subscribers'); ?></span>
233
- </div>
234
- <div class="es_contact_kpi">
235
- <span class="es_contact_kpi_no" style="color: #d40303"><?php echo $es_total_unsubscribed_contacts; ?></span></br>
236
- <span class="es_contact_kpi_text"><?php _e('Unsubscribed', 'email-subscribers'); ?></span>
237
- </div>
238
- <div class="es_contact_kpi">
239
- <span class="es_contact_kpi_no" style="color: #006cc1"><?php echo $es_total_contacts_opened_emails; ?></span></br>
240
- <span class="es_contact_kpi_text"><?php _e('Opened', 'email-subscribers'); ?></span>
241
- </div>
242
- <?php do_action('ig_es_after_contacts_kpis'); ?>
243
- </div>
244
  <?php
245
  }
246
 
@@ -601,17 +607,17 @@ class ES_Contacts_Table extends WP_List_Table {
601
  <tbody>
602
  <tr class="form-field">
603
  <td><label><b><?php _e( 'First Name', 'email-subscribers' ); ?></b></label></td>
604
- <td><input type="text" class="ig-es-contact-first-name" id="ig-es-contact-first-name" name="contact_data[first_name]" value="<?php echo $first_name; ?>"/></td>
605
  </tr>
606
 
607
  <tr class="form-field">
608
  <td><label><b><?php _e( 'Last Name', 'email-subscribers' ); ?></b></label></td>
609
- <td><input type="text" class="ig-es-contact-last-name" id="ig-es-contact-last-name" name="contact_data[last_name]" value="<?php echo $last_name; ?>"/></td>
610
  </tr>
611
 
612
  <tr class="form-field">
613
  <td><label><b><?php _e( 'Email', 'email-subscribers' ); ?></b></label></td>
614
- <td><input type="email" id="email" name="contact_data[email]" value="<?php echo $email; ?>"/></td>
615
  </tr>
616
 
617
  <?php if ( $is_new ) { ?>
@@ -758,13 +764,8 @@ class ES_Contacts_Table extends WP_List_Table {
758
  'delete' => sprintf( __( '<a href="?page=%s&action=%s&subscriber=%s&_wpnonce=%s" onclick="return checkDelete()">Delete</a>', 'email-subscribers' ), esc_attr( $page ), 'delete', absint( $item['id'] ), $delete_nonce ),
759
  );
760
 
761
- $optin_type = get_option( 'ig_es_optin_type' );
762
-
763
- //if ( in_array( $optin_type, array( 'double_optin', 'double_opt_in' ) ) ) {
764
  $actions['resend'] = sprintf( __( '<a href="?page=%s&action=%s&subscriber=%s&_wpnonce=%s">Resend Confirmation<a>', 'email-subscribers' ), esc_attr( ig_es_get_request_data( 'page' ) ), 'resend', absint( $item['id'] ), $delete_nonce );
765
 
766
- //}
767
-
768
  return $title . $this->row_actions( $actions );
769
  }
770
 
@@ -818,12 +819,20 @@ class ES_Contacts_Table extends WP_List_Table {
818
  return $actions;
819
  }
820
 
821
-
822
- public function search_box( $text, $input_id ) {
 
 
 
 
 
 
 
 
823
 
824
  ?>
825
  <p class="search-box box-ma10">
826
- <label class="screen-reader-text" for="<?php echo $input_id ?>"><?php echo $text; ?>:</label>
827
  <input type="search" id="<?php echo $input_id ?>" name="s" value="<?php _admin_search_query(); ?>"/>
828
  <?php submit_button( __( 'Search Contacts', 'email-subscribers' ), 'button', false, false, array( 'id' => 'search-submit' ) ); ?>
829
  </p>
@@ -843,6 +852,10 @@ class ES_Contacts_Table extends WP_List_Table {
843
  <?php }
844
 
845
 
 
 
 
 
846
  /**
847
  * Handles data query and filter, sorting, and pagination.
848
  */
@@ -885,12 +898,6 @@ class ES_Contacts_Table extends WP_List_Table {
885
  }
886
  }
887
 
888
- public function get_contact_id(
889
- $contact
890
- ) {
891
- return $contact['id'];
892
- }
893
-
894
  public function prepare_lists_dropdown() {
895
  $data = '<label for="bulk-action-selector-top" class="screen-reader-text">Select bulk action</label><select name="list_id" id="list_id" class="groupsselect" style="display: none">';
896
  $data .= ES_Common::prepare_list_dropdown_options();
@@ -947,8 +954,8 @@ class ES_Contacts_Table extends WP_List_Table {
947
  if ( ! wp_verify_nonce( $nonce, 'ig_es_delete_subscriber' ) ) {
948
  die( 'You do not have a permission to resend email confirmation' );
949
  } else {
950
- $id = absint( ig_es_get_request_data( 'subscriber' ) );
951
- $resend = ig_es_get_request_data( 'resend', false );
952
  $subscriber = ES()->contacts_db->get_by_id( $id );
953
 
954
  $email = $subscriber['email'];
@@ -959,13 +966,14 @@ class ES_Contacts_Table extends WP_List_Table {
959
  if ( $resend ) {
960
  $message = __( 'Confirmation email has been sent successfully!', 'email-subscribers' );
961
  ES_Common::show_message( $message, 'success' );
 
962
  return;
963
- }else{
964
  $response = ES()->mailer->send_double_optin_email( $email, $merge_tags );
965
- $url = add_query_arg( 'resend', true );
966
  //redirect to resend link and avoid resending email
967
  ?>
968
- <meta http-equiv="refresh" content="0; url=<?php echo $url; ?>"/>
969
  <?php
970
  }
971
 
92
  'url' => add_query_arg( 'action', 'new', 'admin.php?page=es_subscribers' )
93
  ),
94
 
95
+ 'import' => array(
96
+ 'label' => __( 'Import Contacts', 'email-subscribers' ),
97
  'indicator_option' => '',
98
  'indicator_label' => '',
99
  'indicator_type' => '',
100
+ 'action' => 'import',
101
+ 'url' => add_query_arg( 'action', 'import', 'admin.php?page=es_subscribers' )
102
  ),
103
 
104
+ 'export' => array(
105
+ 'label' => __( 'Export Contacts', 'email-subscribers' ),
106
  'indicator_option' => '',
107
  'indicator_label' => '',
108
  'indicator_type' => '',
109
+ 'action' => 'export',
110
+ 'url' => add_query_arg( 'action', 'export', 'admin.php?page=es_subscribers' )
111
  ),
112
 
113
  'sync' => array(
176
  ES_Common::prepare_main_header_navigation( $audience_tab_main_navigation );
177
  ?>
178
  </h1>
179
+
180
  <div class="es-contact-reports">
181
+ <?php $this->get_contacts_reports() ?>
182
  </div>
183
 
184
  <?php Email_Subscribers_Admin::es_feedback(); ?>
216
  $sync->prepare_sync_user();
217
  }
218
 
219
+ /**
220
+ * Get Contacts Reports
221
+ *
222
+ * @since 4.3.1
223
+ */
224
+ public function get_contacts_reports() {
225
+ $es_total_contact = ES_Reports_Data::get_total_contacts();
226
+ $es_total_subscribed_contacts = ES_Reports_Data::get_total_subscribed_contacts( 60 );
227
+ $es_total_unsubscribed_contacts = ES_Reports_Data::get_total_unsubscribed_contacts( 60 );
228
  $es_total_contacts_opened_emails = ES_Reports_Data::get_total_contacts_opened_emails( 60 );
229
  ?>
230
+ <div class="es_total_contact">
231
+ <h2 class="es_contact_kpi_text"><?php _e( 'Contacts', 'email-subscribers' ); ?></h2>
232
+ <span class="es_contact_kpi_no"><?php echo $es_total_contact; ?></span></br>
233
+ </div>
234
+ <div class="es_last_60_days">
235
+ <h2><?php _e( 'Last 60 Days', 'email-subscribers' ); ?></h2>
236
+ <div class="es_contact_kpi">
237
+ <span class="es_contact_kpi_no" style="color: #009e00"><?php echo $es_total_subscribed_contacts; ?></span></br>
238
+ <span class="es_contact_kpi_text"><?php _e( 'Subscribed', 'email-subscribers' ); ?></span>
239
+ </div>
240
+ <div class="es_contact_kpi">
241
+ <span class="es_contact_kpi_no" style="color: #d40303"><?php echo $es_total_unsubscribed_contacts; ?></span></br>
242
+ <span class="es_contact_kpi_text"><?php _e( 'Unsubscribed', 'email-subscribers' ); ?></span>
243
+ </div>
244
+ <div class="es_contact_kpi">
245
+ <span class="es_contact_kpi_no" style="color: #006cc1"><?php echo $es_total_contacts_opened_emails; ?></span></br>
246
+ <span class="es_contact_kpi_text"><?php _e( 'Opened', 'email-subscribers' ); ?></span>
247
+ </div>
248
+ <?php do_action( 'ig_es_after_contacts_kpis' ); ?>
249
+ </div>
250
  <?php
251
  }
252
 
607
  <tbody>
608
  <tr class="form-field">
609
  <td><label><b><?php _e( 'First Name', 'email-subscribers' ); ?></b></label></td>
610
+ <td><input type="text" class="ig-es-contact-first-name" id="ig-es-contact-first-name" name="contact_data[first_name]" value="<?php echo esc_attr( $first_name ); ?>"/></td>
611
  </tr>
612
 
613
  <tr class="form-field">
614
  <td><label><b><?php _e( 'Last Name', 'email-subscribers' ); ?></b></label></td>
615
+ <td><input type="text" class="ig-es-contact-last-name" id="ig-es-contact-last-name" name="contact_data[last_name]" value="<?php echo esc_attr( $last_name ); ?>"/></td>
616
  </tr>
617
 
618
  <tr class="form-field">
619
  <td><label><b><?php _e( 'Email', 'email-subscribers' ); ?></b></label></td>
620
+ <td><input type="email" id="email" name="contact_data[email]" value="<?php echo esc_attr( $email ); ?>"/></td>
621
  </tr>
622
 
623
  <?php if ( $is_new ) { ?>
764
  'delete' => sprintf( __( '<a href="?page=%s&action=%s&subscriber=%s&_wpnonce=%s" onclick="return checkDelete()">Delete</a>', 'email-subscribers' ), esc_attr( $page ), 'delete', absint( $item['id'] ), $delete_nonce ),
765
  );
766
 
 
 
 
767
  $actions['resend'] = sprintf( __( '<a href="?page=%s&action=%s&subscriber=%s&_wpnonce=%s">Resend Confirmation<a>', 'email-subscribers' ), esc_attr( ig_es_get_request_data( 'page' ) ), 'resend', absint( $item['id'] ), $delete_nonce );
768
 
 
 
769
  return $title . $this->row_actions( $actions );
770
  }
771
 
819
  return $actions;
820
  }
821
 
822
+ /**
823
+ * Prepare search box
824
+ *
825
+ * @param string $text
826
+ * @param string $input_id
827
+ *
828
+ * @since 4.0.0
829
+ * @since 4.3.4 Added esc_attr()
830
+ */
831
+ public function search_box( $text = '', $input_id = '' ) {
832
 
833
  ?>
834
  <p class="search-box box-ma10">
835
+ <label class="screen-reader-text" for="<?php echo esc_attr( $input_id ); ?>"><?php echo esc_attr( $text ); ?>:</label>
836
  <input type="search" id="<?php echo $input_id ?>" name="s" value="<?php _admin_search_query(); ?>"/>
837
  <?php submit_button( __( 'Search Contacts', 'email-subscribers' ), 'button', false, false, array( 'id' => 'search-submit' ) ); ?>
838
  </p>
852
  <?php }
853
 
854
 
855
+ public function get_contact_id($contact) {
856
+ return $contact['id'];
857
+ }
858
+
859
  /**
860
  * Handles data query and filter, sorting, and pagination.
861
  */
898
  }
899
  }
900
 
 
 
 
 
 
 
901
  public function prepare_lists_dropdown() {
902
  $data = '<label for="bulk-action-selector-top" class="screen-reader-text">Select bulk action</label><select name="list_id" id="list_id" class="groupsselect" style="display: none">';
903
  $data .= ES_Common::prepare_list_dropdown_options();
954
  if ( ! wp_verify_nonce( $nonce, 'ig_es_delete_subscriber' ) ) {
955
  die( 'You do not have a permission to resend email confirmation' );
956
  } else {
957
+ $id = absint( ig_es_get_request_data( 'subscriber' ) );
958
+ $resend = ig_es_get_request_data( 'resend', false );
959
  $subscriber = ES()->contacts_db->get_by_id( $id );
960
 
961
  $email = $subscriber['email'];
966
  if ( $resend ) {
967
  $message = __( 'Confirmation email has been sent successfully!', 'email-subscribers' );
968
  ES_Common::show_message( $message, 'success' );
969
+
970
  return;
971
+ } else {
972
  $response = ES()->mailer->send_double_optin_email( $email, $merge_tags );
973
+ $url = add_query_arg( 'resend', true );
974
  //redirect to resend link and avoid resending email
975
  ?>
976
+ <meta http-equiv="refresh" content="0; url=<?php echo $url; ?>"/>
977
  <?php
978
  }
979
 
lite/includes/classes/class-es-forms-table.php CHANGED
@@ -738,9 +738,18 @@ class ES_Forms_Table extends WP_List_Table {
738
  return $actions;
739
  }
740
 
 
 
 
 
 
 
 
 
 
741
  public function search_box( $text, $input_id ) { ?>
742
  <p class="search-box">
743
- <label class="screen-reader-text" for="<?php echo $input_id ?>"><?php echo $text; ?>:</label>
744
  <input type="search" id="<?php echo $input_id ?>" name="s" value="<?php _admin_search_query(); ?>"/>
745
  <?php submit_button( __( 'Search Forms', 'email-subscribers' ), 'button', false, false, array( 'id' => 'search-submit' ) ); ?>
746
  </p>
738
  return $actions;
739
  }
740
 
741
+ /**
742
+ * Prepare search box
743
+ *
744
+ * @param string $text
745
+ * @param string $input_id
746
+ *
747
+ * @since 4.0.0
748
+ * @since 4.3.4 Added esc_attr()
749
+ */
750
  public function search_box( $text, $input_id ) { ?>
751
  <p class="search-box">
752
+ <label class="screen-reader-text" for="<?php echo esc_attr($input_id); ?>"><?php echo esc_attr($text); ?>:</label>
753
  <input type="search" id="<?php echo $input_id ?>" name="s" value="<?php _admin_search_query(); ?>"/>
754
  <?php submit_button( __( 'Search Forms', 'email-subscribers' ), 'button', false, false, array( 'id' => 'search-submit' ) ); ?>
755
  </p>
lite/includes/classes/class-es-handle-post-notification.php CHANGED
@@ -240,9 +240,11 @@ class ES_Handle_Post_Notification {
240
  $es_templ_body = str_replace( '{{POSTFULL}}', $post_full, $es_templ_body );
241
 
242
  // add pre header as post excerpt
 
243
  if ( ! empty( $post_excerpt ) ) {
244
- //$es_templ_body = '<span class="es_preheader" style="display: none !important; visibility: hidden; opacity: 0; color: transparent; height: 0; width: 0;">' . $post_excerpt . '</span>' . $es_templ_body;
245
  }
 
246
 
247
  if ( $email_template_id > 0 ) {
248
  $es_templ_body = ES_Common::es_process_template_body( $es_templ_body, $email_template_id );
240
  $es_templ_body = str_replace( '{{POSTFULL}}', $post_full, $es_templ_body );
241
 
242
  // add pre header as post excerpt
243
+ /*
244
  if ( ! empty( $post_excerpt ) ) {
245
+ $es_templ_body = '<span class="es_preheader" style="display: none !important; visibility: hidden; opacity: 0; color: transparent; height: 0; width: 0;">' . $post_excerpt . '</span>' . $es_templ_body;
246
  }
247
+ */
248
 
249
  if ( $email_template_id > 0 ) {
250
  $es_templ_body = ES_Common::es_process_template_body( $es_templ_body, $email_template_id );
lite/includes/classes/class-es-import-subscribers.php CHANGED
@@ -44,6 +44,10 @@ class ES_Import_Subscribers {
44
 
45
  if ( $ext == ".csv" ) {
46
 
 
 
 
 
47
  $statuses = ES_Common::get_statuses_key_name_map();
48
  $es_email_status = ig_es_get_post_data( 'es_email_status' );
49
 
44
 
45
  if ( $ext == ".csv" ) {
46
 
47
+ if ( ! ini_get( "auto_detect_line_endings" ) ) {
48
+ ini_set( "auto_detect_line_endings", '1' );
49
+ }
50
+
51
  $statuses = ES_Common::get_statuses_key_name_map();
52
  $es_email_status = ig_es_get_post_data( 'es_email_status' );
53
 
lite/includes/classes/class-es-lists-table.php CHANGED
@@ -264,7 +264,7 @@ class ES_Lists_Table extends WP_List_Table {
264
  <form method="post" action="admin.php?page=es_lists&action=<?php echo $action; ?>&list=<?php echo $id; ?>&_wpnonce=<?php echo $nonce; ?>">
265
  <div class="row-blog">
266
  <label><?php _e( 'Name', 'email-subscribers' ); ?>: </label>
267
- <input type="text" id="name" name="list_name" value="<?php echo $list_name; ?>"/>
268
  </div>
269
  <input type="hidden" name="submitted" value="submitted"/>
270
  <div class="row-blog"><?php submit_button(); ?></div>
@@ -529,9 +529,18 @@ class ES_Lists_Table extends WP_List_Table {
529
  return $actions;
530
  }
531
 
532
- public function search_box( $text, $input_id ) { ?>
 
 
 
 
 
 
 
 
 
533
  <p class="search-box">
534
- <label class="screen-reader-text" for="<?php echo $input_id ?>"><?php echo $text; ?>:</label>
535
  <input type="search" id="<?php echo $input_id ?>" name="s" value="<?php _admin_search_query(); ?>"/>
536
  <?php submit_button( __( 'Search Lists', 'email-subscribers' ), 'button', false, false, array( 'id' => 'search-submit' ) ); ?>
537
  </p>
264
  <form method="post" action="admin.php?page=es_lists&action=<?php echo $action; ?>&list=<?php echo $id; ?>&_wpnonce=<?php echo $nonce; ?>">
265
  <div class="row-blog">
266
  <label><?php _e( 'Name', 'email-subscribers' ); ?>: </label>
267
+ <input type="text" id="name" name="list_name" value="<?php echo esc_attr($list_name); ?>"/>
268
  </div>
269
  <input type="hidden" name="submitted" value="submitted"/>
270
  <div class="row-blog"><?php submit_button(); ?></div>
529
  return $actions;
530
  }
531
 
532
+ /**
533
+ * Prepare search box
534
+ *
535
+ * @param string $text
536
+ * @param string $input_id
537
+ *
538
+ * @since 4.0.0
539
+ * @since 4.3.4 Added esc_attr()
540
+ */
541
+ public function search_box( $text = '', $input_id = '') { ?>
542
  <p class="search-box">
543
+ <label class="screen-reader-text" for="<?php echo esc_attr($input_id); ?>"><?php echo esc_attr($text); ?>:</label>
544
  <input type="search" id="<?php echo $input_id ?>" name="s" value="<?php _admin_search_query(); ?>"/>
545
  <?php submit_button( __( 'Search Lists', 'email-subscribers' ), 'button', false, false, array( 'id' => 'search-submit' ) ); ?>
546
  </p>
lite/includes/classes/class-es-mailer.php CHANGED
@@ -598,13 +598,10 @@ if ( ! class_exists( 'ES_Mailer' ) ) {
598
  do_action( 'ig_es_email_sending_error', $contact_id, $campaign_id, $message_id, $response );
599
 
600
  //TODO: Log somewhere
601
- } else {
602
- // Successfully Sent Email
603
-
604
- // Track Message Sent
605
- do_action( 'ig_es_message_sent', $contact_id, $campaign_id, $message_id );
606
  }
607
 
 
 
608
  // Reduce Email Sending Limit for this hour
609
  $this->email_limit --;
610
 
@@ -682,6 +679,7 @@ if ( ! class_exists( 'ES_Mailer' ) ) {
682
  $campaign_id = ! empty( $merge_tags['campaign_id'] ) ? $merge_tags['campaign_id'] : 0;
683
  $message->body = $this->set_pre_header_text( $message->body, $campaign_id );
684
  */
 
685
  return $message;
686
  }
687
 
@@ -761,13 +759,13 @@ if ( ! class_exists( 'ES_Mailer' ) ) {
761
  }
762
 
763
  /**
764
- * Get contact merge tags
765
- *
766
  * @param int $contact_id
767
  *
768
  * @return array
769
- *
770
- * @since 4.3.2
771
  */
772
  public function get_contact_merge_tags( $contact_id = 0 ) {
773
  $merge_tags = array();
@@ -1165,4 +1163,4 @@ if ( ! class_exists( 'ES_Mailer' ) ) {
1165
  return $this->prepare_link( $link_data );
1166
  }
1167
  }
1168
- }
598
  do_action( 'ig_es_email_sending_error', $contact_id, $campaign_id, $message_id, $response );
599
 
600
  //TODO: Log somewhere
 
 
 
 
 
601
  }
602
 
603
+ do_action( 'ig_es_message_sent', $contact_id, $campaign_id, $message_id );
604
+
605
  // Reduce Email Sending Limit for this hour
606
  $this->email_limit --;
607
 
679
  $campaign_id = ! empty( $merge_tags['campaign_id'] ) ? $merge_tags['campaign_id'] : 0;
680
  $message->body = $this->set_pre_header_text( $message->body, $campaign_id );
681
  */
682
+
683
  return $message;
684
  }
685
 
759
  }
760
 
761
  /**
762
+ * Get contact merge tags
763
+ *
764
  * @param int $contact_id
765
  *
766
  * @return array
767
+ *
768
+ * @since 4.3.2
769
  */
770
  public function get_contact_merge_tags( $contact_id = 0 ) {
771
  $merge_tags = array();
1163
  return $this->prepare_link( $link_data );
1164
  }
1165
  }
1166
+ }
lite/includes/classes/class-es-queue.php CHANGED
@@ -39,7 +39,7 @@ if ( ! class_exists( 'ES_Queue' ) ) {
39
  add_action( 'plugins_loaded', array( &$this, 'init' ), 1 );
40
 
41
  add_action( 'ig_es_before_message_send', array( &$this, 'set_sending_status' ), 10, 3 );
42
- add_action( 'ig_es_email_sending_error', array( &$this, 'set_status_in_queue' ), 10, 4 );
43
  add_action( 'ig_es_message_sent', array( &$this, 'set_sent_status' ), 10, 3 );
44
  add_action( 'ig_es_message_sent', array( &$this, 'update_email_sent_count' ), 10, 3 );
45
  }
39
  add_action( 'plugins_loaded', array( &$this, 'init' ), 1 );
40
 
41
  add_action( 'ig_es_before_message_send', array( &$this, 'set_sending_status' ), 10, 3 );
42
+ //add_action( 'ig_es_email_sending_error', array( &$this, 'set_status_in_queue' ), 10, 4 );
43
  add_action( 'ig_es_message_sent', array( &$this, 'set_sent_status' ), 10, 3 );
44
  add_action( 'ig_es_message_sent', array( &$this, 'update_email_sent_count' ), 10, 3 );
45
  }
lite/includes/db/class-es-db-actions.php CHANGED
@@ -95,15 +95,15 @@ class ES_DB_Actions extends ES_DB {
95
  $ig_actions_table = IG_ACTIONS_TABLE;
96
 
97
  $args_keys = array_keys( $args );
98
- $args_keys_str = $this->array_to_str( $args_keys );
99
 
100
  $sql = "INSERT INTO $ig_actions_table ($args_keys_str)";
101
 
102
  $args_values = array_values( $args );
103
 
104
- $args_values_str = $this->array_to_str( $args_values, "', '" );
105
 
106
- $sql .= " VALUES ('{$args_values_str}') ON DUPLICATE KEY UPDATE";
107
 
108
  $sql .= ( $explicit ) ? $wpdb->prepare( " created_at = created_at, count = count+1, updated_at = %d", ig_es_get_current_gmt_timestamp() ) : ' count = values(count)';
109
 
95
  $ig_actions_table = IG_ACTIONS_TABLE;
96
 
97
  $args_keys = array_keys( $args );
98
+ $args_keys_str = implode( ", " , $args_keys );
99
 
100
  $sql = "INSERT INTO $ig_actions_table ($args_keys_str)";
101
 
102
  $args_values = array_values( $args );
103
 
104
+ $args_values_str = $this->prepare_for_in_query( $args_values);
105
 
106
+ $sql .= " VALUES ($args_values_str) ON DUPLICATE KEY UPDATE";
107
 
108
  $sql .= ( $explicit ) ? $wpdb->prepare( " created_at = created_at, count = count+1, updated_at = %d", ig_es_get_current_gmt_timestamp() ) : ' count = values(count)';
109
 
lite/includes/db/class-es-db-campaigns.php CHANGED
@@ -366,17 +366,10 @@ class ES_DB_Campaigns extends ES_DB {
366
  * @return string|null
367
  *
368
  * @since 4.2.1
 
369
  */
370
  public function get_total_campaigns( $where = '' ) {
371
-
372
- if ( empty( $where ) ) {
373
- $where = "deleted_at IS NULL OR deleted_at = '0000-00-00 00:00:00'";
374
- }
375
-
376
- $campaigns = $this->count( $where );
377
-
378
- return $campaigns;
379
-
380
  }
381
 
382
  /**
@@ -391,7 +384,7 @@ class ES_DB_Campaigns extends ES_DB {
391
  public function get_total_campaigns_by_type( $type = 'newsletter' ) {
392
  global $wpdb;
393
 
394
- $where = $wpdb->prepare( "type = %s AND (deleted_at IS NULL OR deleted_at = '0000-00-00 00:00:00')", array( $type ) );
395
 
396
  $campaigns = $this->get_total_campaigns( $where );
397
 
@@ -489,6 +482,7 @@ class ES_DB_Campaigns extends ES_DB {
489
  * @return array|object|null
490
  *
491
  * @since 4.2.1
 
492
  */
493
  public function get_campaign_by_parent_id( $id = 0 ) {
494
  global $wpdb;
@@ -505,13 +499,13 @@ class ES_DB_Campaigns extends ES_DB {
505
 
506
  }
507
 
508
-
509
  /**
510
  * Get Active Campaigns
511
  *
512
  * @return array|object|null
513
  *
514
  * @since 4.2.0
 
515
  */
516
  public function get_active_campaigns( $type = '' ) {
517
  global $wpdb;
@@ -564,4 +558,54 @@ class ES_DB_Campaigns extends ES_DB {
564
 
565
  }
566
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
567
  }
366
  * @return string|null
367
  *
368
  * @since 4.2.1
369
+ * @since 4.3.4 Removed deleted_at $where condition
370
  */
371
  public function get_total_campaigns( $where = '' ) {
372
+ return $this->count( $where );
 
 
 
 
 
 
 
 
373
  }
374
 
375
  /**
384
  public function get_total_campaigns_by_type( $type = 'newsletter' ) {
385
  global $wpdb;
386
 
387
+ $where = $wpdb->prepare( "type = %s", array( $type ) );
388
 
389
  $campaigns = $this->get_total_campaigns( $where );
390
 
482
  * @return array|object|null
483
  *
484
  * @since 4.2.1
485
+ * @since 4.3.4 Removed deleted_at condition
486
  */
487
  public function get_campaign_by_parent_id( $id = 0 ) {
488
  global $wpdb;
499
 
500
  }
501
 
 
502
  /**
503
  * Get Active Campaigns
504
  *
505
  * @return array|object|null
506
  *
507
  * @since 4.2.0
508
+ * @since 4.3.4 Removed deleted_at condition
509
  */
510
  public function get_active_campaigns( $type = '' ) {
511
  global $wpdb;
558
 
559
  }
560
 
561
+ /**
562
+ * Delete Campaigns
563
+ *
564
+ * @param $ids
565
+ *
566
+ * @since 4.3.4
567
+ */
568
+ public function delete_campaigns( $ids = array() ) {
569
+
570
+ if ( is_string( $ids ) ) {
571
+ $ids = array( absint( $ids ) );
572
+ }
573
+
574
+ if ( is_array( $ids ) && count( $ids ) > 0 ) {
575
+
576
+ foreach ( $ids as $id ) {
577
+ $this->delete( absint( $id ) );
578
+
579
+ /**
580
+ * Take necessary cleanup steps using this hook
581
+ *
582
+ * @since 4.3.4
583
+ */
584
+ do_action( 'ig_es_campaign_deleted', $id );
585
+ }
586
+
587
+ return true;
588
+ }
589
+
590
+ return false;
591
+ }
592
+
593
+ /**
594
+ * Get all campaign ids by parent_id
595
+ *
596
+ * @param int $parent_campaign_id
597
+ *
598
+ * @return array|string|null
599
+ *
600
+ * @since 4.3.4
601
+ */
602
+ public function get_campaigns_by_parent_id( $parent_campaign_id = 0 ) {
603
+
604
+ if ( empty( $parent_campaign_id ) || 0 == absint( $parent_campaign_id ) ) {
605
+ return array();
606
+ }
607
+
608
+ return $this->get_column_by('id', 'parent_id', $parent_campaign_id, false);
609
+ }
610
+
611
  }
lite/includes/db/class-es-db-contacts.php CHANGED
@@ -39,7 +39,6 @@ class ES_DB_Contacts extends ES_DB {
39
  $this->primary_key = 'id';
40
 
41
  $this->version = '1.0';
42
-
43
  }
44
 
45
  /**
@@ -129,16 +128,12 @@ class ES_DB_Contacts extends ES_DB {
129
 
130
  $subscriber_email_name_map = array();
131
  if ( count( $emails ) > 0 ) {
132
- function temp( $v ) {
133
- return "'" . esc_sql( $v ) . "'";
134
- }
135
-
136
- $emails = array_map( "temp", $emails );
137
 
138
  $ig_contacts_table = IG_CONTACTS_TABLE;
139
 
140
- $emails_str = $this->array_to_str( $emails );
141
- $subscribers = $wpdb->get_results( "SELECT email, first_name, last_name FROM $ig_contacts_table WHERE email IN ( " . $emails_str . ")", ARRAY_A );
 
142
 
143
  if ( count( $subscribers ) > 0 ) {
144
  foreach ( $subscribers as $subscriber ) {
@@ -154,7 +149,6 @@ class ES_DB_Contacts extends ES_DB {
154
  }
155
 
156
  return $subscriber_email_name_map;
157
-
158
  }
159
 
160
  /**
@@ -279,7 +273,7 @@ class ES_DB_Contacts extends ES_DB {
279
  return array();
280
  }
281
 
282
- $ids_str = $this->array_to_str( $ids );
283
 
284
  $where = "id IN ($ids_str)";
285
 
@@ -332,14 +326,13 @@ class ES_DB_Contacts extends ES_DB {
332
  *
333
  * @since 4.2.4
334
  */
335
- public function delete_contacts_by_ids( $ids ) {
336
  global $wpdb;
337
 
338
- $ids = array_map( 'absint', $ids );
339
-
340
- $ids = $this->array_to_str( $ids );
341
 
342
  $where = "id IN ($ids)";
 
343
  $this->delete_by_condition( $where );
344
 
345
  $ig_lists_contacts_table = IG_LISTS_CONTACTS_TABLE;
@@ -362,14 +355,13 @@ class ES_DB_Contacts extends ES_DB {
362
  public function update_contacts_list( $ids, $list_id ) {
363
  global $wpdb;
364
 
365
- $ids = array_map( 'absint', $ids );
366
-
367
- $ids_str = $this->array_to_str( $ids );
368
 
369
  $ig_lists_contacts_table = IG_LISTS_CONTACTS_TABLE;
370
 
371
  //delete all list contact entry
372
  $query = "DELETE FROM $ig_lists_contacts_table WHERE contact_id IN ($ids_str) ";
 
373
  $wpdb->query( $query );
374
 
375
  $values = $place_holders = array();
@@ -386,7 +378,7 @@ class ES_DB_Contacts extends ES_DB {
386
  }
387
 
388
  $query = "INSERT INTO $ig_lists_contacts_table (`list_id`, `contact_id`, `status`, `optin_type`, `subscribed_at`, `subscribed_ip` ) VALUES ";
389
- $query .= $this->array_to_str( $place_holders );
390
  $sql = $wpdb->prepare( "$query ", $values );
391
  if ( $wpdb->query( $sql ) ) {
392
  return true;
@@ -408,9 +400,7 @@ class ES_DB_Contacts extends ES_DB {
408
  public function add_contacts_to_list( $ids, $list_id ) {
409
  global $wpdb;
410
 
411
- $ids = array_map( 'absint', $ids );
412
-
413
- $ids_str = $this->array_to_str( $ids );
414
 
415
  $ig_lists_contacts_table = IG_LISTS_CONTACTS_TABLE;
416
 
@@ -431,7 +421,7 @@ class ES_DB_Contacts extends ES_DB {
431
  $place_holders[] = "( %d, %d, %s, %s, %s, %s )"; /* In my case, i know they will always be integers */
432
  }
433
  $query = "INSERT INTO " . IG_LISTS_CONTACTS_TABLE . " (`list_id`, `contact_id`, `status`, `optin_type`, `subscribed_at`, `subscribed_ip` ) VALUES ";
434
- $query .= $this->array_to_str( $place_holders );
435
  $sql = $wpdb->prepare( "$query ", $values );
436
  if ( $wpdb->query( $sql ) ) {
437
  return true;
@@ -449,18 +439,17 @@ class ES_DB_Contacts extends ES_DB {
449
  * @return bool|int
450
  *
451
  * @since 4.2.4
 
452
  */
453
- public function edit_contact_global_status( $ids, $unsubscribed ) {
454
  global $wpdb;
455
 
456
  $ig_contacts_table = IG_CONTACTS_TABLE;
457
 
458
- $ids = array_map( 'absint', $ids );
459
-
460
- $ids = $this->array_to_str( $ids );
461
 
462
  $sql = "UPDATE $ig_contacts_table SET unsubscribed = %d WHERE id IN ($ids)";
463
- $query = $wpdb->prepare( $sql, array( $unsubscribed ) );
464
 
465
  return $wpdb->query( $query );
466
 
@@ -473,6 +462,9 @@ class ES_DB_Contacts extends ES_DB {
473
  * @param $list_id
474
  *
475
  * @return array
 
 
 
476
  */
477
  public function is_contact_exist_in_list( $email, $list_id ) {
478
  global $wpdb;
@@ -489,7 +481,7 @@ class ES_DB_Contacts extends ES_DB {
489
 
490
  $ig_lists_contacts_table = IG_LISTS_CONTACTS_TABLE;
491
 
492
- $list_ids_str = $this->array_to_str( $list_id );
493
 
494
  $list_query = "SELECT count(*) as count FROM $ig_lists_contacts_table WHERE list_id IN ($list_ids_str) AND contact_id = %s";
495
  $list_sql = $wpdb->prepare( $list_query, $contact_id );
@@ -539,8 +531,7 @@ class ES_DB_Contacts extends ES_DB {
539
  * @return array
540
  *
541
  * @since 4.2.1
542
- *
543
- * @modify 4.2.4
544
  */
545
  public function get_details_by_ids( $contact_ids = array() ) {
546
 
@@ -564,7 +555,8 @@ class ES_DB_Contacts extends ES_DB {
564
  *
565
  * @return array
566
  *
567
- * @sinc 4.0.0
 
568
  */
569
  public function get_contact_ids_by_emails( $emails = array() ) {
570
  global $wpdb;
@@ -574,8 +566,9 @@ class ES_DB_Contacts extends ES_DB {
574
  $query = "SELECT id FROM $ig_contacts_table";
575
 
576
  if ( count( $emails ) > 0 ) {
577
- $emails_str = "'" . $this->array_to_str( $emails, "', '" ) . "'";
578
- $query .= " WHERE email IN ($emails_str)";
 
579
  }
580
 
581
  $ids = $wpdb->get_col( $query );
@@ -591,6 +584,7 @@ class ES_DB_Contacts extends ES_DB {
591
  * @return array
592
  *
593
  * @since 4.0.0
 
594
  */
595
  public function get_email_id_map( $emails = array() ) {
596
  global $wpdb;
@@ -600,7 +594,7 @@ class ES_DB_Contacts extends ES_DB {
600
  $query = "SELECT id, email FROM $ig_contacts_table";
601
 
602
  if ( count( $emails ) > 0 ) {
603
- $emails_str = "'" . $this->array_to_str( $emails, "', '" ) . "'";
604
 
605
  $query .= " WHERE email IN ($emails_str)";
606
  }
@@ -771,28 +765,27 @@ class ES_DB_Contacts extends ES_DB {
771
  * @return bool|int
772
  *
773
  * @since 4.2.0
 
774
  */
775
  public function edit_list_contact_status( $contact_ids, $list_ids, $status ) {
776
  global $wpdb;
777
 
778
- $ids = array_map( 'absint', $contact_ids );
779
- $ids = $this->array_to_str( $ids );
780
 
781
- $list_ids = array_map( 'absint', $list_ids );
782
- $list_ids = $this->array_to_str( $list_ids );
783
 
784
  $current_date = ig_get_current_date_time();
785
 
786
  $ig_contacts_table = IG_LISTS_CONTACTS_TABLE;
787
 
788
  if ( 'subscribed' === $status ) {
789
- $sql = "UPDATE $ig_contacts_table SET status = %s, subscribed_at = %s WHERE contact_id IN ($ids) AND list_id IN ($list_ids)";
790
  $query = $wpdb->prepare( $sql, array( $status, $current_date ) );
791
  } elseif ( 'unsubscribed' === $status ) {
792
- $sql = "UPDATE $ig_contacts_table SET status = %s, unsubscribed_at = %s WHERE contact_id IN ($ids) AND list_id IN ($list_ids)";
793
  $query = $wpdb->prepare( $sql, array( $status, $current_date ) );
794
  } elseif ( 'unconfirmed' === $status ) {
795
- $sql = "UPDATE $ig_contacts_table SET status = %s, optin_type = %d, subscribed_at = NULL, unsubscribed_at = NULL WHERE contact_id IN ($ids) AND list_id IN ($list_ids)";
796
  $query = $wpdb->prepare( $sql, array( $status, IG_DOUBLE_OPTIN ) );
797
  }
798
 
39
  $this->primary_key = 'id';
40
 
41
  $this->version = '1.0';
 
42
  }
43
 
44
  /**
128
 
129
  $subscriber_email_name_map = array();
130
  if ( count( $emails ) > 0 ) {
 
 
 
 
 
131
 
132
  $ig_contacts_table = IG_CONTACTS_TABLE;
133
 
134
+ $emails_str = $this->prepare_for_in_query( $emails );
135
+
136
+ $subscribers = $wpdb->get_results( "SELECT email, first_name, last_name FROM $ig_contacts_table WHERE email IN ($emails_str)", ARRAY_A );
137
 
138
  if ( count( $subscribers ) > 0 ) {
139
  foreach ( $subscribers as $subscriber ) {
149
  }
150
 
151
  return $subscriber_email_name_map;
 
152
  }
153
 
154
  /**
273
  return array();
274
  }
275
 
276
+ $ids_str = $this->prepare_for_in_query( $ids );
277
 
278
  $where = "id IN ($ids_str)";
279
 
326
  *
327
  * @since 4.2.4
328
  */
329
+ public function delete_contacts_by_ids( $ids = array() ) {
330
  global $wpdb;
331
 
332
+ $ids = $this->prepare_for_in_query( $ids );
 
 
333
 
334
  $where = "id IN ($ids)";
335
+
336
  $this->delete_by_condition( $where );
337
 
338
  $ig_lists_contacts_table = IG_LISTS_CONTACTS_TABLE;
355
  public function update_contacts_list( $ids, $list_id ) {
356
  global $wpdb;
357
 
358
+ $ids_str = $this->prepare_for_in_query( $ids );
 
 
359
 
360
  $ig_lists_contacts_table = IG_LISTS_CONTACTS_TABLE;
361
 
362
  //delete all list contact entry
363
  $query = "DELETE FROM $ig_lists_contacts_table WHERE contact_id IN ($ids_str) ";
364
+
365
  $wpdb->query( $query );
366
 
367
  $values = $place_holders = array();
378
  }
379
 
380
  $query = "INSERT INTO $ig_lists_contacts_table (`list_id`, `contact_id`, `status`, `optin_type`, `subscribed_at`, `subscribed_ip` ) VALUES ";
381
+ $query .= implode( ', ', $place_holders );
382
  $sql = $wpdb->prepare( "$query ", $values );
383
  if ( $wpdb->query( $sql ) ) {
384
  return true;
400
  public function add_contacts_to_list( $ids, $list_id ) {
401
  global $wpdb;
402
 
403
+ $ids_str = $this->prepare_for_in_query( $ids );
 
 
404
 
405
  $ig_lists_contacts_table = IG_LISTS_CONTACTS_TABLE;
406
 
421
  $place_holders[] = "( %d, %d, %s, %s, %s, %s )"; /* In my case, i know they will always be integers */
422
  }
423
  $query = "INSERT INTO " . IG_LISTS_CONTACTS_TABLE . " (`list_id`, `contact_id`, `status`, `optin_type`, `subscribed_at`, `subscribed_ip` ) VALUES ";
424
+ $query .= implode( ', ', $place_holders );
425
  $sql = $wpdb->prepare( "$query ", $values );
426
  if ( $wpdb->query( $sql ) ) {
427
  return true;
439
  * @return bool|int
440
  *
441
  * @since 4.2.4
442
+ * @since 4.3.4 Use prepare_for_in_query instead of array_to_str
443
  */
444
+ public function edit_contact_global_status( $ids = array(), $unsubscribed = 0 ) {
445
  global $wpdb;
446
 
447
  $ig_contacts_table = IG_CONTACTS_TABLE;
448
 
449
+ $ids = $this->prepare_for_in_query( $ids );
 
 
450
 
451
  $sql = "UPDATE $ig_contacts_table SET unsubscribed = %d WHERE id IN ($ids)";
452
+ $query = $wpdb->prepare( $sql, $unsubscribed );
453
 
454
  return $wpdb->query( $query );
455
 
462
  * @param $list_id
463
  *
464
  * @return array
465
+ *
466
+ * @since 4.0.0
467
+ * @since 4.3.4 Used prepare_for_in_query instead of array_to_str
468
  */
469
  public function is_contact_exist_in_list( $email, $list_id ) {
470
  global $wpdb;
481
 
482
  $ig_lists_contacts_table = IG_LISTS_CONTACTS_TABLE;
483
 
484
+ $list_ids_str = $this->prepare_for_in_query( $list_id );
485
 
486
  $list_query = "SELECT count(*) as count FROM $ig_lists_contacts_table WHERE list_id IN ($list_ids_str) AND contact_id = %s";
487
  $list_sql = $wpdb->prepare( $list_query, $contact_id );
531
  * @return array
532
  *
533
  * @since 4.2.1
534
+ * @since 4.2.4
 
535
  */
536
  public function get_details_by_ids( $contact_ids = array() ) {
537
 
555
  *
556
  * @return array
557
  *
558
+ * @since 4.0.0
559
+ * @since 4.3.4 Used prepare_for_in_query instead of array_to_str
560
  */
561
  public function get_contact_ids_by_emails( $emails = array() ) {
562
  global $wpdb;
566
  $query = "SELECT id FROM $ig_contacts_table";
567
 
568
  if ( count( $emails ) > 0 ) {
569
+ $emails_str = $this->prepare_for_in_query( $emails );
570
+
571
+ $query .= " WHERE email IN ($emails_str)";
572
  }
573
 
574
  $ids = $wpdb->get_col( $query );
584
  * @return array
585
  *
586
  * @since 4.0.0
587
+ * @since 4.3.4 Used prepare_for_in_query instead of array_to_str
588
  */
589
  public function get_email_id_map( $emails = array() ) {
590
  global $wpdb;
594
  $query = "SELECT id, email FROM $ig_contacts_table";
595
 
596
  if ( count( $emails ) > 0 ) {
597
+ $emails_str = $this->prepare_for_in_query( $emails );
598
 
599
  $query .= " WHERE email IN ($emails_str)";
600
  }
765
  * @return bool|int
766
  *
767
  * @since 4.2.0
768
+ * @since 4.3.4 Used prepare_for_in_query instead of array_to_str
769
  */
770
  public function edit_list_contact_status( $contact_ids, $list_ids, $status ) {
771
  global $wpdb;
772
 
773
+ $contact_ids = $this->prepare_for_in_query( $contact_ids );
 
774
 
775
+ $list_ids = $this->prepare_for_in_query( $list_ids );
 
776
 
777
  $current_date = ig_get_current_date_time();
778
 
779
  $ig_contacts_table = IG_LISTS_CONTACTS_TABLE;
780
 
781
  if ( 'subscribed' === $status ) {
782
+ $sql = "UPDATE $ig_contacts_table SET status = %s, subscribed_at = %s WHERE contact_id IN ($contact_ids) AND list_id IN ($list_ids)";
783
  $query = $wpdb->prepare( $sql, array( $status, $current_date ) );
784
  } elseif ( 'unsubscribed' === $status ) {
785
+ $sql = "UPDATE $ig_contacts_table SET status = %s, unsubscribed_at = %s WHERE contact_id IN ($contact_ids) AND list_id IN ($list_ids)";
786
  $query = $wpdb->prepare( $sql, array( $status, $current_date ) );
787
  } elseif ( 'unconfirmed' === $status ) {
788
+ $sql = "UPDATE $ig_contacts_table SET status = %s, optin_type = %d, subscribed_at = NULL, unsubscribed_at = NULL WHERE contact_id IN ($contact_ids) AND list_id IN ($list_ids)";
789
  $query = $wpdb->prepare( $sql, array( $status, IG_DOUBLE_OPTIN ) );
790
  }
791
 
lite/includes/db/class-es-db-forms.php CHANGED
@@ -162,7 +162,7 @@ class ES_DB_Forms extends ES_DB {
162
  return array();
163
  }
164
 
165
- return $this->get($id);
166
  }
167
 
168
  /**
@@ -341,14 +341,14 @@ class ES_DB_Forms extends ES_DB {
341
  */
342
  public function delete_forms( $ids ) {
343
 
344
- if ( is_int( $ids ) ) {
345
  $ids = array( $ids );
346
  }
347
 
348
  if ( is_array( $ids ) && count( $ids ) > 0 ) {
349
 
350
  foreach ( $ids as $id ) {
351
- $this->delete( $id );
352
 
353
  /**
354
  * Take necessary cleanup steps using this hook
162
  return array();
163
  }
164
 
165
+ return $this->get( $id );
166
  }
167
 
168
  /**
341
  */
342
  public function delete_forms( $ids ) {
343
 
344
+ if ( is_string( $ids ) ) {
345
  $ids = array( $ids );
346
  }
347
 
348
  if ( is_array( $ids ) && count( $ids ) > 0 ) {
349
 
350
  foreach ( $ids as $id ) {
351
+ $this->delete( absint( $id ) );
352
 
353
  /**
354
  * Take necessary cleanup steps using this hook
lite/includes/db/class-es-db-lists-contacts.php CHANGED
@@ -246,11 +246,11 @@ class ES_DB_Lists_Contacts {
246
  public static function edit_subscriber_status( $ids, $status ) {
247
  global $wpdb;
248
 
249
- if ( is_int( $ids ) ) {
250
  $ids = array( $ids );
251
  }
252
 
253
- $ids = implode( ',', array_map( 'absint', $ids ) );
254
 
255
  $current_date = ig_get_current_date_time();
256
  $ig_lists_contact_table = IG_LISTS_CONTACTS_TABLE;
@@ -280,11 +280,12 @@ class ES_DB_Lists_Contacts {
280
  *
281
  * @since 4.1.14
282
  */
283
- public static function is_status_update_required( $ids, $status ) {
284
  global $wpdb;
285
 
286
  $response = false;
287
- if ( is_int( $ids ) ) {
 
288
  $ids = array( $ids );
289
  }
290
 
246
  public static function edit_subscriber_status( $ids, $status ) {
247
  global $wpdb;
248
 
249
+ if ( is_string( $ids ) ) {
250
  $ids = array( $ids );
251
  }
252
 
253
+ $ids = implode( ', ', array_map( 'absint', $ids ) );
254
 
255
  $current_date = ig_get_current_date_time();
256
  $ig_lists_contact_table = IG_LISTS_CONTACTS_TABLE;
280
  *
281
  * @since 4.1.14
282
  */
283
+ public static function is_status_update_required( $ids = array(), $status = '') {
284
  global $wpdb;
285
 
286
  $response = false;
287
+
288
+ if ( is_string( $ids ) ) {
289
  $ids = array( $ids );
290
  }
291
 
lite/includes/db/class-es-db-lists.php CHANGED
@@ -356,14 +356,14 @@ class ES_DB_Lists extends ES_DB {
356
  */
357
  public function delete_lists( $ids ) {
358
 
359
- if ( is_int( $ids ) ) {
360
  $ids = array( $ids );
361
  }
362
 
363
  if ( is_array( $ids ) && count( $ids ) > 0 ) {
364
 
365
  foreach ( $ids as $id ) {
366
- $this->delete( $id );
367
 
368
  /**
369
  * Take necessary cleanup steps using this hook
356
  */
357
  public function delete_lists( $ids ) {
358
 
359
+ if ( is_string( $ids ) ) {
360
  $ids = array( $ids );
361
  }
362
 
363
  if ( is_array( $ids ) && count( $ids ) > 0 ) {
364
 
365
  foreach ( $ids as $id ) {
366
+ $this->delete( absint($id) );
367
 
368
  /**
369
  * Take necessary cleanup steps using this hook
lite/includes/db/class-es-db-mailing-queue.php CHANGED
@@ -98,14 +98,14 @@ class ES_DB_Mailing_Queue {
98
  $meta = maybe_unserialize( $notification['meta'] );
99
 
100
  if ( ! empty( $meta ) ) {
101
- $filter = 'ig_es_refresh_'.$meta['type'].'_content';
102
- $post_id = !empty( $meta['post_id'] ) ? $meta['post_id'] : 0;
103
  $content = array();
104
- $content = apply_filters($filter, $content, array( 'campaign_id' => $notification['campaign_id'], 'post_id' => $post_id ));
105
  if ( ! empty( $content ) ) {
106
  $notification['subject'] = ! empty( $content['subject'] ) ? $content['subject'] : $notification['subject'];
107
  $notification['body'] = ! empty( $content['body'] ) ? $content['body'] : $notification['body'];
108
- $query_sub_str = " , subject = '" . esc_sql($notification['subject']) . "', body = '" . esc_sql($notification['body']) . "' ";
109
  }
110
  }
111
  //update sent date
@@ -169,7 +169,7 @@ class ES_DB_Mailing_Queue {
169
  return $notification;
170
  }
171
 
172
- public static function get_notification_by_campaign_id($campaign_id) {
173
  global $wpdb;
174
 
175
  $notification = array();
@@ -211,8 +211,11 @@ class ES_DB_Mailing_Queue {
211
  public static function delete_notifications( $ids ) {
212
  global $wpdb;
213
 
214
- $ids = implode( ',', array_map( 'absint', $ids ) );
215
- $query = "DELETE FROM " . IG_MAILING_QUEUE_TABLE . " WHERE id IN ($ids)";
 
 
 
216
 
217
  $wpdb->query( $query );
218
  }
98
  $meta = maybe_unserialize( $notification['meta'] );
99
 
100
  if ( ! empty( $meta ) ) {
101
+ $filter = 'ig_es_refresh_' . $meta['type'] . '_content';
102
+ $post_id = ! empty( $meta['post_id'] ) ? $meta['post_id'] : 0;
103
  $content = array();
104
+ $content = apply_filters( $filter, $content, array( 'campaign_id' => $notification['campaign_id'], 'post_id' => $post_id ) );
105
  if ( ! empty( $content ) ) {
106
  $notification['subject'] = ! empty( $content['subject'] ) ? $content['subject'] : $notification['subject'];
107
  $notification['body'] = ! empty( $content['body'] ) ? $content['body'] : $notification['body'];
108
+ $query_sub_str = " , subject = '" . esc_sql( $notification['subject'] ) . "', body = '" . esc_sql( $notification['body'] ) . "' ";
109
  }
110
  }
111
  //update sent date
169
  return $notification;
170
  }
171
 
172
+ public static function get_notification_by_campaign_id( $campaign_id ) {
173
  global $wpdb;
174
 
175
  $notification = array();
211
  public static function delete_notifications( $ids ) {
212
  global $wpdb;
213
 
214
+ $ids = implode( ', ', array_map( 'absint', array_map( 'esc_sql', $ids ) ) );
215
+
216
+ $mailing_queue_table = IG_MAILING_QUEUE_TABLE;
217
+
218
+ $query = "DELETE FROM $mailing_queue_table WHERE id IN ($ids)";
219
 
220
  $wpdb->query( $query );
221
  }
lite/includes/db/class-es-db-notifications.php CHANGED
@@ -27,8 +27,11 @@ class ES_DB_Notifications {
27
 
28
  if ( $post_id > 0 ) {
29
  $post_type = get_post_type( $post_id );
30
- $sSql = "SELECT * FROM " . IG_CAMPAIGNS_TABLE . " WHERE status = 1 AND (deleted_at IS NULL OR deleted_at = '0000-00-00 00:00:00') AND type = 'post_notification'";
31
-
 
 
 
32
  if ( $post_type == "post" ) {
33
  $categories = get_the_category( $post_id );
34
  $total_categories = count( $categories );
27
 
28
  if ( $post_id > 0 ) {
29
  $post_type = get_post_type( $post_id );
30
+
31
+ $campaigns_table = IG_CAMPAIGNS_TABLE;
32
+
33
+ $sSql = $wpdb->prepare( "SELECT * FROM $campaigns_table WHERE status = %d AND type = %s AND (deleted_at IS NULL OR deleted_at = '0000-00-00 00:00:00')", 1, 'post_notification' );
34
+
35
  if ( $post_type == "post" ) {
36
  $categories = get_the_category( $post_id );
37
  $total_categories = count( $categories );
lite/includes/db/class-es-db-sending-queue.php CHANGED
@@ -424,9 +424,11 @@ class ES_DB_Sending_Queue {
424
  public static function delete_sending_queue_by_mailing_id( $mailing_queue_ids ) {
425
  global $wpdb;
426
 
427
- $mailing_queue_ids = implode( ',', array_map( 'absint', $mailing_queue_ids ) );
428
 
429
- $query = "DELETE FROM " . IG_SENDING_QUEUE_TABLE . " WHERE mailing_queue_id IN ($mailing_queue_ids)";
 
 
430
 
431
  $wpdb->query( $query );
432
  }
424
  public static function delete_sending_queue_by_mailing_id( $mailing_queue_ids ) {
425
  global $wpdb;
426
 
427
+ $mailing_queue_ids = implode( ', ', array_map( 'absint', array_map( 'esc_sql', $mailing_queue_ids ) ) );
428
 
429
+ $sending_queue_table = IG_SENDING_QUEUE_TABLE;
430
+
431
+ $query = "DELETE FROM $sending_queue_table WHERE mailing_queue_id IN ($mailing_queue_ids)";
432
 
433
  $wpdb->query( $query );
434
  }
lite/includes/db/class-es-db.php CHANGED
@@ -149,17 +149,24 @@ abstract class ES_DB {
149
  * @param $column
150
  * @param $column_where
151
  * @param $column_value
 
152
  *
153
- * @return string|null
154
  *
155
  * @since 4.0.0
 
156
  */
157
- public function get_column_by( $column, $column_where, $column_value ) {
158
  global $wpdb;
 
159
  $column_where = esc_sql( $column_where );
160
  $column = esc_sql( $column );
161
 
162
- return $wpdb->get_var( $wpdb->prepare( "SELECT $column FROM $this->table_name WHERE $column_where = %s LIMIT 1;", $column_value ) );
 
 
 
 
163
  }
164
 
165
  /**
@@ -276,6 +283,33 @@ abstract class ES_DB {
276
  return true;
277
  }
278
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
279
  /**
280
  * Delete records based on $where
281
  *
@@ -492,18 +526,20 @@ abstract class ES_DB {
492
  }
493
 
494
  /**
495
- * Convert array into str for IN query
496
  *
497
- * @param $array
498
  *
499
  * @return string
500
  *
501
- * @since 4.2.4
502
  */
503
- public function array_to_str( $array, $glue = ', ' ) {
504
- //$array = esc_sql( $array );
 
 
505
  if ( is_array( $array ) && count( $array ) > 0 ) {
506
- return implode( $glue, $array );
507
  }
508
 
509
  return '';
149
  * @param $column
150
  * @param $column_where
151
  * @param $column_value
152
+ * @param bool $only_one
153
  *
154
+ * @return array|string|null
155
  *
156
  * @since 4.0.0
157
+ * @since 4.3.4 Added support to retrieve whole column
158
  */
159
+ public function get_column_by( $column, $column_where, $column_value, $only_one = true ) {
160
  global $wpdb;
161
+
162
  $column_where = esc_sql( $column_where );
163
  $column = esc_sql( $column );
164
 
165
+ if ( $only_one ) {
166
+ return $wpdb->get_var( $wpdb->prepare( "SELECT $column FROM $this->table_name WHERE $column_where = %s LIMIT 1;", $column_value ) );
167
+ } else {
168
+ return $wpdb->get_col( $wpdb->prepare( "SELECT $column FROM $this->table_name WHERE $column_where = %s;", $column_value ) );
169
+ }
170
  }
171
 
172
  /**
283
  return true;
284
  }
285
 
286
+ /**
287
+ * Delete rows by primary key
288
+ *
289
+ * @param array $row_ids
290
+ *
291
+ * @return bool
292
+ *
293
+ * @since 4.3.4
294
+ */
295
+ public function bulk_delete( $row_ids = array() ) {
296
+
297
+ if ( ! is_array( $row_ids ) && empty( $row_ids ) ) {
298
+ return false;
299
+ }
300
+
301
+ $row_ids_str = $this->prepare_for_in_query( $row_ids );
302
+
303
+ $where = "$this->primary_key IN ($row_ids_str)";
304
+
305
+ if ( false === $this->delete_by_condition( $where ) ) {
306
+ return false;
307
+ }
308
+
309
+ return true;
310
+ }
311
+
312
+
313
  /**
314
  * Delete records based on $where
315
  *
526
  }
527
 
528
  /**
529
+ * Prepare string for SQL IN query
530
  *
531
+ * @param array $array
532
  *
533
  * @return string
534
  *
535
+ * @since 4.3.4
536
  */
537
+ public function prepare_for_in_query( $array = array() ) {
538
+
539
+ $array = esc_sql( $array );
540
+
541
  if ( is_array( $array ) && count( $array ) > 0 ) {
542
+ return "'" . implode( "', '", $array ) . "'";
543
  }
544
 
545
  return '';
lite/includes/libraries/class-es-html2text.php CHANGED
@@ -516,9 +516,7 @@ class ES_Html2Text {
516
  $level--;
517
  if ( $level < 0 ) {
518
  $level = 0; // malformed HTML: go to next blockquote
519
- } elseif ( $level > 0 ) {
520
- // skip inner blockquote
521
- } else {
522
  $end = $m[1];
523
  $len = $end - $taglen - $start;
524
  // Get blockquote content
516
  $level--;
517
  if ( $level < 0 ) {
518
  $level = 0; // malformed HTML: go to next blockquote
519
+ } elseif ( $level == 0 ) {
 
 
520
  $end = $m[1];
521
  $len = $end - $taglen - $start;
522
  // Get blockquote content
lite/includes/upgrade/es-update-functions.php CHANGED
@@ -1100,4 +1100,25 @@ function ig_es_update_432_import_bfcm_templates(){
1100
  function ig_es_update_432_db_version() {
1101
  ES_Install::update_db_version( '4.3.2' );
1102
  }
1103
- /* --------------------- ES 4.3.2(End)--------------------------- */
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1100
  function ig_es_update_432_db_version() {
1101
  ES_Install::update_db_version( '4.3.2' );
1102
  }
1103
+ /* --------------------- ES 4.3.2(End)--------------------------- */
1104
+ /**
1105
+ * Delete Campaigns Permanently
1106
+ *
1107
+ * @since 4.3.4
1108
+ */
1109
+ function ig_es_update_434_permanently_delete_campaigns() {
1110
+ global $wpdb;
1111
+
1112
+ $query = "DELETE FROM {$wpdb->prefix}ig_campaigns WHERE deleted_at IS NOT NULL";
1113
+ $wpdb->query($query);
1114
+ }
1115
+
1116
+ /**
1117
+ * Update DB Update history
1118
+ *
1119
+ * @since 4.3.4
1120
+ */
1121
+ function ig_es_update_434_db_version() {
1122
+ ES_Install::update_db_version( '4.3.4' );
1123
+ }
1124
+ /* --------------------- ES 4.3.4(End)--------------------------- */
readme.txt CHANGED
@@ -5,7 +5,7 @@ Author URI: https://www.icegram.com/
5
  Tags: subscription, newsletter, email marketing, post notification, email newsletter form, email signup, email widget, newsletter signup, subscribe, subscription form, bulk emails, signup form, list builder, lead generation, welcome email, contacts
6
  Requires at least: 3.9
7
  Tested up to: 5.3
8
- Stable tag: 4.3.3
9
  License: GPLv3
10
  License URI: http://www.gnu.org/licenses
11
 
@@ -300,12 +300,16 @@ Refer [here](https://www.icegram.com/documentation/es-faq/).
300
 
301
  == Changelog ==
302
 
 
 
 
 
 
303
  **4.3.3 (25.11.2019)**
304
  * Fix: Cron Lock issue
305
  * Fix: Honeypot issue with caching plugin
306
 
307
  **4.3.2 (20.11.2019)**
308
-
309
  * New: Added basic reporting like total subscribed, unsubscribed, open in last 60 days in audience dashboard
310
  * New: Added Pre header in broadcast
311
  * Update: Clear all cron on deactivation
@@ -315,7 +319,6 @@ Refer [here](https://www.icegram.com/documentation/es-faq/).
315
  * Fix: Unsubscribe link issue
316
 
317
  **4.3.1 (13.11.2019)**
318
-
319
  * New: Delete Form Permanently
320
  * New: Delete List Permanently
321
  * Update: Restrict multiple email sending
@@ -326,7 +329,6 @@ Refer [here](https://www.icegram.com/documentation/es-faq/).
326
  * Fix: Fatal error
327
 
328
  **4.3.0 (06.11.2019)**
329
-
330
  * Fix: Test email sending issue
331
  * Fix: New Broadcast issue
332
  * Fix: Import contacts issue
@@ -334,70 +336,68 @@ Refer [here](https://www.icegram.com/documentation/es-faq/).
334
  * Update: .POT File
335
 
336
  **4.2.4 (23.10.2019)**
337
-
338
  * Update: Improve Create Broadcast UI
339
  * Fix: Unable to remove label for Email field in Subscription Form
340
  * Fix: Validate Post Notification data
341
 
342
  **4.2.3 (17.10.2019)**
343
-
344
  * Update: Now, only administrator can access Email Subscribers menus.
345
  * Fix: Email open tracking
346
  * Fix: Vulnerability while exporting contacts
347
  * Fix: Vulnerability while sending test email
348
  * Fix: Check permission before saving settings
349
 
350
- = 4.2.2 (15.10.2019) =
351
  * New: Added configuration option for label & placeholder for subscription form
352
  * Update: Ask subscribers for confirmation before unsubscription
353
  * Fix: Unsubscription issue
354
 
355
- = 4.2.1 (10.10.2019) =
356
  * Update: Added per page screen option for Contacts, Forms, Lists & Campaigns
357
 
358
- = 4.2.0 (01.10.2019) =
359
  * New: [Pepipost](https://pepipost.com/?utm_source=icegram&utm_medium=es_inapp&utm_campaign=pepipost) api support for email sending
360
 
361
- = 4.1.15 (12.09.2019) =
362
  * New: Stop email sending if hourly email sending limit exceeded.
363
  * Update: Added option to customize message after form submission (Email Subscribers > Settings Menu)
364
  * Fixed: Import contacts issue
365
 
366
- = 4.1.14 (28.08.2019) =
367
  * New: Import First Name & Last Name
368
  * Update: Added "Send Welcome email" option to send out Welcome Email.
369
  * Fix: Multiple Welcome & Admin email notification on clicking confirmation link multiple times
370
 
371
- = 4.1.13 (20.08.2019) =
372
  * New: Added option to select "All Categories" in post notifications.
373
  * New: Send "Welcome Email" to contact which are being added from Audience dashboard
374
  * Fix: All Post Notifications were sent for the post with no category selected
375
  * Fix: Typo
376
 
377
- = 4.1.12 (07.08.2019) =
378
  * Fix: Set post categories correctly after migration
379
  * Fix: Get all lists from email list & notification tables
380
 
381
- = 4.1.11 (02.08.2019) =
382
  * Fix: Send multiple email notification issue
383
 
384
- = 4.1.10 (31.07.2019) =
385
  * Update: Added viewed count on reports page
386
  * Fix: Shortcodes were not working in email templates
387
  * Fix: Viewed status was not getting updated
388
  * Fix: Migration issues in reports
389
 
390
- = 4.1.9 (25.07.2019) =
391
  * Update: Admin notification will be sent out only after contacts confirm their subscription
392
  * Update: Show Post Notifications categories in campaigns view
393
  * Fix: Sort contacts by name
394
  * Fix: Email Notification formatting issue
395
 
396
- = 4.1.8 (16.07.2019) =
397
  * New: Now, admin can add/ edit First Name & Last Name of subscribers.
398
  * Fix: Fixed Vulnerabilities (Thanks Tin Duong of Fortinet's FortiGuard Labs, WordPress Plugin Review Team & Ihor Voschyk for reporting)
399
 
400
- = 4.1.7 (15.07.2019) =
401
  * Update: Now, able to sort reports by Subject, Status, Start Date, End Date & Total Contacts
402
  * Update: Now, able to sort forms by Name & Created date
403
  * Update: Now, email template will pick up the latest content while email sending
@@ -405,76 +405,75 @@ Refer [here](https://www.icegram.com/documentation/es-faq/).
405
  * Fix: Migration issue
406
  * Fix: Fixed Vulnerability
407
 
408
- = 4.1.6 (01.07.2019) =
409
  * Update: Added sorting for name field in Audience tab
410
  * Fix: Warning: Illegal string offset 'es_registered'
411
  * Fix: Set list name blank in campaign list page
412
  * Fix: Contacts sort by email was not working.
413
 
414
- = 4.1.5 (20.06.2019) =
415
  * Update: Added "Opt-In Type" column in exported contacts lists
416
  * Update: Allow to send broadcast only if contacts are available in list
417
  * Fix: "Select the list" error
418
 
419
- = 4.1.4 (13.06.2019) =
420
  * New: Added First Name, Last Name in exported csv file
421
  * New: Added {{FIRSTNAME}}, {{LASTNAME}} keyword
422
  * Update: Improve subscription form layout.
423
 
424
- = 4.1.3 (06.06.2019) =
425
  * New: Export contacts by list
426
 
427
- = 4.1.2.2 (31.05.2019) =
428
  * Fix: Fatal error: Call to undefined function get_plugins()
429
 
430
- = 4.1.2.1 (30.05.2019) =
431
  * Fix: Unable to use sync functionality
432
 
433
- = 4.1.2 (29.05.2019) =
434
  * New: Added support to export "Unconfirmed" contacts.
435
 
436
- = 4.1.1 (21.05.2019) =
437
  * Fix: "Oops.. Unexpected error occurred" while subscribing
438
  * Fix: Typo in "Campaigns > Edit Post Notification" title
439
  * Fix: Duplicate lists while syncing WordPress users
440
 
441
- = 4.1 (14.05.2019) =
442
  * New: Now, able to change the label of "Subscribe" button
443
 
444
- = 4.0.18 (07.05.2019) =
445
  * New : Added a feature to duplicate any template
446
  * New : Added support to re run database migration from ES 3.5.18
447
  * Fix : Display "0" above form
448
  * Fix : Migration issue
449
 
450
- = 4.0.17 (03.05.2019) =
451
  * New : New keywords added : {{TOTAL-CONTACTS}} in form description
452
  * Fix : Post/page editor issue with RTL sites
453
 
454
- = 4.0.16 (23.04.2019) =
455
  * New : New keywords added : {{TOTAL-CONTACTS}} , {{SITEURL}}, {{SITENAME}}
456
  * New : Added option to enable/ disable WordPress Cron for Email Subscribers
457
  * New : Added option to enable/ disable email open tracking
458
  * Fix : Database error while sorting list
459
  * Fix : Incorrect viewed and sent dates in report details
460
 
461
-
462
- = 4.0.15 (17.04.2019) =
463
  * Fix: Error with Gutenberg editor
464
  * Fix: Media Upload Error
465
  * Fix: WordPress Media Library grid issue
466
  * Fix: Database error
467
 
468
- = 4.0.14.1 (16.04.2019) =
469
  * Fix: CSS issue
470
 
471
- = 4.0.14 (15.04.2019) =
472
  * Fix : Added plain text email content for html email
473
  * Fix : Email confirmation fails if address contains ‘+’
474
  * Fix : Migration issue
475
  * Update: POT file
476
 
477
- = 4.0.13 (05.04.2019) =
478
  * Fix : Plain text email does not decode HTML entities
479
  * Fix : Not able to select category with special charterers in post notification
480
  * Fix : Not able to send email using Amazon SES
@@ -482,59 +481,59 @@ Refer [here](https://www.icegram.com/documentation/es-faq/).
482
  * Fix : Remove the NAME field when "NO" set in shortcode
483
  * Update: POT file
484
 
485
- = 4.0.12 (01.04.2019) =
486
  * Fix : Parse error: syntax error, unexpected T_FUNCTION
487
  * Update: Remove old css
488
  * Update: POT file
489
 
490
- = 4.0.11 (26.03.2019) =
491
  * New : Added "Add to List" option to the bulk actions of contacts
492
  * New : Link contacts from list view
493
  * Update: Additional security check while opt-in and unsubscription
494
  * Fix : PHP Fatal error: Cannot redeclare temp_filter_category()
495
 
496
- = 4.0.10 (20.03.2019) =
497
  * Update: Added resent confirmation message
498
  * Fix: Duplicate contacts via Rainmaker form
499
  * Fix: Parse error: syntax error, unexpected '['
500
  * Fix: New strings will be available for translations on [WordPress](https://translate.wordpress.org/) (Thanks to [@otto42](https://profiles.wordpress.org/otto42/) and [@dd32](https://profiles.wordpress.org/dd32/))
501
 
502
- = 4.0.9 (15.03.2019) =
503
  * Fix: Post Notification doesn't work with WP 5.0+ and 'Classic Editor'
504
  * Fix: Username is set instead of user's name after Sync WordPress users
505
  * Fix: Welcome Email and Confirmation Email was not working when subscribed via Rainmaker
506
  * Fix: '{{Email}}' keyword is empty in emails
507
 
508
- = 4.0.8 (14.03.2019) =
509
  * Fix: Multiple post notifications issue
510
  * Fix: "500 internal server error" while using Rainmaker Form
511
  * Fix: Post notifications are not being sent while republishing older posts
512
  * Update: Enhance import contacts functionality
513
  * Update: POT file
514
 
515
- = 4.0.7 (13.03.2019) =
516
  * Fix: Parse error: syntax error, unexpected T_FUNCTION in older version of PHP
517
  * Fix: Cron URL set empty
518
  * Fix: Post notifications not being sent for the first time post publish in WP 5.0+
519
  * Update: Show success/ error message on campaign delete.
520
  * Update: Show notice if WordPress Cron is disable.
521
 
522
- = 4.0.6 (12.03.2019) =
523
  * Enhancement: Now, queued emails will be processed on every 15 minutes
524
  * Fix: Parse error: syntax error, unexpected T_FUNCTION, expecting ')'
525
  * Fix: Parse error: syntax error, unexpected '[', expecting ')'
526
  * Update: POT file
527
 
528
- = 4.0.5 (11.03.2019) =
529
  * Update: Enable admin email notification after campaign sent
530
  * Fix: Migration of old Email Subscriber's widgets
531
  * Fix: Could not create, edit list
532
 
533
- = 4.0.4 (07.03.2019) =
534
  * Fix: 'es_subbox' function not working
535
  * Fix: Warning: Cannot modify header information
536
 
537
- = 4.0.3 (06.03.2019) =
538
  * New: Able to process queued emails manually
539
  * Update: Added list wise status for contact on Audience dashboard
540
  * Update: Added status based filtering for contacts
@@ -542,7 +541,7 @@ Refer [here](https://www.icegram.com/documentation/es-faq/).
542
  * Fix: Post Notification not getting triggered
543
  * Fix: Incorrect cron url issue when migrated from other domain
544
 
545
- = 4.0.2 (04.03.2019) =
546
  * Update: Added sync WordPress users functionality
547
  * Update: Added status(Subscribed/ Unsubscribed ) column in Audience dashboard
548
  * Fix: Short description Missing in Widget
@@ -552,9 +551,7 @@ Refer [here](https://www.icegram.com/documentation/es-faq/).
552
  * Fix: Post Notification templates are not available for selection
553
  * Update: POT file
554
 
555
-
556
- = 4.0.1 (02.03.2019) =
557
-
558
  * Fix: Widget sidebar is broken due to Email Subscribers Widget
559
  * Fix: GDPR consent checkbox is missing
560
  * Fix: PHP HTML Mail/ Plain Text email option missing
@@ -563,11 +560,11 @@ Refer [here](https://www.icegram.com/documentation/es-faq/).
563
  * Fix: Compatibility with POST SMTP, WP SES plugin.
564
  * Fix: Accentuated letters and special characters are not working in post categories.
565
 
566
- = 4.0 (01.03.2019) =
567
  * New: [Revamped the plugin](https://www.icegram.com/email-subscribers-plugin-redesign/) - Changes in UI and terminology
568
  * New: Added domain blocking to prevent spam attacks
569
  * Update: POT file
570
 
571
- = Earlier Versions =
572
 
573
  For the changelog of earlier versions, please refer to the separate [changelog.txt](https://plugins.svn.wordpress.org/email-subscribers/trunk/changelog.txt) file.
5
  Tags: subscription, newsletter, email marketing, post notification, email newsletter form, email signup, email widget, newsletter signup, subscribe, subscription form, bulk emails, signup form, list builder, lead generation, welcome email, contacts
6
  Requires at least: 3.9
7
  Tested up to: 5.3
8
+ Stable tag: 4.3.4
9
  License: GPLv3
10
  License URI: http://www.gnu.org/licenses
11
 
300
 
301
  == Changelog ==
302
 
303
+ **4.3.4 (28.11.2019)**
304
+ * Update: Delete Campaigns Permanently
305
+ * Fix: Import issue
306
+ * Fix: Multiple email sending issue
307
+
308
  **4.3.3 (25.11.2019)**
309
  * Fix: Cron Lock issue
310
  * Fix: Honeypot issue with caching plugin
311
 
312
  **4.3.2 (20.11.2019)**
 
313
  * New: Added basic reporting like total subscribed, unsubscribed, open in last 60 days in audience dashboard
314
  * New: Added Pre header in broadcast
315
  * Update: Clear all cron on deactivation
319
  * Fix: Unsubscribe link issue
320
 
321
  **4.3.1 (13.11.2019)**
 
322
  * New: Delete Form Permanently
323
  * New: Delete List Permanently
324
  * Update: Restrict multiple email sending
329
  * Fix: Fatal error
330
 
331
  **4.3.0 (06.11.2019)**
 
332
  * Fix: Test email sending issue
333
  * Fix: New Broadcast issue
334
  * Fix: Import contacts issue
336
  * Update: .POT File
337
 
338
  **4.2.4 (23.10.2019)**
 
339
  * Update: Improve Create Broadcast UI
340
  * Fix: Unable to remove label for Email field in Subscription Form
341
  * Fix: Validate Post Notification data
342
 
343
  **4.2.3 (17.10.2019)**
 
344
  * Update: Now, only administrator can access Email Subscribers menus.
345
  * Fix: Email open tracking
346
  * Fix: Vulnerability while exporting contacts
347
  * Fix: Vulnerability while sending test email
348
  * Fix: Check permission before saving settings
349
 
350
+ **4.2.2 (15.10.2019)**
351
  * New: Added configuration option for label & placeholder for subscription form
352
  * Update: Ask subscribers for confirmation before unsubscription
353
  * Fix: Unsubscription issue
354
 
355
+ **4.2.1 (10.10.2019)**
356
  * Update: Added per page screen option for Contacts, Forms, Lists & Campaigns
357
 
358
+ **4.2.0 (01.10.2019)**
359
  * New: [Pepipost](https://pepipost.com/?utm_source=icegram&utm_medium=es_inapp&utm_campaign=pepipost) api support for email sending
360
 
361
+ **4.1.15 (12.09.2019)**
362
  * New: Stop email sending if hourly email sending limit exceeded.
363
  * Update: Added option to customize message after form submission (Email Subscribers > Settings Menu)
364
  * Fixed: Import contacts issue
365
 
366
+ **4.1.14 (28.08.2019)**
367
  * New: Import First Name & Last Name
368
  * Update: Added "Send Welcome email" option to send out Welcome Email.
369
  * Fix: Multiple Welcome & Admin email notification on clicking confirmation link multiple times
370
 
371
+ **4.1.13 (20.08.2019)**
372
  * New: Added option to select "All Categories" in post notifications.
373
  * New: Send "Welcome Email" to contact which are being added from Audience dashboard
374
  * Fix: All Post Notifications were sent for the post with no category selected
375
  * Fix: Typo
376
 
377
+ **4.1.12 (07.08.2019)**
378
  * Fix: Set post categories correctly after migration
379
  * Fix: Get all lists from email list & notification tables
380
 
381
+ **4.1.11 (02.08.2019)**
382
  * Fix: Send multiple email notification issue
383
 
384
+ **4.1.10 (31.07.2019)**
385
  * Update: Added viewed count on reports page
386
  * Fix: Shortcodes were not working in email templates
387
  * Fix: Viewed status was not getting updated
388
  * Fix: Migration issues in reports
389
 
390
+ **4.1.9 (25.07.2019)**
391
  * Update: Admin notification will be sent out only after contacts confirm their subscription
392
  * Update: Show Post Notifications categories in campaigns view
393
  * Fix: Sort contacts by name
394
  * Fix: Email Notification formatting issue
395
 
396
+ **4.1.8 (16.07.2019)**
397
  * New: Now, admin can add/ edit First Name & Last Name of subscribers.
398
  * Fix: Fixed Vulnerabilities (Thanks Tin Duong of Fortinet's FortiGuard Labs, WordPress Plugin Review Team & Ihor Voschyk for reporting)
399
 
400
+ **4.1.7 (15.07.2019)**
401
  * Update: Now, able to sort reports by Subject, Status, Start Date, End Date & Total Contacts
402
  * Update: Now, able to sort forms by Name & Created date
403
  * Update: Now, email template will pick up the latest content while email sending
405
  * Fix: Migration issue
406
  * Fix: Fixed Vulnerability
407
 
408
+ **4.1.6 (01.07.2019)**
409
  * Update: Added sorting for name field in Audience tab
410
  * Fix: Warning: Illegal string offset 'es_registered'
411
  * Fix: Set list name blank in campaign list page
412
  * Fix: Contacts sort by email was not working.
413
 
414
+ **4.1.5 (20.06.2019)**
415
  * Update: Added "Opt-In Type" column in exported contacts lists
416
  * Update: Allow to send broadcast only if contacts are available in list
417
  * Fix: "Select the list" error
418
 
419
+ **4.1.4 (13.06.2019)**
420
  * New: Added First Name, Last Name in exported csv file
421
  * New: Added {{FIRSTNAME}}, {{LASTNAME}} keyword
422
  * Update: Improve subscription form layout.
423
 
424
+ **4.1.3 (06.06.2019)**
425
  * New: Export contacts by list
426
 
427
+ **4.1.2.2 (31.05.2019)**
428
  * Fix: Fatal error: Call to undefined function get_plugins()
429
 
430
+ **4.1.2.1 (30.05.2019)**
431
  * Fix: Unable to use sync functionality
432
 
433
+ **4.1.2 (29.05.2019)**
434
  * New: Added support to export "Unconfirmed" contacts.
435
 
436
+ **4.1.1 (21.05.2019)**
437
  * Fix: "Oops.. Unexpected error occurred" while subscribing
438
  * Fix: Typo in "Campaigns > Edit Post Notification" title
439
  * Fix: Duplicate lists while syncing WordPress users
440
 
441
+ **4.1 (14.05.2019)**
442
  * New: Now, able to change the label of "Subscribe" button
443
 
444
+ **4.0.18 (07.05.2019)**
445
  * New : Added a feature to duplicate any template
446
  * New : Added support to re run database migration from ES 3.5.18
447
  * Fix : Display "0" above form
448
  * Fix : Migration issue
449
 
450
+ **4.0.17 (03.05.2019)**
451
  * New : New keywords added : {{TOTAL-CONTACTS}} in form description
452
  * Fix : Post/page editor issue with RTL sites
453
 
454
+ **4.0.16 (23.04.2019)**
455
  * New : New keywords added : {{TOTAL-CONTACTS}} , {{SITEURL}}, {{SITENAME}}
456
  * New : Added option to enable/ disable WordPress Cron for Email Subscribers
457
  * New : Added option to enable/ disable email open tracking
458
  * Fix : Database error while sorting list
459
  * Fix : Incorrect viewed and sent dates in report details
460
 
461
+ **4.0.15 (17.04.2019)**
 
462
  * Fix: Error with Gutenberg editor
463
  * Fix: Media Upload Error
464
  * Fix: WordPress Media Library grid issue
465
  * Fix: Database error
466
 
467
+ **4.0.14.1 (16.04.2019)**
468
  * Fix: CSS issue
469
 
470
+ **4.0.14 (15.04.2019)**
471
  * Fix : Added plain text email content for html email
472
  * Fix : Email confirmation fails if address contains ‘+’
473
  * Fix : Migration issue
474
  * Update: POT file
475
 
476
+ **4.0.13 (05.04.2019)**
477
  * Fix : Plain text email does not decode HTML entities
478
  * Fix : Not able to select category with special charterers in post notification
479
  * Fix : Not able to send email using Amazon SES
481
  * Fix : Remove the NAME field when "NO" set in shortcode
482
  * Update: POT file
483
 
484
+ **4.0.12 (01.04.2019)**
485
  * Fix : Parse error: syntax error, unexpected T_FUNCTION
486
  * Update: Remove old css
487
  * Update: POT file
488
 
489
+ **4.0.11 (26.03.2019)**
490
  * New : Added "Add to List" option to the bulk actions of contacts
491
  * New : Link contacts from list view
492
  * Update: Additional security check while opt-in and unsubscription
493
  * Fix : PHP Fatal error: Cannot redeclare temp_filter_category()
494
 
495
+ **4.0.10 (20.03.2019)**
496
  * Update: Added resent confirmation message
497
  * Fix: Duplicate contacts via Rainmaker form
498
  * Fix: Parse error: syntax error, unexpected '['
499
  * Fix: New strings will be available for translations on [WordPress](https://translate.wordpress.org/) (Thanks to [@otto42](https://profiles.wordpress.org/otto42/) and [@dd32](https://profiles.wordpress.org/dd32/))
500
 
501
+ **4.0.9 (15.03.2019)**
502
  * Fix: Post Notification doesn't work with WP 5.0+ and 'Classic Editor'
503
  * Fix: Username is set instead of user's name after Sync WordPress users
504
  * Fix: Welcome Email and Confirmation Email was not working when subscribed via Rainmaker
505
  * Fix: '{{Email}}' keyword is empty in emails
506
 
507
+ **4.0.8 (14.03.2019)**
508
  * Fix: Multiple post notifications issue
509
  * Fix: "500 internal server error" while using Rainmaker Form
510
  * Fix: Post notifications are not being sent while republishing older posts
511
  * Update: Enhance import contacts functionality
512
  * Update: POT file
513
 
514
+ **4.0.7 (13.03.2019)**
515
  * Fix: Parse error: syntax error, unexpected T_FUNCTION in older version of PHP
516
  * Fix: Cron URL set empty
517
  * Fix: Post notifications not being sent for the first time post publish in WP 5.0+
518
  * Update: Show success/ error message on campaign delete.
519
  * Update: Show notice if WordPress Cron is disable.
520
 
521
+ **4.0.6 (12.03.2019)**
522
  * Enhancement: Now, queued emails will be processed on every 15 minutes
523
  * Fix: Parse error: syntax error, unexpected T_FUNCTION, expecting ')'
524
  * Fix: Parse error: syntax error, unexpected '[', expecting ')'
525
  * Update: POT file
526
 
527
+ **4.0.5 (11.03.2019)**
528
  * Update: Enable admin email notification after campaign sent
529
  * Fix: Migration of old Email Subscriber's widgets
530
  * Fix: Could not create, edit list
531
 
532
+ **4.0.4 (07.03.2019)**
533
  * Fix: 'es_subbox' function not working
534
  * Fix: Warning: Cannot modify header information
535
 
536
+ **4.0.3 (06.03.2019)**
537
  * New: Able to process queued emails manually
538
  * Update: Added list wise status for contact on Audience dashboard
539
  * Update: Added status based filtering for contacts
541
  * Fix: Post Notification not getting triggered
542
  * Fix: Incorrect cron url issue when migrated from other domain
543
 
544
+ **4.0.2 (04.03.2019)**
545
  * Update: Added sync WordPress users functionality
546
  * Update: Added status(Subscribed/ Unsubscribed ) column in Audience dashboard
547
  * Fix: Short description Missing in Widget
551
  * Fix: Post Notification templates are not available for selection
552
  * Update: POT file
553
 
554
+ **4.0.1 (02.03.2019)**
 
 
555
  * Fix: Widget sidebar is broken due to Email Subscribers Widget
556
  * Fix: GDPR consent checkbox is missing
557
  * Fix: PHP HTML Mail/ Plain Text email option missing
560
  * Fix: Compatibility with POST SMTP, WP SES plugin.
561
  * Fix: Accentuated letters and special characters are not working in post categories.
562
 
563
+ **4.0 (01.03.2019)**
564
  * New: [Revamped the plugin](https://www.icegram.com/email-subscribers-plugin-redesign/) - Changes in UI and terminology
565
  * New: Added domain blocking to prevent spam attacks
566
  * Update: POT file
567
 
568
+ **Earlier Versions**
569
 
570
  For the changelog of earlier versions, please refer to the separate [changelog.txt](https://plugins.svn.wordpress.org/email-subscribers/trunk/changelog.txt) file.