Newsletter - Version 6.6.6

Version Description

  • Added check on submission for private lists (error shown only to administrator as debug information)
  • Improved right layout on hero block
  • Improved internal actions management (better performances)
  • Added lists, media selector, charmap on text block
  • Absolute path fix form media file with non relative path on database
  • Internal admin pages review for code coherence with our standard
  • Changed the action name from newsletter_unsubscribed to newsletter_user_unsubscribed. See our developer documentation.
  • Removed deprecated function save_profile() on NewsletterSubscription
Download this release

Release Info

Developer satollo
Plugin Icon 128x128 Newsletter
Version 6.6.6
Comparing to
See all releases

Code changes from version 6.6.5 to 6.6.6

emails/blocks/hero/block-right.php CHANGED
@@ -32,6 +32,18 @@
32
  }
33
  </style>
34
 
 
 
 
 
 
 
 
 
 
 
 
 
35
  <table width="49%" align="left" class="hero-table hero-table-right" border="0" cellspacing="0" cellpadding="0">
36
  <tr>
37
  <td align="center" inline-class="title">
@@ -51,12 +63,5 @@
51
  </table>
52
 
53
 
54
- <table width="49%" align="right" class="hero-table" border="0" cellspacing="0" cellpadding="0">
55
- <tr>
56
- <td align="center" valign="top">
57
- <a href="<?php echo $url ?>" target="_blank" rel="noopener nofollow" inline-class="image-a">
58
- <img src="<?php echo $media->url ?>" border="0" alt="<?php echo esc_attr($media->alt) ?>" width="<?php echo $media->width ?>" height="<?php echo $media->height ?>" inline-class="image">
59
- </a>
60
- </td>
61
- </tr>
62
- </table>
32
  }
33
  </style>
34
 
35
+ <div dir="rtl">
36
+
37
+ <table width="49%" align="right" class="hero-table" border="0" cellspacing="0" cellpadding="0">
38
+ <tr>
39
+ <td align="center" valign="top">
40
+ <a href="<?php echo $url ?>" target="_blank" rel="noopener nofollow" inline-class="image-a">
41
+ <img src="<?php echo $media->url ?>" border="0" alt="<?php echo esc_attr($media->alt) ?>" width="<?php echo $media->width ?>" height="<?php echo $media->height ?>" inline-class="image">
42
+ </a>
43
+ </td>
44
+ </tr>
45
+ </table>
46
+
47
  <table width="49%" align="left" class="hero-table hero-table-right" border="0" cellspacing="0" cellpadding="0">
48
  <tr>
49
  <td align="center" inline-class="title">
63
  </table>
64
 
65
 
66
+
67
+ </div>
 
 
 
 
 
 
 
emails/blocks/image/block.php CHANGED
@@ -11,7 +11,7 @@
11
  $defaults = array(
12
  'image' => '',
13
  'url' => '',
14
- 'width'=>0,
15
  'block_background' => '#ffffff',
16
  'block_padding_left' => 0,
17
  'block_padding_right' => 0,
@@ -36,6 +36,11 @@ if (empty($options['image']['id'])) {
36
  }
37
  } else {
38
  $media = tnp_resize($options['image']['id'], array(600, 0));
 
 
 
 
 
39
  $media->alt = $options['image_alt'];
40
  }
41
 
@@ -50,7 +55,7 @@ $url = $options['url'];
50
  max-width: 100%!important;
51
  height: auto!important;
52
  display: block;
53
- width: <?php echo $media->width?>px;
54
  line-height: 0;
55
  margin: 0 auto;
56
  }
11
  $defaults = array(
12
  'image' => '',
13
  'url' => '',
14
+ 'width' => 0,
15
  'block_background' => '#ffffff',
16
  'block_padding_left' => 0,
17
  'block_padding_right' => 0,
36
  }
37
  } else {
38
  $media = tnp_resize($options['image']['id'], array(600, 0));
39
+ // Should never happen but... it happens
40
+ if (!$media) {
41
+ echo 'The selected media file cannot be processed';
42
+ return;
43
+ }
44
  $media->alt = $options['image_alt'];
45
  }
46
 
55
  max-width: 100%!important;
56
  height: auto!important;
57
  display: block;
58
+ width: <?php echo $media->width ?>px;
59
  line-height: 0;
60
  margin: 0 auto;
61
  }
emails/emails.php CHANGED
@@ -11,7 +11,6 @@ class NewsletterEmails extends NewsletterModule {
11
  const EDITOR_TINYMCE = 0;
12
 
13
  static $PRESETS_LIST;
14
-
15
  // Cache
16
  var $blocks = null;
17
 
@@ -29,7 +28,7 @@ class NewsletterEmails extends NewsletterModule {
29
  self::$PRESETS_LIST = array("cta", "invite", "announcement", "posts", "sales", "product", "tour", "simple", "blank");
30
  $this->themes = new NewsletterThemes('emails');
31
  parent::__construct('emails', '1.1.5');
32
- add_action('wp_loaded', array($this, 'hook_wp_loaded'));
33
 
34
  if (is_admin()) {
35
  add_action('wp_ajax_tnpc_render', array($this, 'tnpc_render_callback'));
@@ -94,18 +93,9 @@ class NewsletterEmails extends NewsletterModule {
94
  $options = $this->options_decode(stripslashes_deep($_REQUEST['options']));
95
 
96
  $context = array('type' => '');
97
- if (isset($_REQUEST['context_type']))
98
  $context['type'] = $_REQUEST['context_type'];
99
-
100
- // $defaults = array(
101
- // 'block_padding_top' => 15,
102
- // 'block_padding_bottom' => 15,
103
- // 'block_padding_right' => 0,
104
- // 'block_padding_left' => 0,
105
- // 'block_background' => '#ffffff'
106
- // );
107
- //
108
- // $options = array_merge($defaults, $options);
109
 
110
  $controls = new NewsletterControls($options);
111
  $fields = new NewsletterFields($controls);
@@ -113,12 +103,12 @@ class NewsletterEmails extends NewsletterModule {
113
  $controls->init();
114
  echo '<input type="hidden" name="action" value="tnpc_render">';
115
  echo '<input type="hidden" name="b" value="' . esc_attr($_REQUEST['id']) . '">';
116
- echo '<input type="hidden" name="context_type" value="' . esc_attr( $context['type'] ) . '">';
117
  $inline_edits = '';
118
  if (isset($controls->data['inline_edits'])) {
119
  $inline_edits = $controls->data['inline_edits'];
120
  }
121
- echo '<input type="hidden" name="options[inline_edits]" value="' . esc_attr( serialize( $inline_edits ) ) . '">';
122
 
123
  ob_start();
124
  include $block['dir'] . '/options.php';
@@ -163,7 +153,7 @@ class NewsletterEmails extends NewsletterModule {
163
  echo $content;
164
  }
165
 
166
- wp_die();
167
  }
168
 
169
  function has_dynamic_blocks($theme) {
@@ -176,8 +166,9 @@ class NewsletterEmails extends NewsletterModule {
176
  if (!$block) {
177
  continue;
178
  }
179
- if ($block['type'] == 'dynamic')
180
  return true;
 
181
  }
182
  return false;
183
  }
@@ -195,14 +186,14 @@ class NewsletterEmails extends NewsletterModule {
195
  * @return string
196
  */
197
  function regenerate($email, $context = array()) {
198
-
199
  // Cannot be removed due to compatibility issues with old Automated versions
200
  if (is_object($email)) {
201
  $theme = $email->message;
202
  } else {
203
  $theme = $email;
204
  }
205
-
206
  //$this->logger->debug('Starting email regeneration');
207
  //$this->logger->debug($context);
208
 
@@ -214,7 +205,7 @@ class NewsletterEmails extends NewsletterModule {
214
  $context = array_merge(array('last_run' => 0, 'type' => ''), $context);
215
 
216
  preg_match_all('/data-json="(.*?)"/m', $theme, $matches, PREG_PATTERN_ORDER);
217
-
218
  $result = '';
219
  $subject = '';
220
 
@@ -249,9 +240,9 @@ class NewsletterEmails extends NewsletterModule {
249
  $block_html = ob_get_clean();
250
  $result .= $block_html;
251
  }
252
-
253
  // We need to keep the CSS/HEAD part, the regenearion is only about blocks
254
-
255
  if (is_object($email)) {
256
  $result = TNP_Composer::get_main_wrapper_open($email) . $result . TNP_Composer::get_main_wrapper_close($email);
257
  }
@@ -263,13 +254,13 @@ class NewsletterEmails extends NewsletterModule {
263
  } else {
264
 
265
  }
266
-
267
  if (is_object($email)) {
268
  $email->message = $result;
269
  $email->subject = $subject;
270
  return true;
271
  }
272
-
273
  // Kept for compatibility
274
  return array('body' => $result, 'subject' => $subject);
275
  }
@@ -310,8 +301,9 @@ class NewsletterEmails extends NewsletterModule {
310
  $block_options = get_option('newsletter_main');
311
 
312
  $block = $this->get_block($block_id);
313
-
314
- if (!isset($context['type'])) $context['type'] = '';
 
315
 
316
  // Block not found
317
  if (!$block) {
@@ -332,7 +324,7 @@ class NewsletterEmails extends NewsletterModule {
332
  return;
333
  }
334
 
335
- $out = array('subject' => '', 'return_empty_message' => false, 'stop'=>false, 'skip'=>false);
336
 
337
 
338
  ob_start();
@@ -377,9 +369,9 @@ class NewsletterEmails extends NewsletterModule {
377
  $style .= 'padding-bottom: ' . $options['block_padding_bottom'] . 'px; ';
378
  $style .= 'background-color: ' . $options['block_background'] . ';';
379
 
380
- if (isset($options['block_background_gradient'])) {
381
- $style .= 'background: linear-gradient(180deg, ' . $options['block_background'] . ' 0%, ' . $options['block_background_2'] . ' 100%);';
382
- }
383
 
384
 
385
 
@@ -420,14 +412,14 @@ class NewsletterEmails extends NewsletterModule {
420
  * @param type $block_id
421
  * @param type $wrapper
422
  */
423
- function tnpc_render_callback() {
424
- $block_id = $_POST['b'];
425
- $wrapper = isset( $_POST['full'] );
426
- $options = $this->restore_options_from_request();
427
-
428
- $this->render_block( $block_id, $wrapper, $options );
429
- wp_die();
430
- }
431
 
432
  function tnpc_preview_callback() {
433
  $email = Newsletter::instance()->get_email($_REQUEST['id'], ARRAY_A);
@@ -439,12 +431,12 @@ class NewsletterEmails extends NewsletterModule {
439
 
440
  echo $email['message'];
441
 
442
- wp_die(); // this is required to terminate immediately and return a proper response
443
  }
444
 
445
  function tnpc_css_callback() {
446
  include NEWSLETTER_DIR . '/emails/tnp-composer/css/newsletter.css';
447
- wp_die(); // this is required to terminate immediately and return a proper response
448
  }
449
 
450
  /** Returns the correct admin page to edit the newsletter with the correct editor. */
@@ -501,23 +493,18 @@ class NewsletterEmails extends NewsletterModule {
501
  return $editor_type;
502
  }
503
 
504
- function hook_wp_loaded() {
505
  global $wpdb;
506
 
507
- $newsletter = Newsletter::instance();
508
-
509
- switch ($newsletter->action) {
510
  case 'v':
511
  case 'view':
512
- $email = $this->get_email($_GET['id']);
513
  if (empty($email)) {
514
  header("HTTP/1.0 404 Not Found");
515
  die('Email not found');
516
  }
517
 
518
- $user = NewsletterSubscription::instance()->get_user_from_request();
519
-
520
- if (!is_user_logged_in() || !(current_user_can('editor') || current_user_can('administrator'))) {
521
 
522
  if ($email->status == 'new') {
523
  header("HTTP/1.0 404 Not Found");
@@ -542,7 +529,7 @@ class NewsletterEmails extends NewsletterModule {
542
  header('X-Robots-Tag: noindex,nofollow,noarchive');
543
  header('Cache-Control: no-cache,no-store,private');
544
 
545
- echo $newsletter->replace($email->message, $user, $email);
546
 
547
  die();
548
  break;
@@ -674,7 +661,7 @@ class NewsletterEmails extends NewsletterModule {
674
  $email['message_text'] = 'You need a modern email client to read this email. Read it online: {email_url}.';
675
  }
676
 
677
- $email = $newsletter->save_email($email);
678
 
679
  $edit_url = $this->get_editor_url($email->id, $email->editor);
680
 
@@ -782,7 +769,7 @@ class NewsletterEmails extends NewsletterModule {
782
  $this->blocks = array_merge($extended, $this->blocks);
783
 
784
  $dirs = apply_filters('newsletter_blocks_dir', array());
785
-
786
  //var_dump($dirs);
787
  //die();
788
 
@@ -946,7 +933,7 @@ class NewsletterEmails extends NewsletterModule {
946
  return;
947
  }
948
  $original_subject = $email->subject;
949
-
950
  if ($email->subject == '') {
951
  $email->subject = '[TEST] Dummy subject, it was empty (remember to set it)';
952
  } else {
@@ -983,50 +970,48 @@ class NewsletterEmails extends NewsletterModule {
983
  $email->subject = $original_subject;
984
  }
985
 
986
- function restore_options_from_request() {
987
-
988
- if ( isset( $_POST['options'] ) && is_array( $_POST['options'] ) ) {
989
- // Get all block options
990
- $options = stripslashes_deep( $_POST['options'] );
991
 
992
- // Deserialize inline edits when
993
- // render is preformed on saving block options
994
- if ( isset( $options['inline_edits'] ) && is_serialized( $options['inline_edits'] ) ) {
995
- $options['inline_edits'] = unserialize( $options['inline_edits'] );
996
- }
997
 
998
- // Restore inline edits from data-json
999
- // coming from inline editing
1000
- // and merge with current inline edit
1001
- if ( isset( $_POST['encoded_options'] ) ) {
1002
- $decoded_options = $this->options_decode( $_POST['encoded_options'] );
1003
-
1004
- $to_merge_inline_edits = [];
1005
 
1006
- if ( isset( $decoded_options['inline_edits'] ) ) {
1007
- foreach ( $decoded_options['inline_edits'] as $decoded_inline_edit ) {
1008
- $to_merge_inline_edits[ $decoded_inline_edit['post_id'] . $decoded_inline_edit['type'] ] = $decoded_inline_edit;
1009
- }
1010
- }
1011
 
1012
- //Overwrite with new edited content
1013
- if ( isset( $options['inline_edits'] ) ) {
1014
- foreach ( $options['inline_edits'] as $inline_edit ) {
1015
- $to_merge_inline_edits[ $inline_edit['post_id'] . $inline_edit['type'] ] = $inline_edit;
1016
- }
1017
- }
1018
 
1019
- $options['inline_edits'] = array_values( $to_merge_inline_edits );
1020
- $options = array_merge( $decoded_options, $options );
1021
- }
 
 
1022
 
1023
- return $options;
 
 
 
 
 
1024
 
1025
- }
 
 
1026
 
1027
- return array();
 
1028
 
1029
- }
 
1030
 
1031
  }
1032
 
11
  const EDITOR_TINYMCE = 0;
12
 
13
  static $PRESETS_LIST;
 
14
  // Cache
15
  var $blocks = null;
16
 
28
  self::$PRESETS_LIST = array("cta", "invite", "announcement", "posts", "sales", "product", "tour", "simple", "blank");
29
  $this->themes = new NewsletterThemes('emails');
30
  parent::__construct('emails', '1.1.5');
31
+ add_action('newsletter_action', array($this, 'hook_newsletter_action'), 13, 3);
32
 
33
  if (is_admin()) {
34
  add_action('wp_ajax_tnpc_render', array($this, 'tnpc_render_callback'));
93
  $options = $this->options_decode(stripslashes_deep($_REQUEST['options']));
94
 
95
  $context = array('type' => '');
96
+ if (isset($_REQUEST['context_type'])) {
97
  $context['type'] = $_REQUEST['context_type'];
98
+ }
 
 
 
 
 
 
 
 
 
99
 
100
  $controls = new NewsletterControls($options);
101
  $fields = new NewsletterFields($controls);
103
  $controls->init();
104
  echo '<input type="hidden" name="action" value="tnpc_render">';
105
  echo '<input type="hidden" name="b" value="' . esc_attr($_REQUEST['id']) . '">';
106
+ echo '<input type="hidden" name="context_type" value="' . esc_attr($context['type']) . '">';
107
  $inline_edits = '';
108
  if (isset($controls->data['inline_edits'])) {
109
  $inline_edits = $controls->data['inline_edits'];
110
  }
111
+ echo '<input type="hidden" name="options[inline_edits]" value="' . esc_attr(serialize($inline_edits)) . '">';
112
 
113
  ob_start();
114
  include $block['dir'] . '/options.php';
153
  echo $content;
154
  }
155
 
156
+ die();
157
  }
158
 
159
  function has_dynamic_blocks($theme) {
166
  if (!$block) {
167
  continue;
168
  }
169
+ if ($block['type'] == 'dynamic') {
170
  return true;
171
+ }
172
  }
173
  return false;
174
  }
186
  * @return string
187
  */
188
  function regenerate($email, $context = array()) {
189
+
190
  // Cannot be removed due to compatibility issues with old Automated versions
191
  if (is_object($email)) {
192
  $theme = $email->message;
193
  } else {
194
  $theme = $email;
195
  }
196
+
197
  //$this->logger->debug('Starting email regeneration');
198
  //$this->logger->debug($context);
199
 
205
  $context = array_merge(array('last_run' => 0, 'type' => ''), $context);
206
 
207
  preg_match_all('/data-json="(.*?)"/m', $theme, $matches, PREG_PATTERN_ORDER);
208
+
209
  $result = '';
210
  $subject = '';
211
 
240
  $block_html = ob_get_clean();
241
  $result .= $block_html;
242
  }
243
+
244
  // We need to keep the CSS/HEAD part, the regenearion is only about blocks
245
+
246
  if (is_object($email)) {
247
  $result = TNP_Composer::get_main_wrapper_open($email) . $result . TNP_Composer::get_main_wrapper_close($email);
248
  }
254
  } else {
255
 
256
  }
257
+
258
  if (is_object($email)) {
259
  $email->message = $result;
260
  $email->subject = $subject;
261
  return true;
262
  }
263
+
264
  // Kept for compatibility
265
  return array('body' => $result, 'subject' => $subject);
266
  }
301
  $block_options = get_option('newsletter_main');
302
 
303
  $block = $this->get_block($block_id);
304
+
305
+ if (!isset($context['type']))
306
+ $context['type'] = '';
307
 
308
  // Block not found
309
  if (!$block) {
324
  return;
325
  }
326
 
327
+ $out = array('subject' => '', 'return_empty_message' => false, 'stop' => false, 'skip' => false);
328
 
329
 
330
  ob_start();
369
  $style .= 'padding-bottom: ' . $options['block_padding_bottom'] . 'px; ';
370
  $style .= 'background-color: ' . $options['block_background'] . ';';
371
 
372
+ if (isset($options['block_background_gradient'])) {
373
+ $style .= 'background: linear-gradient(180deg, ' . $options['block_background'] . ' 0%, ' . $options['block_background_2'] . ' 100%);';
374
+ }
375
 
376
 
377
 
412
  * @param type $block_id
413
  * @param type $wrapper
414
  */
415
+ function tnpc_render_callback() {
416
+ $block_id = $_POST['b'];
417
+ $wrapper = isset($_POST['full']);
418
+ $options = $this->restore_options_from_request();
419
+
420
+ $this->render_block($block_id, $wrapper, $options);
421
+ wp_die();
422
+ }
423
 
424
  function tnpc_preview_callback() {
425
  $email = Newsletter::instance()->get_email($_REQUEST['id'], ARRAY_A);
431
 
432
  echo $email['message'];
433
 
434
+ wp_die();
435
  }
436
 
437
  function tnpc_css_callback() {
438
  include NEWSLETTER_DIR . '/emails/tnp-composer/css/newsletter.css';
439
+ wp_die();
440
  }
441
 
442
  /** Returns the correct admin page to edit the newsletter with the correct editor. */
493
  return $editor_type;
494
  }
495
 
496
+ function hook_newsletter_action($action, $user, $email) {
497
  global $wpdb;
498
 
499
+ switch ($action) {
 
 
500
  case 'v':
501
  case 'view':
 
502
  if (empty($email)) {
503
  header("HTTP/1.0 404 Not Found");
504
  die('Email not found');
505
  }
506
 
507
+ if (!Newsletter::instance()->is_allowed()) {
 
 
508
 
509
  if ($email->status == 'new') {
510
  header("HTTP/1.0 404 Not Found");
529
  header('X-Robots-Tag: noindex,nofollow,noarchive');
530
  header('Cache-Control: no-cache,no-store,private');
531
 
532
+ echo $this->replace($email->message, $user, $email);
533
 
534
  die();
535
  break;
661
  $email['message_text'] = 'You need a modern email client to read this email. Read it online: {email_url}.';
662
  }
663
 
664
+ $email = $this->save_email($email);
665
 
666
  $edit_url = $this->get_editor_url($email->id, $email->editor);
667
 
769
  $this->blocks = array_merge($extended, $this->blocks);
770
 
771
  $dirs = apply_filters('newsletter_blocks_dir', array());
772
+
773
  //var_dump($dirs);
774
  //die();
775
 
933
  return;
934
  }
935
  $original_subject = $email->subject;
936
+
937
  if ($email->subject == '') {
938
  $email->subject = '[TEST] Dummy subject, it was empty (remember to set it)';
939
  } else {
970
  $email->subject = $original_subject;
971
  }
972
 
973
+ function restore_options_from_request() {
 
 
 
 
974
 
975
+ if (isset($_POST['options']) && is_array($_POST['options'])) {
976
+ // Get all block options
977
+ $options = stripslashes_deep($_POST['options']);
 
 
978
 
979
+ // Deserialize inline edits when
980
+ // render is preformed on saving block options
981
+ if (isset($options['inline_edits']) && is_serialized($options['inline_edits'])) {
982
+ $options['inline_edits'] = unserialize($options['inline_edits']);
983
+ }
 
 
984
 
985
+ // Restore inline edits from data-json
986
+ // coming from inline editing
987
+ // and merge with current inline edit
988
+ if (isset($_POST['encoded_options'])) {
989
+ $decoded_options = $this->options_decode($_POST['encoded_options']);
990
 
991
+ $to_merge_inline_edits = [];
 
 
 
 
 
992
 
993
+ if (isset($decoded_options['inline_edits'])) {
994
+ foreach ($decoded_options['inline_edits'] as $decoded_inline_edit) {
995
+ $to_merge_inline_edits[$decoded_inline_edit['post_id'] . $decoded_inline_edit['type']] = $decoded_inline_edit;
996
+ }
997
+ }
998
 
999
+ //Overwrite with new edited content
1000
+ if (isset($options['inline_edits'])) {
1001
+ foreach ($options['inline_edits'] as $inline_edit) {
1002
+ $to_merge_inline_edits[$inline_edit['post_id'] . $inline_edit['type']] = $inline_edit;
1003
+ }
1004
+ }
1005
 
1006
+ $options['inline_edits'] = array_values($to_merge_inline_edits);
1007
+ $options = array_merge($decoded_options, $options);
1008
+ }
1009
 
1010
+ return $options;
1011
+ }
1012
 
1013
+ return array();
1014
+ }
1015
 
1016
  }
1017
 
includes/addon.php CHANGED
@@ -16,7 +16,7 @@ class NewsletterAddon {
16
  $this->version = $version;
17
  if (is_admin()) {
18
  $old_version = get_option('newsletter_' . $name . '_version');
19
- if ($version != $old_version) {
20
  $this->upgrade($old_version === false);
21
  update_option('newsletter_' . $name . '_version', $version, false);
22
  }
@@ -24,15 +24,25 @@ class NewsletterAddon {
24
  add_action('newsletter_init', array($this, 'init'));
25
  }
26
 
 
 
 
 
 
27
  function upgrade($first_install = false) {
28
 
29
  }
30
-
 
 
 
 
31
  function init() {
32
 
33
  }
34
 
35
  /**
 
36
  *
37
  * @return NewsletterLogger
38
  */
@@ -44,6 +54,7 @@ class NewsletterAddon {
44
  }
45
 
46
  /**
 
47
  *
48
  * @return NewsletterLogger
49
  */
@@ -54,12 +65,23 @@ class NewsletterAddon {
54
  return $this->admin_logger;
55
  }
56
 
 
 
 
 
 
57
  function setup_options() {
58
- if ($this->options)
59
  return;
 
60
  $this->options = get_option('newsletter_' . $this->name, array());
61
  }
62
 
 
 
 
 
 
63
  function save_options($options) {
64
  update_option('newsletter_' . $this->name, $options);
65
  $this->options = $options;
@@ -72,6 +94,8 @@ class NewsletterAddon {
72
  }
73
 
74
  /**
 
 
75
  * @global wpdb $wpdb
76
  * @param string $query
77
  */
@@ -86,11 +110,17 @@ class NewsletterAddon {
86
  }
87
  return $r;
88
  }
89
-
90
  }
91
 
92
  /**
93
- * Used by mailers as base-class.
 
 
 
 
 
 
 
94
  */
95
  class NewsletterMailerAddon extends NewsletterAddon {
96
 
@@ -102,6 +132,9 @@ class NewsletterMailerAddon extends NewsletterAddon {
102
  $this->enabled = !empty($this->options['enabled']);
103
  }
104
 
 
 
 
105
  function init() {
106
  parent::init();
107
  add_action('newsletter_register_mailer', function () {
@@ -112,7 +145,7 @@ class NewsletterMailerAddon extends NewsletterAddon {
112
  }
113
 
114
  /**
115
- *
116
  * @return NewsletterMailer
117
  */
118
  function get_mailer() {
@@ -132,6 +165,14 @@ class NewsletterMailerAddon extends NewsletterAddon {
132
  $this->enabled = !empty($options['enabled']);
133
  }
134
 
 
 
 
 
 
 
 
 
135
  static function get_test_message($to, $subject = '') {
136
  $message = new TNP_Mailer_Message();
137
  $message->to = $to;
@@ -152,6 +193,14 @@ class NewsletterMailerAddon extends NewsletterAddon {
152
  return $message;
153
  }
154
 
 
 
 
 
 
 
 
 
155
  function get_test_messages($to, $count) {
156
  $messages = array();
157
  for ($i = 0; $i < $count; $i++) {
16
  $this->version = $version;
17
  if (is_admin()) {
18
  $old_version = get_option('newsletter_' . $name . '_version');
19
+ if ($version !== $old_version) {
20
  $this->upgrade($old_version === false);
21
  update_option('newsletter_' . $name . '_version', $version, false);
22
  }
24
  add_action('newsletter_init', array($this, 'init'));
25
  }
26
 
27
+ /**
28
+ * Method to be overridden and invoked on version change or on first install.
29
+ *
30
+ * @param bool $first_install
31
+ */
32
  function upgrade($first_install = false) {
33
 
34
  }
35
+
36
+ /**
37
+ * Method to be overridden to initialize the add-on. It is invoked when Newsletter
38
+ * fires the <code>newsletter_init</code> event.
39
+ */
40
  function init() {
41
 
42
  }
43
 
44
  /**
45
+ * General logger for this add-on.
46
  *
47
  * @return NewsletterLogger
48
  */
54
  }
55
 
56
  /**
57
+ * Specific logger for administrator actions.
58
  *
59
  * @return NewsletterLogger
60
  */
65
  return $this->admin_logger;
66
  }
67
 
68
+ /**
69
+ * Loads and prepares the options. It can be used to late initialize the options to save some resources on
70
+ * add-ons which do not need to do something on each page load.
71
+ * @return array
72
+ */
73
  function setup_options() {
74
+ if ($this->options) {
75
  return;
76
+ }
77
  $this->options = get_option('newsletter_' . $this->name, array());
78
  }
79
 
80
+ /**
81
+ * Saved the options under the correct keys and update the internal $options
82
+ * property.
83
+ * @param array $options
84
+ */
85
  function save_options($options) {
86
  update_option('newsletter_' . $this->name, $options);
87
  $this->options = $options;
94
  }
95
 
96
  /**
97
+ * Equivalent to $wpdb->query() but logs the event in case of error.
98
+ *
99
  * @global wpdb $wpdb
100
  * @param string $query
101
  */
110
  }
111
  return $r;
112
  }
 
113
  }
114
 
115
  /**
116
+ * Used by mailers add-ons as base-class. Some specific options collected by the mailer
117
+ * are interpreted automatically.
118
+ *
119
+ * They are:
120
+ *
121
+ * `enabled` if not empty it means the mailer is active and should be registered
122
+ *
123
+ * The options are set up in the constructor, there is no need to setup them later.
124
  */
125
  class NewsletterMailerAddon extends NewsletterAddon {
126
 
132
  $this->enabled = !empty($this->options['enabled']);
133
  }
134
 
135
+ /**
136
+ * This method must be called as `parent::init()` is overridden.
137
+ */
138
  function init() {
139
  parent::init();
140
  add_action('newsletter_register_mailer', function () {
145
  }
146
 
147
  /**
148
+ * Must return an implementation of NewsletterMailer.
149
  * @return NewsletterMailer
150
  */
151
  function get_mailer() {
165
  $this->enabled = !empty($options['enabled']);
166
  }
167
 
168
+ /**
169
+ * Returns a TNP_Mailer_Message built to send a test message to the <code>$to</code>
170
+ * email address.
171
+ *
172
+ * @param string $to
173
+ * @param string $subject
174
+ * @return TNP_Mailer_Message
175
+ */
176
  static function get_test_message($to, $subject = '') {
177
  $message = new TNP_Mailer_Message();
178
  $message->to = $to;
193
  return $message;
194
  }
195
 
196
+ /**
197
+ * Returns a set of test messages to be sent to the specified email address. Used for
198
+ * turbo mode tests. Each message has a different generated subject.
199
+ *
200
+ * @param string $to The destination mailbox
201
+ * @param int $count Number of message objects to create
202
+ * @return TNP_Mailer_Message[]
203
+ */
204
  function get_test_messages($to, $count) {
205
  $messages = array();
206
  for ($i = 0; $i < $count; $i++) {
includes/controls.php CHANGED
@@ -289,8 +289,8 @@ class NewsletterControls {
289
  $this->button_data = $_REQUEST['btn'];
290
  }
291
  // Fields analysis
292
- if (isset($_REQUEST['fields'])) {
293
- $fields = $_REQUEST['fields'];
294
  if (is_array($fields)) {
295
  foreach ($fields as $name => $type) {
296
  if ($type == 'datetime') {
@@ -299,7 +299,7 @@ class NewsletterControls {
299
  // GMT 0 and then we subtract the GMT offset (the example date and time on GMT+2 happens
300
  // "before").
301
 
302
- $time = gmmktime($_REQUEST[$name . '_hour'], 0, 0, $_REQUEST[$name . '_month'], $_REQUEST[$name . '_day'], $_REQUEST[$name . '_year']);
303
  $time -= get_option('gmt_offset') * 3600;
304
  $this->data[$name] = $time;
305
  }
@@ -340,9 +340,10 @@ class NewsletterControls {
340
  die('Invalid call');
341
  }
342
 
343
- function get_value($name) {
344
- if (!isset($this->data[$name]))
345
- return null;
 
346
  return $this->data[$name];
347
  }
348
 
@@ -1255,8 +1256,13 @@ class NewsletterControls {
1255
  * Date and time (hour) selector. Timestamp stored.
1256
  */
1257
  function datetime($name) {
1258
- echo '<input type="hidden" name="fields[' . esc_attr($name) . ']" value="datetime">';
1259
- $time = $this->data[$name] + get_option('gmt_offset') * 3600;
 
 
 
 
 
1260
  $year = gmdate('Y', $time);
1261
  $day = gmdate('j', $time);
1262
  $month = gmdate('m', $time);
289
  $this->button_data = $_REQUEST['btn'];
290
  }
291
  // Fields analysis
292
+ if (isset($_REQUEST['tnp_fields'])) {
293
+ $fields = $_REQUEST['tnp_fields'];
294
  if (is_array($fields)) {
295
  foreach ($fields as $name => $type) {
296
  if ($type == 'datetime') {
299
  // GMT 0 and then we subtract the GMT offset (the example date and time on GMT+2 happens
300
  // "before").
301
 
302
+ $time = gmmktime((int)$_REQUEST[$name . '_hour'], 0, 0, (int)$_REQUEST[$name . '_month'], (int)$_REQUEST[$name . '_day'], (int)$_REQUEST[$name . '_year']);
303
  $time -= get_option('gmt_offset') * 3600;
304
  $this->data[$name] = $time;
305
  }
340
  die('Invalid call');
341
  }
342
 
343
+ function get_value($name, $def = null) {
344
+ if (!isset($this->data[$name])) {
345
+ return $def;
346
+ }
347
  return $this->data[$name];
348
  }
349
 
1256
  * Date and time (hour) selector. Timestamp stored.
1257
  */
1258
  function datetime($name) {
1259
+ echo '<input type="hidden" name="tnp_fields[' . esc_attr($name) . ']" value="datetime">';
1260
+ $value = (int)$this->get_value($name);
1261
+ if (empty($value)) {
1262
+ $value = time();
1263
+ }
1264
+
1265
+ $time = $value + get_option('gmt_offset') * 3600;
1266
  $year = gmdate('Y', $time);
1267
  $day = gmdate('j', $time);
1268
  $month = gmdate('m', $time);
includes/fields.php CHANGED
@@ -149,7 +149,7 @@ class NewsletterFields {
149
 
150
  if (version_compare($wp_version, '4.8', '>=')) {
151
  echo '<script>wp.editor.remove("options-', $name, '");';
152
- echo 'wp.editor.initialize("options-', $name, '", { tinymce: {content_style: "body {background-color: #f4f4f4;}", toolbar1: "undo redo | formatselect fontselect fontsizeselect | bold italic forecolor backcolor | link unlink | alignleft aligncenter alignright alignjustify | bullist numlist outdent indent | removeformat | help", fontsize_formats: "11px 12px 14px 16px 18px 24px 36px 48px", plugins: "link textcolor colorpicker", default_link_target: "_blank", relative_urls : false, convert_urls: false}});</script>';
153
  }
154
  $this->_description($attrs);
155
  $this->_close();
149
 
150
  if (version_compare($wp_version, '4.8', '>=')) {
151
  echo '<script>wp.editor.remove("options-', $name, '");';
152
+ echo 'wp.editor.initialize("options-', $name, '", { tinymce: {content_style: "body {background-color: #f4f4f4;}", toolbar1: "undo redo | formatselect fontselect fontsizeselect | bold italic forecolor backcolor | link unlink | alignleft aligncenter alignright alignjustify | bullist numlist outdent indent | removeformat | wp_add_media | charmap", fontsize_formats: "11px 12px 14px 16px 18px 24px 36px 48px", plugins: "link textcolor colorpicker lists wordpress charmap", default_link_target: "_blank", relative_urls : false, convert_urls: false}});</script>';
153
  }
154
  $this->_description($attrs);
155
  $this->_close();
includes/helper.php CHANGED
@@ -95,11 +95,14 @@ function tnp_post_date($post, $format = null) {
95
  * @return string
96
  */
97
  function tnp_media_resize($media_id, $size) {
98
- if (empty($media_id))
99
  return '';
 
 
100
  $relative_file = get_post_meta($media_id, '_wp_attached_file', true);
101
- if (empty($relative_file))
102
  return '';
 
103
 
104
  $width = $size[0];
105
  $height = $size[1];
@@ -109,6 +112,14 @@ function tnp_media_resize($media_id, $size) {
109
  }
110
 
111
  $uploads = wp_upload_dir();
 
 
 
 
 
 
 
 
112
  $absolute_file = $uploads['basedir'] . '/' . $relative_file;
113
  // Relative and absolute name of the thumbnail.
114
  $pathinfo = pathinfo($relative_file);
@@ -189,6 +200,13 @@ function tnp_resize($media_id, $size) {
189
  if (empty($relative_file)) {
190
  return null;
191
  }
 
 
 
 
 
 
 
192
 
193
  $width = $size[0];
194
  $height = $size[1];
95
  * @return string
96
  */
97
  function tnp_media_resize($media_id, $size) {
98
+ if (empty($media_id)) {
99
  return '';
100
+ }
101
+
102
  $relative_file = get_post_meta($media_id, '_wp_attached_file', true);
103
+ if (empty($relative_file)) {
104
  return '';
105
+ }
106
 
107
  $width = $size[0];
108
  $height = $size[1];
112
  }
113
 
114
  $uploads = wp_upload_dir();
115
+
116
+ // Based on _wp_relative_upload_path() function for blog which store the
117
+ // full patch of media files
118
+ if (0 === strpos($relative_file, $uploads['basedir'])) {
119
+ $relative_file = str_replace($uploads['basedir'], '', $relative_file);
120
+ $relative_file = ltrim($relative_file, '/');
121
+ }
122
+
123
  $absolute_file = $uploads['basedir'] . '/' . $relative_file;
124
  // Relative and absolute name of the thumbnail.
125
  $pathinfo = pathinfo($relative_file);
200
  if (empty($relative_file)) {
201
  return null;
202
  }
203
+
204
+ // Based on _wp_relative_upload_path() function for blog which store the
205
+ // full patch of media files
206
+ if (0 === strpos($relative_file, $uploads['basedir'])) {
207
+ $relative_file = str_replace($uploads['basedir'], '', $relative_file);
208
+ $relative_file = ltrim($relative_file, '/');
209
+ }
210
 
211
  $width = $size[0];
212
  $height = $size[1];
includes/module.php CHANGED
@@ -154,7 +154,10 @@ abstract class TNP_User {
154
  * @property array $options The subscriber status
155
  * */
156
  abstract class TNP_Email {
157
-
 
 
 
158
  }
159
 
160
  class NewsletterModule {
@@ -965,6 +968,8 @@ class NewsletterModule {
965
  /** Searches for a user using the nk parameter or the ni and nt parameters. Tries even with the newsletter cookie.
966
  * If found, the user object is returned or null.
967
  * The user is returned without regards to his status that should be checked by caller.
 
 
968
  *
969
  * @return TNP_User
970
  */
@@ -1091,7 +1096,7 @@ class NewsletterModule {
1091
  if ($die_on_fail) {
1092
  die(__('No subscriber found.', 'newsletter'));
1093
  } else {
1094
- return null;
1095
  }
1096
  }
1097
 
@@ -1105,11 +1110,17 @@ class NewsletterModule {
1105
  if ($die_on_fail) {
1106
  die(__('No subscriber found.', 'newsletter'));
1107
  } else {
1108
- return null;
1109
  }
1110
  }
1111
  return $user;
1112
  }
 
 
 
 
 
 
1113
 
1114
  /**
1115
  * @param string $language The language for the list labels (it does not affect the lists returned)
@@ -1495,7 +1506,7 @@ class NewsletterModule {
1495
  $this->logger->debug('Status change to ' . $status . ' of subscriber ' . $user->id . ' from ' . $_SERVER['REQUEST_URI']);
1496
 
1497
  $this->query($wpdb->prepare("update " . NEWSLETTER_USERS_TABLE . " set status=%s where id=%d limit 1", $status, $user->id));
1498
-
1499
  return $this->get_user($user);
1500
  }
1501
 
@@ -1511,8 +1522,7 @@ class NewsletterModule {
1511
  $token = $this->get_token();
1512
 
1513
  $this->query($wpdb->prepare("update " . NEWSLETTER_USERS_TABLE . " set token=%s where id=%d limit 1", $token, $user->id));
1514
-
1515
- return $this->get_user($user);
1516
  }
1517
 
1518
  /**
@@ -2108,6 +2118,15 @@ class NewsletterModule {
2108
 
2109
  return '[' . $blogname . '] ' . $subject;
2110
  }
 
 
 
 
 
 
 
 
 
2111
 
2112
  }
2113
 
154
  * @property array $options The subscriber status
155
  * */
156
  abstract class TNP_Email {
157
+ const STATUS_DRAFT = 'new';
158
+ const STATUS_SENT = 'sent';
159
+ const STATUS_SENDING = 'sending';
160
+ const STATUS_PAUSED = 'paused';
161
  }
162
 
163
  class NewsletterModule {
968
  /** Searches for a user using the nk parameter or the ni and nt parameters. Tries even with the newsletter cookie.
969
  * If found, the user object is returned or null.
970
  * The user is returned without regards to his status that should be checked by caller.
971
+ *
972
+ * DO NOT REMOVE EVEN IF OLD
973
  *
974
  * @return TNP_User
975
  */
1096
  if ($die_on_fail) {
1097
  die(__('No subscriber found.', 'newsletter'));
1098
  } else {
1099
+ return $this->get_user_from_logged_in_user();
1100
  }
1101
  }
1102
 
1110
  if ($die_on_fail) {
1111
  die(__('No subscriber found.', 'newsletter'));
1112
  } else {
1113
+ return $this->get_user_from_logged_in_user();
1114
  }
1115
  }
1116
  return $user;
1117
  }
1118
+
1119
+ function get_user_from_logged_in_user() {
1120
+ if (is_user_logged_in()) {
1121
+ return $this->get_user_by_wp_user_id(get_current_user_id());
1122
+ }
1123
+ }
1124
 
1125
  /**
1126
  * @param string $language The language for the list labels (it does not affect the lists returned)
1506
  $this->logger->debug('Status change to ' . $status . ' of subscriber ' . $user->id . ' from ' . $_SERVER['REQUEST_URI']);
1507
 
1508
  $this->query($wpdb->prepare("update " . NEWSLETTER_USERS_TABLE . " set status=%s where id=%d limit 1", $status, $user->id));
1509
+ $user->status = $status;
1510
  return $this->get_user($user);
1511
  }
1512
 
1522
  $token = $this->get_token();
1523
 
1524
  $this->query($wpdb->prepare("update " . NEWSLETTER_USERS_TABLE . " set token=%s where id=%d limit 1", $token, $user->id));
1525
+ $user->token = $token;
 
1526
  }
1527
 
1528
  /**
2118
 
2119
  return '[' . $blogname . '] ' . $subject;
2120
  }
2121
+
2122
+ function dienow($message, $admin_message = null)
2123
+ {
2124
+ if ($admin_message && current_user_can('administrator')) {
2125
+ $message .= '<br><br><strong>Text below only visibile to administrarors</strong><br>';
2126
+ $message .= $admin_message;
2127
+ }
2128
+ wp_die($message, 200);
2129
+ }
2130
 
2131
  }
2132
 
plugin.php CHANGED
@@ -4,7 +4,7 @@
4
  Plugin Name: Newsletter
5
  Plugin URI: https://www.thenewsletterplugin.com/plugins/newsletter
6
  Description: Newsletter is a cool plugin to create your own subscriber list, to send newsletters, to build your business. <strong>Before update give a look to <a href="https://www.thenewsletterplugin.com/category/release">this page</a> to know what's changed.</strong>
7
- Version: 6.6.5
8
  Author: Stefano Lissa & The Newsletter Team
9
  Author URI: https://www.thenewsletterplugin.com
10
  Disclaimer: Use at your own risk. No warranty expressed or implied is provided.
@@ -35,7 +35,7 @@ if (version_compare(phpversion(), '5.6', '<')) {
35
  return;
36
  }
37
 
38
- define('NEWSLETTER_VERSION', '6.6.5');
39
 
40
  global $newsletter, $wpdb;
41
 
@@ -254,8 +254,9 @@ class Newsletter extends NewsletterModule {
254
  die();
255
  }
256
 
257
- //$user = $this->get_user_from_request();
258
- do_action('newsletter_action', $this->action);
 
259
  }
260
 
261
  function update_cron_stats() {
4
  Plugin Name: Newsletter
5
  Plugin URI: https://www.thenewsletterplugin.com/plugins/newsletter
6
  Description: Newsletter is a cool plugin to create your own subscriber list, to send newsletters, to build your business. <strong>Before update give a look to <a href="https://www.thenewsletterplugin.com/category/release">this page</a> to know what's changed.</strong>
7
+ Version: 6.6.6
8
  Author: Stefano Lissa & The Newsletter Team
9
  Author URI: https://www.thenewsletterplugin.com
10
  Disclaimer: Use at your own risk. No warranty expressed or implied is provided.
35
  return;
36
  }
37
 
38
+ define('NEWSLETTER_VERSION', '6.6.6');
39
 
40
  global $newsletter, $wpdb;
41
 
254
  die();
255
  }
256
 
257
+ $user = $this->get_user_from_request();
258
+ $email = $this->get_email_from_request();
259
+ do_action('newsletter_action', $this->action, $user, $email);
260
  }
261
 
262
  function update_cron_stats() {
profile/profile.php CHANGED
@@ -21,23 +21,24 @@ class NewsletterProfile extends NewsletterModule {
21
  add_shortcode('newsletter_profile', array($this, 'shortcode_newsletter_profile'));
22
  add_filter('newsletter_replace', array($this, 'hook_newsletter_replace'), 10, 3);
23
  add_filter('newsletter_page_text', array($this, 'hook_newsletter_page_text'), 10, 3);
24
- add_action('newsletter_action', array($this, 'hook_newsletter_action'));
25
  }
26
 
27
- function hook_newsletter_action($action) {
28
- global $wpdb;
 
 
 
 
 
29
 
30
  switch ($action) {
31
  case 'profile':
32
  case 'p':
33
  case 'pe':
34
- $user = $this->check_user();
35
- $email = $this->get_email_from_request();
36
- if ($user == null) {
37
- die('No subscriber found.');
38
- }
39
  $profile_url = $this->build_message_url($this->options['url'], 'profile', $user, $email);
40
- $profile_url = apply_filters('newsletter_profile_url', $profile_url, $user, $email);
41
 
42
  wp_redirect($profile_url);
43
  die();
@@ -46,15 +47,13 @@ class NewsletterProfile extends NewsletterModule {
46
 
47
  case 'profile-save':
48
  case 'ps':
49
- $user = $this->save_profile();
50
- $email = $this->get_email_from_request();
51
  // $user->alert is a temporary field
52
  wp_redirect($this->build_message_url($this->options['url'], 'profile', $user, $email, $user->alert));
53
  die();
54
  break;
55
 
56
  case 'profile_export':
57
- $user = $this->get_user_from_request(true);
58
  header('Content-Type: application/json;charset=UTF-8');
59
  echo $this->to_json($user);
60
  die();
@@ -70,6 +69,9 @@ class NewsletterProfile extends NewsletterModule {
70
  }
71
 
72
  /**
 
 
 
73
  *
74
  * @param stdClass $user
75
  */
@@ -133,29 +135,29 @@ class NewsletterProfile extends NewsletterModule {
133
 
134
  $fields = array('name', 'surname', 'sex', 'created', 'ip', 'email');
135
  $data = array(
136
- 'email'=>$user->email,
137
- 'name'=>$user->name,
138
- 'last_name'=>$user->surname,
139
- 'gender'=>$user->sex,
140
- 'created'=>$user->created,
141
- 'ip'=>$user->ip,
142
- );
143
-
144
  // Lists
145
  $data['lists'] = array();
146
-
147
  $lists = $this->get_lists_public();
148
  foreach ($lists as $list) {
149
  $field = 'list_' . $list->id;
150
  if ($user->$field == 1) {
151
  $data['lists'][] = $list->name;
152
- }
153
  }
154
-
155
  // Profile
156
  $options_profile = get_option('newsletter_profile', array());
157
  $data['profiles'] = array();
158
- for ($i=1; $i<NEWSLETTER_PROFILE_MAX; $i++) {
159
  $field = 'profile_' . $i;
160
  if ($options_profile[$field . '_status'] != 1 && $options_profile[$field . '_status'] != 2) {
161
  continue;
@@ -169,14 +171,16 @@ class NewsletterProfile extends NewsletterModule {
169
  $newsletters = array();
170
  foreach ($sent as $item) {
171
  $action = 'none';
172
- if ($item->open == 1)
173
  $action = 'read';
174
- else if ($item->open == 2)
175
  $action = 'click';
 
176
 
177
  $email = $this->get_email($item->email_id);
178
- if (!$email)
179
  continue;
 
180
  // 'id'=>$item->email_id,
181
  $newsletters[] = array('subject' => $email->subject, 'action' => $action, 'sent' => date('Y-m-d h:i:s', $email->send_on));
182
  }
@@ -191,9 +195,15 @@ class NewsletterProfile extends NewsletterModule {
191
  return json_encode($data, JSON_PRETTY_PRINT);
192
  }
193
 
 
 
 
 
 
 
194
  function get_profile_form($user) {
195
  // Do not pay attention to option name here, it's a compatibility problem
196
-
197
  $language = $this->get_user_language($user);
198
  $options = NewsletterSubscription::instance()->get_options('profile', $language);
199
 
@@ -257,8 +267,9 @@ class NewsletterProfile extends NewsletterModule {
257
  for ($j = 0; $j < count($opts); $j++) {
258
  $opts[$j] = trim($opts[$j]);
259
  $buffer .= '<option';
260
- if ($opts[$j] == $user->$field)
261
  $buffer .= ' selected';
 
262
  $buffer .= '>' . esc_html($opts[$j]) . '</option>';
263
  }
264
  $buffer .= '</select>';
@@ -293,7 +304,7 @@ class NewsletterProfile extends NewsletterModule {
293
  $buffer .= $x['field'];
294
  $buffer .= "</div>\n";
295
  }
296
-
297
  $local_options = $this->get_options('', $this->get_user_language($user));
298
 
299
  // Privacy
@@ -322,16 +333,14 @@ class NewsletterProfile extends NewsletterModule {
322
  }
323
 
324
  /**
325
- * Saves the subscriber data.
 
326
  *
327
  * @return type
328
  */
329
- function save_profile() {
330
  global $wpdb;
331
 
332
- // Get the current subscriber, fail if not found
333
- $user = $this->get_user_from_request(true);
334
-
335
  // Conatains the cleaned up user data to be saved
336
  $data = array();
337
  $data['id'] = $user->id;
@@ -427,7 +436,6 @@ class NewsletterProfile extends NewsletterModule {
427
  if (isset($alert)) {
428
  $user->alert = $alert;
429
  } else {
430
- // TODO: Move this label on profile settings panel
431
  $user->alert = $this->options['saved'];
432
  }
433
  return $user;
@@ -437,7 +445,6 @@ class NewsletterProfile extends NewsletterModule {
437
  global $wpdb, $charset_collate;
438
 
439
  parent::upgrade();
440
-
441
  }
442
 
443
  function admin_menu() {
@@ -446,7 +453,7 @@ class NewsletterProfile extends NewsletterModule {
446
 
447
  // Patch to avoid conflicts with the "newsletter_profile" option of the subscription module
448
  // TODO: Fix it
449
- public function get_prefix($sub = '', $language='') {
450
  if (empty($sub)) {
451
  $sub = 'main';
452
  }
21
  add_shortcode('newsletter_profile', array($this, 'shortcode_newsletter_profile'));
22
  add_filter('newsletter_replace', array($this, 'hook_newsletter_replace'), 10, 3);
23
  add_filter('newsletter_page_text', array($this, 'hook_newsletter_page_text'), 10, 3);
24
+ add_action('newsletter_action', array($this, 'hook_newsletter_action'), 12, 3);
25
  }
26
 
27
+ function hook_newsletter_action($action, $user, $email) {
28
+
29
+ if (in_array($action, ['p', 'profile', 'pe', 'profile-save', 'profile_export', 'ps'])) {
30
+ if (!$user || $user->status != TNP_User::STATUS_CONFIRMED) {
31
+ $this->dienow('The subscriber was not found or is not confirmed.');
32
+ }
33
+ }
34
 
35
  switch ($action) {
36
  case 'profile':
37
  case 'p':
38
  case 'pe':
39
+
 
 
 
 
40
  $profile_url = $this->build_message_url($this->options['url'], 'profile', $user, $email);
41
+ $profile_url = apply_filters('newsletter_profile_url', $profile_url, $user);
42
 
43
  wp_redirect($profile_url);
44
  die();
47
 
48
  case 'profile-save':
49
  case 'ps':
50
+ $user = $this->save_profile($user);
 
51
  // $user->alert is a temporary field
52
  wp_redirect($this->build_message_url($this->options['url'], 'profile', $user, $email, $user->alert));
53
  die();
54
  break;
55
 
56
  case 'profile_export':
 
57
  header('Content-Type: application/json;charset=UTF-8');
58
  echo $this->to_json($user);
59
  die();
69
  }
70
 
71
  /**
72
+ * URL to the subscriber profile edit action. This URL MUST NEVER be changed by
73
+ * 3rd party plugins. Plugins can change the final URL after the action has been executed using the
74
+ * <code>newsletter_profile_url</code> filter.
75
  *
76
  * @param stdClass $user
77
  */
135
 
136
  $fields = array('name', 'surname', 'sex', 'created', 'ip', 'email');
137
  $data = array(
138
+ 'email' => $user->email,
139
+ 'name' => $user->name,
140
+ 'last_name' => $user->surname,
141
+ 'gender' => $user->sex,
142
+ 'created' => $user->created,
143
+ 'ip' => $user->ip,
144
+ );
145
+
146
  // Lists
147
  $data['lists'] = array();
148
+
149
  $lists = $this->get_lists_public();
150
  foreach ($lists as $list) {
151
  $field = 'list_' . $list->id;
152
  if ($user->$field == 1) {
153
  $data['lists'][] = $list->name;
154
+ }
155
  }
156
+
157
  // Profile
158
  $options_profile = get_option('newsletter_profile', array());
159
  $data['profiles'] = array();
160
+ for ($i = 1; $i < NEWSLETTER_PROFILE_MAX; $i++) {
161
  $field = 'profile_' . $i;
162
  if ($options_profile[$field . '_status'] != 1 && $options_profile[$field . '_status'] != 2) {
163
  continue;
171
  $newsletters = array();
172
  foreach ($sent as $item) {
173
  $action = 'none';
174
+ if ($item->open == 1) {
175
  $action = 'read';
176
+ } else if ($item->open == 2) {
177
  $action = 'click';
178
+ }
179
 
180
  $email = $this->get_email($item->email_id);
181
+ if (!$email) {
182
  continue;
183
+ }
184
  // 'id'=>$item->email_id,
185
  $newsletters[] = array('subject' => $email->subject, 'action' => $action, 'sent' => date('Y-m-d h:i:s', $email->send_on));
186
  }
195
  return json_encode($data, JSON_PRETTY_PRINT);
196
  }
197
 
198
+ /**
199
+ * Build the profile editing form for the specified subscriber.
200
+ *
201
+ * @param TNP_User $user
202
+ * @return string
203
+ */
204
  function get_profile_form($user) {
205
  // Do not pay attention to option name here, it's a compatibility problem
206
+
207
  $language = $this->get_user_language($user);
208
  $options = NewsletterSubscription::instance()->get_options('profile', $language);
209
 
267
  for ($j = 0; $j < count($opts); $j++) {
268
  $opts[$j] = trim($opts[$j]);
269
  $buffer .= '<option';
270
+ if ($opts[$j] == $user->$field) {
271
  $buffer .= ' selected';
272
+ }
273
  $buffer .= '>' . esc_html($opts[$j]) . '</option>';
274
  }
275
  $buffer .= '</select>';
304
  $buffer .= $x['field'];
305
  $buffer .= "</div>\n";
306
  }
307
+
308
  $local_options = $this->get_options('', $this->get_user_language($user));
309
 
310
  // Privacy
333
  }
334
 
335
  /**
336
+ * Saves the subscriber data extracting them from the $_REQUEST and for the
337
+ * subscriber identified by the <code>$user</code> object.
338
  *
339
  * @return type
340
  */
341
+ function save_profile($user) {
342
  global $wpdb;
343
 
 
 
 
344
  // Conatains the cleaned up user data to be saved
345
  $data = array();
346
  $data['id'] = $user->id;
436
  if (isset($alert)) {
437
  $user->alert = $alert;
438
  } else {
 
439
  $user->alert = $this->options['saved'];
440
  }
441
  return $user;
445
  global $wpdb, $charset_collate;
446
 
447
  parent::upgrade();
 
448
  }
449
 
450
  function admin_menu() {
453
 
454
  // Patch to avoid conflicts with the "newsletter_profile" option of the subscription module
455
  // TODO: Fix it
456
+ public function get_prefix($sub = '', $language = '') {
457
  if (empty($sub)) {
458
  $sub = 'main';
459
  }
readme.txt CHANGED
@@ -109,10 +109,22 @@ Thank you, The Newsletter Team
109
 
110
  == Changelog ==
111
 
 
 
 
 
 
 
 
 
 
 
 
112
  = 6.6.5 =
113
 
114
  * Fixed email reference lost on double step cancellation
115
  * Update to support Instasend
 
116
 
117
  = 6.6.4 =
118
 
109
 
110
  == Changelog ==
111
 
112
+ = 6.6.6 =
113
+
114
+ * Added check on submission for private lists (error shown only to administrator as debug information)
115
+ * Improved right layout on hero block
116
+ * Improved internal actions management (better performances)
117
+ * Added lists, media selector, charmap on text block
118
+ * Absolute path fix form media file with non relative path on database
119
+ * Internal admin pages review for code coherence with our standard
120
+ * Changed the action name from `newsletter_unsubscribed` to `newsletter_user_unsubscribed`. [See our developer documentation](https://www.thenewsletterplugin.com/documentation/developers/).
121
+ * Removed deprecated function `save_profile()` on NewsletterSubscription
122
+
123
  = 6.6.5 =
124
 
125
  * Fixed email reference lost on double step cancellation
126
  * Update to support Instasend
127
+ * Added "optin" support on shortcodes (see the documentation)
128
 
129
  = 6.6.4 =
130
 
subscription/subscription.php CHANGED
@@ -42,7 +42,7 @@ class NewsletterSubscription extends NewsletterModule {
42
  }
43
 
44
  function hook_init() {
45
- add_action('wp_loaded', array($this, 'hook_wp_loaded'));
46
  if (is_admin()) {
47
  add_action('admin_init', array($this, 'hook_admin_init'));
48
  } else {
@@ -281,22 +281,19 @@ class NewsletterSubscription extends NewsletterModule {
281
  * @global wpdb $wpdb
282
  * @return mixed
283
  */
284
- function hook_wp_loaded() {
285
  global $wpdb;
286
 
287
- $newsletter = Newsletter::instance();
288
-
289
- switch ($newsletter->action) {
290
  case 'profile-change':
291
  if ($this->antibot_form_check()) {
292
- $user = $this->get_user_from_request();
293
- if (!$user || $user->status != 'C') {
294
- die('Subscriber not found or not active.');
295
  }
296
 
297
- $email = $this->get_email_from_request();
298
  if (!$email) {
299
- die('Newsletter not found');
300
  }
301
 
302
  if (isset($_REQUEST['list'])) {
@@ -304,11 +301,11 @@ class NewsletterSubscription extends NewsletterModule {
304
 
305
  // Check if the list is public
306
  $list = $this->get_list($list_id);
307
- if (!$list || $list->status == 0) {
308
- die('Private list.');
309
  }
310
 
311
- $url = $_REQUEST['redirect'];
312
 
313
  $this->set_user_list($user, $list_id, $_REQUEST['value']);
314
 
@@ -334,8 +331,7 @@ class NewsletterSubscription extends NewsletterModule {
334
  case 'subscribe':
335
 
336
  if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
337
- //$antibot_logger->fatal('HTTP method invalid');
338
- die('Invalid');
339
  }
340
 
341
  $options_antibot = $this->get_options('antibot');
@@ -368,7 +364,7 @@ class NewsletterSubscription extends NewsletterModule {
368
 
369
  if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
370
  //$antibot_logger->fatal('HTTP method invalid');
371
- die('Invalid');
372
  }
373
 
374
  $user = $this->subscribe();
@@ -383,7 +379,7 @@ class NewsletterSubscription extends NewsletterModule {
383
  $key = 'confirmation';
384
 
385
 
386
- $message = $newsletter->replace($this->options[$key . '_text'], $user);
387
  if (isset($this->options[$key . '_tracking'])) {
388
  $message .= $this->options[$key . '_tracking'];
389
  }
@@ -393,6 +389,7 @@ class NewsletterSubscription extends NewsletterModule {
393
  case 'c':
394
  case 'confirm':
395
  if ($this->antibot_form_check()) {
 
396
  $user = $this->confirm();
397
  if ($user->status == 'E') {
398
  $this->show_message('error', $user->id);
@@ -414,25 +411,6 @@ class NewsletterSubscription extends NewsletterModule {
414
  function upgrade() {
415
  global $wpdb, $charset_collate;
416
 
417
- // Possible migration
418
- $options_antibot = $this->get_options('antibot');
419
-
420
- if (empty($options_antibot)) {
421
- $options = $this->get_options();
422
- foreach (array('address_blacklist', 'ip_blacklist', 'akismet', 'captcha', 'antiflood') as $key) {
423
- if (isset($options[$key])) {
424
- $options_antibot[$key] = $options[$key];
425
- }
426
- }
427
- if (isset($options['antibot_disable'])) {
428
- $options_antibot['disabled'] = $options['antibot_disable'];
429
- } else {
430
- $options_antibot['disabled'] = 0;
431
- }
432
-
433
- $this->save_options($options_antibot, 'antibot');
434
- }
435
-
436
  parent::upgrade();
437
 
438
  $newsletter = Newsletter::instance();
@@ -688,27 +666,6 @@ class NewsletterSubscription extends NewsletterModule {
688
  return $user;
689
  }
690
 
691
- // if ($this->options['multiple'] == 2) {
692
- // $lists_changed = false;
693
- // if (isset($_REQUEST['nl']) && is_array($_REQUEST['nl'])) {
694
- // foreach ($_REQUEST['nl'] as $list_id) {
695
- // $list_id = (int) $list_id;
696
- // if ($list_id <= 0 || $list_id > NEWSLETTER_LIST_MAX)
697
- // continue;
698
- // $field = 'list_' . $list_id;
699
- // if ($user->$field == 0) {
700
- // $lists_changed = true;
701
- // break;
702
- // }
703
- // }
704
- // }
705
- //
706
- // if (!$lists_changed) {
707
- // $user->status = 'E';
708
- // return $user;
709
- // }
710
- // }
711
-
712
  // If the subscriber is confirmed, we cannot change his data in double opt in mode, we need to
713
  // temporary store and wait for activation
714
  if ($user->status == Newsletter::STATUS_CONFIRMED && $opt_in == self::OPTIN_DOUBLE) {
@@ -836,7 +793,7 @@ class NewsletterSubscription extends NewsletterModule {
836
  foreach ($_REQUEST['nl'] as $list_id) {
837
  $list = $this->get_list($list_id);
838
  if ($list->status === TNP_List::STATUS_PRIVATE) {
839
- die('Message visible only to the administrator. List ' . $list_id . ' has been submitted but it is set as private. Please fix the subscription form.');
840
  }
841
  }
842
  }
@@ -983,15 +940,6 @@ class NewsletterSubscription extends NewsletterModule {
983
  return $this->mail($user, $subject, $message);
984
  }
985
 
986
- /**
987
- * Saves the subscriber data.
988
- *
989
- * @return type
990
- */
991
- function save_profile() {
992
- return NewsletterProfile::instance()->save_profile();
993
- }
994
-
995
  function is_double_optin() {
996
  return $this->options['noconfirmation'] == 0;
997
  }
@@ -1122,6 +1070,10 @@ class NewsletterSubscription extends NewsletterModule {
1122
  if (isset($attrs['referrer'])) {
1123
  $buffer .= '<input type="hidden" name="nr" value="' . esc_attr($attrs['referrer']) . '">' . "\n";
1124
  }
 
 
 
 
1125
 
1126
  if (isset($attrs['confirmation_url'])) {
1127
  if ($attrs['confirmation_url'] == '#') {
@@ -1161,6 +1113,14 @@ class NewsletterSubscription extends NewsletterModule {
1161
  return $buffer;
1162
  }
1163
 
 
 
 
 
 
 
 
 
1164
  function _shortcode_label($name, $attrs, $suffix = null) {
1165
  $options_profile = $this->get_options('profile', $this->get_current_language());
1166
 
@@ -1377,6 +1337,7 @@ class NewsletterSubscription extends NewsletterModule {
1377
  * Returns the form html code for subscription.
1378
  *
1379
  * @return string The html code of the subscription form
 
1380
  */
1381
  function get_subscription_form_html5($referrer = null, $action = null, $attrs = array()) {
1382
  return $this->get_subscription_form($referrer, $action, $attrs);
@@ -1417,10 +1378,11 @@ class NewsletterSubscription extends NewsletterModule {
1417
  $language = $this->get_current_language();
1418
  $options_profile = $this->get_options('profile', $language);
1419
 
1420
-
1421
  if (isset($attrs['action'])) {
1422
  $action = $attrs['action'];
1423
  }
 
1424
  if (isset($attrs['referrer'])) {
1425
  $referrer = $attrs['referrer'];
1426
  }
@@ -1444,6 +1406,10 @@ class NewsletterSubscription extends NewsletterModule {
1444
 
1445
  $buffer .= '<input type="hidden" name="nlang" value="' . esc_attr($language) . '">' . "\n";
1446
 
 
 
 
 
1447
  if (!empty($referrer)) {
1448
  $buffer .= '<input type="hidden" name="nr" value="' . esc_attr($referrer) . '">' . "\n";
1449
  }
42
  }
43
 
44
  function hook_init() {
45
+ add_action('newsletter_action', array($this, 'hook_newsletter_action'), 10, 3);
46
  if (is_admin()) {
47
  add_action('admin_init', array($this, 'hook_admin_init'));
48
  } else {
281
  * @global wpdb $wpdb
282
  * @return mixed
283
  */
284
+ function hook_newsletter_action($action, $user, $email) {
285
  global $wpdb;
286
 
287
+ switch ($action) {
 
 
288
  case 'profile-change':
289
  if ($this->antibot_form_check()) {
290
+
291
+ if (!$user || $user->status != TNP_user::STATUS_CONFIRMED) {
292
+ $this->dienow('Subscriber not found or not confirmed.');
293
  }
294
 
 
295
  if (!$email) {
296
+ $this->dienow('Newsletter not found');
297
  }
298
 
299
  if (isset($_REQUEST['list'])) {
301
 
302
  // Check if the list is public
303
  $list = $this->get_list($list_id);
304
+ if (!$list || $list->status == TNP_List::STATUS_PRIVATE) {
305
+ $this->dienow('List change not allowed.', 'Please check if the list is marked as "disbaled/private".');
306
  }
307
 
308
+ $url = esc_url_raw($_REQUEST['redirect']);
309
 
310
  $this->set_user_list($user, $list_id, $_REQUEST['value']);
311
 
331
  case 'subscribe':
332
 
333
  if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
334
+ $this->dienow('Invalid request');
 
335
  }
336
 
337
  $options_antibot = $this->get_options('antibot');
364
 
365
  if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
366
  //$antibot_logger->fatal('HTTP method invalid');
367
+ $this->dienow('Invalid request');
368
  }
369
 
370
  $user = $this->subscribe();
379
  $key = 'confirmation';
380
 
381
 
382
+ $message = $this->replace($this->options[$key . '_text'], $user);
383
  if (isset($this->options[$key . '_tracking'])) {
384
  $message .= $this->options[$key . '_tracking'];
385
  }
389
  case 'c':
390
  case 'confirm':
391
  if ($this->antibot_form_check()) {
392
+ // TODO: Change to accept $user
393
  $user = $this->confirm();
394
  if ($user->status == 'E') {
395
  $this->show_message('error', $user->id);
411
  function upgrade() {
412
  global $wpdb, $charset_collate;
413
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
414
  parent::upgrade();
415
 
416
  $newsletter = Newsletter::instance();
666
  return $user;
667
  }
668
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
669
  // If the subscriber is confirmed, we cannot change his data in double opt in mode, we need to
670
  // temporary store and wait for activation
671
  if ($user->status == Newsletter::STATUS_CONFIRMED && $opt_in == self::OPTIN_DOUBLE) {
793
  foreach ($_REQUEST['nl'] as $list_id) {
794
  $list = $this->get_list($list_id);
795
  if ($list->status === TNP_List::STATUS_PRIVATE) {
796
+ $this->dienow('Invalid list', 'List ' . $list_id . ' has been submitted but it is set as private. Please fix the subscription form.');
797
  }
798
  }
799
  }
940
  return $this->mail($user, $subject, $message);
941
  }
942
 
 
 
 
 
 
 
 
 
 
943
  function is_double_optin() {
944
  return $this->options['noconfirmation'] == 0;
945
  }
1070
  if (isset($attrs['referrer'])) {
1071
  $buffer .= '<input type="hidden" name="nr" value="' . esc_attr($attrs['referrer']) . '">' . "\n";
1072
  }
1073
+
1074
+ if (isset($attrs['optin'])) {
1075
+ $buffer .= '<input type="hidden" name="optin" value="' . esc_attr($attrs['optin']) . '">' . "\n";
1076
+ }
1077
 
1078
  if (isset($attrs['confirmation_url'])) {
1079
  if ($attrs['confirmation_url'] == '#') {
1113
  return $buffer;
1114
  }
1115
 
1116
+ /**
1117
+ * Internal use only
1118
+ *
1119
+ * @param type $name
1120
+ * @param type $attrs
1121
+ * @param type $suffix
1122
+ * @return string
1123
+ */
1124
  function _shortcode_label($name, $attrs, $suffix = null) {
1125
  $options_profile = $this->get_options('profile', $this->get_current_language());
1126
 
1337
  * Returns the form html code for subscription.
1338
  *
1339
  * @return string The html code of the subscription form
1340
+ * @deprecated since version 6.6.0
1341
  */
1342
  function get_subscription_form_html5($referrer = null, $action = null, $attrs = array()) {
1343
  return $this->get_subscription_form($referrer, $action, $attrs);
1378
  $language = $this->get_current_language();
1379
  $options_profile = $this->get_options('profile', $language);
1380
 
1381
+ // Possible alternative form actions (used by...?)
1382
  if (isset($attrs['action'])) {
1383
  $action = $attrs['action'];
1384
  }
1385
+
1386
  if (isset($attrs['referrer'])) {
1387
  $referrer = $attrs['referrer'];
1388
  }
1406
 
1407
  $buffer .= '<input type="hidden" name="nlang" value="' . esc_attr($language) . '">' . "\n";
1408
 
1409
+ if (!empty($attrs['optin'])) {
1410
+ $buffer .= '<input type="hidden" name="optin" value="' . esc_attr($attrs['optin']) . '">' . "\n";
1411
+ }
1412
+
1413
  if (!empty($referrer)) {
1414
  $buffer .= '<input type="hidden" name="nr" value="' . esc_attr($referrer) . '">' . "\n";
1415
  }
unsubscription/index.php CHANGED
@@ -1,34 +1,30 @@
1
  <?php
 
2
  defined('ABSPATH') || exit;
3
 
4
  @include_once NEWSLETTER_INCLUDES_DIR . '/controls.php';
5
  $controls = new NewsletterControls();
6
- $module = NewsletterUnsubscription::instance();
7
 
8
- $current_language = $module->get_current_language();
9
 
10
- $is_all_languages = $module->is_all_languages();
11
 
12
  if (!$is_all_languages) {
13
- $controls->warnings[] = 'You are configuring the language <strong>' . $current_language . '</strong>. Switch to "all languages" to see every options.';
14
  }
15
 
16
  if (!$controls->is_action()) {
17
- $controls->data = $module->get_options('', $current_language);
18
  } else {
19
  if ($controls->is_action('save')) {
20
- //$controls->data['unsubscription_text'] = NewsletterModule::clean_url_tags($controls->data['unsubscription_text']);
21
- //$controls->data['unsubscribed_text'] = NewsletterModule::clean_url_tags($controls->data['unsubscribed_text']);
22
- //$controls->data['unsubscribed_message'] = NewsletterModule::clean_url_tags($controls->data['unsubscribed_message']);
23
-
24
- $module->save_options($controls->data, '', null, $current_language);
25
- $controls->data = $module->get_options('', $current_language);
26
  $controls->add_message_saved();
27
  }
28
 
29
  if ($controls->is_action('reset')) {
30
  // On reset we ignore the current language
31
- $controls->data = $module->reset_options();
32
  }
33
  }
34
  ?>
1
  <?php
2
+ /* @var $this NewsletterUnsubscription */
3
  defined('ABSPATH') || exit;
4
 
5
  @include_once NEWSLETTER_INCLUDES_DIR . '/controls.php';
6
  $controls = new NewsletterControls();
 
7
 
8
+ $current_language = $this->get_current_language();
9
 
10
+ $is_all_languages = $this->is_all_languages();
11
 
12
  if (!$is_all_languages) {
13
+ $controls->warnings[] = 'You are configuring the language <strong>' . $current_language . '</strong>. Switch to "all languages" to see all options.';
14
  }
15
 
16
  if (!$controls->is_action()) {
17
+ $controls->data = $this->get_options('', $current_language);
18
  } else {
19
  if ($controls->is_action('save')) {
20
+ $this->save_options($controls->data, '', null, $current_language);
21
+ $controls->data = $this->get_options('', $current_language);
 
 
 
 
22
  $controls->add_message_saved();
23
  }
24
 
25
  if ($controls->is_action('reset')) {
26
  // On reset we ignore the current language
27
+ $controls->data = $this->reset_options();
28
  }
29
  }
30
  ?>
unsubscription/unsubscription.php CHANGED
@@ -17,40 +17,34 @@ class NewsletterUnsubscription extends NewsletterModule {
17
  }
18
 
19
  function __construct() {
20
- parent::__construct('unsubscription', '1.0.2');
21
 
22
  add_filter('newsletter_replace', array($this, 'hook_newsletter_replace'), 10, 3);
23
  add_filter('newsletter_page_text', array($this, 'hook_newsletter_page_text'), 10, 3);
24
  add_filter('newsletter_message_headers', array($this, 'hook_add_unsubscribe_headers_to_email'), 10, 3);
25
 
26
- add_action('newsletter_action', array($this, 'hook_newsletter_action'));
27
  }
28
 
29
- function hook_newsletter_action($action) {
30
- global $wpdb;
 
 
 
 
 
31
 
32
  switch ($action) {
33
  case 'u':
34
- $user = $this->get_user_from_request();
35
- $email = $this->get_email_from_request();
36
- if ($user == null) {
37
- $url = $this->build_message_url(null, 'unsubscription_error', $user);
38
- } else {
39
- $url = $this->build_message_url(null, 'unsubscribe', $user, $email);
40
- }
41
  wp_redirect($url);
42
  die();
43
  break;
44
 
45
  case 'uc':
46
  if ($this->antibot_form_check()) {
47
- $user = $this->unsubscribe();
48
- $email = $this->get_email_from_request();
49
- if ($user->status == 'E') {
50
- $url = $this->build_message_url(null, 'unsubscription_error', $user);
51
- } else {
52
- $url = $this->build_message_url(null, 'unsubscribed', $user, $email);
53
- }
54
  wp_redirect($url);
55
  } else {
56
  $this->request_to_antibot_form('Unsubscribe');
@@ -58,16 +52,17 @@ class NewsletterUnsubscription extends NewsletterModule {
58
  die();
59
  break;
60
 
61
- case 'lu': //List Unsubscribe - action from oneclick unsubscribe header
 
62
  if ($this->one_click_list_unsubscribe_check()) {
63
- $this->unsubscribe();
64
  }
65
  die();
66
  break;
67
 
68
  case 'reactivate':
69
  if ($this->antibot_form_check()) {
70
- $user = $this->reactivate();
71
  $url = $this->build_message_url(null, 'reactivated', $user);
72
  wp_redirect($url);
73
  } else {
@@ -83,23 +78,22 @@ class NewsletterUnsubscription extends NewsletterModule {
83
  *
84
  * @return TNP_User
85
  */
86
- function unsubscribe() {
87
- $user = $this->get_user_from_request(true);
88
-
89
  if ($user->status == TNP_User::STATUS_UNSUBSCRIBED) {
90
  return $user;
91
  }
92
 
93
- $user = $this->refresh_user_token($user);
94
- $user = $this->set_user_status($user, TNP_User::STATUS_UNSUBSCRIBED);
95
 
96
  $this->add_user_log($user, 'unsubscribe');
97
 
98
- do_action('newsletter_unsubscribed', $user);
99
 
100
- global $wpdb;
101
 
102
- $email = $this->get_email_from_request();
103
  if ($email) {
104
  $wpdb->update(NEWSLETTER_USERS_TABLE, array('unsub_email_id' => (int) $email->id, 'unsub_time' => time()), array('id' => $user->id));
105
  }
@@ -142,13 +136,13 @@ class NewsletterUnsubscription extends NewsletterModule {
142
  *
143
  * @return TNP_User
144
  */
145
- function reactivate() {
146
- $user = $this->get_user_from_request(true);
147
-
148
- $user = $this->set_user_status($user, TNP_User::STATUS_CONFIRMED);
 
 
149
  $this->add_user_log($user, 'reactivate');
150
-
151
- return $user;
152
  }
153
 
154
  function hook_newsletter_replace($text, $user, $email) {
@@ -193,24 +187,7 @@ class NewsletterUnsubscription extends NewsletterModule {
193
  }
194
 
195
  function upgrade() {
196
- global $wpdb, $charset_collate;
197
-
198
  parent::upgrade();
199
-
200
- // Migration code
201
- if (empty($this->options) || empty($this->options['unsubscribe_text'])) {
202
- // Options of the subscription module (worng name, I know)
203
- $options = get_option('newsletter');
204
- $this->options['unsubscribe_text'] = $options['unsubscription_text'];
205
-
206
- $this->options['reactivated_text'] = $options['reactivated_text'];
207
-
208
- $this->options['unsubscribed_text'] = $options['unsubscribed_text'];
209
- $this->options['unsubscribed_message'] = $options['unsubscribed_message'];
210
- $this->options['unsubscribed_subject'] = $options['unsubscribed_subject'];
211
-
212
- $this->save_options($this->options);
213
- }
214
  }
215
 
216
  function admin_menu() {
17
  }
18
 
19
  function __construct() {
20
+ parent::__construct('unsubscription', '1.0.3');
21
 
22
  add_filter('newsletter_replace', array($this, 'hook_newsletter_replace'), 10, 3);
23
  add_filter('newsletter_page_text', array($this, 'hook_newsletter_page_text'), 10, 3);
24
  add_filter('newsletter_message_headers', array($this, 'hook_add_unsubscribe_headers_to_email'), 10, 3);
25
 
26
+ add_action('newsletter_action', array($this, 'hook_newsletter_action'), 11, 3);
27
  }
28
 
29
+ function hook_newsletter_action($action, $user, $email) {
30
+
31
+ if (in_array($action, ['u', 'uc', 'lu', 'reactivate'])) {
32
+ if (!$user) {
33
+ $this->dienow('The subscriber was not found.');
34
+ }
35
+ }
36
 
37
  switch ($action) {
38
  case 'u':
39
+ $url = $this->build_message_url(null, 'unsubscribe', $user, $email);
 
 
 
 
 
 
40
  wp_redirect($url);
41
  die();
42
  break;
43
 
44
  case 'uc':
45
  if ($this->antibot_form_check()) {
46
+ $this->unsubscribe($user, $email);
47
+ $url = $this->build_message_url(null, 'unsubscribed', $user, $email);
 
 
 
 
 
48
  wp_redirect($url);
49
  } else {
50
  $this->request_to_antibot_form('Unsubscribe');
52
  die();
53
  break;
54
 
55
+ case 'lu':
56
+ // List Unsubscribe - action from oneclick unsubscribe header
57
  if ($this->one_click_list_unsubscribe_check()) {
58
+ $this->unsubscribe($user, $email);
59
  }
60
  die();
61
  break;
62
 
63
  case 'reactivate':
64
  if ($this->antibot_form_check()) {
65
+ $this->reactivate($user);
66
  $url = $this->build_message_url(null, 'reactivated', $user);
67
  wp_redirect($url);
68
  } else {
78
  *
79
  * @return TNP_User
80
  */
81
+ function unsubscribe($user, $email = null) {
82
+ global $wpdb;
83
+
84
  if ($user->status == TNP_User::STATUS_UNSUBSCRIBED) {
85
  return $user;
86
  }
87
 
88
+ $this->refresh_user_token($user);
89
+ $this->set_user_status($user, TNP_User::STATUS_UNSUBSCRIBED);
90
 
91
  $this->add_user_log($user, 'unsubscribe');
92
 
93
+ do_action('newsletter_user_unsubscribed', $user);
94
 
95
+
96
 
 
97
  if ($email) {
98
  $wpdb->update(NEWSLETTER_USERS_TABLE, array('unsub_email_id' => (int) $email->id, 'unsub_time' => time()), array('id' => $user->id));
99
  }
136
  *
137
  * @return TNP_User
138
  */
139
+ function reactivate($user = null) {
140
+ // For compatibility, to be removed
141
+ if (!$user) {
142
+ $user = $this->get_user_from_request(true);
143
+ }
144
+ $this->set_user_status($user, TNP_User::STATUS_CONFIRMED);
145
  $this->add_user_log($user, 'reactivate');
 
 
146
  }
147
 
148
  function hook_newsletter_replace($text, $user, $email) {
187
  }
188
 
189
  function upgrade() {
 
 
190
  parent::upgrade();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
191
  }
192
 
193
  function admin_menu() {
users/edit.php CHANGED
@@ -1,16 +1,17 @@
1
  <?php
 
 
2
  defined('ABSPATH') || exit;
3
 
4
  require_once NEWSLETTER_INCLUDES_DIR . '/controls.php';
5
  $controls = new NewsletterControls();
6
- $module = NewsletterUsers::instance();
7
 
8
  $id = (int) $_GET['id'];
9
- $user = $module->get_user($id);
10
 
11
  if ($controls->is_action('save')) {
12
 
13
- $email = $module->normalize_email($controls->data['email']);
14
  if (empty($email)) {
15
  $controls->errors = __('Wrong email address', 'newsletter');
16
  } else {
@@ -19,7 +20,7 @@ if ($controls->is_action('save')) {
19
 
20
 
21
  if (empty($controls->errors)) {
22
- $u = $module->get_user($controls->data['email']);
23
  if ($u && $u->id != $id) {
24
  $controls->errors = __('The email address is already in use', 'newsletter');
25
  }
@@ -34,12 +35,12 @@ if ($controls->is_action('save')) {
34
  }
35
 
36
  if (empty($controls->data['token'])) {
37
- $controls->data['token'] = $module->get_token();
38
  }
39
 
40
  $controls->data['id'] = $id;
41
- $user = $module->save_user($controls->data);
42
- $module->add_user_log($user, 'edit');
43
  if ($user === false) {
44
  $controls->errors = __('Error. Check the log files.', 'newsletter');
45
  } else {
@@ -50,8 +51,8 @@ if ($controls->is_action('save')) {
50
  }
51
 
52
  if ($controls->is_action('delete')) {
53
- $module->delete_user($id);
54
- $controls->js_redirect($module->get_admin_page_url('index'));
55
  return;
56
  }
57
 
1
  <?php
2
+ /* @var $this NewsletterUsers */
3
+
4
  defined('ABSPATH') || exit;
5
 
6
  require_once NEWSLETTER_INCLUDES_DIR . '/controls.php';
7
  $controls = new NewsletterControls();
 
8
 
9
  $id = (int) $_GET['id'];
10
+ $user = $this->get_user($id);
11
 
12
  if ($controls->is_action('save')) {
13
 
14
+ $email = $this->normalize_email($controls->data['email']);
15
  if (empty($email)) {
16
  $controls->errors = __('Wrong email address', 'newsletter');
17
  } else {
20
 
21
 
22
  if (empty($controls->errors)) {
23
+ $u = $this->get_user($controls->data['email']);
24
  if ($u && $u->id != $id) {
25
  $controls->errors = __('The email address is already in use', 'newsletter');
26
  }
35
  }
36
 
37
  if (empty($controls->data['token'])) {
38
+ $controls->data['token'] = $this->get_token();
39
  }
40
 
41
  $controls->data['id'] = $id;
42
+ $user = $this->save_user($controls->data);
43
+ $this->add_user_log($user, 'edit');
44
  if ($user === false) {
45
  $controls->errors = __('Error. Check the log files.', 'newsletter');
46
  } else {
51
  }
52
 
53
  if ($controls->is_action('delete')) {
54
+ $this->delete_user($id);
55
+ $controls->js_redirect($this->get_admin_page_url('index'));
56
  return;
57
  }
58
 
users/index.php CHANGED
@@ -1,10 +1,10 @@
1
  <?php
 
2
  defined('ABSPATH') || exit;
3
 
4
  require_once NEWSLETTER_INCLUDES_DIR . '/controls.php';
5
 
6
  $controls = new NewsletterControls();
7
- $module = NewsletterUsers::instance();
8
 
9
  $options = $controls->data;
10
  $options_profile = get_option('newsletter_profile');
@@ -17,27 +17,27 @@ if ($controls->is_action()) {
17
  } else {
18
  $controls->data['search_page'] = (int) $controls->data['search_page'] - 1;
19
  }
20
- $module->save_options($controls->data, 'search');
21
  } else {
22
- $controls->data = $module->get_options('search');
23
  if (empty($controls->data['search_page']))
24
  $controls->data['search_page'] = 0;
25
  }
26
 
27
  if ($controls->is_action('resend')) {
28
- $user = $module->get_user($controls->button_data);
29
  NewsletterSubscription::instance()->send_message('confirmation', $user, true);
30
  $controls->messages = __('Activation email sent.', 'newsletter');
31
  }
32
 
33
  if ($controls->is_action('resend_welcome')) {
34
- $user = $module->get_user($controls->button_data);
35
  NewsletterSubscription::instance()->send_message('confirmed', $user, true);
36
  $controls->messages = __('Welcome email sent.', 'newsletter');
37
  }
38
 
39
  if ($controls->is_action('remove')) {
40
- $module->delete_user($controls->button_data);
41
  unset($controls->data['subscriber_id']);
42
  }
43
 
@@ -196,7 +196,7 @@ $controls->data['search_page'] ++;
196
 
197
  <td>
198
  <small>
199
- <?php echo $module->get_user_status_label($s) ?>
200
  </small>
201
  </td>
202
 
@@ -204,7 +204,7 @@ $controls->data['search_page'] ++;
204
  <td>
205
  <small>
206
  <?php
207
- $lists = $module->get_lists();
208
  foreach ($lists as $item) {
209
  $l = 'list_' . $item->id;
210
  if ($s->$l == 1)
@@ -216,7 +216,7 @@ $controls->data['search_page'] ++;
216
  <?php } ?>
217
 
218
  <td>
219
- <a class="button-secondary" href="<?php echo $module->get_admin_page_url('edit'); ?>&amp;id=<?php echo $s->id; ?>"><?php _e('Edit', 'newsletter') ?></a>
220
  </td>
221
  <td>
222
  <?php $controls->button_confirm('remove', __('Remove', 'newsletter'), '', $s->id); ?>
1
  <?php
2
+ /* @var $this NewsletterUsers */
3
  defined('ABSPATH') || exit;
4
 
5
  require_once NEWSLETTER_INCLUDES_DIR . '/controls.php';
6
 
7
  $controls = new NewsletterControls();
 
8
 
9
  $options = $controls->data;
10
  $options_profile = get_option('newsletter_profile');
17
  } else {
18
  $controls->data['search_page'] = (int) $controls->data['search_page'] - 1;
19
  }
20
+ $this->save_options($controls->data, 'search');
21
  } else {
22
+ $controls->data = $this->get_options('search');
23
  if (empty($controls->data['search_page']))
24
  $controls->data['search_page'] = 0;
25
  }
26
 
27
  if ($controls->is_action('resend')) {
28
+ $user = $this->get_user($controls->button_data);
29
  NewsletterSubscription::instance()->send_message('confirmation', $user, true);
30
  $controls->messages = __('Activation email sent.', 'newsletter');
31
  }
32
 
33
  if ($controls->is_action('resend_welcome')) {
34
+ $user = $this->get_user($controls->button_data);
35
  NewsletterSubscription::instance()->send_message('confirmed', $user, true);
36
  $controls->messages = __('Welcome email sent.', 'newsletter');
37
  }
38
 
39
  if ($controls->is_action('remove')) {
40
+ $this->delete_user($controls->button_data);
41
  unset($controls->data['subscriber_id']);
42
  }
43
 
196
 
197
  <td>
198
  <small>
199
+ <?php echo $this->get_user_status_label($s) ?>
200
  </small>
201
  </td>
202
 
204
  <td>
205
  <small>
206
  <?php
207
+ $lists = $this->get_lists();
208
  foreach ($lists as $item) {
209
  $l = 'list_' . $item->id;
210
  if ($s->$l == 1)
216
  <?php } ?>
217
 
218
  <td>
219
+ <a class="button-secondary" href="<?php echo $this->get_admin_page_url('edit'); ?>&amp;id=<?php echo $s->id; ?>"><?php _e('Edit', 'newsletter') ?></a>
220
  </td>
221
  <td>
222
  <?php $controls->button_confirm('remove', __('Remove', 'newsletter'), '', $s->id); ?>
users/massive.php CHANGED
@@ -1,12 +1,12 @@
1
  <?php
2
  /* @var $wpdb wpdb */
 
3
 
4
  defined('ABSPATH') || exit;
5
 
6
- @include_once NEWSLETTER_INCLUDES_DIR . '/controls.php';
7
 
8
  $controls = new NewsletterControls();
9
- $module = NewsletterUsers::instance();
10
 
11
  if ($controls->is_action('remove_unconfirmed')) {
12
  $r = $wpdb->query("delete from " . NEWSLETTER_USERS_TABLE . " where status='S'");
@@ -50,8 +50,8 @@ if ($controls->is_action('list_remove')) {
50
 
51
  if ($controls->is_action('list_delete')) {
52
  $count = $wpdb->query("delete from " . NEWSLETTER_USERS_TABLE . " where list_" . ((int) $controls->data['list']) . "<>0");
53
- $module->clean_sent_table();
54
- $module->clean_stats_table();
55
 
56
  $controls->messages = $count . ' ' . __('deleted', 'newsletter');
57
  }
@@ -267,7 +267,7 @@ if ($controls->is_action('bounces')) {
267
  </td>
268
  </tr>
269
 
270
- <?php if ($module->is_multilanguage()) { ?>
271
  <tr>
272
  <td>Language</td>
273
  <td>
1
  <?php
2
  /* @var $wpdb wpdb */
3
+ /* @var $this NewsletterUsers */
4
 
5
  defined('ABSPATH') || exit;
6
 
7
+ include_once NEWSLETTER_INCLUDES_DIR . '/controls.php';
8
 
9
  $controls = new NewsletterControls();
 
10
 
11
  if ($controls->is_action('remove_unconfirmed')) {
12
  $r = $wpdb->query("delete from " . NEWSLETTER_USERS_TABLE . " where status='S'");
50
 
51
  if ($controls->is_action('list_delete')) {
52
  $count = $wpdb->query("delete from " . NEWSLETTER_USERS_TABLE . " where list_" . ((int) $controls->data['list']) . "<>0");
53
+ $this->clean_sent_table();
54
+ $this->clean_stats_table();
55
 
56
  $controls->messages = $count . ' ' . __('deleted', 'newsletter');
57
  }
267
  </td>
268
  </tr>
269
 
270
+ <?php if ($this->is_multilanguage()) { ?>
271
  <tr>
272
  <td>Language</td>
273
  <td>
users/new.php CHANGED
@@ -1,9 +1,9 @@
1
  <?php
 
2
  defined('ABSPATH') || exit;
3
 
4
  require_once NEWSLETTER_INCLUDES_DIR . '/controls.php';
5
  $controls = new NewsletterControls();
6
- $module = NewsletterUsers::instance();
7
 
8
  if ($controls->is_action('save')) {
9
 
@@ -15,12 +15,12 @@ if ($controls->is_action('save')) {
15
  $controls->data['status'] = 'C';
16
  $controls->data['sex'] = 'n';
17
 
18
- $user = $module->save_user($controls->data);
19
  if ($user === false) {
20
  $controls->errors = __('This subscriber already exists.', 'newsletter');
21
  } else {
22
  echo '<script>';
23
- echo 'location.href="' . $module->get_admin_page_url('edit') . '&id=' . $user->id . '"';
24
  echo '</script>';
25
  return;
26
  }
1
  <?php
2
+ /* @var $this NewsletterUsers */
3
  defined('ABSPATH') || exit;
4
 
5
  require_once NEWSLETTER_INCLUDES_DIR . '/controls.php';
6
  $controls = new NewsletterControls();
 
7
 
8
  if ($controls->is_action('save')) {
9
 
15
  $controls->data['status'] = 'C';
16
  $controls->data['sex'] = 'n';
17
 
18
+ $user = $this->save_user($controls->data);
19
  if ($user === false) {
20
  $controls->errors = __('This subscriber already exists.', 'newsletter');
21
  } else {
22
  echo '<script>';
23
+ echo 'location.href="' . $this->get_admin_page_url('edit') . '&id=' . $user->id . '"';
24
  echo '</script>';
25
  return;
26
  }
users/statistics.php CHANGED
@@ -1,16 +1,16 @@
1
  <?php
2
- if (!defined('ABSPATH'))
3
- exit;
4
 
5
- @include_once NEWSLETTER_INCLUDES_DIR . '/controls.php';
 
 
6
 
7
  wp_enqueue_script('tnp-chart');
8
 
9
  $all_count = $wpdb->get_var("select count(*) from " . NEWSLETTER_USERS_TABLE);
10
  $options_profile = get_option('newsletter_profile');
11
 
12
- $module = NewsletterUsers::instance();
13
- $controls = new NewsletterControls();
14
  ?>
15
 
16
  <script type="text/javascript" src="https://www.gstatic.com/charts/loader.js"></script>
@@ -89,9 +89,9 @@ $controls = new NewsletterControls();
89
  </tbody>
90
  </table>
91
 
92
- <?php if ($module->is_multilanguage()) { ?>
93
  <h3>By language</h3>
94
- <?php $languages = $module->get_languages(); ?>
95
 
96
  <table class="widefat" style="width: auto">
97
  <thead>
@@ -133,7 +133,7 @@ $controls = new NewsletterControls();
133
  </tr>
134
  </thead>
135
  <tbody>
136
- <?php $lists = $module->get_lists(); ?>
137
  <?php foreach ($lists as $list) { ?>
138
  <tr>
139
  <td><?php echo $list->id ?></td>
1
  <?php
2
+ /* @var $this NewsletterUsers */
3
+ defined('ABSPATH') || exit;
4
 
5
+
6
+ include_once NEWSLETTER_INCLUDES_DIR . '/controls.php';
7
+ $controls = new NewsletterControls();
8
 
9
  wp_enqueue_script('tnp-chart');
10
 
11
  $all_count = $wpdb->get_var("select count(*) from " . NEWSLETTER_USERS_TABLE);
12
  $options_profile = get_option('newsletter_profile');
13
 
 
 
14
  ?>
15
 
16
  <script type="text/javascript" src="https://www.gstatic.com/charts/loader.js"></script>
89
  </tbody>
90
  </table>
91
 
92
+ <?php if ($this->is_multilanguage()) { ?>
93
  <h3>By language</h3>
94
+ <?php $languages = $this->get_languages(); ?>
95
 
96
  <table class="widefat" style="width: auto">
97
  <thead>
133
  </tr>
134
  </thead>
135
  <tbody>
136
+ <?php $lists = $this->get_lists(); ?>
137
  <?php foreach ($lists as $list) { ?>
138
  <tr>
139
  <td><?php echo $list->id ?></td>