Email Subscribers & Newsletters - Version 4.1.4

Version Description

(13.06.2019) = * New: Added First Name, Last Name in exported csv file * New: Added {{FIRSTNAME}}, {{LASTNAME}} keyword * Update: Improve subscription form layout.

Download this release

Release Info

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

Code changes from version 4.1.3 to 4.1.4

admin/css/email-subscribers-admin.css CHANGED
@@ -1182,23 +1182,11 @@ div.es .last {
1182
  margin-right: 0;
1183
  }
1184
 
1185
- .ig-es-feedback-button {
1186
- height: 40px;
1187
- border: solid 3px #CCCCCC;
1188
- background: #333;
1189
- width: 100px;
1190
- line-height: 32px;
1191
- -webkit-transform: rotate(-90deg);
1192
- font-weight: 600;
1193
- color: white;
1194
- transform: rotate(-90deg);
1195
- -ms-transform: rotate(-90deg);
1196
- -moz-transform: rotate(-90deg);
1197
- text-align: center;
1198
- font-size: 17px;
1199
- position: fixed;
1200
- right: -40px;
1201
- top: 45%;
1202
- font-family: "Roboto", helvetica, arial, sans-serif;
1203
- z-index: 999;
1204
  }
 
 
 
 
 
1182
  margin-right: 0;
1183
  }
1184
 
1185
+ .ig-es-pricing-img {
1186
+ padding-bottom: 2em;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1187
  }
1188
+
1189
+ .email-subscribers_page_es_pricing #wpwrap #wpcontent {
1190
+ background-color: #f1f1f1;
1191
+ }
1192
+
admin/images/email-subscribers-pricing.png ADDED
Binary file
admin/partials/pricing.php CHANGED
@@ -45,8 +45,10 @@ if ( ! defined( 'ABSPATH' ) ) {
45
  }
46
  </style>
47
  <div class="es-starter-gopro">
48
- <img src="<?php echo EMAIL_SUBSCRIBERS_URL.'/admin/images/pricing.png' ?>"/><br/>
49
- <a class="button large green-light" href="https://www.icegram.com/email-subscribers-pricing/?utm_source=in_app&utm_medium=go_pro_monthly&utm_campaign=starter_launch" target="_blank"> <?php _e('Get Started @ $9/month', 'email-subscribers') ?></a>
50
  <div class="mid-or">OR</div>
51
- <a class="button large green" href="https://www.icegram.com/email-subscribers-pricing/?utm_source=in_app&utm_medium=go_pro_yearly&utm_campaign=starter_launch" target="_blank"> <?php _e('Get Started @ $49/year', 'email-subscribers') ?></a>
52
  </div>
 
 
45
  }
46
  </style>
47
  <div class="es-starter-gopro">
48
+ <img class="ig-es-pricing-img" src="<?php echo EMAIL_SUBSCRIBERS_URL.'/admin/images/email-subscribers-pricing.png' ?>"/><br/>
49
+ <a class="button large green-light" href="https://www.icegram.com/?buy-now=409349&qty=1&page=6&with-cart=0&utm_source=in_app&utm_medium=go_pro_monthly&utm_campaign=es_upsale" target="_blank"> <?php _e('Get Started @ $9/month', 'email-subscribers') ?></a>
50
  <div class="mid-or">OR</div>
51
+ <a class="button large green" href="https://www.icegram.com/?buy-now=407190&qty=1&page=6&with-cart=0&utm_source=in_app&utm_medium=go_pro_yearly&utm_campaign=es_upsale" target="_blank"> <?php _e('Get Started @ $49/year', 'email-subscribers') ?></a>
52
  </div>
53
+
54
+
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.1.3
7
  * Author: Icegram
8
  * Author URI: https://www.icegram.com/
9
  * Requires at least: 3.9
@@ -24,7 +24,7 @@ if ( ! defined( 'WPINC' ) ) {
24
  * Define constants
25
  */
26
  define( 'ES_PLUGIN_DIR', dirname( __FILE__ ) );
27
- define( 'ES_PLUGIN_VERSION', '4.1.3' );
28
  define( 'ES_PLUGIN_BASE_NAME', plugin_basename( __FILE__ ) );
29
 
30
  if ( ! defined( 'ES_PLUGIN_FILE' ) ) {
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.1.4
7
  * Author: Icegram
8
  * Author URI: https://www.icegram.com/
9
  * Requires at least: 3.9
24
  * Define constants
25
  */
26
  define( 'ES_PLUGIN_DIR', dirname( __FILE__ ) );
27
+ define( 'ES_PLUGIN_VERSION', '4.1.4' );
28
  define( 'ES_PLUGIN_BASE_NAME', plugin_basename( __FILE__ ) );
29
 
30
  if ( ! defined( 'ES_PLUGIN_FILE' ) ) {
includes/admin/class-es-export-subscribers.php CHANGED
@@ -82,11 +82,11 @@ class Export_Subscribers {
82
 
83
  $export_lists = array(
84
 
85
- 'all' => __( 'All Contacts', 'email-subscribers' ),
86
- 'active' => __( 'Subscribed Contacts', 'email-subscribers' ),
87
- 'inactive' => __( 'Unsubscribed Contacts', 'email-subscribers' ),
88
- 'unconfirmed' => __( 'Unconfirmed Contacts', 'email-subscribers' ),
89
- 'select_list' => $list_dropdown_html
90
  );
91
 
92
  $i = 1;
@@ -155,37 +155,27 @@ class Export_Subscribers {
155
 
156
  switch ( $status ) {
157
  case 'all':
158
- // All Subscribers
159
- $sql = "SELECT COUNT(email) FROM " . IG_CONTACTS_TABLE;
160
  break;
161
 
162
- case 'active':
163
- // Active Subscribers
164
- $sql = "SELECT COUNT(email) FROM " . IG_CONTACTS_TABLE . " WHERE unsubscribed = 0 OR unsubscribed IS NULL";
165
  break;
166
 
167
- case 'inactive':
168
- // InActive Subscribers
169
- $sql = "SELECT COUNT(email) FROM " . IG_CONTACTS_TABLE . " WHERE unsubscribed = 1 ";
170
  break;
171
 
172
  case 'unconfirmed':
173
- $sql = "SELECT count(distinct(contact_id)) FROM " . IG_LISTS_CONTACTS_TABLE . " WHERE status = 'unconfirmed'";
174
  break;
175
 
176
- case 'registered':
177
- case 'commented':
178
- // Registered/ Commented Subscribers
179
- $sql = "SELECT COUNT(*) FROM " . $wpdb->prefix . "users";
180
  break;
181
  }
182
 
183
- if ( 'select_list' === $status ) {
184
- return '-';
185
- } else {
186
- return $wpdb->get_var( $sql );
187
- }
188
-
189
  }
190
 
191
 
@@ -222,9 +212,17 @@ class Export_Subscribers {
222
  </p>
223
 
224
  <?php
225
-
226
  }
227
 
 
 
 
 
 
 
 
 
 
228
  public function generate_csv( $status = 'all', $list_id = '' ) {
229
 
230
  global $wpdb;
@@ -235,69 +233,78 @@ class Export_Subscribers {
235
  $email_subscribe_table = IG_CONTACTS_TABLE;
236
  $contact_lists_table = IG_LISTS_CONTACTS_TABLE;
237
 
238
- if ( 'active' === $status ) {
239
- $query = "SELECT `first_name`, `last_name`, `email`, `status`, `unsubscribed`, `created_at` FROM $email_subscribe_table WHERE unsubscribed = 0 OR unsubscribed IS NULL";
240
- } elseif ( 'inactive' === $status ) {
241
- $query = "SELECT `first_name`, `last_name`, `email`, `status`, `unsubscribed`, `created_at` FROM $email_subscribe_table WHERE unsubscribed = 1 ";
242
- } elseif ( 'all' === $status ) {
243
- $query = "SELECT `first_name`, `last_name`, `email`, `status`, `unsubscribed`, `created_at` FROM $email_subscribe_table";
244
  } elseif ( 'unconfirmed' === $status ) {
245
- $query = "SELECT `first_name`, `last_name`, `email`, `status`, `unsubscribed`, `created_at` FROM $email_subscribe_table WHERE id IN (SELECT distinct(contact_id) FROM {$contact_lists_table} WHERE status = 'unconfirmed' )";
246
  } elseif ( 'select_list' === $status ) {
247
- $query = "SELECT `contact_id`, `status` FROM " . IG_LISTS_CONTACTS_TABLE . " WHERE list_id = %d ";
 
 
 
248
  }
249
 
250
  $subscribers = array();
 
251
 
252
- if ( 'select_list' === $status ) {
253
- $results = $wpdb->get_results( $wpdb->prepare( $query, $list_id ), ARRAY_A );
 
 
254
 
255
- if ( count( $results ) > 0 ) {
256
- $contact_id_status_map = array();
257
- foreach ( $results as $result ) {
258
- $contact_id_status_map[ $result['contact_id'] ] = $result['status'];
259
  }
260
 
261
- $contact_ids_str = "'" . implode( "' , '", array_keys( $contact_id_status_map ) ) . "' ";
262
-
263
- $query = "SELECT `id`, `first_name`, `last_name`, `email`, `created_at` FROM {$email_subscribe_table} WHERE id IN ({$contact_ids_str})";
264
- $subscribers = $wpdb->get_results( $query, ARRAY_A );
265
  }
266
 
267
- } else {
 
 
 
268
  $subscribers = $wpdb->get_results( $query, ARRAY_A );
269
  }
270
 
271
-
272
  $csv_output = '';
273
  if ( count( $subscribers ) > 0 ) {
274
 
275
  $headers = array(
276
- __( 'Name', 'email-subscribers' ),
 
277
  __( 'Email', 'email-subscribers' ),
 
278
  __( 'Status', 'email-subscribers' ),
279
  __( 'Created On', 'email-subscribers' )
280
  );
281
 
282
- $csv_output .= '"' . implode( '", "', $headers ) . '"';
283
- $csv_output .= "\n";
 
284
 
285
  foreach ( $subscribers as $key => $subscriber ) {
286
 
287
- $data['name'] = str_replace('"', ' ', trim( $subscriber['first_name'] . ' ' . $subscriber['last_name'] ));
288
- $data['email'] = str_replace('"', ' ', trim( $subscriber['email'] ));
289
-
290
- if ( 'select_list' === $status ) {
291
- $data['status'] = ucfirst( $contact_id_status_map[ $subscriber['id'] ] );
292
- } elseif ( 'unconfirmed' === $status ) {
293
- $data['status'] = __( 'Unconfirmed', 'email-subscribers' );
294
- } else {
295
- $data['status'] = ( $subscriber['unsubscribed'] == 1 ) ? __( 'Unsubscribed', 'email-subscribers' ) : __( 'Subscribed', 'email-subscribers' );
 
 
 
 
296
  }
297
- $data['created_at'] = $subscriber['created_at'];
298
-
299
- $csv_output .= '"' . implode( '", "', $data ) . '"';
300
- $csv_output .= "\n";
301
  }
302
  }
303
 
82
 
83
  $export_lists = array(
84
 
85
+ 'all' => __( 'All Contacts', 'email-subscribers' ),
86
+ 'subscribed' => __( 'Subscribed Contacts', 'email-subscribers' ),
87
+ 'unsubscribed' => __( 'Unsubscribed Contacts', 'email-subscribers' ),
88
+ 'unconfirmed' => __( 'Unconfirmed Contacts', 'email-subscribers' ),
89
+ 'select_list' => $list_dropdown_html
90
  );
91
 
92
  $i = 1;
155
 
156
  switch ( $status ) {
157
  case 'all':
158
+ $sql = "SELECT COUNT(*) FROM " . IG_LISTS_CONTACTS_TABLE;
 
159
  break;
160
 
161
+ case 'subscribed':
162
+ $sql = $wpdb->prepare( "SELECT COUNT(*) FROM " . IG_LISTS_CONTACTS_TABLE . " WHERE status = %s", 'subscribed' );
 
163
  break;
164
 
165
+ case 'unsubscribed':
166
+ $sql = $wpdb->prepare( "SELECT COUNT(email) FROM " . IG_CONTACTS_TABLE . " WHERE status = %s", 'unsubscribed' );
 
167
  break;
168
 
169
  case 'unconfirmed':
170
+ $sql = $wpdb->prepare( "SELECT count(contact_id) FROM " . IG_LISTS_CONTACTS_TABLE . " WHERE status = %s", 'unconfirmed' );
171
  break;
172
 
173
+ case 'select_list':
174
+ return '-';
 
 
175
  break;
176
  }
177
 
178
+ return $wpdb->get_var( $sql );
 
 
 
 
 
179
  }
180
 
181
 
212
  </p>
213
 
214
  <?php
 
215
  }
216
 
217
+ /**
218
+ * Generate CSV
219
+ * first_name, last_name, email, status, list, subscribed_at, unsubscribed_at
220
+ *
221
+ * @param string $status
222
+ * @param string $list_id
223
+ *
224
+ * @return string
225
+ */
226
  public function generate_csv( $status = 'all', $list_id = '' ) {
227
 
228
  global $wpdb;
233
  $email_subscribe_table = IG_CONTACTS_TABLE;
234
  $contact_lists_table = IG_LISTS_CONTACTS_TABLE;
235
 
236
+ if ( 'all' === $status ) {
237
+ $query = "SELECT * FROM " . IG_LISTS_CONTACTS_TABLE;
238
+ } elseif ( 'subscribed' === $status ) {
239
+ $query = $wpdb->prepare( "SELECT * FROM {$contact_lists_table} WHERE status = %s", 'subscribed' );
240
+ } elseif ( 'unsubscribed' === $status ) {
241
+ $query = $wpdb->prepare( "SELECT * FROM {$contact_lists_table} WHERE status = %s", 'unsubscribed' );
242
  } elseif ( 'unconfirmed' === $status ) {
243
+ $query = $wpdb->prepare( "SELECT * FROM {$contact_lists_table} WHERE status = %s", 'unconfirmed' );
244
  } elseif ( 'select_list' === $status ) {
245
+ $query = $wpdb->prepare( "SELECT * FROM {$contact_lists_table} WHERE list_id = %d ", $list_id );
246
+ } else {
247
+ // If nothing comes, export only 10 contacts
248
+ $query = "SELECT * FROM " . IG_LISTS_CONTACTS_TABLE . " LIMIT 0, 10";
249
  }
250
 
251
  $subscribers = array();
252
+ $results = $wpdb->get_results( $query, ARRAY_A );
253
 
254
+ if ( count( $results ) > 0 ) {
255
+ $contact_list_map = array();
256
+ $contact_ids = array();
257
+ foreach ( $results as $result ) {
258
 
259
+ if ( ! in_array( $result['contact_id'], $contact_ids ) ) {
260
+ $contact_ids[] = $result['contact_id'];
 
 
261
  }
262
 
263
+ $contact_list_map[ $result['contact_id'] ][] = array(
264
+ 'status' => $result['status'],
265
+ 'list_id' => $result['list_id']
266
+ );
267
  }
268
 
269
+ $contact_ids_str = "'" . implode( "' , '", $contact_ids ) . "' ";
270
+
271
+ $query = "SELECT `id`, `first_name`, `last_name`, `email`, `created_at` FROM {$email_subscribe_table} WHERE id IN ({$contact_ids_str})";
272
+
273
  $subscribers = $wpdb->get_results( $query, ARRAY_A );
274
  }
275
 
 
276
  $csv_output = '';
277
  if ( count( $subscribers ) > 0 ) {
278
 
279
  $headers = array(
280
+ __( 'First Name', 'email-subscribers' ),
281
+ __( 'Last Name', 'email-subscribers' ),
282
  __( 'Email', 'email-subscribers' ),
283
+ __( 'List', 'email-subscribers' ),
284
  __( 'Status', 'email-subscribers' ),
285
  __( 'Created On', 'email-subscribers' )
286
  );
287
 
288
+ $lists_id_name_map = ES_DB_Lists::get_list_id_name_map();
289
+ $csv_output .= '"' . implode( '", "', $headers ) . '"';
290
+ $csv_output .= "\n";
291
 
292
  foreach ( $subscribers as $key => $subscriber ) {
293
 
294
+ $data['first_name'] = trim( str_replace( '"', ' ', $subscriber['first_name'] ) );
295
+ $data['last_name'] = trim( str_replace( '"', ' ', $subscriber['last_name'] ) );
296
+ $data['email'] = trim( str_replace( '"', ' ', $subscriber['email'] ) );
297
+
298
+ $contact_id = $subscriber['id'];
299
+ if ( ! empty( $contact_list_map[ $contact_id ] ) ) {
300
+ foreach ( $contact_list_map[ $contact_id ] as $list_details ) {
301
+ $data['list'] = $lists_id_name_map[ $list_details['list_id'] ];
302
+ $data['status'] = ucfirst( $list_details['status'] );
303
+ $data['created_at'] = $subscriber['created_at'];
304
+ $csv_output .= '"' . implode( '", "', $data ) . '"';
305
+ $csv_output .= "\n";
306
+ }
307
  }
 
 
 
 
308
  }
309
  }
310
 
includes/admin/class-es-handle-subscription.php CHANGED
@@ -122,7 +122,7 @@ class ES_Handle_Subscription {
122
 
123
  $contact_id = ES_DB_Contacts::add_subscriber( $data );
124
 
125
- do_action('ig_es_contact_added', $data);
126
  }
127
 
128
  if ( count( $this->list_ids ) > 0 ) {
@@ -210,11 +210,13 @@ class ES_Handle_Subscription {
210
  }
211
 
212
  $template_data = array(
213
- 'email' => $this->email,
214
- 'db_id' => $this->db_id,
215
- 'name' => $this->first_name,
216
- 'guid' => $this->guid,
217
- 'list_name' => $list_name
 
 
218
  );
219
 
220
  $subject = ES_Mailer::prepare_welcome_email_subject( $template_data );
@@ -234,10 +236,12 @@ class ES_Handle_Subscription {
234
  public function send_double_optin_notification() {
235
 
236
  $template_data = array(
237
- 'email' => $this->email,
238
- 'db_id' => $this->db_id,
239
- 'name' => $this->first_name,
240
- 'guid' => $this->guid
 
 
241
  );
242
 
243
  $subject = get_option( 'ig_es_confirmation_mail_subject', true );
@@ -272,9 +276,11 @@ class ES_Handle_Subscription {
272
  }
273
 
274
  $template_data = array(
275
- 'name' => ES_Common::prepare_name_from_first_name_last_name( $this->first_name, $this->last_name ),
276
- 'email' => $this->email,
277
- 'list_name' => $list_name
 
 
278
  );
279
 
280
  if ( count( $admin_emails ) > 0 ) {
@@ -296,11 +302,12 @@ class ES_Handle_Subscription {
296
  //honey-pot validation
297
  //$hp_key = "esfpx_es_hp_" . wp_create_nonce( 'es_hp' );
298
  $data_keys = array_keys( $data );
299
- $hp_key = "esfpx_es_hp_";
300
  foreach ( $data_keys as $i => $key ) {
301
- if ( strpos( $key, $hp_key ) === 0) {
302
  if ( ! isset( $data[ $data_keys[ $i ] ] ) || ! empty( $data[ $data_keys[ $i ] ] ) ) {
303
  $es_response['message'] = 'es_unexpected_error_notice';
 
304
  return $es_response;
305
  }
306
  }
122
 
123
  $contact_id = ES_DB_Contacts::add_subscriber( $data );
124
 
125
+ do_action( 'ig_es_contact_added', $data );
126
  }
127
 
128
  if ( count( $this->list_ids ) > 0 ) {
210
  }
211
 
212
  $template_data = array(
213
+ 'email' => $this->email,
214
+ 'db_id' => $this->db_id,
215
+ 'name' => $this->first_name,
216
+ 'first_name' => $this->first_name,
217
+ 'last_name' => $this->last_name,
218
+ 'guid' => $this->guid,
219
+ 'list_name' => $list_name
220
  );
221
 
222
  $subject = ES_Mailer::prepare_welcome_email_subject( $template_data );
236
  public function send_double_optin_notification() {
237
 
238
  $template_data = array(
239
+ 'email' => $this->email,
240
+ 'db_id' => $this->db_id,
241
+ 'name' => $this->first_name,
242
+ 'first_name' => $this->first_name,
243
+ 'last_name' => $this->last_name,
244
+ 'guid' => $this->guid
245
  );
246
 
247
  $subject = get_option( 'ig_es_confirmation_mail_subject', true );
276
  }
277
 
278
  $template_data = array(
279
+ 'name' => ES_Common::prepare_name_from_first_name_last_name( $this->first_name, $this->last_name ),
280
+ 'first_name' => $this->first_name,
281
+ 'last_name' => $this->last_name,
282
+ 'email' => $this->email,
283
+ 'list_name' => $list_name
284
  );
285
 
286
  if ( count( $admin_emails ) > 0 ) {
302
  //honey-pot validation
303
  //$hp_key = "esfpx_es_hp_" . wp_create_nonce( 'es_hp' );
304
  $data_keys = array_keys( $data );
305
+ $hp_key = "esfpx_es_hp_";
306
  foreach ( $data_keys as $i => $key ) {
307
+ if ( strpos( $key, $hp_key ) === 0 ) {
308
  if ( ! isset( $data[ $data_keys[ $i ] ] ) || ! empty( $data[ $data_keys[ $i ] ] ) ) {
309
  $es_response['message'] = 'es_unexpected_error_notice';
310
+
311
  return $es_response;
312
  }
313
  }
includes/admin/class-es-subscribers-table.php CHANGED
@@ -62,7 +62,7 @@ class ES_Subscribers_Table extends WP_List_Table {
62
  'sync' => array(
63
  'label' => __( 'Sync', 'email-subscribers' ),
64
  'indicator_option' => 'ig_es_show_sync_tab',
65
- 'indicator_label' => __('New', 'email-subscribers'),
66
  'indicator_type' => 'new',
67
  'action' => 'sync',
68
  'url' => add_query_arg( 'action', 'sync', 'admin.php?page=es_subscribers' )
@@ -119,10 +119,10 @@ class ES_Subscribers_Table extends WP_List_Table {
119
  ?>
120
 
121
  <h1 class="wp-heading-inline">
122
- <?php
123
- _e( 'Audience > Contacts', 'email-subscribers' );
124
- ES_Common::prepare_main_header_navigation($audience_tab_main_navigation);
125
- ?>
126
  </h1>
127
 
128
  <?php Email_Subscribers_Admin::es_feedback(); ?>
@@ -759,10 +759,12 @@ class ES_Subscribers_Table extends WP_List_Table {
759
  $id = absint( Email_Subscribers::get_request( 'subscriber' ) );
760
  $subscriber = ES_DB_Contacts::get_subscribers_by_id( $id );
761
  $template_data = array(
762
- 'email' => $subscriber['email'],
763
- 'db_id' => $subscriber['id'],
764
- 'name' => $subscriber['first_name'],
765
- 'guid' => $subscriber['hash']
 
 
766
  );
767
 
768
  $subject = get_option( 'ig_es_confirmation_mail_subject', true );
62
  'sync' => array(
63
  'label' => __( 'Sync', 'email-subscribers' ),
64
  'indicator_option' => 'ig_es_show_sync_tab',
65
+ 'indicator_label' => __( 'New', 'email-subscribers' ),
66
  'indicator_type' => 'new',
67
  'action' => 'sync',
68
  'url' => add_query_arg( 'action', 'sync', 'admin.php?page=es_subscribers' )
119
  ?>
120
 
121
  <h1 class="wp-heading-inline">
122
+ <?php
123
+ _e( 'Audience > Contacts', 'email-subscribers' );
124
+ ES_Common::prepare_main_header_navigation( $audience_tab_main_navigation );
125
+ ?>
126
  </h1>
127
 
128
  <?php Email_Subscribers_Admin::es_feedback(); ?>
759
  $id = absint( Email_Subscribers::get_request( 'subscriber' ) );
760
  $subscriber = ES_DB_Contacts::get_subscribers_by_id( $id );
761
  $template_data = array(
762
+ 'email' => $subscriber['email'],
763
+ 'db_id' => $subscriber['id'],
764
+ 'name' => $subscriber['first_name'],
765
+ 'first_name' => $subscriber['first_name'],
766
+ 'last_name' => $subscriber['last_name'],
767
+ 'guid' => $subscriber['hash']
768
  );
769
 
770
  $subject = get_option( 'ig_es_confirmation_mail_subject', true );
includes/class-email-subscribers.php CHANGED
@@ -91,10 +91,9 @@ class Email_Subscribers {
91
  $this->define_admin_hooks();
92
  $this->define_public_hooks();
93
 
94
-
95
- $ig_es_tracker = 'IG_Tracker_V_1_0_2';
96
  if ( is_admin() ) {
97
- $ig_es_feedback = new IG_Feedback_V_1_0_2( 'Email Subscribers', 'email-subscribers', 'ig_es', 'esfree.', false );
98
  $ig_es_feedback->render_deactivate_feedback();
99
  }
100
 
@@ -341,8 +340,8 @@ class Email_Subscribers {
341
  'includes/pro-features.php',
342
 
343
  // Feedback
344
- 'includes/feedback/class-ig-tracker-v-1-0-2.php',
345
- 'includes/feedback/class-ig-feedback-v-1-0-2.php',
346
  'includes/feedback.php'
347
  );
348
 
91
  $this->define_admin_hooks();
92
  $this->define_public_hooks();
93
 
94
+ $ig_es_tracker = 'IG_Tracker_V_1_0_3';
 
95
  if ( is_admin() ) {
96
+ $ig_es_feedback = new IG_Feedback_V_1_0_3( 'Email Subscribers', 'email-subscribers', 'ig_es', 'esfree.', false );
97
  $ig_es_feedback->render_deactivate_feedback();
98
  }
99
 
340
  'includes/pro-features.php',
341
 
342
  // Feedback
343
+ 'includes/feedback/class-ig-tracker-v-1-0-3.php',
344
+ 'includes/feedback/class-ig-feedback-v-1-0-3.php',
345
  'includes/feedback.php'
346
  );
347
 
includes/class-es-common.php CHANGED
@@ -894,7 +894,7 @@ Class ES_Common {
894
  'force' => false
895
  );
896
 
897
- $params = wp_parse_args($params, $default_params);
898
 
899
  if ( ! empty( $params['event'] ) ) {
900
 
@@ -925,22 +925,45 @@ Class ES_Common {
925
  $feedback->render_stars( $params );
926
  } elseif ( 'emoji' === $params['type'] ) {
927
  $feedback->render_emoji( $params );
 
 
928
  }
929
  }
930
  }
931
 
932
  }
933
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
934
  public static function get_ig_es_meta_info() {
935
 
936
  $total_contacts = ES_DB_Contacts::get_total_subscribers();
 
937
  $total_newsletters = ES_DB_Campaigns::get_total_campaigns_by_type( 'newsletter' );
938
  $total_post_notifications = ES_DB_Campaigns::get_total_campaigns_by_type( 'post_notification' );
939
 
940
  $meta_info = array(
941
  'total_contacts' => $total_contacts,
 
942
  'total_newsletters' => $total_newsletters,
943
- 'total_post_notifications' => $total_post_notifications
 
944
  );
945
 
946
  return $meta_info;
894
  'force' => false
895
  );
896
 
897
+ $params = wp_parse_args( $params, $default_params );
898
 
899
  if ( ! empty( $params['event'] ) ) {
900
 
925
  $feedback->render_stars( $params );
926
  } elseif ( 'emoji' === $params['type'] ) {
927
  $feedback->render_emoji( $params );
928
+ } elseif ( 'feedback' === $params['type'] ) {
929
+ $feedback->render_general_feedback( $params );
930
  }
931
  }
932
  }
933
 
934
  }
935
 
936
+ public static function get_all_settings() {
937
+
938
+ global $wpdb;
939
+
940
+ $query = "SELECT option_name, option_value FROM {$wpdb->prefix}options WHERE option_name LIKE 'ig_es_%' AND option_name != 'ig_es_managed_blocked_domains' ";
941
+
942
+ $results = $wpdb->get_results( $query, ARRAY_A );
943
+
944
+ $options_name_value_map = array();
945
+ if(count($results) > 0 ) {
946
+ foreach ($results as $result) {
947
+ $options_name_value_map[$result['option_name']] = $result['option_value'];
948
+ }
949
+ }
950
+
951
+ return $options_name_value_map;
952
+ }
953
+
954
  public static function get_ig_es_meta_info() {
955
 
956
  $total_contacts = ES_DB_Contacts::get_total_subscribers();
957
+ $total_lists = ES_DB_Lists::count_lists();
958
  $total_newsletters = ES_DB_Campaigns::get_total_campaigns_by_type( 'newsletter' );
959
  $total_post_notifications = ES_DB_Campaigns::get_total_campaigns_by_type( 'post_notification' );
960
 
961
  $meta_info = array(
962
  'total_contacts' => $total_contacts,
963
+ 'total_lists' => $total_lists,
964
  'total_newsletters' => $total_newsletters,
965
+ 'total_post_notifications' => $total_post_notifications,
966
+ 'settings' => self::get_all_settings()
967
  );
968
 
969
  return $meta_info;
includes/class-es-mailer.php CHANGED
@@ -12,7 +12,6 @@ class ES_Mailer {
12
 
13
  }
14
 
15
-
16
  /* prepare cron email*/
17
  public static function prepare_and_send_email( $mails, $notification ) {
18
 
@@ -37,13 +36,17 @@ class ES_Mailer {
37
  $email = $mail['email'];
38
  $id = $mail['contact_id'];
39
  $guid = $mail['mailing_queue_hash'];
40
- $email_name = ! empty( $emails_name_map[ $email ] ) ? $emails_name_map[ $email ] : '';
 
 
41
 
42
  $keywords = array(
43
- 'name' => $email_name,
44
- 'email' => $email,
45
- 'guid' => $guid,
46
- 'dbid' => $id
 
 
47
  );
48
 
49
  // Preparing email body
@@ -65,11 +68,15 @@ class ES_Mailer {
65
  $blog_name = get_option( 'blogname' );
66
  $site_url = home_url( '/' );
67
 
68
- $name = isset( $data['name'] ) ? $data['name'] : '';
69
- $email = isset( $data['email'] ) ? $data['email'] : '';
70
- $list_name = isset( $data['list_name'] ) ? $data['list_name'] : '';
 
 
71
 
72
  $content = str_replace( "{{NAME}}", $name, $content );
 
 
73
  $content = str_replace( "{{EMAIL}}", $email, $content );
74
  $content = str_replace( "{{GROUP}}", $list_name, $content );
75
  $content = str_replace( "{{LIST}}", $list_name, $content );
@@ -115,17 +122,21 @@ class ES_Mailer {
115
  $total_contacts = ES_DB_Contacts::count_active_subscribers_by_list_id();
116
  $content = stripslashes( get_option( 'ig_es_welcome_email_content', '' ) );
117
 
118
- $name = isset( $data['name'] ) ? $data['name'] : '';
119
- $email = isset( $data['email'] ) ? $data['email'] : '';
120
- $list_name = isset( $data['list_name'] ) ? $data['list_name'] : '';
121
- $db_id = isset( $data['db_id'] ) ? $data['db_id'] : '';
122
- $guid = ES_DB_Contacts::get_contact_hash_by_id( $db_id );
 
 
123
  // $guid = isset( $data['guid'] ) ? $data['guid'] : '';
124
  $guid = ! empty( $guid ) ? $guid : '';
125
 
126
  $unsubscribe_link = self::prepare_link( 'unsubscribe', $db_id, $email, $guid );
127
 
128
  $content = str_replace( "{{NAME}}", $name, $content );
 
 
129
  $content = str_replace( "{{EMAIL}}", $email, $content );
130
  $content = str_replace( "{{SITENAME}}", $blog_name, $content );
131
  $content = str_replace( "{{GROUP}}", $list_name, $content );
@@ -150,13 +161,17 @@ class ES_Mailer {
150
  $db_id = isset( $data['db_id'] ) ? $data['db_id'] : '';
151
  $guid = ES_DB_Contacts::get_contact_hash_by_id( $db_id );
152
  // $guid = isset( $data['guid'] ) ? $data['guid'] : '';
153
- $guid = ! empty( $guid ) ? $guid : '';
154
- $email = isset( $data['email'] ) ? $data['email'] : '';
155
- $name = isset( $data['name'] ) ? $data['name'] : '';
 
 
156
 
157
  $subscribe_link = self::prepare_link( 'subscribe', $db_id, $email, $guid );
158
 
159
  $content = str_replace( "{{NAME}}", $name, $content );
 
 
160
  $content = str_replace( "{{EMAIL}}", $email, $content );
161
  $content = str_replace( "{{LINK}}", $subscribe_link, $content );
162
  $content = str_replace( "{{SITENAME}}", $blog_name, $content );
@@ -171,10 +186,14 @@ class ES_Mailer {
171
 
172
  public static function prepare_email_template( $template_content, $keywords, $template_id = 0 ) {
173
 
174
- $name = isset( $keywords['name'] ) ? $keywords['name'] : '';
175
- $email = isset( $keywords['email'] ) ? $keywords['email'] : '';
 
 
176
 
177
  $template_content = str_replace( "{{NAME}}", $name, $template_content );
 
 
178
  $template_content = str_replace( "{{EMAIL}}", $email, $template_content );
179
 
180
  $template_content = convert_chars( convert_smilies( wptexturize( $template_content ) ) );
@@ -341,6 +360,7 @@ class ES_Mailer {
341
 
342
  $response = array();
343
  $response = apply_filters( $send_email_via . '_do_send', $response, $data );
 
344
  return $response;
345
  } else {
346
  mail( $to_email, $subject, $email_template, $headers );
12
 
13
  }
14
 
 
15
  /* prepare cron email*/
16
  public static function prepare_and_send_email( $mails, $notification ) {
17
 
36
  $email = $mail['email'];
37
  $id = $mail['contact_id'];
38
  $guid = $mail['mailing_queue_hash'];
39
+ $email_name = ! empty( $emails_name_map[ $email ] ) ? $emails_name_map[ $email ]['name'] : '';
40
+ $first_name = ! empty( $emails_name_map[ $email ] ) ? $emails_name_map[ $email ]['first_name'] : '';
41
+ $last_name = ! empty( $emails_name_map[ $email ] ) ? $emails_name_map[ $email ]['last_name'] : '';
42
 
43
  $keywords = array(
44
+ 'name' => $email_name,
45
+ 'first_name' => $first_name,
46
+ 'last_name' => $last_name,
47
+ 'email' => $email,
48
+ 'guid' => $guid,
49
+ 'dbid' => $id
50
  );
51
 
52
  // Preparing email body
68
  $blog_name = get_option( 'blogname' );
69
  $site_url = home_url( '/' );
70
 
71
+ $name = isset( $data['name'] ) ? $data['name'] : '';
72
+ $first_name = isset( $data['first_name'] ) ? $data['first_name'] : '';
73
+ $last_name = isset( $data['last_name'] ) ? $data['last_name'] : '';
74
+ $email = isset( $data['email'] ) ? $data['email'] : '';
75
+ $list_name = isset( $data['list_name'] ) ? $data['list_name'] : '';
76
 
77
  $content = str_replace( "{{NAME}}", $name, $content );
78
+ $content = str_replace( "{{FIRSTNAME}}", $first_name, $content );
79
+ $content = str_replace( "{{LASTNAME}}", $last_name, $content );
80
  $content = str_replace( "{{EMAIL}}", $email, $content );
81
  $content = str_replace( "{{GROUP}}", $list_name, $content );
82
  $content = str_replace( "{{LIST}}", $list_name, $content );
122
  $total_contacts = ES_DB_Contacts::count_active_subscribers_by_list_id();
123
  $content = stripslashes( get_option( 'ig_es_welcome_email_content', '' ) );
124
 
125
+ $name = isset( $data['name'] ) ? $data['name'] : '';
126
+ $first_name = isset( $data['first_name'] ) ? $data['first_name'] : '';
127
+ $last_name = isset( $data['last_name'] ) ? $data['last_name'] : '';
128
+ $email = isset( $data['email'] ) ? $data['email'] : '';
129
+ $list_name = isset( $data['list_name'] ) ? $data['list_name'] : '';
130
+ $db_id = isset( $data['db_id'] ) ? $data['db_id'] : '';
131
+ $guid = ES_DB_Contacts::get_contact_hash_by_id( $db_id );
132
  // $guid = isset( $data['guid'] ) ? $data['guid'] : '';
133
  $guid = ! empty( $guid ) ? $guid : '';
134
 
135
  $unsubscribe_link = self::prepare_link( 'unsubscribe', $db_id, $email, $guid );
136
 
137
  $content = str_replace( "{{NAME}}", $name, $content );
138
+ $content = str_replace( "{{FIRSTNAME}}", $first_name, $content );
139
+ $content = str_replace( "{{LASTNAME}}", $last_name, $content );
140
  $content = str_replace( "{{EMAIL}}", $email, $content );
141
  $content = str_replace( "{{SITENAME}}", $blog_name, $content );
142
  $content = str_replace( "{{GROUP}}", $list_name, $content );
161
  $db_id = isset( $data['db_id'] ) ? $data['db_id'] : '';
162
  $guid = ES_DB_Contacts::get_contact_hash_by_id( $db_id );
163
  // $guid = isset( $data['guid'] ) ? $data['guid'] : '';
164
+ $guid = ! empty( $guid ) ? $guid : '';
165
+ $email = isset( $data['email'] ) ? $data['email'] : '';
166
+ $name = isset( $data['name'] ) ? $data['name'] : '';
167
+ $first_name = isset( $data['first_name'] ) ? $data['first_name'] : '';
168
+ $last_name = isset( $data['last_name'] ) ? $data['last_name'] : '';
169
 
170
  $subscribe_link = self::prepare_link( 'subscribe', $db_id, $email, $guid );
171
 
172
  $content = str_replace( "{{NAME}}", $name, $content );
173
+ $content = str_replace( "{{FIRSTNAME}}", $first_name, $content );
174
+ $content = str_replace( "{{LASTNAME}}", $last_name, $content );
175
  $content = str_replace( "{{EMAIL}}", $email, $content );
176
  $content = str_replace( "{{LINK}}", $subscribe_link, $content );
177
  $content = str_replace( "{{SITENAME}}", $blog_name, $content );
186
 
187
  public static function prepare_email_template( $template_content, $keywords, $template_id = 0 ) {
188
 
189
+ $name = isset( $keywords['name'] ) ? $keywords['name'] : '';
190
+ $email = isset( $keywords['email'] ) ? $keywords['email'] : '';
191
+ $first_name = isset( $keywords['first_name'] ) ? $keywords['first_name'] : '';
192
+ $last_name = isset( $keywords['last_name'] ) ? $keywords['last_name'] : '';
193
 
194
  $template_content = str_replace( "{{NAME}}", $name, $template_content );
195
+ $template_content = str_replace( "{{FIRSTNAME}}", $first_name, $template_content );
196
+ $template_content = str_replace( "{{LASTNAME}}", $last_name, $template_content );
197
  $template_content = str_replace( "{{EMAIL}}", $email, $template_content );
198
 
199
  $template_content = convert_chars( convert_smilies( wptexturize( $template_content ) ) );
360
 
361
  $response = array();
362
  $response = apply_filters( $send_email_via . '_do_send', $response, $data );
363
+
364
  return $response;
365
  } else {
366
  mail( $to_email, $subject, $email_template, $headers );
includes/db/class-es-db-contacts.php CHANGED
@@ -91,7 +91,11 @@ class ES_DB_Contacts {
91
  if ( count( $subscribers ) > 0 ) {
92
  foreach ( $subscribers as $subscriber ) {
93
  $name = ES_Common::prepare_name_from_first_name_last_name( $subscriber['first_name'], $subscriber['last_name'] );
94
- $subscriber_email_name_map[ $subscriber['email'] ] = $name;
 
 
 
 
95
  }
96
  }
97
  }
91
  if ( count( $subscribers ) > 0 ) {
92
  foreach ( $subscribers as $subscriber ) {
93
  $name = ES_Common::prepare_name_from_first_name_last_name( $subscriber['first_name'], $subscriber['last_name'] );
94
+ $subscriber_email_name_map[ $subscriber['email'] ] = array(
95
+ 'name' => $name,
96
+ 'first_name' => $subscriber['first_name'],
97
+ 'last_name' => $subscriber['last_name']
98
+ );
99
  }
100
  }
101
  }
includes/es-backward.php CHANGED
@@ -36,8 +36,8 @@ class es_cls_dbquery {
36
  $name = $first_name;
37
  }
38
 
39
- $guid = ES_Common::generate_guid();
40
- $sub_data = array(
41
  'first_name' => $first_name,
42
  'last_name' => $last_name,
43
  'email' => $email,
@@ -47,9 +47,9 @@ class es_cls_dbquery {
47
  'created_at' => ig_get_current_date_time(),
48
  );
49
  $contact_id = ES_DB_Contacts::get_contact_id_by_email( $email );
50
- if( !$contact_id ){
51
  $contact_id = ES_DB_Contacts::add_subscriber( $sub_data );
52
- }
53
 
54
  if ( $contact_id ) {
55
 
@@ -78,10 +78,12 @@ class es_cls_dbquery {
78
 
79
  // Send Email Notification
80
  $data = array(
81
- 'name' => $name,
82
- 'email' => $email,
83
- 'db_id' => $contact_id,
84
- 'guid' => $guid
 
 
85
  );
86
 
87
  if ( $optin_type == 1 ) {
@@ -104,12 +106,13 @@ class es_cls_dbquery {
104
  ES_Mailer::send( $email, $subject, $content );
105
  }
106
 
107
-
108
  $list_name = ES_DB_Lists::get_list_id_name_map( $list_id );
109
  $template_data = array(
110
- 'name' => $name,
111
- 'email' => $email,
112
- 'list_name' => $list_name
 
 
113
  );
114
 
115
  ES_Common::send_signup_notification_to_admins( $template_data );
36
  $name = $first_name;
37
  }
38
 
39
+ $guid = ES_Common::generate_guid();
40
+ $sub_data = array(
41
  'first_name' => $first_name,
42
  'last_name' => $last_name,
43
  'email' => $email,
47
  'created_at' => ig_get_current_date_time(),
48
  );
49
  $contact_id = ES_DB_Contacts::get_contact_id_by_email( $email );
50
+ if ( ! $contact_id ) {
51
  $contact_id = ES_DB_Contacts::add_subscriber( $sub_data );
52
+ }
53
 
54
  if ( $contact_id ) {
55
 
78
 
79
  // Send Email Notification
80
  $data = array(
81
+ 'name' => $name,
82
+ 'first_name' => $sub_data['first_name'],
83
+ 'last_name' => $sub_data['last_name'],
84
+ 'email' => $email,
85
+ 'db_id' => $contact_id,
86
+ 'guid' => $guid
87
  );
88
 
89
  if ( $optin_type == 1 ) {
106
  ES_Mailer::send( $email, $subject, $content );
107
  }
108
 
 
109
  $list_name = ES_DB_Lists::get_list_id_name_map( $list_id );
110
  $template_data = array(
111
+ 'name' => $name,
112
+ 'first_name' => $sub_data['first_name'],
113
+ 'last_name' => $sub_data['last_name'],
114
+ 'email' => $email,
115
+ 'list_name' => $list_name
116
  );
117
 
118
  ES_Common::send_signup_notification_to_admins( $template_data );
includes/feedback.php CHANGED
@@ -13,8 +13,8 @@ if ( ! function_exists( 'ig_es_get_additional_info' ) ) {
13
 
14
  if ( $system_info ) {
15
 
16
- $additional_info['active_plugins'] = $ig_es_tracker::get_active_plugins();
17
- $additional_info['inactive_plugins'] = $ig_es_tracker::get_inactive_plugins();
18
  $additional_info['current_theme'] = $ig_es_tracker::get_current_theme_info();
19
  $additional_info['wp_info'] = $ig_es_tracker::get_wp_info();
20
  $additional_info['server_info'] = $ig_es_tracker::get_server_info();
@@ -24,7 +24,6 @@ if ( ! function_exists( 'ig_es_get_additional_info' ) ) {
24
  }
25
 
26
  return $additional_info;
27
-
28
  }
29
 
30
  }
@@ -84,4 +83,53 @@ function ig_es_render_feedback_widget() {
84
 
85
  }
86
 
87
- //add_action( 'admin_footer', 'ig_es_render_feedback_widget' );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
13
 
14
  if ( $system_info ) {
15
 
16
+ $additional_info['active_plugins'] = implode( ', ', $ig_es_tracker::get_active_plugins() );
17
+ $additional_info['inactive_plugins'] = implode( ', ', $ig_es_tracker::get_inactive_plugins() );
18
  $additional_info['current_theme'] = $ig_es_tracker::get_current_theme_info();
19
  $additional_info['wp_info'] = $ig_es_tracker::get_wp_info();
20
  $additional_info['server_info'] = $ig_es_tracker::get_server_info();
24
  }
25
 
26
  return $additional_info;
 
27
  }
28
 
29
  }
83
 
84
  }
85
 
86
+ function ig_es_render_general_feedback_widget() {
87
+
88
+ if ( is_admin() ) {
89
+
90
+ if ( defined( 'DOING_AJAX' ) && DOING_AJAX ) {
91
+ return;
92
+ }
93
+
94
+ global $ig_es_feedback;
95
+
96
+ $screen = get_current_screen();
97
+ $screen_id = $screen ? $screen->id : '';
98
+
99
+ $show_on_screens = array(
100
+ 'toplevel_page_es_dashboard',
101
+ 'email-subscribers_page_es_subscribers',
102
+ 'email-subscribers_page_es_lists',
103
+ 'email-subscribers_page_es_forms',
104
+ 'email-subscribers_page_es_campaigns',
105
+ 'email-subscribers_page_es_reports',
106
+ 'email-subscribers_page_es_settings',
107
+ 'email-subscribers_page_es_general_information',
108
+ 'email-subscribers_page_es_pricing'
109
+ );
110
+
111
+ if ( ! in_array( $screen_id, $show_on_screens ) ) {
112
+ return;
113
+ }
114
+
115
+ $event = 'plugin.feedback';
116
+
117
+ $params = array(
118
+ 'type' => 'feedback',
119
+ 'event' => $event,
120
+ 'title' => "Have feedback or question for us?",
121
+ 'position' => 'center',
122
+ 'width' => 600,
123
+ 'force' => true,
124
+ 'confirmButtonText' => __( 'Send', 'email-subscribers' ),
125
+ 'consent_text' => __( sprintf( 'By clicking on send button you are agree to our <a href="%s" target="_blank">Privacy Policy</a>', "https://www.icegram.com/privacy-policy/" ), 'email-subscribers' ),
126
+ 'email' => get_option( 'admin_email' ),
127
+ 'name' => ''
128
+ );
129
+
130
+ ES_Common::render_feedback_widget( $params );
131
+ }
132
+ }
133
+
134
+ //add_action( 'admin_footer', 'ig_es_render_feedback_widget' );
135
+ add_action( 'admin_footer', 'ig_es_render_general_feedback_widget' );
includes/feedback/assets/css/feedback.css ADDED
@@ -0,0 +1,59 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ .ig-es-feedback-button {
2
+ height: 40px;
3
+ border: solid 3px #CCCCCC;
4
+ background: #333;
5
+ width: 100px;
6
+ line-height: 32px;
7
+ -webkit-transform: rotate(-90deg);
8
+ font-weight: 600;
9
+ color: white;
10
+ transform: rotate(-90deg);
11
+ -ms-transform: rotate(-90deg);
12
+ -moz-transform: rotate(-90deg);
13
+ text-align: center;
14
+ font-size: 17px;
15
+ position: fixed;
16
+ right: -40px;
17
+ top: 45%;
18
+ font-family: "Roboto", helvetica, arial, sans-serif;
19
+ z-index: 999;
20
+ cursor: pointer;
21
+ }
22
+
23
+
24
+ .ig-powered-by {
25
+ font-size: 12px;
26
+ }
27
+
28
+ /* General Feedback Form */
29
+ .ig-general-feedback .ig-feedback-data-name {
30
+ width: 50%;
31
+ float: left;
32
+ }
33
+
34
+ .ig-general-feedback .ig-feedback-data-email {
35
+ width: 50%;
36
+ float: left;
37
+ }
38
+
39
+ .ig-general-feedback .ig-feedback-data-email input,
40
+ .ig-general-feedback .ig-feedback-data-name input,
41
+ .email-subscribers_page_es_settings .ig-general-feedback .ig-feedback-data-email input,
42
+ .email-subscribers_page_es_settings .ig-general-feedback .ig-feedback-data-name input {
43
+ width: 84%;
44
+ }
45
+
46
+ .ig-general-feedback label {
47
+ display: inline-block;
48
+ margin-bottom: 3px;
49
+ color: #484848;
50
+ }
51
+
52
+ #swal2-content {
53
+ text-align: left;
54
+ }
55
+
56
+ .email-subscribers_page_es_settings .ig-feedback-data-message textarea, .ig-feedback-data-message textarea {
57
+ height: 200px;
58
+ width: 92%
59
+ }
includes/feedback/assets/css/sweetalert2.css CHANGED
@@ -1446,8 +1446,4 @@ body.swal2-no-backdrop .swal2-shown.swal2-bottom-end, body.swal2-no-backdrop .sw
1446
  body.swal2-shown:not(.swal2-no-backdrop):not(.swal2-toast-shown) .swal2-container {
1447
  position: initial !important;
1448
  }
1449
- }
1450
-
1451
- .ig-powered-by {
1452
- font-size: 12px;
1453
  }
1446
  body.swal2-shown:not(.swal2-no-backdrop):not(.swal2-toast-shown) .swal2-container {
1447
  position: initial !important;
1448
  }
 
 
 
 
1449
  }
includes/feedback/{class-ig-feedback-v-1-0-2.php → class-ig-feedback-v-1-0-3.php} RENAMED
@@ -15,7 +15,7 @@
15
 
16
  defined( 'ABSPATH' ) || exit;
17
 
18
- if ( ! class_exists( 'IG_Feedback_V_1_0_2' ) ) {
19
  /**
20
  * Icegram Deactivation Survey.
21
  *
@@ -27,7 +27,7 @@ if ( ! class_exists( 'IG_Feedback_V_1_0_2' ) ) {
27
  * @license GPL-2.0+
28
  * @copyright Copyright (c) 2019
29
  */
30
- class IG_Feedback_V_1_0_2 {
31
 
32
  /**
33
  * The API URL where we will send feedback data.
@@ -147,9 +147,19 @@ if ( ! class_exists( 'IG_Feedback_V_1_0_2' ) ) {
147
 
148
  wp_register_style( 'ig-feedback-emoji', plugin_dir_url( __FILE__ ) . 'assets/css/emoji.css' );
149
  wp_enqueue_style( 'ig-feedback-emoji' );
 
 
 
150
  }
151
 
152
- public function render_widget( $params = array() ) {
 
 
 
 
 
 
 
153
 
154
  $default_params = array(
155
  'event' => 'feedback',
@@ -160,13 +170,21 @@ if ( ! class_exists( 'IG_Feedback_V_1_0_2' ) ) {
160
  'allowOutsideClick' => false,
161
  'allowEscapeKey' => true,
162
  'showCloseButton' => true,
163
- 'confirmButtonText' => __( 'Ok', 'email-subscribers' ),
164
  'backdrop' => true,
165
- 'delay' => 3 // In Seconds
 
166
  );
167
 
168
  $params = wp_parse_args( $params, $default_params );
169
 
 
 
 
 
 
 
 
170
  $title = $params['title'];
171
  $slug = sanitize_title( $title );
172
  $event = $this->event_prefix . $params['event'];
@@ -204,6 +222,7 @@ if ( ! class_exists( 'IG_Feedback_V_1_0_2' ) ) {
204
  }
205
 
206
  function showWidget(delay) {
 
207
  setTimeout(function () {
208
 
209
  Swal.mixin({
@@ -353,6 +372,187 @@ if ( ! class_exists( 'IG_Feedback_V_1_0_2' ) ) {
353
 
354
  }
355
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
356
  /**
357
  * Get Feedback API url
358
  *
@@ -804,20 +1004,23 @@ if ( ! class_exists( 'IG_Feedback_V_1_0_2' ) ) {
804
  $is_dev_mode = ! empty( $data['misc']['is_dev_mode'] ) ? $data['misc']['is_dev_mode'] : false;
805
  $set_transient = ! empty( $data['misc']['set_transient'] ) ? $data['misc']['set_transient'] : false;
806
  $system_info = ! empty( $data['misc']['system_info'] ) ? $data['misc']['system_info'] : false;
 
807
 
808
  unset( $data['misc'] );
809
 
810
- $meta_info = array(
811
  'plugin' => sanitize_key( $plugin ),
812
  'locale' => get_locale(),
813
  'wp_version' => get_bloginfo( 'version' )
814
  );
815
 
 
 
816
  $additional_info = array();
817
  $additional_info = apply_filters( $plugin_abbr . '_additional_feedback_meta_info', $additional_info, $system_info ); // Get Additional meta information
818
 
819
  if ( is_array( $additional_info ) && count( $additional_info ) > 0 ) {
820
- $meta_info = $meta_info + $additional_info;
821
  }
822
 
823
  $data['meta'] = $meta_info;
15
 
16
  defined( 'ABSPATH' ) || exit;
17
 
18
+ if ( ! class_exists( 'IG_Feedback_V_1_0_3' ) ) {
19
  /**
20
  * Icegram Deactivation Survey.
21
  *
27
  * @license GPL-2.0+
28
  * @copyright Copyright (c) 2019
29
  */
30
+ class IG_Feedback_V_1_0_3 {
31
 
32
  /**
33
  * The API URL where we will send feedback data.
147
 
148
  wp_register_style( 'ig-feedback-emoji', plugin_dir_url( __FILE__ ) . 'assets/css/emoji.css' );
149
  wp_enqueue_style( 'ig-feedback-emoji' );
150
+
151
+ wp_register_style( 'ig-feedback', plugin_dir_url( __FILE__ ) . 'assets/css/feedback.css' );
152
+ wp_enqueue_style( 'ig-feedback' );
153
  }
154
 
155
+ /**
156
+ * Prepare Widget Params
157
+ *
158
+ * @param array $params
159
+ *
160
+ * @since 1.0.3
161
+ */
162
+ public function prepare_widget_params( $params = array() ) {
163
 
164
  $default_params = array(
165
  'event' => 'feedback',
170
  'allowOutsideClick' => false,
171
  'allowEscapeKey' => true,
172
  'showCloseButton' => true,
173
+ 'confirmButtonText' => 'Ok',
174
  'backdrop' => true,
175
+ 'delay' => 3, // In Seconds
176
+ 'consent_text' => 'You are agree to our terms and condition' // In Seconds
177
  );
178
 
179
  $params = wp_parse_args( $params, $default_params );
180
 
181
+ return $params;
182
+ }
183
+
184
+ public function render_widget( $params = array() ) {
185
+
186
+ $params = $this->prepare_widget_params( $params );
187
+
188
  $title = $params['title'];
189
  $slug = sanitize_title( $title );
190
  $event = $this->event_prefix . $params['event'];
222
  }
223
 
224
  function showWidget(delay) {
225
+
226
  setTimeout(function () {
227
 
228
  Swal.mixin({
372
 
373
  }
374
 
375
+ /**
376
+ * Render General Feedback Sidebar Button Widget
377
+ *
378
+ * @since 1.0.3
379
+ */
380
+ public function render_general_feedback( $params = array() ) {
381
+
382
+ $params = $this->prepare_widget_params( $params );
383
+
384
+ ob_start();
385
+
386
+ ?>
387
+
388
+ <form class="ig-general-feedback" id="ig-general-feedback">
389
+ <p class="ig-feedback-data-name">
390
+ <label class="ig-label">Name</label><br/>
391
+ <input type="text" name="feedback_data[name]" id="ig-feedback-data-name" value="<?php echo $params['name']; ?>"/>
392
+ </p>
393
+ <p class="ig-feedback-data-email">
394
+ <label class="ig-label"">Email</label><br/>
395
+ <input type="email" name="feedback_data[email]" id="ig-feedback-data-email" value="<?php echo $params['email']; ?>"/>
396
+ </p>
397
+ <p class="ig-feedback-data-message">
398
+ <label class="ig-label"">Feedback</label><br/>
399
+ <textarea name="feedback_data[details]" id="ig-feedback-data-message"></textarea>
400
+ </p>
401
+ <p>
402
+ <input type="checkbox" name="feedback_data[collect_system_info]" id="ig-feedback-data-consent"/><?php echo $params['consent_text']; ?>
403
+ </p>
404
+ </form>
405
+
406
+ <?php
407
+
408
+ $html = str_replace( array( "\r", "\n" ), '', trim( ob_get_clean() ) );
409
+
410
+ $params['html'] = $html;
411
+
412
+ $title = $params['title'];
413
+ $slug = sanitize_title( $title );
414
+ $event = $this->event_prefix . $params['event'];
415
+ $html = ! empty( $params['html'] ) ? $params['html'] : '';
416
+
417
+ ob_start();
418
+ ?>
419
+
420
+ <script type="text/javascript">
421
+
422
+ jQuery(document).ready(function ($) {
423
+
424
+ function doSend(details, meta, system_info) {
425
+
426
+ var data = {
427
+ action: '<?php echo $this->ajax_action; ?>',
428
+ feedback: {
429
+ type: '<?php echo $params['type']; ?>',
430
+ slug: '<?php echo $slug; ?>',
431
+ title: '<?php echo esc_js( $title ); ?>',
432
+ details: details
433
+ },
434
+
435
+ event: '<?php echo $event; ?>',
436
+
437
+ // Add additional information
438
+ misc: {
439
+ plugin: '<?php echo $this->plugin; ?>',
440
+ plugin_abbr: '<?php echo $this->plugin_abbr; ?>',
441
+ is_dev_mode: '<?php echo $this->is_dev_mode; ?>',
442
+ set_transient: '<?php echo $params['set_transient']; ?>',
443
+ meta_info: meta,
444
+ system_info: system_info
445
+ }
446
+ };
447
+
448
+ return jQuery.post(ajaxurl, data);
449
+ }
450
+
451
+ function validateEmail(email) {
452
+ var emailReg = /^([\w-\.]+@([\w-]+\.)+[\w-]{2,4})?$/;
453
+ if( !emailReg.test( email ) ) {
454
+ return false;
455
+ } else {
456
+ return true;
457
+ }
458
+ }
459
+
460
+ $('#wpwrap').append('<div class="ig-es-feedback-button">Feedback</div>');
461
+
462
+ $('.ig-es-feedback-button').on('click', function () {
463
+
464
+ Swal.mixin({
465
+ footer: '<?php echo $this->footer; ?>',
466
+ position: '<?php echo $params['position']; ?>',
467
+ width: <?php echo $params['width']; ?>,
468
+ animation: false,
469
+ focusConfirm: false,
470
+ allowEscapeKey: true,
471
+ showCloseButton: '<?php echo $params['showCloseButton']; ?>',
472
+ allowOutsideClick: '<?php echo $params['allowOutsideClick']; ?>',
473
+ showLoaderOnConfirm: true,
474
+ confirmButtonText: '<?php echo $params['confirmButtonText']; ?>',
475
+ backdrop: '<?php echo (int) $params['backdrop']; ?>'
476
+ }).queue([
477
+ {
478
+ title: '<p class="ig-feedback-title"><?php echo esc_js( $params['title'] ); ?></p>',
479
+ html: '<?php echo $html; ?>',
480
+ customClass: {
481
+ popup: 'animated fadeInUpBig'
482
+ },
483
+ onOpen: () => {
484
+
485
+ Swal.disableButtons();
486
+ $('#ig-feedback-data-consent').on('click', function () {
487
+ if ($(this).attr('checked') === 'checked') {
488
+ Swal.enableButtons();
489
+ } else {
490
+ Swal.disableButtons();
491
+ }
492
+ });
493
+
494
+ },
495
+ preConfirm: () => {
496
+
497
+ var email = $('#ig-feedback-data-email').val();
498
+ var name = $('#ig-feedback-data-name').val();
499
+ var message = $('#ig-feedback-data-message').val();
500
+ var consent = $('#ig-feedback-data-consent').attr('checked');
501
+
502
+ if (consent !== 'checked') {
503
+ Swal.showValidationMessage('Please give your consent');
504
+ return;
505
+ }
506
+
507
+ if(email !== '' && !validateEmail(email)) {
508
+ Swal.showValidationMessage('Please enter valid email');
509
+ return;
510
+ }
511
+
512
+ if (message === '') {
513
+ Swal.showValidationMessage('Please enter your message');
514
+ return;
515
+ }
516
+
517
+
518
+
519
+ var meta = {
520
+ name: name,
521
+ email: email
522
+ };
523
+
524
+ return doSend(message, meta, true);
525
+ }
526
+ },
527
+
528
+ ]).then(response => {
529
+
530
+ if (response.hasOwnProperty('value')) {
531
+
532
+ Swal.fire({
533
+ type: 'success',
534
+ width: <?php echo $params['width']; ?>,
535
+ title: "Thank You!",
536
+ showConfirmButton: false,
537
+ position: '<?php echo $params['position']; ?>',
538
+ timer: 1500,
539
+ animation: false
540
+ });
541
+
542
+ }
543
+ });
544
+
545
+
546
+ });
547
+ });
548
+
549
+ </script>
550
+
551
+
552
+ <?php
553
+
554
+ }
555
+
556
  /**
557
  * Get Feedback API url
558
  *
1004
  $is_dev_mode = ! empty( $data['misc']['is_dev_mode'] ) ? $data['misc']['is_dev_mode'] : false;
1005
  $set_transient = ! empty( $data['misc']['set_transient'] ) ? $data['misc']['set_transient'] : false;
1006
  $system_info = ! empty( $data['misc']['system_info'] ) ? $data['misc']['system_info'] : false;
1007
+ $meta_info = ! empty( $data['misc']['meta_info'] ) ? $data['misc']['meta_info'] : array();
1008
 
1009
  unset( $data['misc'] );
1010
 
1011
+ $default_meta_info = array(
1012
  'plugin' => sanitize_key( $plugin ),
1013
  'locale' => get_locale(),
1014
  'wp_version' => get_bloginfo( 'version' )
1015
  );
1016
 
1017
+ $meta_info = wp_parse_args( $meta_info, $default_meta_info );
1018
+
1019
  $additional_info = array();
1020
  $additional_info = apply_filters( $plugin_abbr . '_additional_feedback_meta_info', $additional_info, $system_info ); // Get Additional meta information
1021
 
1022
  if ( is_array( $additional_info ) && count( $additional_info ) > 0 ) {
1023
+ $meta_info = array_merge( $meta_info, $additional_info );
1024
  }
1025
 
1026
  $data['meta'] = $meta_info;
includes/feedback/{class-ig-tracker-v-1-0-2.php → class-ig-tracker-v-1-0-3.php} RENAMED
@@ -4,7 +4,7 @@ if ( ! defined( 'ABSPATH' ) ) {
4
  exit; // Exit if accessed directly.
5
  }
6
 
7
- if ( ! class_exists( 'IG_Tracker_V_1_0_2' ) ) {
8
 
9
  /**
10
  * Icegram tracker.
@@ -14,7 +14,7 @@ if ( ! class_exists( 'IG_Tracker_V_1_0_2' ) ) {
14
  *
15
  * @since 1.0.0
16
  */
17
- class IG_Tracker_V_1_0_2 {
18
 
19
  /**
20
  * Get Active, Inactive or all plugins info
@@ -44,7 +44,6 @@ if ( ! class_exists( 'IG_Tracker_V_1_0_2' ) ) {
44
  $active_plugins = ! empty( $active_plugins ) ? array_merge( $sitewide_activated_plugins, $active_plugins ) : $sitewide_activated_plugins;
45
  }
46
 
47
- $i = 0;
48
  foreach ( $all_plugins as $plugin_path => $plugin ) {
49
  // If the plugin isn't active, don't show it.
50
  if ( in_array( $plugin_path, $active_plugins ) ) {
@@ -73,7 +72,7 @@ if ( ! class_exists( 'IG_Tracker_V_1_0_2' ) ) {
73
  return $plugins['active_plugins'];
74
  } elseif ( 'inactive' === $status ) {
75
  return $plugins['inactive_plugins'];
76
- } elseif ( 'all' === $status ) {
77
  return array_merge( $plugins['active_plugins'], $plugins['inactive_plugins'] );
78
  }
79
  }
4
  exit; // Exit if accessed directly.
5
  }
6
 
7
+ if ( ! class_exists( 'IG_Tracker_V_1_0_3' ) ) {
8
 
9
  /**
10
  * Icegram tracker.
14
  *
15
  * @since 1.0.0
16
  */
17
+ class IG_Tracker_V_1_0_3 {
18
 
19
  /**
20
  * Get Active, Inactive or all plugins info
44
  $active_plugins = ! empty( $active_plugins ) ? array_merge( $sitewide_activated_plugins, $active_plugins ) : $sitewide_activated_plugins;
45
  }
46
 
 
47
  foreach ( $all_plugins as $plugin_path => $plugin ) {
48
  // If the plugin isn't active, don't show it.
49
  if ( in_array( $plugin_path, $active_plugins ) ) {
72
  return $plugins['active_plugins'];
73
  } elseif ( 'inactive' === $status ) {
74
  return $plugins['inactive_plugins'];
75
+ } else {
76
  return array_merge( $plugins['active_plugins'], $plugins['inactive_plugins'] );
77
  }
78
  }
public/class-email-subscribers-public.php CHANGED
@@ -168,10 +168,12 @@ class Email_Subscribers_Public {
168
 
169
  $contact = ES_DB_Contacts::get_subsribers_email_name_map( array( $email ) );
170
  $data = array(
171
- 'name' => $contact[ $email ],
172
- 'email' => $email,
173
- 'db_id' => $db_id,
174
- 'guid' => $guid
 
 
175
  );
176
 
177
  $enable_welcome_email = get_option( 'ig_es_enable_welcome_email', 'no' );
@@ -211,7 +213,7 @@ class Email_Subscribers_Public {
211
  'wp_user_id' => 0
212
  );
213
 
214
- $contact_data = wp_parse_args($contact_data, $default_data);
215
 
216
  $contact = ES_DB_Contacts::is_subscriber_exist_in_list( $email, $list_id );
217
  if ( empty( $contact['contact_id'] ) ) {
@@ -234,7 +236,7 @@ class Email_Subscribers_Public {
234
  'subscribed_ip' => null
235
  );
236
 
237
- ES_DB_Lists_Contacts::delete_list_contacts( $contact_id, array($list_id) );
238
 
239
  $result = ES_DB_Lists_Contacts::add_lists_contacts( $list_contact_data );
240
  }
168
 
169
  $contact = ES_DB_Contacts::get_subsribers_email_name_map( array( $email ) );
170
  $data = array(
171
+ 'name' => ! empty( $contact[ $email ] ) ? $contact[ $email ]['name'] : '',
172
+ 'first_name' => ! empty( $contact[ $email ] ) ? $contact[ $email ]['first_name'] : '',
173
+ 'last_name' => ! empty( $contact[ $email ] ) ? $contact[ $email ]['last_name'] : '',
174
+ 'email' => $email,
175
+ 'db_id' => $db_id,
176
+ 'guid' => $guid
177
  );
178
 
179
  $enable_welcome_email = get_option( 'ig_es_enable_welcome_email', 'no' );
213
  'wp_user_id' => 0
214
  );
215
 
216
+ $contact_data = wp_parse_args( $contact_data, $default_data );
217
 
218
  $contact = ES_DB_Contacts::is_subscriber_exist_in_list( $email, $list_id );
219
  if ( empty( $contact['contact_id'] ) ) {
236
  'subscribed_ip' => null
237
  );
238
 
239
+ ES_DB_Lists_Contacts::delete_list_contacts( $contact_id, array( $list_id ) );
240
 
241
  $result = ES_DB_Lists_Contacts::add_lists_contacts( $list_contact_data );
242
  }
public/css/email-subscribers-public.css CHANGED
@@ -47,4 +47,8 @@
47
  }
48
  .es-field-wrap{
49
  margin-bottom: 0.6em;
 
 
 
 
50
  }
47
  }
48
  .es-field-wrap{
49
  margin-bottom: 0.6em;
50
+ }
51
+
52
+ .ig-es-form-list-selection tr {
53
+ border-bottom: none;
54
  }
public/partials/class-es-shortcode.php CHANGED
@@ -149,7 +149,7 @@ class ES_Shortcode {
149
  // Lists
150
  if ( ! empty( $list_ids ) && $show_list ) {
151
  $lists_id_name_map = ES_DB_Lists::get_list_id_name_map();
152
- $list_html = self::prepare_lists_checkboxes( $lists_id_name_map, $list_ids );
153
  } elseif ( ! empty( $list_ids ) && ! $show_list ) {
154
  $list_html = '';
155
  foreach ( $list_ids as $id ) {
@@ -208,7 +208,7 @@ class ES_Shortcode {
208
  }
209
 
210
  public static function prepare_lists_checkboxes( $lists, $list_ids = array(), $columns = 3, $selected_lists = array(), $contact_id = 0 ) {
211
- $lists_html = '<div><table><tr>';
212
  $i = 0;
213
  foreach ( $lists as $list_id => $list_name ) {
214
  if ( $i != 0 && ( $i % $columns ) === 0 ) {
@@ -223,7 +223,7 @@ class ES_Shortcode {
223
  }
224
  $lists_html .= '<td>' . $status_span . '<label><input type="checkbox" name="lists[]" checked="checked" value="' . $list_id . '" />' . $list_name . '</label></td>';
225
  } else {
226
- $lists_html .= '<td><label><input type="checkbox" name="lists[]" value="' . $list_id . '" />' . $list_name . '</label></td>';
227
  }
228
  $i ++;
229
  }
@@ -233,7 +233,6 @@ class ES_Shortcode {
233
  return $lists_html;
234
  }
235
 
236
-
237
  }
238
 
239
 
149
  // Lists
150
  if ( ! empty( $list_ids ) && $show_list ) {
151
  $lists_id_name_map = ES_DB_Lists::get_list_id_name_map();
152
+ $list_html = self::prepare_lists_checkboxes( $lists_id_name_map, $list_ids, 1 );
153
  } elseif ( ! empty( $list_ids ) && ! $show_list ) {
154
  $list_html = '';
155
  foreach ( $list_ids as $id ) {
208
  }
209
 
210
  public static function prepare_lists_checkboxes( $lists, $list_ids = array(), $columns = 3, $selected_lists = array(), $contact_id = 0 ) {
211
+ $lists_html = '<div><br /><p><b>' . __('Select List(s)', 'email-subscribers') .'*</b></p><table class="ig-es-form-list-selection"><tr>';
212
  $i = 0;
213
  foreach ( $lists as $list_id => $list_name ) {
214
  if ( $i != 0 && ( $i % $columns ) === 0 ) {
223
  }
224
  $lists_html .= '<td>' . $status_span . '<label><input type="checkbox" name="lists[]" checked="checked" value="' . $list_id . '" />' . $list_name . '</label></td>';
225
  } else {
226
+ $lists_html .= '<td><input type="checkbox" name="lists[]" value="' . $list_id . '" />' . $list_name . '</td>';
227
  }
228
  $i ++;
229
  }
233
  return $lists_html;
234
  }
235
 
 
236
  }
237
 
238
 
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.2.1
8
- Stable tag: 4.1.3
9
  License: GPLv3
10
  License URI: http://www.gnu.org/licenses
11
 
@@ -305,6 +305,11 @@ Use our free plugin [Email Subscribers - Group Selector](https://wordpress.org/p
305
 
306
  == Changelog ==
307
 
 
 
 
 
 
308
  = 4.1.3 (06.06.2019) =
309
  * New: Export contacts by list
310
 
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.2.1
8
+ Stable tag: 4.1.4
9
  License: GPLv3
10
  License URI: http://www.gnu.org/licenses
11
 
305
 
306
  == Changelog ==
307
 
308
+ = 4.1.4 (13.06.2019) =
309
+ * New: Added First Name, Last Name in exported csv file
310
+ * New: Added {{FIRSTNAME}}, {{LASTNAME}} keyword
311
+ * Update: Improve subscription form layout.
312
+
313
  = 4.1.3 (06.06.2019) =
314
  * New: Export contacts by list
315