Newsletter - Version 6.3.6

Version Description

  • Improved error detection
  • Fixed stats collection for Autoresponder
  • Changed the init sequence to grant full load of other plugins (newsletter preview problems on some installations)
  • Better reporting on tests
Download this release

Release Info

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

Code changes from version 6.3.5 to 6.3.6

emails/emails.php CHANGED
@@ -956,7 +956,7 @@ class NewsletterEmails extends NewsletterModule {
956
  if ($email->subject == '') {
957
  $email->subject = '[TEST] Dummy subject, it was empty (remember to set it)';
958
  } else {
959
- $email->subject = '[TEST] ' . $email->subject;
960
  }
961
  $users = NewsletterUsers::instance()->get_test_users();
962
  if (count($users) == 0) {
@@ -964,15 +964,22 @@ class NewsletterEmails extends NewsletterModule {
964
  '. <a href="https://www.thenewsletterplugin.com/plugins/newsletter/subscribers-module#test" target="_blank"><strong>' .
965
  __('Read more', 'newsletter') . '</strong></a>.';
966
  } else {
967
- $r = Newsletter::instance()->send($email, $users);
 
 
 
 
968
  if (is_wp_error($r)) {
969
- $controls->errors = $r->get_error_message();
970
- $controls->errors .= '<br><a href="https://www.thenewsletterplugin.com/documentation/email-sending-issues" target="_blank"><strong>' . __('Read more about delivery issues', 'newsletter') . '</strong></a>.';
 
 
 
 
971
  } else {
972
- $controls->messages = __('Test newsletter sent to:', 'newsletter');
973
- foreach ($users as $user) {
974
- $controls->messages .= ' ' . $user->email;
975
- }
976
  $controls->messages .= '.<br>';
977
  $controls->messages .= '<a href="https://www.thenewsletterplugin.com/documentation/subscribers#test" target="_blank"><strong>' .
978
  __('Read more about test subscribers', 'newsletter') . '</strong></a>.<br>';
956
  if ($email->subject == '') {
957
  $email->subject = '[TEST] Dummy subject, it was empty (remember to set it)';
958
  } else {
959
+ $email->subject = $email->subject . ' (TEST)';
960
  }
961
  $users = NewsletterUsers::instance()->get_test_users();
962
  if (count($users) == 0) {
964
  '. <a href="https://www.thenewsletterplugin.com/plugins/newsletter/subscribers-module#test" target="_blank"><strong>' .
965
  __('Read more', 'newsletter') . '</strong></a>.';
966
  } else {
967
+ $r = Newsletter::instance()->send($email, $users, true);
968
+ $emails = array();
969
+ foreach ($users as $user) {
970
+ $emails[] = '<a href="admin.php?page=newsletter_users_edit&id=' . $user->id . '" target="_blank">' . $user->email . '</a>';
971
+ }
972
  if (is_wp_error($r)) {
973
+ $controls->errors = 'Something went wrong. Check the error logs on status page.<br>';
974
+ $controls->errors .= __('Test subscribers:', 'newsletter');
975
+ $controls->errors .= ' ' . implode(', ', $emails);
976
+ $controls->errors .= '<br>';
977
+ $controls->errors .= '<strong>' . esc_html($r->get_error_message()) . '</strong><br>';
978
+ $controls->errors .= '<a href="https://www.thenewsletterplugin.com/documentation/email-sending-issues" target="_blank"><strong>' . __('Read more about delivery issues', 'newsletter') . '</strong></a>.';
979
  } else {
980
+ $controls->messages = __('Test subscribers:', 'newsletter');
981
+
982
+ $controls->messages .= ' ' . implode(', ', $emails);
 
983
  $controls->messages .= '.<br>';
984
  $controls->messages .= '<a href="https://www.thenewsletterplugin.com/documentation/subscribers#test" target="_blank"><strong>' .
985
  __('Read more about test subscribers', 'newsletter') . '</strong></a>.<br>';
includes/controls.php CHANGED
@@ -1554,7 +1554,7 @@ class NewsletterControls {
1554
  if ($time == false) {
1555
  $buffer = 'none';
1556
  } else {
1557
- $buffer = gmdate(get_option('date_format') . ' ' . get_option('time_format'), $time + get_option('gmt_offset') * 3600);
1558
  }
1559
  if ($now) {
1560
  $buffer .= ' (now: ' . gmdate(get_option('date_format') . ' ' .
1554
  if ($time == false) {
1555
  $buffer = 'none';
1556
  } else {
1557
+ $buffer = date_i18n(get_option('date_format') . ' ' . get_option('time_format'), $time + get_option('gmt_offset') * 3600);
1558
  }
1559
  if ($now) {
1560
  $buffer .= ' (now: ' . gmdate(get_option('date_format') . ' ' .
includes/module.php CHANGED
@@ -138,6 +138,10 @@ class NewsletterAddon {
138
 
139
  }
140
 
 
 
 
 
141
  function get_logger() {
142
  if (!$this->logger) {
143
  $this->logger = new NewsletterLogger($this->name);
@@ -567,6 +571,17 @@ class NewsletterModule {
567
  }
568
  return $r;
569
  }
 
 
 
 
 
 
 
 
 
 
 
570
 
571
  /**
572
  *
138
 
139
  }
140
 
141
+ /**
142
+ *
143
+ * @return NewsletterLogger
144
+ */
145
  function get_logger() {
146
  if (!$this->logger) {
147
  $this->logger = new NewsletterLogger($this->name);
571
  }
572
  return $r;
573
  }
574
+
575
+ function get_results($query) {
576
+ global $wpdb;
577
+ $r = $wpdb->get_results($query);
578
+ if ($r === false) {
579
+ $logger = $this->get_logger();
580
+ $logger->fatal($query);
581
+ $logger->fatal($wpdb->last_error);
582
+ }
583
+ return $r;
584
+ }
585
 
586
  /**
587
  *
includes/store.php CHANGED
@@ -1,5 +1,5 @@
1
  <?php
2
- if (!defined('ABSPATH')) exit;
3
 
4
  @require_once NEWSLETTER_INCLUDES_DIR . '/logger.php';
5
 
@@ -35,7 +35,7 @@ class NewsletterStore {
35
  global $wpdb;
36
  $field_name = (string)$field_name;
37
  if (preg_match('/^[a-zA-Z_]+$/', $field_name) == 0) {
38
- $this->logger->error('Invalis field name: ' . $field_name);
39
  return false;
40
  }
41
  $id = (int)$id;
@@ -225,7 +225,7 @@ class NewsletterStore {
225
  $this->logger->error('Invalis field name: ' . $field_name);
226
  return false;
227
  }
228
- $result = $wpdb->query($wpdb->prepare("update $table set $field=%s where id=%d", $value, $id));
229
 
230
  if ($wpdb->last_error) {
231
  $this->logger->error($wpdb->last_error);
1
  <?php
2
+ defined('ABSPATH') || exit;
3
 
4
  @require_once NEWSLETTER_INCLUDES_DIR . '/logger.php';
5
 
35
  global $wpdb;
36
  $field_name = (string)$field_name;
37
  if (preg_match('/^[a-zA-Z_]+$/', $field_name) == 0) {
38
+ $this->logger->fatal('Invalis field name: ' . $field_name);
39
  return false;
40
  }
41
  $id = (int)$id;
225
  $this->logger->error('Invalis field name: ' . $field_name);
226
  return false;
227
  }
228
+ $result = $wpdb->query($wpdb->prepare("update $table set $field=%s where id=%d limit 1", $value, $id));
229
 
230
  if ($wpdb->last_error) {
231
  $this->logger->error($wpdb->last_error);
main/defaults.php CHANGED
@@ -21,6 +21,7 @@ $options = array(
21
  'ip'=>'',
22
  'page'=>0,
23
  'disable_cron_notice'=>0,
 
24
 
25
  'header_logo' => '',
26
  'header_title' => get_bloginfo('name'),
21
  'ip'=>'',
22
  'page'=>0,
23
  'disable_cron_notice'=>0,
24
+ 'do_shortcodes'=>0,
25
 
26
  'header_logo' => '',
27
  'header_title' => get_bloginfo('name'),
main/main.php CHANGED
@@ -351,6 +351,17 @@ if (!empty($return_path)) {
351
  <?php $controls->help('https://www.thenewsletterplugin.com/plugins/newsletter/newsletter-configuration#encoding') ?>
352
  </td>
353
  </tr>
 
 
 
 
 
 
 
 
 
 
 
354
  </table>
355
 
356
  </div>
351
  <?php $controls->help('https://www.thenewsletterplugin.com/plugins/newsletter/newsletter-configuration#encoding') ?>
352
  </td>
353
  </tr>
354
+
355
+ <tr>
356
+ <th>
357
+ <?php _e('Execute shortcodes on newsletters', 'newsletter') ?>
358
+ <?php $controls->field_help("https://www.thenewsletterplugin.com/documentation/newsletter-configuration#shortcodes")?>
359
+ </th>
360
+ <td>
361
+ <?php $controls->yesno('do_shortcodes', 40); ?>
362
+ <?php $controls->field_help("https://www.thenewsletterplugin.com/documentation/newsletter-configuration#shortcodes")?>
363
+ </td>
364
+ </tr>
365
  </table>
366
 
367
  </div>
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.3.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.
@@ -28,7 +28,7 @@
28
 
29
  */
30
 
31
- define('NEWSLETTER_VERSION', '6.3.5');
32
 
33
  global $newsletter, $wpdb;
34
 
@@ -71,9 +71,6 @@ if (!defined('NEWSLETTER_CRON_INTERVAL'))
71
  if (!defined('NEWSLETTER_HEADER'))
72
  define('NEWSLETTER_HEADER', true);
73
 
74
- if (!defined('NEWSLETTER_DEBUG'))
75
- define('NEWSLETTER_DEBUG', false);
76
-
77
  // Force the whole system log level to this value
78
  //define('NEWSLETTER_LOG_LEVEL', 4);
79
 
@@ -135,27 +132,30 @@ class Newsletter extends NewsletterModule {
135
  $this->action = $_POST['na'];
136
  }
137
 
138
- if (!empty($this->action)) {
139
- // For old versions of wp super cache
140
- $_GET['preview'] = 'true';
141
- }
142
-
143
  $this->time_start = time();
144
 
145
  // Here because the upgrade is called by the parent constructor and uses the scheduler
146
- add_filter('cron_schedules', array($this, 'hook_cron_schedules'), 1000);
 
 
 
 
 
 
 
147
  parent::__construct('main', '1.5.1', null, array('info', 'smtp'));
148
 
149
  $max = $this->options['scheduler_max'];
150
  if (!is_numeric($max)) {
151
  $max = 100;
152
  }
153
- $this->max_emails = max(floor($max / 12), 1);
154
 
 
155
  add_action('init', array($this, 'hook_init'), 1);
 
 
156
  add_action('newsletter', array($this, 'hook_newsletter'), 1);
157
- //add_action('newsletter_extension_versions', array($this, 'hook_newsletter_extension_versions'), 1);
158
- add_action('plugins_loaded', array($this, 'hook_plugins_loaded'));
159
 
160
  $this->update_cron_stats();
161
 
@@ -176,6 +176,82 @@ class Newsletter extends NewsletterModule {
176
  }
177
  }
178
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
179
  function update_cron_stats() {
180
  if (defined('DOING_CRON') && DOING_CRON) {
181
  $calls = get_option('newsletter_diagnostic_cron_calls', array());
@@ -385,80 +461,6 @@ class Newsletter extends NewsletterModule {
385
 
386
  }
387
 
388
- function hook_init() {
389
- global $wpdb;
390
-
391
- if (isset($this->options['debug']) && $this->options['debug'] == 1) {
392
- ini_set('log_errors', 1);
393
- ini_set('error_log', WP_CONTENT_DIR . '/logs/newsletter/php-' . date('Y-m') . '-' . get_option('newsletter_logger_secret') . '.txt');
394
- }
395
-
396
- add_shortcode('newsletter_replace', array($this, 'shortcode_newsletter_replace'));
397
-
398
- if (!method_exists('NewsletterExtensions', 'hook_site_transient_update_plugins')) {
399
- add_filter('site_transient_update_plugins', array($this, 'hook_site_transient_update_plugins'));
400
- }
401
-
402
- if (is_admin()) {
403
- add_action('in_admin_header', array($this, 'hook_in_admin_header'), 1000);
404
-
405
- if ($this->is_admin_page()) {
406
- $newsletter_url = plugins_url('newsletter');
407
- wp_enqueue_script('jquery-ui-tabs');
408
- wp_enqueue_script('jquery-ui-tooltip');
409
- wp_enqueue_media();
410
- wp_enqueue_style('tnp-admin', $newsletter_url . '/admin.css', array(), filemtime(NEWSLETTER_DIR . '/admin.css'));
411
- wp_enqueue_script('tnp-admin', $newsletter_url . '/admin.js', array('jquery'), time());
412
-
413
- wp_enqueue_style('wp-color-picker');
414
- wp_enqueue_script('wp-color-picker');
415
-
416
- wp_enqueue_style('tnp-select2', $newsletter_url . '/vendor/select2/select2.css');
417
- wp_enqueue_script('tnp-select2', $newsletter_url . '/vendor/select2/select2.min.js');
418
- wp_enqueue_script('tnp-jquery-vmap', $newsletter_url . '/vendor/jqvmap/jquery.vmap.min.js', array('jquery'));
419
- wp_enqueue_script('tnp-jquery-vmap-world', $newsletter_url . '/vendor/jqvmap/jquery.vmap.world.js', array('tnp-jquery-vmap'));
420
- wp_enqueue_style('tnp-jquery-vmap', $newsletter_url . '/vendor/jqvmap/jqvmap.min.css');
421
-
422
- wp_register_script('tnp-chart', $newsletter_url . '/vendor/chartjs/Chart.min.js', array('jquery'));
423
-
424
- $dismissed = get_option('newsletter_dismissed', array());
425
-
426
- if (isset($_GET['dismiss'])) {
427
- $dismissed[$_GET['dismiss']] = 1;
428
- update_option('newsletter_dismissed', $dismissed);
429
- wp_redirect($_SERVER['HTTP_REFERER']);
430
- exit();
431
- }
432
- }
433
- } else {
434
- add_action('wp_enqueue_scripts', array($this, 'hook_wp_enqueue_scripts'));
435
- }
436
-
437
- do_action('newsletter_init');
438
-
439
- if (empty($this->action)) {
440
- return;
441
- }
442
-
443
- if ($this->action == 'fu') {
444
- $user = $this->check_user();
445
- if ($user == null) {
446
- die('No user');
447
- }
448
- $wpdb->query("update " . NEWSLETTER_USERS_TABLE . " set followup=2 where id=" . $user->id);
449
- $options_followup = get_option('newsletter_followup');
450
- $this->message = $options_followup['unsubscribed_text'];
451
- return;
452
- }
453
-
454
- if ($this->action == 'test') {
455
- echo 'ok';
456
- die();
457
- }
458
-
459
- do_action('newsletter_action', $this->action);
460
- }
461
-
462
  function hook_in_admin_header() {
463
  if (!$this->is_admin_page()) {
464
  add_action('admin_notices', array($this, 'hook_admin_notices'));
@@ -554,7 +556,7 @@ class Newsletter extends NewsletterModule {
554
  function hook_newsletter() {
555
  global $wpdb;
556
 
557
- $this->logger->debug('hook_newsletter> Start');
558
 
559
  // Do not accept job activation before at least 4 minutes are elapsed from the last run.
560
  if (!$this->check_transient('engine', NEWSLETTER_CRON_INTERVAL)) {
@@ -562,16 +564,21 @@ class Newsletter extends NewsletterModule {
562
  }
563
 
564
  // Retrieve all emails in "sending" status
565
- $emails = $wpdb->get_results("select * from " . NEWSLETTER_EMAILS_TABLE . " where status='sending' and send_on<" . time() . " order by id asc");
566
- $this->logger->debug('hook_newsletter> Emails found in sending status: ' . count($emails));
 
567
  foreach ($emails as $email) {
568
- $this->logger->debug('hook_newsletter> Sending email ' . $email->id);
569
- $this->send($email);
 
 
 
 
570
  }
571
  // Remove the semaphore so the delivery engine can be activated again
572
  $this->delete_transient('engine');
573
 
574
- $this->logger->debug('hook_newsletter> End');
575
  }
576
 
577
  /**
@@ -584,7 +591,7 @@ class Newsletter extends NewsletterModule {
584
  * @param array $users
585
  * @return boolean True if the proccess completed, false if limits was reached. On false the caller should no continue to call it with other emails.
586
  */
587
- function send($email, $users = null) {
588
  global $wpdb;
589
 
590
  ignore_user_abort(true);
@@ -598,10 +605,10 @@ class Newsletter extends NewsletterModule {
598
  $email->id = 0;
599
  }
600
 
601
- $this->logger->debug('send> Email ID: ' . $email->id);
602
 
603
  // This stops the update of last_id and sent fields since it's not a scheduled delivery but a test or something else (like an autoresponder)
604
- $test = $users != null;
605
 
606
  if ($users == null) {
607
 
@@ -619,10 +626,10 @@ class Newsletter extends NewsletterModule {
619
  $email->options = maybe_unserialize($email->options);
620
  $max_emails = apply_filters('newsletter_send_max_emails', $this->max_emails, $email);
621
 
622
- $this->logger->debug('send> Max emails per run: ' . $max_emails);
623
 
624
  if (empty($max_emails)) {
625
- $this->logger->error('send> Max emails empty after the filter');
626
  $max_emails = $this->max_emails;
627
  }
628
 
@@ -630,26 +637,25 @@ class Newsletter extends NewsletterModule {
630
  $query = $email->query;
631
  $query .= " and id>" . $email->last_id . " order by id limit " . $max_emails;
632
 
633
- $this->logger->debug('send> Query: ' . $query);
634
 
635
- $users = $wpdb->get_results($query);
636
 
637
- $this->logger->debug('send> Loaded users: ' . count($users));
638
 
639
  // If there was a database error, do nothing
640
- if ($wpdb->last_error) {
641
- $this->logger->fatal($wpdb->last_error);
642
- $this->logger->fatal($wpdb->last_query);
643
- return;
644
  }
645
 
646
  if (empty($users)) {
647
- $this->logger->info('send> No more users, set as sent');
648
  $wpdb->query("update " . NEWSLETTER_EMAILS_TABLE . " set status='sent', total=sent where id=" . $email->id . " limit 1");
649
  return true;
650
  }
651
 
652
- //$users = apply_filters('newsletter_send_users', $users, $email);
 
653
  }
654
 
655
  $start_time = microtime(true);
@@ -658,43 +664,49 @@ class Newsletter extends NewsletterModule {
658
 
659
  $mailer = $this->get_mailer();
660
 
661
- // TODO: Reduce the $users to respect the limits
662
  $batch_size = $mailer->get_batch_size();
663
 
 
 
664
  // For batch size == 1 (normal condition) we optimize
665
  if ($batch_size == 1) {
 
666
  foreach ($users as $user) {
667
- if (!$test && $this->limits_exceeded()) {
668
  $result = false;
669
  break;
670
  }
671
 
 
672
  $user = apply_filters('newsletter_send_user', $user);
673
  $message = $this->build_message($email, $user);
674
- $r = $mailer->send($message);
675
  if (!$test) {
 
676
  $wpdb->query("update " . NEWSLETTER_EMAILS_TABLE . " set sent=sent+1, last_id=" . $user->id . " where id=" . $email->id . " limit 1");
677
- $this->save_sent($message->user_id, $email, !empty($message->error) ? 1 : 0, $message->error);
678
-
679
- // Check the error level
680
- if (is_wp_error($r) && $r->get_error_code() == NewsletterMailer::ERROR_FATAL) {
681
- return $r;
682
- }
683
- } else {
684
- if (is_wp_error($r)) return $r;
685
  }
686
- // TODO: Review if they're useful
687
- $this->email_limit--;
688
- $count++;
 
 
 
 
 
 
 
 
689
  }
 
 
 
690
  } else {
 
691
  $chunks = array_chunk($users, $batch_size);
692
 
693
  foreach ($chunks as $chunk) {
694
 
695
- // Before try to send, check the limits.
696
- // TODO: Remove when the above todo is implemented
697
- if (!$test && $this->limits_exceeded()) {
698
  $result = false;
699
  break;
700
  }
@@ -702,13 +714,15 @@ class Newsletter extends NewsletterModule {
702
  $messages = array();
703
 
704
  foreach ($chunk as $user) {
705
- $this->logger->debug('send> Processing user ID: ' . $user->id);
706
- $user = apply_filters('newsletter_send_user', $user);
707
 
 
 
708
  $message = $this->build_message($email, $user);
709
 
710
  $messages[] = $message;
 
711
  if (!$test) {
 
712
  $wpdb->query("update " . NEWSLETTER_EMAILS_TABLE . " set sent=sent+1, last_id=" . $user->id . " where id=" . $email->id . " limit 1");
713
  }
714
  $this->email_limit--;
@@ -717,15 +731,16 @@ class Newsletter extends NewsletterModule {
717
 
718
  $r = $mailer->send_batch($messages);
719
 
720
- if (!$test) {
721
- foreach ($messages as $message) {
722
- $this->save_sent($message->user_id, $email, !empty($message->error) ? 1 : 0, $message->error);
723
- }
724
- if (is_wp_error($r) && $r->get_error_code() == NewsletterMailer::ERROR_FATAL) {
725
- return $r;
726
  }
727
  }
728
-
 
 
 
 
729
  }
730
  }
731
 
@@ -740,6 +755,13 @@ class Newsletter extends NewsletterModule {
740
 
741
  update_option('newsletter_diagnostic_send_calls', $send_calls, false);
742
  }
 
 
 
 
 
 
 
743
  return $result;
744
  }
745
 
@@ -764,6 +786,9 @@ class Newsletter extends NewsletterModule {
764
  $message->body = preg_replace('/data-json=".*?"/is', '', $email->message);
765
  $message->body = preg_replace('/ +/s', ' ', $message->body);
766
  $message->body = $this->replace($message->body, $user, $email);
 
 
 
767
  $message->body = apply_filters('newsletter_message_html', $message->body, $email, $user);
768
 
769
  $message->body_text = $this->replace($email->message_text, $user, $email);
@@ -775,41 +800,32 @@ class Newsletter extends NewsletterModule {
775
 
776
  $message->subject = $this->replace($email->subject, $user);
777
  $message->subject = apply_filters('newsletter_message_subject', $message->subject, $email, $user);
778
-
779
  // TODO: Use the $email properties when available
780
  $message->from = $this->options['sender_email'];
781
  $message->from_name = $this->options['sender_name'];
782
-
783
  $message->email_id = $email->id;
784
  $message->user_id = $user->id;
785
-
786
  return $message;
787
  }
788
 
789
- function save_sent($user, $email, $status = 0, $error = '') {
 
 
 
 
 
 
790
  global $wpdb;
791
- //$this->logger->debug('Saving sent data');
792
- $user_id = 0;
793
- if (is_numeric($user)) {
794
- $user_id = $user;
795
- } else if (is_array($user) && isset($user['id'])) {
796
- $user_id = $user['id'];
797
- } else if (is_object($user) && isset($user->id)) {
798
- $user_id = $user->id;
799
- } else if (is_string($user)) {
800
- // is an email
801
- $user = $this->get_user($user);
802
- if ($user) {
803
- $user_id = $user->id;
804
- }
805
- }
806
 
807
- $email_id = $this->to_int_id($email);
808
-
809
- if (!$user_id) {
810
  return;
811
  }
812
- $wpdb->query($wpdb->prepare("insert into " . $wpdb->prefix . 'newsletter_sent (user_id, email_id, time, status, error) values (%d, %d, %d, %d, %s) on duplicate key update time=%d, status=%d, error=%s', $user_id, $email_id, time(), $status, $error, time(), $status, $error));
 
 
813
  }
814
 
815
  /**
@@ -820,7 +836,7 @@ class Newsletter extends NewsletterModule {
820
  global $wpdb;
821
 
822
  if (!$this->limits_set) {
823
- $this->logger->debug('limits_exceeded> Setting the limits for the first time');
824
 
825
  @set_time_limit(NEWSLETTER_CRON_INTERVAL + 30);
826
 
@@ -831,14 +847,14 @@ class Newsletter extends NewsletterModule {
831
 
832
  $this->time_limit = $this->time_start + $max_time;
833
 
834
- $this->logger->info('limits_exceeded> Max time set to ' . $max_time);
835
 
836
  $max = (int) $this->options['scheduler_max'];
837
  if (!$max) {
838
  $max = 100;
839
  }
840
  $this->email_limit = max(floor($max / 12), 1);
841
- $this->logger->debug('limits_exceeded> Max number of emails can send: ' . $this->email_limit);
842
 
843
  $wpdb->query("set session wait_timeout=300");
844
  // From default-constants.php
@@ -851,12 +867,12 @@ class Newsletter extends NewsletterModule {
851
 
852
  // The time limit is set on constructor, since it has to be set as early as possible
853
  if (time() > $this->time_limit) {
854
- $this->logger->info('limits_exceeded> Max execution time limit reached');
855
  return true;
856
  }
857
 
858
  if ($this->email_limit <= 0) {
859
- $this->logger->info('limits_exceeded> Max emails limit reached');
860
  return true;
861
  }
862
  return false;
@@ -872,7 +888,8 @@ class Newsletter extends NewsletterModule {
872
 
873
  function register_mailer($mailer) {
874
  //$this->logger->debug($mailer);
875
- if (!$mailer) return;
 
876
  if ($mailer instanceof NewsletterMailer) {
877
  $this->mailer = $mailer;
878
  } else {
@@ -959,14 +976,6 @@ class Newsletter extends NewsletterModule {
959
  wp_clear_scheduled_hook('newsletter');
960
  }
961
 
962
- function hook_cron_schedules($schedules) {
963
- $schedules['newsletter'] = array(
964
- 'interval' => NEWSLETTER_CRON_INTERVAL, // seconds
965
- 'display' => 'Every 5 minutes by Newsletter'
966
- );
967
- return $schedules;
968
- }
969
-
970
  function shortcode_newsletter_form($attrs, $content) {
971
  return $this->form($attrs['form']);
972
  }
@@ -1149,7 +1158,7 @@ class Newsletter extends NewsletterModule {
1149
 
1150
  return $extensions;
1151
  }
1152
-
1153
  function clear_extensions_cache() {
1154
  delete_transient('tnp_extensions_json');
1155
  }
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.3.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.
28
 
29
  */
30
 
31
+ define('NEWSLETTER_VERSION', '6.3.6');
32
 
33
  global $newsletter, $wpdb;
34
 
71
  if (!defined('NEWSLETTER_HEADER'))
72
  define('NEWSLETTER_HEADER', true);
73
 
 
 
 
74
  // Force the whole system log level to this value
75
  //define('NEWSLETTER_LOG_LEVEL', 4);
76
 
132
  $this->action = $_POST['na'];
133
  }
134
 
 
 
 
 
 
135
  $this->time_start = time();
136
 
137
  // Here because the upgrade is called by the parent constructor and uses the scheduler
138
+ add_filter('cron_schedules', function () {
139
+ $schedules['newsletter'] = array(
140
+ 'interval' => NEWSLETTER_CRON_INTERVAL, // seconds
141
+ 'display' => 'Every ' . NEWSLETTER_CRON_INTERVAL . ' seconds by Newsletter'
142
+ );
143
+ return $schedules;
144
+ }, 1000);
145
+
146
  parent::__construct('main', '1.5.1', null, array('info', 'smtp'));
147
 
148
  $max = $this->options['scheduler_max'];
149
  if (!is_numeric($max)) {
150
  $max = 100;
151
  }
152
+ $this->max_emails = max(floor($max / (3600 / NEWSLETTER_CRON_INTERVAL)), 1);
153
 
154
+ add_action('plugins_loaded', array($this, 'hook_plugins_loaded'));
155
  add_action('init', array($this, 'hook_init'), 1);
156
+ add_action('wp_loaded', array($this, 'hook_wp_loaded'), 1);
157
+
158
  add_action('newsletter', array($this, 'hook_newsletter'), 1);
 
 
159
 
160
  $this->update_cron_stats();
161
 
176
  }
177
  }
178
 
179
+ function hook_init() {
180
+ global $wpdb;
181
+
182
+ if (isset($this->options['debug']) && $this->options['debug'] == 1) {
183
+ ini_set('log_errors', 1);
184
+ ini_set('error_log', WP_CONTENT_DIR . '/logs/newsletter/php-' . date('Y-m') . '-' . get_option('newsletter_logger_secret') . '.txt');
185
+ }
186
+
187
+ add_shortcode('newsletter_replace', array($this, 'shortcode_newsletter_replace'));
188
+
189
+ if (!method_exists('NewsletterExtensions', 'hook_site_transient_update_plugins')) {
190
+ add_filter('site_transient_update_plugins', array($this, 'hook_site_transient_update_plugins'));
191
+ }
192
+
193
+ if (is_admin()) {
194
+ add_action('in_admin_header', array($this, 'hook_in_admin_header'), 1000);
195
+
196
+ if ($this->is_admin_page()) {
197
+ $newsletter_url = plugins_url('newsletter');
198
+ wp_enqueue_script('jquery-ui-tabs');
199
+ wp_enqueue_script('jquery-ui-tooltip');
200
+ wp_enqueue_media();
201
+ wp_enqueue_style('tnp-admin', $newsletter_url . '/admin.css', array(), filemtime(NEWSLETTER_DIR . '/admin.css'));
202
+ wp_enqueue_script('tnp-admin', $newsletter_url . '/admin.js', array('jquery'), time());
203
+
204
+ wp_enqueue_style('wp-color-picker');
205
+ wp_enqueue_script('wp-color-picker');
206
+
207
+ wp_enqueue_style('tnp-select2', $newsletter_url . '/vendor/select2/select2.css');
208
+ wp_enqueue_script('tnp-select2', $newsletter_url . '/vendor/select2/select2.min.js');
209
+ wp_enqueue_script('tnp-jquery-vmap', $newsletter_url . '/vendor/jqvmap/jquery.vmap.min.js', array('jquery'));
210
+ wp_enqueue_script('tnp-jquery-vmap-world', $newsletter_url . '/vendor/jqvmap/jquery.vmap.world.js', array('tnp-jquery-vmap'));
211
+ wp_enqueue_style('tnp-jquery-vmap', $newsletter_url . '/vendor/jqvmap/jqvmap.min.css');
212
+
213
+ wp_register_script('tnp-chart', $newsletter_url . '/vendor/chartjs/Chart.min.js', array('jquery'));
214
+
215
+ $dismissed = get_option('newsletter_dismissed', array());
216
+
217
+ if (isset($_GET['dismiss'])) {
218
+ $dismissed[$_GET['dismiss']] = 1;
219
+ update_option('newsletter_dismissed', $dismissed);
220
+ wp_redirect($_SERVER['HTTP_REFERER']);
221
+ exit();
222
+ }
223
+ }
224
+ } else {
225
+ add_action('wp_enqueue_scripts', array($this, 'hook_wp_enqueue_scripts'));
226
+ }
227
+
228
+ do_action('newsletter_init');
229
+ }
230
+
231
+ function hook_wp_loaded() {
232
+ if (empty($this->action)) {
233
+ return;
234
+ }
235
+
236
+ if ($this->action == 'fu') {
237
+ $user = $this->check_user();
238
+ if ($user == null) {
239
+ die('No user');
240
+ }
241
+ $wpdb->query("update " . NEWSLETTER_USERS_TABLE . " set followup=2 where id=" . $user->id);
242
+ $options_followup = get_option('newsletter_followup');
243
+ $this->message = $options_followup['unsubscribed_text'];
244
+ return;
245
+ }
246
+
247
+ if ($this->action == 'test') {
248
+ echo 'ok';
249
+ die();
250
+ }
251
+
252
+ do_action('newsletter_action', $this->action);
253
+ }
254
+
255
  function update_cron_stats() {
256
  if (defined('DOING_CRON') && DOING_CRON) {
257
  $calls = get_option('newsletter_diagnostic_cron_calls', array());
461
 
462
  }
463
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
464
  function hook_in_admin_header() {
465
  if (!$this->is_admin_page()) {
466
  add_action('admin_notices', array($this, 'hook_admin_notices'));
556
  function hook_newsletter() {
557
  global $wpdb;
558
 
559
+ $this->logger->debug(__METHOD__ . '> Start');
560
 
561
  // Do not accept job activation before at least 4 minutes are elapsed from the last run.
562
  if (!$this->check_transient('engine', NEWSLETTER_CRON_INTERVAL)) {
564
  }
565
 
566
  // Retrieve all emails in "sending" status
567
+ $emails = $this->get_results("select * from " . NEWSLETTER_EMAILS_TABLE . " where status='sending' and send_on<" . time() . " order by id asc");
568
+ $this->logger->debug(__METHOD__ . '> Emails found in sending status: ' . count($emails));
569
+
570
  foreach ($emails as $email) {
571
+ $this->logger->info(__METHOD__ . '> Start newsletter ' . $email->id);
572
+ $r = $this->send($email);
573
+ if ($this->limits_exceeded()) {
574
+ break;
575
+ }
576
+ $this->logger->info(__METHOD__ . '> End newsletter ' . $email->id);
577
  }
578
  // Remove the semaphore so the delivery engine can be activated again
579
  $this->delete_transient('engine');
580
 
581
+ $this->logger->debug(__METHOD__ . '> End');
582
  }
583
 
584
  /**
591
  * @param array $users
592
  * @return boolean True if the proccess completed, false if limits was reached. On false the caller should no continue to call it with other emails.
593
  */
594
+ function send($email, $users = null, $test = false) {
595
  global $wpdb;
596
 
597
  ignore_user_abort(true);
605
  $email->id = 0;
606
  }
607
 
608
+ $this->logger->info(__METHOD__ . '> Start run for email ' . $email->id);
609
 
610
  // This stops the update of last_id and sent fields since it's not a scheduled delivery but a test or something else (like an autoresponder)
611
+ $supplied_users = $users != null;
612
 
613
  if ($users == null) {
614
 
626
  $email->options = maybe_unserialize($email->options);
627
  $max_emails = apply_filters('newsletter_send_max_emails', $this->max_emails, $email);
628
 
629
+ $this->logger->debug(__METHOD__ . '> Max emails per run: ' . $max_emails);
630
 
631
  if (empty($max_emails)) {
632
+ $this->logger->debug(__METHOD__ . '> Max emails empty after the filter');
633
  $max_emails = $this->max_emails;
634
  }
635
 
637
  $query = $email->query;
638
  $query .= " and id>" . $email->last_id . " order by id limit " . $max_emails;
639
 
640
+ $this->logger->debug(__METHOD__ . '> Query: ' . $query);
641
 
642
+ $users = $this->get_results($query);
643
 
644
+ $this->logger->debug(__METHOD__ . '> Loaded users: ' . count($users));
645
 
646
  // If there was a database error, do nothing
647
+ if ($users === false) {
648
+ return new WP_Error('1', 'Unable to query subscribers, check the logs');
 
 
649
  }
650
 
651
  if (empty($users)) {
652
+ $this->logger->info(__METHOD__ . '> No more users, set as sent');
653
  $wpdb->query("update " . NEWSLETTER_EMAILS_TABLE . " set status='sent', total=sent where id=" . $email->id . " limit 1");
654
  return true;
655
  }
656
 
657
+ } else {
658
+ $this->logger->info(__METHOD__ . '> Subscribers supplied');
659
  }
660
 
661
  $start_time = microtime(true);
664
 
665
  $mailer = $this->get_mailer();
666
 
 
667
  $batch_size = $mailer->get_batch_size();
668
 
669
+ $this->logger->debug(__METHOD__ . '> Batch size: ' . $batch_size);
670
+
671
  // For batch size == 1 (normal condition) we optimize
672
  if ($batch_size == 1) {
673
+
674
  foreach ($users as $user) {
675
+ if (!$supplied_users && !$test && $this->limits_exceeded()) {
676
  $result = false;
677
  break;
678
  }
679
 
680
+ $this->logger->debug(__METHOD__ . '> Processing user ID: ' . $user->id);
681
  $user = apply_filters('newsletter_send_user', $user);
682
  $message = $this->build_message($email, $user);
683
+
684
  if (!$test) {
685
+ $this->save_sent_message($message);
686
  $wpdb->query("update " . NEWSLETTER_EMAILS_TABLE . " set sent=sent+1, last_id=" . $user->id . " where id=" . $email->id . " limit 1");
 
 
 
 
 
 
 
 
687
  }
688
+
689
+ $r = $mailer->send($message);
690
+
691
+ if (!$test && !empty($message->error)) {
692
+ $this->save_sent_message($message);
693
+ }
694
+
695
+ if (is_wp_error($r)) {
696
+ $this->logger->error($r);
697
+ return $r;
698
+ }
699
  }
700
+ // TODO: Review if they're useful
701
+ $this->email_limit--;
702
+ $count++;
703
  } else {
704
+
705
  $chunks = array_chunk($users, $batch_size);
706
 
707
  foreach ($chunks as $chunk) {
708
 
709
+ if (!$supplied_users && !$test && $this->limits_exceeded()) {
 
 
710
  $result = false;
711
  break;
712
  }
714
  $messages = array();
715
 
716
  foreach ($chunk as $user) {
 
 
717
 
718
+ $this->logger->debug(__METHOD__ . '> Processing user ID: ' . $user->id);
719
+ $user = apply_filters('newsletter_send_user', $user);
720
  $message = $this->build_message($email, $user);
721
 
722
  $messages[] = $message;
723
+
724
  if (!$test) {
725
+ $this->save_sent_message($message);
726
  $wpdb->query("update " . NEWSLETTER_EMAILS_TABLE . " set sent=sent+1, last_id=" . $user->id . " where id=" . $email->id . " limit 1");
727
  }
728
  $this->email_limit--;
731
 
732
  $r = $mailer->send_batch($messages);
733
 
734
+ foreach ($messages as $message) {
735
+ if (!$test && !empty($message->error)) {
736
+ $this->save_sent_message($message);
 
 
 
737
  }
738
  }
739
+
740
+ if (is_wp_error($r)) {
741
+ $this->logger->error($r);
742
+ return $r;
743
+ }
744
  }
745
  }
746
 
755
 
756
  update_option('newsletter_diagnostic_send_calls', $send_calls, false);
757
  }
758
+
759
+ if ($supplied_users && $this->limits_exceeded()) {
760
+ $result = false;
761
+ }
762
+
763
+ $this->logger->info(__METHOD__ . '> End run for email ' . $email->id);
764
+
765
  return $result;
766
  }
767
 
786
  $message->body = preg_replace('/data-json=".*?"/is', '', $email->message);
787
  $message->body = preg_replace('/ +/s', ' ', $message->body);
788
  $message->body = $this->replace($message->body, $user, $email);
789
+ if ($this->options['do_shortcodes']) {
790
+ $message->body = do_shortcode($message->body);
791
+ }
792
  $message->body = apply_filters('newsletter_message_html', $message->body, $email, $user);
793
 
794
  $message->body_text = $this->replace($email->message_text, $user, $email);
800
 
801
  $message->subject = $this->replace($email->subject, $user);
802
  $message->subject = apply_filters('newsletter_message_subject', $message->subject, $email, $user);
803
+
804
  // TODO: Use the $email properties when available
805
  $message->from = $this->options['sender_email'];
806
  $message->from_name = $this->options['sender_name'];
807
+
808
  $message->email_id = $email->id;
809
  $message->user_id = $user->id;
810
+
811
  return $message;
812
  }
813
 
814
+ /**
815
+ *
816
+ * @param TNP_Mailer_Message $message
817
+ * @param int $status
818
+ * @param string $error
819
+ */
820
+ function save_sent_message($message) {
821
  global $wpdb;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
822
 
823
+ if (!$message->user_id || !$message->email_id) {
 
 
824
  return;
825
  }
826
+ $status = empty($message->error) ? 0 : 1;
827
+
828
+ $this->query($wpdb->prepare("insert into " . $wpdb->prefix . 'newsletter_sent (user_id, email_id, time, status, error) values (%d, %d, %d, %d, %s) on duplicate key update time=%d, status=%d, error=%s', $message->user_id, $message->email_id, time(), $status, $message->error, time(), $status, $message->error));
829
  }
830
 
831
  /**
836
  global $wpdb;
837
 
838
  if (!$this->limits_set) {
839
+ $this->logger->debug(__METHOD__ . '> Setting the limits for the first time');
840
 
841
  @set_time_limit(NEWSLETTER_CRON_INTERVAL + 30);
842
 
847
 
848
  $this->time_limit = $this->time_start + $max_time;
849
 
850
+ $this->logger->info(__METHOD__ . '> Max time set to ' . $max_time);
851
 
852
  $max = (int) $this->options['scheduler_max'];
853
  if (!$max) {
854
  $max = 100;
855
  }
856
  $this->email_limit = max(floor($max / 12), 1);
857
+ $this->logger->debug(__METHOD__ . '> Max number of emails can send: ' . $this->email_limit);
858
 
859
  $wpdb->query("set session wait_timeout=300");
860
  // From default-constants.php
867
 
868
  // The time limit is set on constructor, since it has to be set as early as possible
869
  if (time() > $this->time_limit) {
870
+ $this->logger->info(__METHOD__ . '> Max execution time limit reached');
871
  return true;
872
  }
873
 
874
  if ($this->email_limit <= 0) {
875
+ $this->logger->info(__METHOD__ . '> Max emails limit reached');
876
  return true;
877
  }
878
  return false;
888
 
889
  function register_mailer($mailer) {
890
  //$this->logger->debug($mailer);
891
+ if (!$mailer)
892
+ return;
893
  if ($mailer instanceof NewsletterMailer) {
894
  $this->mailer = $mailer;
895
  } else {
976
  wp_clear_scheduled_hook('newsletter');
977
  }
978
 
 
 
 
 
 
 
 
 
979
  function shortcode_newsletter_form($attrs, $content) {
980
  return $this->form($attrs['form']);
981
  }
1158
 
1159
  return $extensions;
1160
  }
1161
+
1162
  function clear_extensions_cache() {
1163
  delete_transient('tnp_extensions_json');
1164
  }
readme.txt CHANGED
@@ -1,8 +1,8 @@
1
  === Newsletter ===
2
  Tags: email, email marketing, newsletter, newsletter subscribers, welcome email, signup forms, contact, lead generation, popup, marketing automation
3
  Requires at least: 3.4.0
4
- Tested up to: 5.2.3
5
- Stable tag: 6.3.5
6
  Requires PHP: 5.6
7
  Contributors: satollo,webagile,michael-travan
8
 
@@ -109,6 +109,13 @@ Thank you, The Newsletter Team
109
 
110
  == Changelog ==
111
 
 
 
 
 
 
 
 
112
  = 6.3.5 =
113
 
114
  * New addons panel
1
  === Newsletter ===
2
  Tags: email, email marketing, newsletter, newsletter subscribers, welcome email, signup forms, contact, lead generation, popup, marketing automation
3
  Requires at least: 3.4.0
4
+ Tested up to: 5.2.4
5
+ Stable tag: 6.3.6
6
  Requires PHP: 5.6
7
  Contributors: satollo,webagile,michael-travan
8
 
109
 
110
  == Changelog ==
111
 
112
+ = 6.3.6 =
113
+
114
+ * Improved error detection
115
+ * Fixed stats collection for Autoresponder
116
+ * Changed the init sequence to grant full load of other plugins (newsletter preview problems on some installations)
117
+ * Better reporting on tests
118
+
119
  = 6.3.5 =
120
 
121
  * New addons panel