Newsletter - Version 7.3.8

Version Description

  • Fixed graph scale on System/Scheduler panel
  • Fixed untraslated labels on subscriber management panels
  • Fixed the "toggle" private/public status on sent newsletter
  • Removed the "action call test" from the status panel since it does not work with some providers but does not affect the correct working of Newsletter
  • Added developer information on this readme
Download this release

Release Info

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

Code changes from version 7.3.7 to 7.3.8

Files changed (7) hide show
  1. emails/blocks/posts/options.php +118 -117
  2. emails/edit.php +2 -2
  3. plugin.php +1418 -1418
  4. readme.txt +407 -392
  5. system/scheduler.php +1 -1
  6. system/status.php +3 -41
  7. users/users.php +7 -7
emails/blocks/posts/options.php CHANGED
@@ -1,117 +1,118 @@
1
- <?php
2
- /* @var $options array contains all the options the current block we're ediging contains */
3
- /* @var $controls NewsletterControls */
4
- /* @var $fields NewsletterFields */
5
-
6
- $extensions_url = '?page=newsletter_main_extension';
7
- if (class_exists('NewsletterExtensions')) {
8
- $extensions_url = '?page=newsletter_extensions_index';
9
- }
10
- ?>
11
- <p>
12
- Custom post types can be added using our <a href="<?php echo $extensions_url ?>" target="_blank">Advanced Composer Blocks Addon</a>.
13
- </p>
14
-
15
- <?php if ($context['type'] == 'automated') { ?>
16
-
17
- <div class="tnp-field-box">
18
- <p>
19
- <strong>AUTOMATED</strong><br>
20
- While composing all posts are shown while on sending posts are extrated following the rules below.
21
- </p>
22
- <?php $fields->select('automated_disabled', '', ['' => 'Use the last newsletter date and...', '1' => 'Do not consider the last newsletter']) ?>
23
-
24
- <div class="tnp-field-row">
25
- <div class="tnp-field-col-2">
26
- <?php
27
- $fields->select('automated_include', __('If there are new posts', 'newsletter'),
28
- [
29
- 'new' => __('Include only new posts', 'newsletter'),
30
- 'max' => __('Include specified max posts', 'newsletter')
31
- ],
32
- ['description' => '', 'class' => 'tnp-small'])
33
- ?>
34
- </div>
35
- <div class="tnp-field-col-2">
36
- <?php
37
- $fields->select('automated', __('If there are not new posts', 'newsletter'),
38
- [
39
- '' => 'Show the message below',
40
- '1' => 'Do not send the newsletter',
41
- '2' => 'Remove this block'
42
- ],
43
- ['description' => '', 'class' => 'tnp-small'])
44
- ?>
45
- <?php $fields->text('automated_no_contents', null, ['placeholder' => 'No new posts message']) ?>
46
- </div>
47
- </div>
48
- <div style="clear: both"></div>
49
- </div>
50
- <?php } ?>
51
-
52
-
53
- <?php
54
- $fields->select('layout', __('Layout', 'newsletter'),
55
- [
56
- 'one' => __('One column', 'newsletter'),
57
- 'one-2' => __('One column variant', 'newsletter'),
58
- 'two' => __('Two columns', 'newsletter'),
59
- 'big-image' => __('One column, big image', 'newsletter'),
60
- 'full-post' => __('Full post', 'newsletter')
61
- ])
62
- ?>
63
-
64
-
65
- <div class="tnp-field-row">
66
- <label class="tnp-row-label"><?php _e('Post info', 'newsletter') ?></label>
67
- <div class="tnp-field-col-3">
68
- <?php $fields->checkbox('show_date', __('Show date', 'newsletter')) ?>
69
- </div>
70
- <div class="tnp-field-col-3">
71
- <?php $fields->checkbox('show_author', __('Show author', 'newsletter')) ?>
72
- </div>
73
- <div class="tnp-field-col-3">
74
- <?php $fields->checkbox('show_image', __('Show image', 'newsletter')) ?>
75
- </div>
76
- <div style="clear: both"></div>
77
- </div>
78
-
79
- <div class="tnp-field-row">
80
- <div class="tnp-field-col-2">
81
- <?php $fields->select_number('max', __('Max posts', 'newsletter'), 1, 40); ?>
82
- </div>
83
- <div class="tnp-field-col-2">
84
- <?php $fields->select_number('post_offset', __('Posts offset', 'newsletter'), 0, 20); ?>
85
- </div>
86
- </div>
87
-
88
- <div class="tnp-field-row">
89
- <div class="tnp-field-col-2">
90
- <?php $fields->number('excerpt_length', __('Excerpt words', 'newsletter'), array('min' => 0)); ?>
91
- </div>
92
- <div class="tnp-field-col-2">
93
- <?php $fields->yesno('show_read_more_button', 'Show read more button') ?>
94
- </div>
95
- <div style="clear: both"></div>
96
- </div>
97
-
98
- <?php $fields->language(); ?>
99
-
100
- <?php $fields->section(__('Filters', 'newsletter')) ?>
101
- <?php $fields->categories(); ?>
102
- <?php $fields->text('tags', __('Tags', 'newsletter'), ['description' => __('Comma separated')]); ?>
103
-
104
- <?php $fields->section(__('Styles', 'newsletter')) ?>
105
- <?php $fields->font('title_font', __('Title font', 'newsletter'), ['family_default' => true, 'size_default' => true, 'weight_default' => true]) ?>
106
- <?php $fields->font('font', __('Excerpt font', 'newsletter'), ['family_default' => true, 'size_default' => true, 'weight_default' => true]) ?>
107
- <?php
108
- $fields->button('button', __('Read more button', 'newsletter'), [
109
- 'url' => false,
110
- 'family_default' => true,
111
- 'size_default' => true,
112
- 'weight_default' => true
113
- ])
114
- ?>
115
-
116
- <?php $fields->block_commons() ?>
117
-
 
1
+ <?php
2
+ /* @var $options array contains all the options the current block we're ediging contains */
3
+ /* @var $controls NewsletterControls */
4
+ /* @var $fields NewsletterFields */
5
+
6
+ $extensions_url = '?page=newsletter_main_extension';
7
+ if (class_exists('NewsletterExtensions')) {
8
+ $extensions_url = '?page=newsletter_extensions_index';
9
+ }
10
+ ?>
11
+ <p>
12
+ Custom post types can be added using our <a href="<?php echo $extensions_url ?>" target="_blank">Advanced Composer Blocks Addon</a>.
13
+ </p>
14
+
15
+ <?php if ($context['type'] == 'automated') { ?>
16
+
17
+ <div class="tnp-field-box">
18
+ <p>
19
+ <strong>AUTOMATED</strong><br>
20
+ While composing all posts are shown while on sending posts are extrated following the rules below.
21
+ <a href="https://www.thenewsletterplugin.com/documentation/addons/extended-features/automated-extension/#regeneration" target="_blank">Read more</a>.
22
+ </p>
23
+ <?php $fields->select('automated_disabled', '', ['' => 'Use the last newsletter date and...', '1' => 'Do not consider the last newsletter']) ?>
24
+
25
+ <div class="tnp-field-row">
26
+ <div class="tnp-field-col-2">
27
+ <?php
28
+ $fields->select('automated_include', __('If there are new posts', 'newsletter'),
29
+ [
30
+ 'new' => __('Include only new posts', 'newsletter'),
31
+ 'max' => __('Include specified max posts', 'newsletter')
32
+ ],
33
+ ['description' => '', 'class' => 'tnp-small'])
34
+ ?>
35
+ </div>
36
+ <div class="tnp-field-col-2">
37
+ <?php
38
+ $fields->select('automated', __('If there are not new posts', 'newsletter'),
39
+ [
40
+ '' => 'Show the message below',
41
+ '1' => 'Do not send the newsletter',
42
+ '2' => 'Remove this block'
43
+ ],
44
+ ['description' => '', 'class' => 'tnp-small'])
45
+ ?>
46
+ <?php $fields->text('automated_no_contents', null, ['placeholder' => 'No new posts message']) ?>
47
+ </div>
48
+ </div>
49
+ <div style="clear: both"></div>
50
+ </div>
51
+ <?php } ?>
52
+
53
+
54
+ <?php
55
+ $fields->select('layout', __('Layout', 'newsletter'),
56
+ [
57
+ 'one' => __('One column', 'newsletter'),
58
+ 'one-2' => __('One column variant', 'newsletter'),
59
+ 'two' => __('Two columns', 'newsletter'),
60
+ 'big-image' => __('One column, big image', 'newsletter'),
61
+ 'full-post' => __('Full post', 'newsletter')
62
+ ])
63
+ ?>
64
+
65
+
66
+ <div class="tnp-field-row">
67
+ <label class="tnp-row-label"><?php _e('Post info', 'newsletter') ?></label>
68
+ <div class="tnp-field-col-3">
69
+ <?php $fields->checkbox('show_date', __('Show date', 'newsletter')) ?>
70
+ </div>
71
+ <div class="tnp-field-col-3">
72
+ <?php $fields->checkbox('show_author', __('Show author', 'newsletter')) ?>
73
+ </div>
74
+ <div class="tnp-field-col-3">
75
+ <?php $fields->checkbox('show_image', __('Show image', 'newsletter')) ?>
76
+ </div>
77
+ <div style="clear: both"></div>
78
+ </div>
79
+
80
+ <div class="tnp-field-row">
81
+ <div class="tnp-field-col-2">
82
+ <?php $fields->select_number('max', __('Max posts', 'newsletter'), 1, 40); ?>
83
+ </div>
84
+ <div class="tnp-field-col-2">
85
+ <?php $fields->select_number('post_offset', __('Posts offset', 'newsletter'), 0, 20); ?>
86
+ </div>
87
+ </div>
88
+
89
+ <div class="tnp-field-row">
90
+ <div class="tnp-field-col-2">
91
+ <?php $fields->number('excerpt_length', __('Excerpt words', 'newsletter'), array('min' => 0)); ?>
92
+ </div>
93
+ <div class="tnp-field-col-2">
94
+ <?php $fields->yesno('show_read_more_button', 'Show read more button') ?>
95
+ </div>
96
+ <div style="clear: both"></div>
97
+ </div>
98
+
99
+ <?php $fields->language(); ?>
100
+
101
+ <?php $fields->section(__('Filters', 'newsletter')) ?>
102
+ <?php $fields->categories(); ?>
103
+ <?php $fields->text('tags', __('Tags', 'newsletter'), ['description' => __('Comma separated')]); ?>
104
+
105
+ <?php $fields->section(__('Styles', 'newsletter')) ?>
106
+ <?php $fields->font('title_font', __('Title font', 'newsletter'), ['family_default' => true, 'size_default' => true, 'weight_default' => true]) ?>
107
+ <?php $fields->font('font', __('Excerpt font', 'newsletter'), ['family_default' => true, 'size_default' => true, 'weight_default' => true]) ?>
108
+ <?php
109
+ $fields->button('button', __('Read more button', 'newsletter'), [
110
+ 'url' => false,
111
+ 'family_default' => true,
112
+ 'size_default' => true,
113
+ 'weight_default' => true
114
+ ])
115
+ ?>
116
+
117
+ <?php $fields->block_commons() ?>
118
+
emails/edit.php CHANGED
@@ -50,7 +50,7 @@ if ($controls->is_action('abort')) {
50
 
51
  if ($controls->is_action('change-private')) {
52
  $data = [];
53
- $data['private'] = $controls->data['private'] ? 1 : 0;
54
  $data['id'] = $email['id'];
55
  $email = $this->save_email($data, ARRAY_A);
56
  $controls->add_message_saved();
@@ -487,7 +487,7 @@ if ($email['status'] != 'sent') {
487
  <td>
488
  <?php $controls->yesno('private'); ?>
489
  <?php if ($email['status'] == 'sent') { ?>
490
- <?php $controls->button('change-private', __('Toggle')) ?>
491
  <?php } ?>
492
  <p class="description">
493
  <?php _e('Hide/show from public sent newsletter list.', 'newsletter') ?>
50
 
51
  if ($controls->is_action('change-private')) {
52
  $data = [];
53
+ $data['private'] = $controls->data['private'];
54
  $data['id'] = $email['id'];
55
  $email = $this->save_email($data, ARRAY_A);
56
  $controls->add_message_saved();
487
  <td>
488
  <?php $controls->yesno('private'); ?>
489
  <?php if ($email['status'] == 'sent') { ?>
490
+ <?php $controls->button('change-private', __('Save')) ?>
491
  <?php } ?>
492
  <p class="description">
493
  <?php _e('Hide/show from public sent newsletter list.', 'newsletter') ?>
plugin.php CHANGED
@@ -1,1418 +1,1418 @@
1
- <?php
2
-
3
- /*
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: 7.3.7
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.
11
- Text Domain: newsletter
12
- License: GPLv2 or later
13
- Requires at least: 4.6
14
- Requires PHP: 5.6
15
-
16
- Copyright 2009-2022 The Newsletter Team (email: info@thenewsletterplugin.com, web: https://www.thenewsletterplugin.com)
17
-
18
- Newsletter is free software: you can redistribute it and/or modify
19
- it under the terms of the GNU General Public License as published by
20
- the Free Software Foundation, either version 2 of the License, or
21
- any later version.
22
-
23
- Newsletter is distributed in the hope that it will be useful,
24
- but WITHOUT ANY WARRANTY; without even the implied warranty of
25
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
26
- GNU General Public License for more details.
27
-
28
- You should have received a copy of the GNU General Public License
29
- along with Newsletter. If not, see https://www.gnu.org/licenses/gpl-2.0.html.
30
-
31
- */
32
-
33
- if (version_compare(phpversion(), '5.6', '<')) {
34
- add_action('admin_notices', function () {
35
- echo '<div class="notice notice-error"><p>PHP version 5.6 or greater is required for Newsletter. Ask your provider to upgrade. <a href="https://www.php.net/supported-versions.php" target="_blank">Read more on PHP versions</a></p></div>';
36
- });
37
- return;
38
- }
39
-
40
- define('NEWSLETTER_VERSION', '7.3.7');
41
-
42
- global $newsletter, $wpdb;
43
-
44
- // For acceptance tests, DO NOT CHANGE
45
- if (!defined('NEWSLETTER_DEBUG'))
46
- define('NEWSLETTER_DEBUG', false);
47
-
48
- if (!defined('NEWSLETTER_EXTENSION_UPDATE'))
49
- define('NEWSLETTER_EXTENSION_UPDATE', true);
50
-
51
- if (!defined('NEWSLETTER_EMAILS_TABLE'))
52
- define('NEWSLETTER_EMAILS_TABLE', $wpdb->prefix . 'newsletter_emails');
53
-
54
- if (!defined('NEWSLETTER_USERS_TABLE'))
55
- define('NEWSLETTER_USERS_TABLE', $wpdb->prefix . 'newsletter');
56
-
57
- if (!defined('NEWSLETTER_STATS_TABLE'))
58
- define('NEWSLETTER_STATS_TABLE', $wpdb->prefix . 'newsletter_stats');
59
-
60
- if (!defined('NEWSLETTER_SENT_TABLE'))
61
- define('NEWSLETTER_SENT_TABLE', $wpdb->prefix . 'newsletter_sent');
62
-
63
- define('NEWSLETTER_SLUG', 'newsletter');
64
-
65
- define('NEWSLETTER_DIR', __DIR__);
66
- define('NEWSLETTER_INCLUDES_DIR', __DIR__ . '/includes');
67
-
68
- // Deperacted since plugin can change the plugins_url()
69
- define('NEWSLETTER_URL', WP_PLUGIN_URL . '/newsletter');
70
-
71
- if (!defined('NEWSLETTER_LIST_MAX'))
72
- define('NEWSLETTER_LIST_MAX', 40);
73
-
74
- if (!defined('NEWSLETTER_PROFILE_MAX'))
75
- define('NEWSLETTER_PROFILE_MAX', 20);
76
-
77
- if (!defined('NEWSLETTER_FORMS_MAX'))
78
- define('NEWSLETTER_FORMS_MAX', 10);
79
-
80
- if (!defined('NEWSLETTER_HEADER'))
81
- define('NEWSLETTER_HEADER', true);
82
-
83
- require_once NEWSLETTER_INCLUDES_DIR . '/module.php';
84
- require_once NEWSLETTER_INCLUDES_DIR . '/TNP.php';
85
- require_once NEWSLETTER_INCLUDES_DIR . '/cron.php';
86
-
87
- class Newsletter extends NewsletterModule {
88
-
89
- // Limits to respect to avoid memory, time or provider limits
90
- var $time_start;
91
- var $time_limit = 0;
92
- var $max_emails = null;
93
-
94
- var $mailer = null;
95
-
96
- var $action = '';
97
-
98
- /** @var Newsletter */
99
- static $instance;
100
-
101
- const STATUS_NOT_CONFIRMED = 'S';
102
- const STATUS_CONFIRMED = 'C';
103
-
104
- /**
105
- * @return Newsletter
106
- */
107
- static function instance() {
108
- if (self::$instance == null) {
109
- self::$instance = new Newsletter();
110
- }
111
- return self::$instance;
112
- }
113
-
114
- function __construct() {
115
-
116
- // Grab it before a plugin decides to remove it.
117
- if (isset($_GET['na'])) {
118
- $this->action = $_GET['na'];
119
- }
120
- if (isset($_POST['na'])) {
121
- $this->action = $_POST['na'];
122
- }
123
-
124
- $this->time_start = time();
125
-
126
- parent::__construct('main', '1.6.7', null, ['info', 'smtp']);
127
-
128
- add_action('plugins_loaded', [$this, 'hook_plugins_loaded']);
129
- add_action('init', [$this, 'hook_init'], 1);
130
- add_action('wp_loaded', [$this, 'hook_wp_loaded'], 1);
131
-
132
- add_action('newsletter', [$this, 'hook_newsletter'], 1);
133
-
134
- register_activation_hook(__FILE__, [$this, 'hook_activate']);
135
- register_deactivation_hook(__FILE__, [$this, 'hook_deactivate']);
136
-
137
- add_action('admin_init', [$this, 'hook_admin_init']);
138
-
139
- if (is_admin()) {
140
- add_action('admin_head', [$this, 'hook_admin_head']);
141
-
142
- // Protection against strange schedule removal on some installations
143
- if (!wp_next_scheduled('newsletter') && (!defined('WP_INSTALLING') || !WP_INSTALLING)) {
144
- wp_schedule_event(time() + 30, 'newsletter', 'newsletter');
145
- }
146
-
147
- add_action('admin_menu', [$this, 'add_extensions_menu'], 90);
148
-
149
- add_filter('display_post_states', [$this, 'add_notice_to_chosen_profile_page_hook'], 10, 2);
150
-
151
- if ($this->is_admin_page()) {
152
- // Remove the emoji replacer to save to database the original emoji characters (see even woocommerce for the same problem)
153
- remove_action('admin_print_scripts', 'print_emoji_detection_script');
154
- add_action('admin_enqueue_scripts', [$this, 'hook_admin_enqueue_scripts']);
155
- }
156
-
157
- }
158
- }
159
-
160
- function hook_plugins_loaded() {
161
- // Used to load dependant modules
162
- do_action('newsletter_loaded', NEWSLETTER_VERSION);
163
-
164
- if (function_exists('load_plugin_textdomain')) {
165
- load_plugin_textdomain('newsletter', false, plugin_basename(__DIR__) . '/languages');
166
- }
167
- }
168
-
169
- function hook_init() {
170
- global $wpdb;
171
-
172
- if (isset($this->options['debug']) && $this->options['debug'] == 1) {
173
- ini_set('log_errors', 1);
174
- ini_set('error_log', WP_CONTENT_DIR . '/logs/newsletter/php-' . date('Y-m') . '-' . get_option('newsletter_logger_secret') . '.txt');
175
- }
176
-
177
- add_shortcode('newsletter_replace', [$this, 'shortcode_newsletter_replace']);
178
-
179
- add_filter('site_transient_update_plugins', [$this, 'hook_site_transient_update_plugins']);
180
-
181
- if (is_admin()) {
182
- if (!class_exists('NewsletterExtensions')) {
183
-
184
- add_filter('plugin_row_meta', function ($plugin_meta, $plugin_file) {
185
-
186
- static $slugs = array();
187
- if (empty($slugs)) {
188
- $addons = $this->getTnpExtensions();
189
- if ($addons) {
190
- foreach ($addons as $addon) {
191
- $slugs[] = $addon->wp_slug;
192
- }
193
- }
194
- }
195
- if (array_search($plugin_file, $slugs) !== false) {
196
-
197
- $plugin_meta[] = '<a href="admin.php?page=newsletter_main_extensions" style="font-weight: bold">Newsletter Addons Manager required</a>';
198
- }
199
- return $plugin_meta;
200
- }, 10, 2);
201
- }
202
-
203
- add_action('in_admin_header', array($this, 'hook_in_admin_header'), 1000);
204
-
205
- if ($this->is_admin_page()) {
206
-
207
- $dismissed = get_option('newsletter_dismissed', []);
208
-
209
- if (isset($_GET['dismiss'])) {
210
- $dismissed[$_GET['dismiss']] = 1;
211
- update_option('newsletter_dismissed', $dismissed);
212
- wp_redirect($_SERVER['HTTP_REFERER']);
213
- exit();
214
- }
215
- }
216
- } else {
217
- add_action('wp_enqueue_scripts', [$this, 'hook_wp_enqueue_scripts']);
218
- }
219
-
220
- do_action('newsletter_init');
221
- }
222
-
223
- function hook_wp_loaded() {
224
- if (empty($this->action)) {
225
- return;
226
- }
227
-
228
- if ($this->action == 'test') {
229
- // This response is tested, do not change it!
230
- echo 'ok';
231
- die();
232
- }
233
-
234
- if ($this->action === 'nul') {
235
- $this->dienow('This link is not active on newsletter preview', 'You can send a test message to test subscriber to have the real working link.');
236
- }
237
-
238
- $user = $this->get_user_from_request();
239
- $email = $this->get_email_from_request();
240
- do_action('newsletter_action', $this->action, $user, $email);
241
- }
242
-
243
- function hook_activate() {
244
- // Ok, why? When the plugin is not active WordPress may remove the scheduled "newsletter" action because
245
- // the every-five-minutes schedule named "newsletter" is not present.
246
- // Since the activation does not forces an upgrade, that schedule must be reactivated here. It is activated on
247
- // the upgrade method as well for the user which upgrade the plugin without deactivte it (many).
248
- if (!wp_next_scheduled('newsletter')) {
249
- wp_schedule_event(time() + 30, 'newsletter', 'newsletter');
250
- }
251
-
252
- $install_time = get_option('newsletter_install_time');
253
- if (!$install_time) {
254
- update_option('newsletter_install_time', time(), false);
255
- }
256
-
257
- touch(NEWSLETTER_LOG_DIR . '/index.html');
258
-
259
- Newsletter::instance()->upgrade();
260
- NewsletterUsers::instance()->upgrade();
261
- NewsletterEmails::instance()->upgrade();
262
- NewsletterSubscription::instance()->upgrade();
263
- NewsletterStatistics::instance()->upgrade();
264
- NewsletterProfile::instance()->upgrade();
265
- }
266
-
267
- function first_install() {
268
- parent::first_install();
269
- update_option('newsletter_show_welcome', '1', false);
270
- }
271
-
272
- function upgrade() {
273
- global $wpdb, $charset_collate;
274
-
275
- require_once(ABSPATH . 'wp-admin/includes/upgrade.php');
276
-
277
- parent::upgrade();
278
-
279
- $sql = "CREATE TABLE `" . $wpdb->prefix . "newsletter_emails` (
280
- `id` int(11) NOT NULL AUTO_INCREMENT,
281
- `language` varchar(10) NOT NULL DEFAULT '',
282
- `subject` varchar(255) NOT NULL DEFAULT '',
283
- `message` longtext,
284
- `created` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
285
- `status` enum('new','sending','sent','paused','error') NOT NULL DEFAULT 'new',
286
- `total` int(11) NOT NULL DEFAULT '0',
287
- `last_id` int(11) NOT NULL DEFAULT '0',
288
- `sent` int(11) NOT NULL DEFAULT '0',
289
- `track` int(11) NOT NULL DEFAULT '1',
290
- `list` int(11) NOT NULL DEFAULT '0',
291
- `type` varchar(50) NOT NULL DEFAULT '',
292
- `query` longtext,
293
- `editor` tinyint(4) NOT NULL DEFAULT '0',
294
- `sex` varchar(20) NOT NULL DEFAULT '',
295
- `theme` varchar(50) NOT NULL DEFAULT '',
296
- `message_text` longtext,
297
- `preferences` longtext,
298
- `send_on` int(11) NOT NULL DEFAULT '0',
299
- `token` varchar(10) NOT NULL DEFAULT '',
300
- `options` longtext,
301
- `private` tinyint(1) NOT NULL DEFAULT '0',
302
- `click_count` int(10) unsigned NOT NULL DEFAULT '0',
303
- `version` varchar(10) NOT NULL DEFAULT '',
304
- `open_count` int(10) unsigned NOT NULL DEFAULT '0',
305
- `unsub_count` int(10) unsigned NOT NULL DEFAULT '0',
306
- `error_count` int(10) unsigned NOT NULL DEFAULT '0',
307
- `stats_time` int(10) unsigned NOT NULL DEFAULT '0',
308
- `updated` int(10) unsigned NOT NULL DEFAULT '0',
309
- PRIMARY KEY (`id`)
310
- ) $charset_collate;";
311
-
312
- dbDelta($sql);
313
-
314
- // WP does not manage composite primary key when it tries to upgrade a table...
315
- $suppress_errors = $wpdb->suppress_errors(true);
316
-
317
- dbDelta("CREATE TABLE " . $wpdb->prefix . "newsletter_sent (
318
- email_id int(10) unsigned NOT NULL DEFAULT '0',
319
- user_id int(10) unsigned NOT NULL DEFAULT '0',
320
- status tinyint(1) unsigned NOT NULL DEFAULT '0',
321
- open tinyint(1) unsigned NOT NULL DEFAULT '0',
322
- time int(10) unsigned NOT NULL DEFAULT '0',
323
- error varchar(255) NOT NULL DEFAULT '',
324
- ip varchar(100) NOT NULL DEFAULT '',
325
- PRIMARY KEY (email_id,user_id),
326
- KEY user_id (user_id),
327
- KEY email_id (email_id)
328
- ) $charset_collate;");
329
- $wpdb->suppress_errors($suppress_errors);
330
-
331
- // Some setting check to avoid the common support request for mis-configurations
332
- $options = $this->get_options();
333
-
334
- if (empty($options['scheduler_max']) || !is_numeric($options['scheduler_max'])) {
335
- $options['scheduler_max'] = 100;
336
- $this->save_options($options);
337
- }
338
-
339
- wp_clear_scheduled_hook('newsletter');
340
- wp_schedule_event(time() + 30, 'newsletter', 'newsletter');
341
-
342
- if (!empty($this->options['editor'])) {
343
- if (empty($this->options['roles'])) {
344
- $this->options['roles'] = array('editor');
345
- unset($this->options['editor']);
346
- }
347
- $this->save_options($this->options);
348
- }
349
-
350
- // Clear the addons and license caches
351
- delete_transient('newsletter_license_data');
352
- $this->clear_extensions_cache();
353
-
354
- touch(NEWSLETTER_LOG_DIR . '/index.html');
355
-
356
- return true;
357
- }
358
-
359
- function is_allowed() {
360
- if (current_user_can('administrator')) {
361
- return true;
362
- }
363
- if (!empty($this->options['roles'])) {
364
- foreach ($this->options['roles'] as $role) {
365
- if (current_user_can($role)) {
366
- return true;
367
- }
368
- }
369
- }
370
- return false;
371
- }
372
-
373
- function admin_menu() {
374
- if (!$this->is_allowed()) {
375
- return;
376
- }
377
-
378
- add_menu_page('Newsletter', 'Newsletter', 'exist', 'newsletter_main_index', '', plugins_url('newsletter') . '/admin/images/menu-icon.png', '30.333');
379
-
380
- $this->add_menu_page('index', __('Dashboard', 'newsletter'));
381
- $this->add_admin_page('info', __('Company info', 'newsletter'));
382
-
383
- if (current_user_can('administrator')) {
384
- $this->add_menu_page('welcome', __('Welcome', 'newsletter'));
385
- $this->add_menu_page('main', __('Settings', 'newsletter'));
386
-
387
- // Pages not on menu
388
- $this->add_admin_page('smtp', 'SMTP');
389
- $this->add_admin_page('diagnostic', __('Diagnostic', 'newsletter'));
390
- $this->add_admin_page('test', __('Test', 'newsletter'));
391
- }
392
- }
393
-
394
- function add_extensions_menu() {
395
- if (!class_exists('NewsletterExtensions')) {
396
- $this->add_menu_page('extensions', '<span style="color:#27AE60; font-weight: bold;">' . __('Addons', 'newsletter') . '</span>');
397
- }
398
- }
399
-
400
- function hook_in_admin_header() {
401
- if (!$this->is_admin_page()) {
402
- add_action('admin_notices', array($this, 'hook_admin_notices'));
403
- return;
404
- }
405
- remove_all_actions('admin_notices');
406
- remove_all_actions('all_admin_notices');
407
- add_action('admin_notices', array($this, 'hook_admin_notices'));
408
- }
409
-
410
- function hook_admin_notices() {
411
- // Check of Newsletter dedicated page
412
- if (!empty($this->options['page'])) {
413
- if (get_post_status($this->options['page']) !== 'publish') {
414
- echo '<div class="notice notice-error"><p>The Newsletter dedicated page is not published. <a href="', site_url('/wp-admin/post.php') . '?post=', $this->options['page'], '&action=edit"><strong>Edit the page</strong></a> or <a href="admin.php?page=newsletter_main_main"><strong>review the main settings</strong></a>.</p></div>';
415
- }
416
- }
417
-
418
- if (isset($this->options['debug']) && $this->options['debug'] == 1) {
419
- echo '<div class="notice notice-warning"><p>The Newsletter plugin is in <strong>debug mode</strong>. When done change it on Newsletter <a href="admin.php?page=newsletter_main_main"><strong>main settings</strong></a>. Do not keep the debug mode active on production sites.</p></div>';
420
- }
421
- }
422
-
423
- function hook_wp_enqueue_scripts() {
424
- if (empty($this->options['css_disabled']) && apply_filters('newsletter_enqueue_style', true)) {
425
- wp_enqueue_style('newsletter', plugins_url('newsletter') . '/style.css', [], NEWSLETTER_VERSION);
426
- if (!empty($this->options['css'])) {
427
- wp_add_inline_style('newsletter', $this->options['css']);
428
- }
429
- } else {
430
- if (!empty($this->options['css'])) {
431
- add_action('wp_head', function () {
432
- echo '<style>', $this->options['css'], '</style>';
433
- });
434
- }
435
- }
436
- }
437
-
438
- function hook_admin_enqueue_scripts() {
439
-
440
- $newsletter_url = plugins_url('newsletter');
441
- wp_enqueue_script('jquery-ui-tabs');
442
- wp_enqueue_script('jquery-ui-tooltip');
443
- wp_enqueue_script('jquery-ui-draggable');
444
- wp_enqueue_media();
445
-
446
- wp_enqueue_script('tnp-admin', $newsletter_url . '/admin/admin.js', ['jquery'], NEWSLETTER_VERSION);
447
-
448
- wp_enqueue_style('tnp-select2', $newsletter_url . '/vendor/select2/css/select2.min.css', [], NEWSLETTER_VERSION);
449
- wp_enqueue_script('tnp-select2', $newsletter_url . '/vendor/select2/js/select2.min.js', ['jquery'], NEWSLETTER_VERSION);
450
-
451
- wp_enqueue_style('tnp-modal', $newsletter_url . '/admin/modal.css', [], NEWSLETTER_VERSION);
452
- wp_enqueue_script('tnp-modal', $newsletter_url . '/admin/modal.js', ['jquery'], NEWSLETTER_VERSION, true);
453
-
454
- wp_enqueue_style('tnp-toast', $newsletter_url . '/admin/toast.css', [], NEWSLETTER_VERSION);
455
- wp_enqueue_script('tnp-toast', $newsletter_url . '/admin/toast.js', ['jquery'], NEWSLETTER_VERSION);
456
-
457
- wp_enqueue_style('tnp-admin-font', 'https://use.typekit.net/jlj2wjy.css');
458
- wp_enqueue_style('tnp-admin-fontawesome', $newsletter_url . '/vendor/fa/css/all.min.css', [], NEWSLETTER_VERSION);
459
- wp_enqueue_style('tnp-admin-jquery-ui', $newsletter_url . '/vendor/jquery-ui/jquery-ui.min.css', [], NEWSLETTER_VERSION);
460
- wp_enqueue_style('tnp-admin', $newsletter_url . '/admin/admin.css', [], NEWSLETTER_VERSION);
461
- wp_enqueue_style('tnp-admin-dropdown', $newsletter_url . '/admin/dropdown.css', [], NEWSLETTER_VERSION);
462
- wp_enqueue_style('tnp-admin-tabs', $newsletter_url . '/admin/tabs.css', [], NEWSLETTER_VERSION);
463
- wp_enqueue_style('tnp-admin-controls', $newsletter_url . '/admin/controls.css', [], NEWSLETTER_VERSION);
464
- wp_enqueue_style('tnp-admin-fields', $newsletter_url . '/admin/fields.css', [], NEWSLETTER_VERSION);
465
- wp_enqueue_style('tnp-admin-widgets', $newsletter_url . '/admin/widgets.css', [], NEWSLETTER_VERSION);
466
- wp_enqueue_style('tnp-admin-extensions', $newsletter_url . '/admin/extensions.css', [], NEWSLETTER_VERSION);
467
-
468
- $translations_array = array(
469
- 'save_to_update_counter' => __('Save the newsletter to update the counter!', 'newsletter')
470
- );
471
- wp_localize_script('tnp-admin', 'tnp_translations', $translations_array);
472
-
473
- wp_enqueue_script('tnp-jquery-vmap', $newsletter_url . '/vendor/jqvmap/jquery.vmap.min.js', ['jquery'], NEWSLETTER_VERSION);
474
- wp_enqueue_script('tnp-jquery-vmap-world', $newsletter_url . '/vendor/jqvmap/jquery.vmap.world.js', ['tnp-jquery-vmap'], NEWSLETTER_VERSION);
475
- wp_enqueue_style('tnp-jquery-vmap', $newsletter_url . '/vendor/jqvmap/jqvmap.min.css', [], NEWSLETTER_VERSION);
476
-
477
- wp_register_script('tnp-chart', $newsletter_url . '/vendor/chartjs/Chart.min.js', ['jquery'], NEWSLETTER_VERSION);
478
-
479
- wp_enqueue_script('tnp-color-picker', $newsletter_url . '/vendor/spectrum/spectrum.min.js', ['jquery']);
480
- wp_enqueue_style('tnp-color-picker', $newsletter_url . '/vendor/spectrum/spectrum.min.css', [], NEWSLETTER_VERSION);
481
- }
482
-
483
- function shortcode_newsletter_replace($attrs, $content) {
484
- $content = do_shortcode($content);
485
- $content = $this->replace($content, $this->get_user_from_request(), $this->get_email_from_request());
486
- return $content;
487
- }
488
-
489
- function is_admin_page() {
490
- if (!isset($_GET['page'])) {
491
- return false;
492
- }
493
- $page = $_GET['page'];
494
- return strpos($page, 'newsletter_') === 0;
495
- }
496
-
497
- function hook_admin_init() {
498
- // Verificare il contesto
499
- if (isset($_GET['page']) && $_GET['page'] === 'newsletter_main_welcome')
500
- return;
501
- if (get_option('newsletter_show_welcome')) {
502
- delete_option('newsletter_show_welcome');
503
- wp_redirect(admin_url('admin.php?page=newsletter_main_welcome'));
504
- }
505
- }
506
-
507
- function hook_admin_head() {
508
- // Small global rule for sidebar menu entries
509
- echo '<style>';
510
- echo '.tnp-side-menu { color: #E67E22!important; }';
511
- echo '</style>';
512
- }
513
-
514
- function relink($text, $email_id, $user_id, $email_token = '') {
515
- return NewsletterStatistics::instance()->relink($text, $email_id, $user_id, $email_token);
516
- }
517
-
518
- /**
519
- * Runs every 5 minutes and look for emails that need to be processed.
520
- */
521
- function hook_newsletter() {
522
-
523
- $this->logger->debug(__METHOD__ . '> Start');
524
-
525
- if (!$this->check_transient('engine', NEWSLETTER_CRON_INTERVAL)) {
526
- $this->logger->debug(__METHOD__ . '> Engine already active, exit');
527
- return;
528
- }
529
-
530
- $emails = $this->get_results("select * from " . NEWSLETTER_EMAILS_TABLE . " where status='sending' and send_on<" . time() . " order by id asc");
531
- $this->logger->debug(__METHOD__ . '> Emails found in sending status: ' . count($emails));
532
-
533
- foreach ($emails as $email) {
534
- $this->logger->debug(__METHOD__ . '> Start newsletter ' . $email->id);
535
- $email->options = maybe_unserialize($email->options);
536
- $r = $this->send($email);
537
- $this->logger->debug(__METHOD__ . '> End newsletter ' . $email->id);
538
- if (!$r) {
539
- $this->logger->debug(__METHOD__ . '> Engine returned false, there is no more capacity');
540
- break;
541
- }
542
- }
543
- // Remove the semaphore so the delivery engine can be activated again
544
- $this->delete_transient('engine');
545
-
546
- $this->logger->debug(__METHOD__ . '> End');
547
- }
548
-
549
- function get_send_speed($email = null) {
550
- $this->logger->debug(__METHOD__ . '> Computing delivery speed');
551
- $mailer = $this->get_mailer();
552
- $speed = (int) $mailer->get_speed();
553
- if (!$speed) {
554
- $this->logger->debug(__METHOD__ . '> Speed not set by mailer, use the default');
555
- $speed = (int) $this->options['scheduler_max'];
556
- } else {
557
- $this->logger->debug(__METHOD__ . '> Speed set by mailer');
558
- }
559
-
560
- //$speed = (int) apply_filters('newsletter_send_speed', $speed, $email);
561
- // Fail safe setting
562
- $runs_per_hour = $this->get_runs_per_hour();
563
- if (!$speed || $speed < $runs_per_hour) {
564
- return $runs_per_hour;
565
- }
566
-
567
- $this->logger->debug(__METHOD__ . '> Speed: ' . $speed);
568
- return $speed;
569
- }
570
-
571
- function get_send_delay() {
572
- return 0;
573
- }
574
-
575
- function skip_this_run($email = null) {
576
- return (boolean) apply_filters('newsletter_send_skip', false, $email);
577
- }
578
-
579
- function get_runs_per_hour() {
580
- return (int) (3600 / NEWSLETTER_CRON_INTERVAL);
581
- }
582
-
583
- function get_emails_per_run() {
584
- $speed = $this->get_send_speed();
585
- $max = (int)($speed / $this->get_runs_per_hour());
586
-
587
- return $max;
588
- }
589
-
590
- function get_max_emails($email) {
591
- // Obsolete, here from Speed Control Addon
592
- $max = (int) apply_filters('newsletter_send_max_emails', $this->max_emails, $email);
593
-
594
- return min($max, $this->max_emails);
595
- }
596
-
597
- function fix_email($email) {
598
- if (empty($email->query)) {
599
- $email->query = "select * from " . NEWSLETTER_USERS_TABLE . " where status='C'";
600
- }
601
- if (empty($email->id)) {
602
- $email->id = 0;
603
- }
604
- }
605
-
606
- function send_setup() {
607
- $this->logger->debug(__METHOD__ . '> Setup delivery engine');
608
- if (is_null($this->max_emails)) {
609
- $this->max_emails = $this->get_emails_per_run();
610
- $this->logger->debug(__METHOD__ . '> Max emails: ' . $this->max_emails);
611
- ignore_user_abort(true);
612
-
613
- @set_time_limit(NEWSLETTER_CRON_INTERVAL + 30);
614
-
615
- $max_time = (int) (@ini_get('max_execution_time') * 0.95);
616
- if ($max_time == 0 || $max_time > NEWSLETTER_CRON_INTERVAL) {
617
- $max_time = (int) (NEWSLETTER_CRON_INTERVAL * 0.95);
618
- }
619
-
620
- $this->time_limit = $this->time_start + $max_time;
621
-
622
- $this->logger->debug(__METHOD__ . '> Max time set to ' . $max_time);
623
- } else {
624
- $this->logger->debug(__METHOD__ . '> Already setup');
625
- }
626
- }
627
-
628
- function time_exceeded() {
629
- if ($this->time_limit && time() > $this->time_limit) {
630
- $this->logger->info(__METHOD__ . '> Max execution time limit reached');
631
- return true;
632
- }
633
- }
634
-
635
- /**
636
- * Sends an email to targeted users or to given users. If a list of users is given (usually a list of test users)
637
- * the query inside the email to retrieve users is not used.
638
- *
639
- * @global wpdb $wpdb
640
- * @global type $newsletter_feed
641
- * @param TNP_Email $email
642
- * @param array $users
643
- * @return boolean|WP_Error True if the process completed, false if limits was reached. On false the caller should no continue to call it with other emails.
644
- */
645
- function send($email, $users = null, $test = false) {
646
- global $wpdb;
647
-
648
- if (is_array($email)) {
649
- $email = (object) $email;
650
- }
651
-
652
- $this->logger->info(__METHOD__ . '> Send email ' . $email->id);
653
-
654
- $this->send_setup();
655
-
656
- if ($this->max_emails <= 0) {
657
- $this->logger->info(__METHOD__ . '> No more capacity');
658
- return false;
659
- }
660
-
661
- $this->fix_email($email);
662
-
663
- // This stops the update of last_id and sent fields since
664
- // it's not a scheduled delivery but a test or something else (like an autoresponder)
665
- $supplied_users = $users != null;
666
-
667
- if (!$supplied_users) {
668
-
669
- if ($this->skip_this_run($email)) {
670
- return true;
671
- }
672
-
673
- // Speed change for specific email by Speed Control Addon
674
- $max_emails = $this->get_max_emails($email);
675
- if ($max_emails <= 0) {
676
- return true;
677
- }
678
-
679
- $query = $email->query;
680
- $query .= " and id>" . $email->last_id . " order by id limit " . $max_emails;
681
-
682
- $this->logger->debug(__METHOD__ . '> Query: ' . $query);
683
-
684
- //Retrieve subscribers
685
- $users = $this->get_results($query);
686
-
687
- $this->logger->debug(__METHOD__ . '> Loaded subscribers: ' . count($users));
688
-
689
- // If there was a database error, return error
690
- if ($users === false) {
691
- return new WP_Error('1', 'Unable to query subscribers, check the logs');
692
- }
693
-
694
- if (empty($users)) {
695
- $this->logger->info(__METHOD__ . '> No more users, set as sent');
696
- $wpdb->query("update " . NEWSLETTER_EMAILS_TABLE . " set status='sent', total=sent where id=" . $email->id . " limit 1");
697
- do_action('newsletter_ended_sending_newsletter', $email);
698
- return true;
699
- }
700
- } else {
701
- $this->logger->info(__METHOD__ . '> Subscribers supplied');
702
- }
703
-
704
- $start_time = microtime(true);
705
- $count = 0;
706
- $result = true;
707
-
708
- $mailer = $this->get_mailer();
709
-
710
- $batch_size = $mailer->get_batch_size();
711
-
712
- $this->logger->debug(__METHOD__ . '> Batch size: ' . $batch_size);
713
-
714
- // For batch size == 1 (normal condition) we optimize
715
- if ($batch_size == 1) {
716
-
717
- foreach ($users as $user) {
718
-
719
- $this->logger->debug(__METHOD__ . '> Processing user ID: ' . $user->id);
720
- $user = apply_filters('newsletter_send_user', $user);
721
- $message = $this->build_message($email, $user);
722
-
723
- // Save even test emails since people wants to see some stats even for test emails. Stats are reset upon the real "send" of a newsletter
724
- $this->save_sent_message($message);
725
-
726
- //Se non è un test incremento il contatore delle email spedite. Perchè incremento prima di spedire??
727
- if (!$test) {
728
- $wpdb->query("update " . NEWSLETTER_EMAILS_TABLE . " set sent=sent+1, last_id=" . $user->id . " where id=" . $email->id . " limit 1");
729
- }
730
-
731
- $r = $mailer->send($message);
732
-
733
- if (!empty($message->error)) {
734
- $this->logger->error($message);
735
- $this->save_sent_message($message);
736
- }
737
-
738
- if (is_wp_error($r)) {
739
- $this->logger->error($r);
740
-
741
- // For fatal error, the newsletter status i changed to error (and the delivery stopped)
742
- if (!$test && $r->get_error_code() == NewsletterMailer::ERROR_FATAL) {
743
- $this->set_error_state_of_email($email, $r->get_error_message());
744
- return $r;
745
- }
746
- }
747
-
748
- if (!$supplied_users && !$test && $this->time_exceeded()) {
749
- $result = false;
750
- break;
751
- }
752
- }
753
-
754
- $this->max_emails--;
755
- $count++;
756
- } else {
757
-
758
- $chunks = array_chunk($users, $batch_size);
759
-
760
- foreach ($chunks as $chunk) {
761
-
762
- $messages = [];
763
-
764
- // Peeparing a batch of messages
765
- foreach ($chunk as $user) {
766
- $this->logger->debug(__METHOD__ . '> Processing user ID: ' . $user->id);
767
- $user = apply_filters('newsletter_send_user', $user);
768
- $message = $this->build_message($email, $user);
769
- $this->save_sent_message($message);
770
- $messages[] = $message;
771
-
772
- if (!$test) {
773
- $wpdb->query("update " . NEWSLETTER_EMAILS_TABLE . " set sent=sent+1, last_id=" . $user->id . " where id=" . $email->id . " limit 1");
774
- }
775
- $this->max_emails--;
776
- $count++;
777
- }
778
-
779
- $r = $mailer->send_batch($messages);
780
-
781
- // Updating the status of the sent messages
782
- foreach ($messages as $message) {
783
- if (!empty($message->error)) {
784
- $this->save_sent_message($message);
785
- }
786
- }
787
-
788
- // The batch went in error
789
- if (is_wp_error($r)) {
790
- $this->logger->error($r);
791
-
792
- if (!$test && $r->get_error_code() == NewsletterMailer::ERROR_FATAL) {
793
- $this->set_error_state_of_email($email, $r->get_error_message());
794
- return $r;
795
- }
796
- }
797
-
798
- if (!$supplied_users && !$test && $this->time_exceeded()) {
799
- $result = false;
800
- break;
801
- }
802
- }
803
- }
804
-
805
- $end_time = microtime(true);
806
-
807
- // Stats only for newsletter with enough emails in a batch (we exclude the Autoresponder since it send one email per call)
808
- if (!$test && !$supplied_users && $count > 5) {
809
- $this->update_send_stats($start_time, $end_time, $count, $result);
810
- }
811
-
812
- // Cached general statistics are reset
813
- if (!$test) {
814
- NewsletterStatistics::instance()->reset_stats_time($email->id);
815
- }
816
-
817
- $this->logger->info(__METHOD__ . '> End run for email ' . $email->id);
818
-
819
- return $result;
820
- }
821
-
822
- function update_send_stats($start_time, $end_time, $count, $result) {
823
- $send_calls = get_option('newsletter_diagnostic_send_calls', []);
824
- $send_calls[] = [$start_time, $end_time, $count, $result];
825
-
826
- if (count($send_calls) > 100) {
827
- array_shift($send_calls);
828
- }
829
-
830
- update_option('newsletter_diagnostic_send_calls', $send_calls, false);
831
- }
832
-
833
- /**
834
- * @param TNP_Email $email
835
- */
836
- private function set_error_state_of_email($email, $message = '') {
837
- // Handle only message type at the moment
838
- if ($email->type !== 'message') {
839
- return;
840
- }
841
-
842
- do_action('newsletter_error_on_sending', $email, $message);
843
-
844
- $edited_email = new TNP_Email();
845
- $edited_email->id = $email->id;
846
- $edited_email->status = TNP_Email::STATUS_ERROR;
847
- $edited_email->options = $email->options;
848
- $edited_email->options['error_message'] = $message;
849
-
850
- $this->save_email($edited_email);
851
- }
852
-
853
- /**
854
- *
855
- * @param TNP_Email $email
856
- * @param TNP_User $user
857
- * @return \TNP_Mailer_Message
858
- */
859
- function build_message($email, $user) {
860
-
861
- $message = new TNP_Mailer_Message();
862
-
863
- $message->to = $user->email;
864
-
865
- $message->headers = [];
866
- $message->headers['Precedence'] = 'bulk';
867
- $message->headers['X-Newsletter-Email-Id'] = $email->id;
868
- $message->headers['X-Auto-Response-Suppress'] = 'OOF, AutoReply';
869
- $message->headers = apply_filters('newsletter_message_headers', $message->headers, $email, $user);
870
-
871
- $message->body = preg_replace('/data-json=".*?"/is', '', $email->message);
872
- $message->body = preg_replace('/ +/s', ' ', $message->body);
873
- $message->body = $this->replace($message->body, $user, $email);
874
- if ($this->options['do_shortcodes']) {
875
- $message->body = do_shortcode($message->body);
876
- }
877
- $message->body = apply_filters('newsletter_message_html', $message->body, $email, $user);
878
-
879
- $message->body_text = $this->replace($email->message_text, $user, $email);
880
- $message->body_text = apply_filters('newsletter_message_text', $message->body_text, $email, $user);
881
-
882
- if ($email->track == 1) {
883
- $message->body = $this->relink($message->body, $email->id, $user->id, $email->token);
884
- }
885
-
886
- $message->subject = $this->replace($email->subject, $user);
887
- $message->subject = apply_filters('newsletter_message_subject', $message->subject, $email, $user);
888
-
889
- if (!empty($email->options['sender_email'])) {
890
- $message->from = $email->options['sender_email'];
891
- } else {
892
- $message->from = $this->options['sender_email'];
893
- }
894
-
895
- if (!empty($email->options['sender_name'])) {
896
- $message->from_name = $email->options['sender_name'];
897
- } else {
898
- $message->from_name = $this->options['sender_name'];
899
- }
900
-
901
- $message->email_id = $email->id;
902
- $message->user_id = $user->id;
903
-
904
- return apply_filters('newsletter_message', $message, $email, $user);
905
- }
906
-
907
- /**
908
- *
909
- * @param TNP_Mailer_Message $message
910
- * @param int $status
911
- * @param string $error
912
- */
913
- function save_sent_message($message) {
914
- global $wpdb;
915
-
916
- if (!$message->user_id || !$message->email_id) {
917
- return;
918
- }
919
- $status = empty($message->error) ? 0 : 1;
920
-
921
- $error = mb_substr($message->error, 0, 250);
922
-
923
- $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, $error, time(), $status, $error));
924
- }
925
-
926
- /**
927
- * @deprecated since version 7.3.0
928
- */
929
- function limits_exceeded() {
930
- return false;
931
- }
932
-
933
- /**
934
- * @deprecated since version 6.0.0
935
- */
936
- function register_mail_method($callable) {
937
- }
938
-
939
- function register_mailer($mailer) {
940
- if ($mailer instanceof NewsletterMailer) {
941
- $this->mailer = $mailer;
942
- }
943
- }
944
-
945
- /**
946
- * Returns the current registered mailer which must be used to send emails.
947
- *
948
- * @return NewsletterMailer
949
- */
950
- function get_mailer() {
951
- if ($this->mailer) {
952
- return $this->mailer;
953
- }
954
-
955
- do_action('newsletter_register_mailer');
956
-
957
- if (!$this->mailer) {
958
- // Compatibility
959
- $smtp = $this->get_options('smtp');
960
- if (!empty($smtp['enabled'])) {
961
- $this->mailer = new NewsletterDefaultSMTPMailer($smtp);
962
- } else {
963
- $this->mailer = new NewsletterDefaultMailer();
964
- }
965
- }
966
- return $this->mailer;
967
- }
968
-
969
- /**
970
- *
971
- * @param TNP_Mailer_Message $message
972
- * @return type
973
- */
974
- function deliver($message) {
975
- $mailer = $this->get_mailer();
976
- if (empty($message->from))
977
- $message->from = $this->options['sender_email'];
978
- if (empty($message->from_name))
979
- $mailer->from_name = $this->options['sender_name'];
980
- return $mailer->send($message);
981
- }
982
-
983
- /**
984
- *
985
- * @param type $to
986
- * @param type $subject
987
- * @param string|array $message If string is considered HTML, is array should contains the keys "html" and "text"
988
- * @param type $headers
989
- * @param type $enqueue
990
- * @param type $from
991
- * @return boolean
992
- */
993
- function mail($to, $subject, $message, $headers = array(), $enqueue = false, $from = false) {
994
-
995
- if (empty($subject)) {
996
- $this->logger->error('mail> Subject empty, skipped');
997
- return true;
998
- }
999
-
1000
- $mailer_message = new TNP_Mailer_Message();
1001
- $mailer_message->to = $to;
1002
- $mailer_message->subject = $subject;
1003
- $mailer_message->from = $this->options['sender_email'];
1004
- $mailer_message->from_name = $this->options['sender_name'];
1005
-
1006
- if (!empty($headers)) {
1007
- $mailer_message->headers = $headers;
1008
- }
1009
- $mailer_message->headers['X-Auto-Response-Suppress'] = 'OOF, AutoReply';
1010
-
1011
- // Message carrige returns and line feeds clean up
1012
- if (!is_array($message)) {
1013
- $mailer_message->body = $this->clean_eol($message);
1014
- } else {
1015
- if (!empty($message['text'])) {
1016
- $mailer_message->body_text = $this->clean_eol($message['text']);
1017
- }
1018
-
1019
- if (!empty($message['html'])) {
1020
- $mailer_message->body = $this->clean_eol($message['html']);
1021
- }
1022
- }
1023
-
1024
- $this->logger->debug($mailer_message);
1025
-
1026
- $mailer = $this->get_mailer();
1027
-
1028
- $r = $mailer->send($mailer_message);
1029
-
1030
- return !is_wp_error($r);
1031
- }
1032
-
1033
- function hook_deactivate() {
1034
- wp_clear_scheduled_hook('newsletter');
1035
- }
1036
-
1037
- function find_file($file1, $file2) {
1038
- if (is_file($file1))
1039
- return $file1;
1040
- return $file2;
1041
- }
1042
-
1043
- function hook_site_transient_update_plugins($value) {
1044
- static $extra_response = array();
1045
-
1046
- //$this->logger->debug('Update plugins transient called');
1047
-
1048
- if (!$value || !is_object($value)) {
1049
- //$this->logger->info('Empty object');
1050
- return $value;
1051
- }
1052
-
1053
- if (!isset($value->response) || !is_array($value->response)) {
1054
- $value->response = array();
1055
- }
1056
-
1057
- // Already computed? Use it! (this filter is called many times in a single request)
1058
- if ($extra_response) {
1059
- //$this->logger->debug('Already updated');
1060
- $value->response = array_merge($value->response, $extra_response);
1061
- return $value;
1062
- }
1063
-
1064
- $extensions = $this->getTnpExtensions();
1065
-
1066
- // Ops...
1067
- if (!$extensions) {
1068
- return $value;
1069
- }
1070
-
1071
- foreach ($extensions as $extension) {
1072
- unset($value->response[$extension->wp_slug]);
1073
- unset($value->no_update[$extension->wp_slug]);
1074
- }
1075
-
1076
- // Someone doesn't want our addons updated, let respect it (this constant should be defined in wp-config.php)
1077
- if (!NEWSLETTER_EXTENSION_UPDATE) {
1078
- //$this->logger->info('Updates disabled');
1079
- return $value;
1080
- }
1081
-
1082
- include_once(ABSPATH . 'wp-admin/includes/plugin.php');
1083
-
1084
- // Ok, that is really bad (should we remove it? is there a minimum WP version?)
1085
- if (!function_exists('get_plugin_data')) {
1086
- //$this->logger->error('No get_plugin_data function available!');
1087
- return $value;
1088
- }
1089
-
1090
- $license_key = $this->get_license_key();
1091
-
1092
- // Here we prepare the update information BUT do not add the link to the package which is privided
1093
- // by our Addons Manager (due to WP policies)
1094
- foreach ($extensions as $extension) {
1095
-
1096
- // Patch for names convention
1097
- $extension->plugin = $extension->wp_slug;
1098
-
1099
- //$this->logger->debug('Processing ' . $extension->plugin);
1100
- //$this->logger->debug($extension);
1101
-
1102
- $plugin_data = false;
1103
- if (file_exists(WP_PLUGIN_DIR . '/' . $extension->plugin)) {
1104
- $plugin_data = get_plugin_data(WP_PLUGIN_DIR . '/' . $extension->plugin, false, false);
1105
- } else if (file_exists(WPMU_PLUGIN_DIR . '/' . $extension->plugin)) {
1106
- $plugin_data = get_plugin_data(WPMU_PLUGIN_DIR . '/' . $extension->plugin, false, false);
1107
- }
1108
-
1109
- if (!$plugin_data) {
1110
- //$this->logger->debug('Seems not installed');
1111
- continue;
1112
- }
1113
-
1114
- $plugin = new stdClass();
1115
- $plugin->id = $extension->id;
1116
- $plugin->slug = $extension->slug;
1117
- $plugin->plugin = $extension->plugin;
1118
- $plugin->new_version = $extension->version;
1119
- $plugin->url = $extension->url;
1120
- if (class_exists('NewsletterExtensions')) {
1121
- // NO filters here!
1122
- $plugin->package = NewsletterExtensions::$instance->get_package($extension->id, $license_key);
1123
- } else {
1124
- $plugin->package = '';
1125
- }
1126
- // [banners] => Array
1127
- // (
1128
- // [2x] => https://ps.w.org/wp-rss-aggregator/assets/banner-1544x500.png?rev=2040548
1129
- // [1x] => https://ps.w.org/wp-rss-aggregator/assets/banner-772x250.png?rev=2040548
1130
- // )
1131
- // [icons] => Array
1132
- // (
1133
- // [2x] => https://ps.w.org/advanced-custom-fields/assets/icon-256x256.png?rev=1082746
1134
- // [1x] => https://ps.w.org/advanced-custom-fields/assets/icon-128x128.png?rev=1082746
1135
- // )
1136
- if (version_compare($extension->version, $plugin_data['Version']) > 0) {
1137
- //$this->logger->debug('There is a new version');
1138
- $extra_response[$extension->plugin] = $plugin;
1139
- } else {
1140
- // Maybe useless...
1141
- //$this->logger->debug('There is NOT a new version');
1142
- $value->no_update[$extension->plugin] = $plugin;
1143
- }
1144
- //$this->logger->debug('Added');
1145
- }
1146
-
1147
- $value->response = array_merge($value->response, $extra_response);
1148
-
1149
- return $value;
1150
- }
1151
-
1152
- /**
1153
- * @deprecated since version 6.1.9
1154
- */
1155
- function get_extension_version($extension_id) {
1156
- return null;
1157
- }
1158
-
1159
- /**
1160
- * @deprecated since version 6.1.9
1161
- */
1162
- function set_extension_update_data($value, $extension) {
1163
- return $value;
1164
- }
1165
-
1166
- /**
1167
- * Retrieve the extensions form the tnp site
1168
- * @return array
1169
- */
1170
- function getTnpExtensions() {
1171
-
1172
- $extensions_json = get_transient('tnp_extensions_json');
1173
-
1174
- if (empty($extensions_json)) {
1175
- $url = "http://www.thenewsletterplugin.com/wp-content/extensions.json?ver=" . NEWSLETTER_VERSION;
1176
- $extensions_response = wp_remote_get($url);
1177
-
1178
- if (is_wp_error($extensions_response)) {
1179
- // Cache anyway for blogs which cannot connect outside
1180
- $extensions_json = '[]';
1181
- set_transient('tnp_extensions_json', $extensions_json, 72 * 60 * 60);
1182
- $this->logger->error($extensions_response);
1183
- } else {
1184
-
1185
- $extensions_json = wp_remote_retrieve_body($extensions_response);
1186
-
1187
- // Not clear cases
1188
- if (empty($extensions_json) || !json_decode($extensions_json)) {
1189
- $this->logger->error('Invalid json from thenewsletterplugin.com: retrying in 72 hours');
1190
- $this->logger->error('JSON: ' . $extensions_json);
1191
- $extensions_json = '[]';
1192
- }
1193
- set_transient('tnp_extensions_json', $extensions_json, 72 * 60 * 60);
1194
- }
1195
- }
1196
-
1197
- $extensions = json_decode($extensions_json);
1198
-
1199
- return $extensions;
1200
- }
1201
-
1202
- function clear_extensions_cache() {
1203
- delete_transient('tnp_extensions_json');
1204
- }
1205
-
1206
- var $panels = array();
1207
-
1208
- function add_panel($key, $panel) {
1209
- if (!isset($this->panels[$key]))
1210
- $this->panels[$key] = array();
1211
- if (!isset($panel['id']))
1212
- $panel['id'] = sanitize_key($panel['label']);
1213
- $this->panels[$key][] = $panel;
1214
- }
1215
-
1216
- function has_license() {
1217
- return !empty($this->options['contract_key']);
1218
- }
1219
-
1220
- function get_sender_name() {
1221
- return $this->options['sender_name'];
1222
- }
1223
-
1224
- function get_sender_email() {
1225
- return $this->options['sender_email'];
1226
- }
1227
-
1228
- /**
1229
- *
1230
- * @return int
1231
- */
1232
- function get_newsletter_page_id() {
1233
- return (int) $this->options['page'];
1234
- }
1235
-
1236
- /**
1237
- *
1238
- * @return WP_Post
1239
- */
1240
- function get_newsletter_page() {
1241
- return get_post($this->get_newsletter_page_id());
1242
- }
1243
-
1244
- /**
1245
- * Returns the Newsletter dedicated page URL or an alternative URL if that page if not
1246
- * configured or not available.
1247
- *
1248
- * @staticvar string $url
1249
- * @return string
1250
- */
1251
- function get_newsletter_page_url($language = '') {
1252
-
1253
- $page = $this->get_newsletter_page();
1254
-
1255
- if (!$page || $page->post_status !== 'publish') {
1256
- return $this->build_action_url('m');
1257
- }
1258
-
1259
- $newsletter_page_url = get_permalink($page->ID);
1260
- if ($language && $newsletter_page_url) {
1261
- if (class_exists('SitePress')) {
1262
- $newsletter_page_url = apply_filters('wpml_permalink', $newsletter_page_url, $language, true);
1263
- }
1264
- if (function_exists('pll_get_post')) {
1265
- $translated_page = get_permalink(pll_get_post($page->ID, $language));
1266
- if ($translated_page) {
1267
- $newsletter_page_url = $translated_page;
1268
- }
1269
- }
1270
- }
1271
-
1272
- return $newsletter_page_url;
1273
- }
1274
-
1275
- function get_license_key() {
1276
- if (defined('NEWSLETTER_LICENSE_KEY')) {
1277
- return NEWSLETTER_LICENSE_KEY;
1278
- } else {
1279
- if (!empty($this->options['contract_key'])) {
1280
- return trim($this->options['contract_key']);
1281
- }
1282
- }
1283
- return false;
1284
- }
1285
-
1286
- /**
1287
- * Get the data connected to the specified license code on man settings.
1288
- *
1289
- * - false if no license is present
1290
- * - WP_Error if something went wrong if getting the license data
1291
- * - object with expiration and addons list
1292
- *
1293
- * @param boolean $refresh
1294
- * @return \WP_Error|boolean|object
1295
- */
1296
- function get_license_data($refresh = false) {
1297
-
1298
- $this->logger->debug('Getting license data');
1299
-
1300
- $license_key = $this->get_license_key();
1301
- if (empty($license_key)) {
1302
- $this->logger->debug('License was empty');
1303
- delete_transient('newsletter_license_data');
1304
- return false;
1305
- }
1306
-
1307
- if (!$refresh) {
1308
- $license_data = get_transient('newsletter_license_data');
1309
- if ($license_data !== false && is_object($license_data)) {
1310
- $this->logger->debug('License data found on cache');
1311
- return $license_data;
1312
- }
1313
- }
1314
-
1315
- $this->logger->debug('Refreshing the license data');
1316
-
1317
- $license_data_url = 'https://www.thenewsletterplugin.com/wp-content/plugins/file-commerce-pro/get-license-data.php';
1318
-
1319
- $response = wp_remote_post($license_data_url, array(
1320
- 'body' => array('k' => $license_key)
1321
- ));
1322
-
1323
- // Fall back to http...
1324
- if (is_wp_error($response)) {
1325
- $this->logger->error($response);
1326
- $this->logger->error('Falling back to http');
1327
- $license_data_url = str_replace('https', 'http', $license_data_url);
1328
- $response = wp_remote_post($license_data_url, array(
1329
- 'body' => array('k' => $license_key)
1330
- ));
1331
- if (is_wp_error($response)) {
1332
- $this->logger->error($response);
1333
- set_transient('newsletter_license_data', $response, DAY_IN_SECONDS);
1334
- return $response;
1335
- }
1336
- }
1337
-
1338
- $download_message = 'You can download all addons from www.thenewsletterplugin.com if your license is valid.';
1339
-
1340
- if (wp_remote_retrieve_response_code($response) != '200') {
1341
- $this->logger->error('license data error: ' . wp_remote_retrieve_response_code($response));
1342
- $data = new WP_Error(wp_remote_retrieve_response_code($response), 'License validation service error. <br>' . $download_message);
1343
- set_transient('newsletter_license_data', $data, DAY_IN_SECONDS);
1344
- return $data;
1345
- }
1346
-
1347
- $json = wp_remote_retrieve_body($response);
1348
- $data = json_decode($json);
1349
-
1350
- if (!is_object($data)) {
1351
- $this->logger->error($json);
1352
- $data = new WP_Error(1, 'License validation service error. <br>' . $download_message);
1353
- set_transient('newsletter_license_data', $data, DAY_IN_SECONDS);
1354
- return $data;
1355
- }
1356
-
1357
- if (isset($data->message)) {
1358
- $data = new WP_Error(1, $data->message . ' (check the license on Newsletter main settings)');
1359
- set_transient('newsletter_license_data', $data, DAY_IN_SECONDS);
1360
- return $data;
1361
- }
1362
-
1363
- $expiration = WEEK_IN_SECONDS;
1364
- // If the license expires in few days, make the transient live only few days, so it will be refreshed
1365
- if ($data->expire > time() && $data->expire - time() < WEEK_IN_SECONDS) {
1366
- $expiration = $data->expire - time();
1367
- }
1368
- set_transient('newsletter_license_data', $data, $expiration);
1369
-
1370
- return $data;
1371
- }
1372
-
1373
- /**
1374
- * @deprecated
1375
- * @param type $license_key
1376
- * @return \WP_Error
1377
- */
1378
- public static function check_license($license_key) {
1379
- $response = wp_remote_get('http://www.thenewsletterplugin.com/wp-content/plugins/file-commerce-pro/check.php?k=' . urlencode($license_key), array('sslverify' => false));
1380
- if (is_wp_error($response)) {
1381
- /* @var $response WP_Error */
1382
- return new WP_Error(-1, 'It seems that your blog cannot contact the license validator. Ask your provider to unlock the HTTP/HTTPS connections to www.thenewsletterplugin.com<br>'
1383
- . esc_html($response->get_error_code()) . ' - ' . esc_html($response->get_error_message()));
1384
- } else if ($response['response']['code'] != 200) {
1385
- return new WP_Error(-1, '[' . $response['response']['code'] . '] The license seems expired or not valid, please check your <a href="https://www.thenewsletterplugin.com/account">license code and status</a>, thank you.'
1386
- . '<br>You can anyway download the professional extension from https://www.thenewsletterplugin.com.');
1387
- } elseif ($expires = json_decode(wp_remote_retrieve_body($response))) {
1388
- return array('expires' => $expires->expire, 'message' => 'Your license is valid and expires on ' . esc_html(date('Y-m-d', $expires->expire)));
1389
- } else {
1390
- return new WP_Error(-1, 'Unable to detect the license expiration. Debug data to report to the support: <code>' . esc_html(wp_remote_retrieve_body($response)) . '</code>');
1391
- }
1392
- }
1393
-
1394
- function add_notice_to_chosen_profile_page_hook($post_states, $post) {
1395
-
1396
- if ($post->ID == $this->options['page']) {
1397
- $post_states[] = __('Newsletter plugin page, do not delete', 'newsletter');
1398
- }
1399
-
1400
- return $post_states;
1401
- }
1402
-
1403
- }
1404
-
1405
- $newsletter = Newsletter::instance();
1406
-
1407
- if (is_admin()) {
1408
- require_once NEWSLETTER_DIR . '/system/system.php';
1409
- }
1410
-
1411
- require_once NEWSLETTER_DIR . '/subscription/subscription.php';
1412
- require_once NEWSLETTER_DIR . '/unsubscription/unsubscription.php';
1413
- require_once NEWSLETTER_DIR . '/profile/profile.php';
1414
- require_once NEWSLETTER_DIR . '/emails/emails.php';
1415
- require_once NEWSLETTER_DIR . '/users/users.php';
1416
- require_once NEWSLETTER_DIR . '/statistics/statistics.php';
1417
- require_once NEWSLETTER_DIR . '/widget/standard.php';
1418
- require_once NEWSLETTER_DIR . '/widget/minimal.php';
1
+ <?php
2
+
3
+ /*
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: 7.3.8
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.
11
+ Text Domain: newsletter
12
+ License: GPLv2 or later
13
+ Requires at least: 4.6
14
+ Requires PHP: 5.6
15
+
16
+ Copyright 2009-2022 The Newsletter Team (email: info@thenewsletterplugin.com, web: https://www.thenewsletterplugin.com)
17
+
18
+ Newsletter is free software: you can redistribute it and/or modify
19
+ it under the terms of the GNU General Public License as published by
20
+ the Free Software Foundation, either version 2 of the License, or
21
+ any later version.
22
+
23
+ Newsletter is distributed in the hope that it will be useful,
24
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
25
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
26
+ GNU General Public License for more details.
27
+
28
+ You should have received a copy of the GNU General Public License
29
+ along with Newsletter. If not, see https://www.gnu.org/licenses/gpl-2.0.html.
30
+
31
+ */
32
+
33
+ if (version_compare(phpversion(), '5.6', '<')) {
34
+ add_action('admin_notices', function () {
35
+ echo '<div class="notice notice-error"><p>PHP version 5.6 or greater is required for Newsletter. Ask your provider to upgrade. <a href="https://www.php.net/supported-versions.php" target="_blank">Read more on PHP versions</a></p></div>';
36
+ });
37
+ return;
38
+ }
39
+
40
+ define('NEWSLETTER_VERSION', '7.3.8');
41
+
42
+ global $newsletter, $wpdb;
43
+
44
+ // For acceptance tests, DO NOT CHANGE
45
+ if (!defined('NEWSLETTER_DEBUG'))
46
+ define('NEWSLETTER_DEBUG', false);
47
+
48
+ if (!defined('NEWSLETTER_EXTENSION_UPDATE'))
49
+ define('NEWSLETTER_EXTENSION_UPDATE', true);
50
+
51
+ if (!defined('NEWSLETTER_EMAILS_TABLE'))
52
+ define('NEWSLETTER_EMAILS_TABLE', $wpdb->prefix . 'newsletter_emails');
53
+
54
+ if (!defined('NEWSLETTER_USERS_TABLE'))
55
+ define('NEWSLETTER_USERS_TABLE', $wpdb->prefix . 'newsletter');
56
+
57
+ if (!defined('NEWSLETTER_STATS_TABLE'))
58
+ define('NEWSLETTER_STATS_TABLE', $wpdb->prefix . 'newsletter_stats');
59
+
60
+ if (!defined('NEWSLETTER_SENT_TABLE'))
61
+ define('NEWSLETTER_SENT_TABLE', $wpdb->prefix . 'newsletter_sent');
62
+
63
+ define('NEWSLETTER_SLUG', 'newsletter');
64
+
65
+ define('NEWSLETTER_DIR', __DIR__);
66
+ define('NEWSLETTER_INCLUDES_DIR', __DIR__ . '/includes');
67
+
68
+ // Deperacted since plugin can change the plugins_url()
69
+ define('NEWSLETTER_URL', WP_PLUGIN_URL . '/newsletter');
70
+
71
+ if (!defined('NEWSLETTER_LIST_MAX'))
72
+ define('NEWSLETTER_LIST_MAX', 40);
73
+
74
+ if (!defined('NEWSLETTER_PROFILE_MAX'))
75
+ define('NEWSLETTER_PROFILE_MAX', 20);
76
+
77
+ if (!defined('NEWSLETTER_FORMS_MAX'))
78
+ define('NEWSLETTER_FORMS_MAX', 10);
79
+
80
+ if (!defined('NEWSLETTER_HEADER'))
81
+ define('NEWSLETTER_HEADER', true);
82
+
83
+ require_once NEWSLETTER_INCLUDES_DIR . '/module.php';
84
+ require_once NEWSLETTER_INCLUDES_DIR . '/TNP.php';
85
+ require_once NEWSLETTER_INCLUDES_DIR . '/cron.php';
86
+
87
+ class Newsletter extends NewsletterModule {
88
+
89
+ // Limits to respect to avoid memory, time or provider limits
90
+ var $time_start;
91
+ var $time_limit = 0;
92
+ var $max_emails = null;
93
+
94
+ var $mailer = null;
95
+
96
+ var $action = '';
97
+
98
+ /** @var Newsletter */
99
+ static $instance;
100
+
101
+ const STATUS_NOT_CONFIRMED = 'S';
102
+ const STATUS_CONFIRMED = 'C';
103
+
104
+ /**
105
+ * @return Newsletter
106
+ */
107
+ static function instance() {
108
+ if (self::$instance == null) {
109
+ self::$instance = new Newsletter();
110
+ }
111
+ return self::$instance;
112
+ }
113
+
114
+ function __construct() {
115
+
116
+ // Grab it before a plugin decides to remove it.
117
+ if (isset($_GET['na'])) {
118
+ $this->action = $_GET['na'];
119
+ }
120
+ if (isset($_POST['na'])) {
121
+ $this->action = $_POST['na'];
122
+ }
123
+
124
+ $this->time_start = time();
125
+
126
+ parent::__construct('main', '1.6.7', null, ['info', 'smtp']);
127
+
128
+ add_action('plugins_loaded', [$this, 'hook_plugins_loaded']);
129
+ add_action('init', [$this, 'hook_init'], 1);
130
+ add_action('wp_loaded', [$this, 'hook_wp_loaded'], 1);
131
+
132
+ add_action('newsletter', [$this, 'hook_newsletter'], 1);
133
+
134
+ register_activation_hook(__FILE__, [$this, 'hook_activate']);
135
+ register_deactivation_hook(__FILE__, [$this, 'hook_deactivate']);
136
+
137
+ add_action('admin_init', [$this, 'hook_admin_init']);
138
+
139
+ if (is_admin()) {
140
+ add_action('admin_head', [$this, 'hook_admin_head']);
141
+
142
+ // Protection against strange schedule removal on some installations
143
+ if (!wp_next_scheduled('newsletter') && (!defined('WP_INSTALLING') || !WP_INSTALLING)) {
144
+ wp_schedule_event(time() + 30, 'newsletter', 'newsletter');
145
+ }
146
+
147
+ add_action('admin_menu', [$this, 'add_extensions_menu'], 90);
148
+
149
+ add_filter('display_post_states', [$this, 'add_notice_to_chosen_profile_page_hook'], 10, 2);
150
+
151
+ if ($this->is_admin_page()) {
152
+ // Remove the emoji replacer to save to database the original emoji characters (see even woocommerce for the same problem)
153
+ remove_action('admin_print_scripts', 'print_emoji_detection_script');
154
+ add_action('admin_enqueue_scripts', [$this, 'hook_admin_enqueue_scripts']);
155
+ }
156
+
157
+ }
158
+ }
159
+
160
+ function hook_plugins_loaded() {
161
+ // Used to load dependant modules
162
+ do_action('newsletter_loaded', NEWSLETTER_VERSION);
163
+
164
+ if (function_exists('load_plugin_textdomain')) {
165
+ load_plugin_textdomain('newsletter', false, plugin_basename(__DIR__) . '/languages');
166
+ }
167
+ }
168
+
169
+ function hook_init() {
170
+ global $wpdb;
171
+
172
+ if (isset($this->options['debug']) && $this->options['debug'] == 1) {
173
+ ini_set('log_errors', 1);
174
+ ini_set('error_log', WP_CONTENT_DIR . '/logs/newsletter/php-' . date('Y-m') . '-' . get_option('newsletter_logger_secret') . '.txt');
175
+ }
176
+
177
+ add_shortcode('newsletter_replace', [$this, 'shortcode_newsletter_replace']);
178
+
179
+ add_filter('site_transient_update_plugins', [$this, 'hook_site_transient_update_plugins']);
180
+
181
+ if (is_admin()) {
182
+ if (!class_exists('NewsletterExtensions')) {
183
+
184
+ add_filter('plugin_row_meta', function ($plugin_meta, $plugin_file) {
185
+
186
+ static $slugs = array();
187
+ if (empty($slugs)) {
188
+ $addons = $this->getTnpExtensions();
189
+ if ($addons) {
190
+ foreach ($addons as $addon) {
191
+ $slugs[] = $addon->wp_slug;
192
+ }
193
+ }
194
+ }
195
+ if (array_search($plugin_file, $slugs) !== false) {
196
+
197
+ $plugin_meta[] = '<a href="admin.php?page=newsletter_main_extensions" style="font-weight: bold">Newsletter Addons Manager required</a>';
198
+ }
199
+ return $plugin_meta;
200
+ }, 10, 2);
201
+ }
202
+
203
+ add_action('in_admin_header', array($this, 'hook_in_admin_header'), 1000);
204
+
205
+ if ($this->is_admin_page()) {
206
+
207
+ $dismissed = get_option('newsletter_dismissed', []);
208
+
209
+ if (isset($_GET['dismiss'])) {
210
+ $dismissed[$_GET['dismiss']] = 1;
211
+ update_option('newsletter_dismissed', $dismissed);
212
+ wp_redirect($_SERVER['HTTP_REFERER']);
213
+ exit();
214
+ }
215
+ }
216
+ } else {
217
+ add_action('wp_enqueue_scripts', [$this, 'hook_wp_enqueue_scripts']);
218
+ }
219
+
220
+ do_action('newsletter_init');
221
+ }
222
+
223
+ function hook_wp_loaded() {
224
+ if (empty($this->action)) {
225
+ return;
226
+ }
227
+
228
+ if ($this->action == 'test') {
229
+ // This response is tested, do not change it!
230
+ echo 'ok';
231
+ die();
232
+ }
233
+
234
+ if ($this->action === 'nul') {
235
+ $this->dienow('This link is not active on newsletter preview', 'You can send a test message to test subscriber to have the real working link.');
236
+ }
237
+
238
+ $user = $this->get_user_from_request();
239
+ $email = $this->get_email_from_request();
240
+ do_action('newsletter_action', $this->action, $user, $email);
241
+ }
242
+
243
+ function hook_activate() {
244
+ // Ok, why? When the plugin is not active WordPress may remove the scheduled "newsletter" action because
245
+ // the every-five-minutes schedule named "newsletter" is not present.
246
+ // Since the activation does not forces an upgrade, that schedule must be reactivated here. It is activated on
247
+ // the upgrade method as well for the user which upgrade the plugin without deactivte it (many).
248
+ if (!wp_next_scheduled('newsletter')) {
249
+ wp_schedule_event(time() + 30, 'newsletter', 'newsletter');
250
+ }
251
+
252
+ $install_time = get_option('newsletter_install_time');
253
+ if (!$install_time) {
254
+ update_option('newsletter_install_time', time(), false);
255
+ }
256
+
257
+ touch(NEWSLETTER_LOG_DIR . '/index.html');
258
+
259
+ Newsletter::instance()->upgrade();
260
+ NewsletterUsers::instance()->upgrade();
261
+ NewsletterEmails::instance()->upgrade();
262
+ NewsletterSubscription::instance()->upgrade();
263
+ NewsletterStatistics::instance()->upgrade();
264
+ NewsletterProfile::instance()->upgrade();
265
+ }
266
+
267
+ function first_install() {
268
+ parent::first_install();
269
+ update_option('newsletter_show_welcome', '1', false);
270
+ }
271
+
272
+ function upgrade() {
273
+ global $wpdb, $charset_collate;
274
+
275
+ require_once(ABSPATH . 'wp-admin/includes/upgrade.php');
276
+
277
+ parent::upgrade();
278
+
279
+ $sql = "CREATE TABLE `" . $wpdb->prefix . "newsletter_emails` (
280
+ `id` int(11) NOT NULL AUTO_INCREMENT,
281
+ `language` varchar(10) NOT NULL DEFAULT '',
282
+ `subject` varchar(255) NOT NULL DEFAULT '',
283
+ `message` longtext,
284
+ `created` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
285
+ `status` enum('new','sending','sent','paused','error') NOT NULL DEFAULT 'new',
286
+ `total` int(11) NOT NULL DEFAULT '0',
287
+ `last_id` int(11) NOT NULL DEFAULT '0',
288
+ `sent` int(11) NOT NULL DEFAULT '0',
289
+ `track` int(11) NOT NULL DEFAULT '1',
290
+ `list` int(11) NOT NULL DEFAULT '0',
291
+ `type` varchar(50) NOT NULL DEFAULT '',
292
+ `query` longtext,
293
+ `editor` tinyint(4) NOT NULL DEFAULT '0',
294
+ `sex` varchar(20) NOT NULL DEFAULT '',
295
+ `theme` varchar(50) NOT NULL DEFAULT '',
296
+ `message_text` longtext,
297
+ `preferences` longtext,
298
+ `send_on` int(11) NOT NULL DEFAULT '0',
299
+ `token` varchar(10) NOT NULL DEFAULT '',
300
+ `options` longtext,
301
+ `private` tinyint(1) NOT NULL DEFAULT '0',
302
+ `click_count` int(10) unsigned NOT NULL DEFAULT '0',
303
+ `version` varchar(10) NOT NULL DEFAULT '',
304
+ `open_count` int(10) unsigned NOT NULL DEFAULT '0',
305
+ `unsub_count` int(10) unsigned NOT NULL DEFAULT '0',
306
+ `error_count` int(10) unsigned NOT NULL DEFAULT '0',
307
+ `stats_time` int(10) unsigned NOT NULL DEFAULT '0',
308
+ `updated` int(10) unsigned NOT NULL DEFAULT '0',
309
+ PRIMARY KEY (`id`)
310
+ ) $charset_collate;";
311
+
312
+ dbDelta($sql);
313
+
314
+ // WP does not manage composite primary key when it tries to upgrade a table...
315
+ $suppress_errors = $wpdb->suppress_errors(true);
316
+
317
+ dbDelta("CREATE TABLE " . $wpdb->prefix . "newsletter_sent (
318
+ email_id int(10) unsigned NOT NULL DEFAULT '0',
319
+ user_id int(10) unsigned NOT NULL DEFAULT '0',
320
+ status tinyint(1) unsigned NOT NULL DEFAULT '0',
321
+ open tinyint(1) unsigned NOT NULL DEFAULT '0',
322
+ time int(10) unsigned NOT NULL DEFAULT '0',
323
+ error varchar(255) NOT NULL DEFAULT '',
324
+ ip varchar(100) NOT NULL DEFAULT '',
325
+ PRIMARY KEY (email_id,user_id),
326
+ KEY user_id (user_id),
327
+ KEY email_id (email_id)
328
+ ) $charset_collate;");
329
+ $wpdb->suppress_errors($suppress_errors);
330
+
331
+ // Some setting check to avoid the common support request for mis-configurations
332
+ $options = $this->get_options();
333
+
334
+ if (empty($options['scheduler_max']) || !is_numeric($options['scheduler_max'])) {
335
+ $options['scheduler_max'] = 100;
336
+ $this->save_options($options);
337
+ }
338
+
339
+ wp_clear_scheduled_hook('newsletter');
340
+ wp_schedule_event(time() + 30, 'newsletter', 'newsletter');
341
+
342
+ if (!empty($this->options['editor'])) {
343
+ if (empty($this->options['roles'])) {
344
+ $this->options['roles'] = array('editor');
345
+ unset($this->options['editor']);
346
+ }
347
+ $this->save_options($this->options);
348
+ }
349
+
350
+ // Clear the addons and license caches
351
+ delete_transient('newsletter_license_data');
352
+ $this->clear_extensions_cache();
353
+
354
+ touch(NEWSLETTER_LOG_DIR . '/index.html');
355
+
356
+ return true;
357
+ }
358
+
359
+ function is_allowed() {
360
+ if (current_user_can('administrator')) {
361
+ return true;
362
+ }
363
+ if (!empty($this->options['roles'])) {
364
+ foreach ($this->options['roles'] as $role) {
365
+ if (current_user_can($role)) {
366
+ return true;
367
+ }
368
+ }
369
+ }
370
+ return false;
371
+ }
372
+
373
+ function admin_menu() {
374
+ if (!$this->is_allowed()) {
375
+ return;
376
+ }
377
+
378
+ add_menu_page('Newsletter', 'Newsletter', 'exist', 'newsletter_main_index', '', plugins_url('newsletter') . '/admin/images/menu-icon.png', '30.333');
379
+
380
+ $this->add_menu_page('index', __('Dashboard', 'newsletter'));
381
+ $this->add_admin_page('info', __('Company info', 'newsletter'));
382
+
383
+ if (current_user_can('administrator')) {
384
+ $this->add_menu_page('welcome', __('Welcome', 'newsletter'));
385
+ $this->add_menu_page('main', __('Settings', 'newsletter'));
386
+
387
+ // Pages not on menu
388
+ $this->add_admin_page('smtp', 'SMTP');
389
+ $this->add_admin_page('diagnostic', __('Diagnostic', 'newsletter'));
390
+ $this->add_admin_page('test', __('Test', 'newsletter'));
391
+ }
392
+ }
393
+
394
+ function add_extensions_menu() {
395
+ if (!class_exists('NewsletterExtensions')) {
396
+ $this->add_menu_page('extensions', '<span style="color:#27AE60; font-weight: bold;">' . __('Addons', 'newsletter') . '</span>');
397
+ }
398
+ }
399
+
400
+ function hook_in_admin_header() {
401
+ if (!$this->is_admin_page()) {
402
+ add_action('admin_notices', array($this, 'hook_admin_notices'));
403
+ return;
404
+ }
405
+ remove_all_actions('admin_notices');
406
+ remove_all_actions('all_admin_notices');
407
+ add_action('admin_notices', array($this, 'hook_admin_notices'));
408
+ }
409
+
410
+ function hook_admin_notices() {
411
+ // Check of Newsletter dedicated page
412
+ if (!empty($this->options['page'])) {
413
+ if (get_post_status($this->options['page']) !== 'publish') {
414
+ echo '<div class="notice notice-error"><p>The Newsletter dedicated page is not published. <a href="', site_url('/wp-admin/post.php') . '?post=', $this->options['page'], '&action=edit"><strong>Edit the page</strong></a> or <a href="admin.php?page=newsletter_main_main"><strong>review the main settings</strong></a>.</p></div>';
415
+ }
416
+ }
417
+
418
+ if (isset($this->options['debug']) && $this->options['debug'] == 1) {
419
+ echo '<div class="notice notice-warning"><p>The Newsletter plugin is in <strong>debug mode</strong>. When done change it on Newsletter <a href="admin.php?page=newsletter_main_main"><strong>main settings</strong></a>. Do not keep the debug mode active on production sites.</p></div>';
420
+ }
421
+ }
422
+
423
+ function hook_wp_enqueue_scripts() {
424
+ if (empty($this->options['css_disabled']) && apply_filters('newsletter_enqueue_style', true)) {
425
+ wp_enqueue_style('newsletter', plugins_url('newsletter') . '/style.css', [], NEWSLETTER_VERSION);
426
+ if (!empty($this->options['css'])) {
427
+ wp_add_inline_style('newsletter', $this->options['css']);
428
+ }
429
+ } else {
430
+ if (!empty($this->options['css'])) {
431
+ add_action('wp_head', function () {
432
+ echo '<style>', $this->options['css'], '</style>';
433
+ });
434
+ }
435
+ }
436
+ }
437
+
438
+ function hook_admin_enqueue_scripts() {
439
+
440
+ $newsletter_url = plugins_url('newsletter');
441
+ wp_enqueue_script('jquery-ui-tabs');
442
+ wp_enqueue_script('jquery-ui-tooltip');
443
+ wp_enqueue_script('jquery-ui-draggable');
444
+ wp_enqueue_media();
445
+
446
+ wp_enqueue_script('tnp-admin', $newsletter_url . '/admin/admin.js', ['jquery'], NEWSLETTER_VERSION);
447
+
448
+ wp_enqueue_style('tnp-select2', $newsletter_url . '/vendor/select2/css/select2.min.css', [], NEWSLETTER_VERSION);
449
+ wp_enqueue_script('tnp-select2', $newsletter_url . '/vendor/select2/js/select2.min.js', ['jquery'], NEWSLETTER_VERSION);
450
+
451
+ wp_enqueue_style('tnp-modal', $newsletter_url . '/admin/modal.css', [], NEWSLETTER_VERSION);
452
+ wp_enqueue_script('tnp-modal', $newsletter_url . '/admin/modal.js', ['jquery'], NEWSLETTER_VERSION, true);
453
+
454
+ wp_enqueue_style('tnp-toast', $newsletter_url . '/admin/toast.css', [], NEWSLETTER_VERSION);
455
+ wp_enqueue_script('tnp-toast', $newsletter_url . '/admin/toast.js', ['jquery'], NEWSLETTER_VERSION);
456
+
457
+ wp_enqueue_style('tnp-admin-font', 'https://use.typekit.net/jlj2wjy.css');
458
+ wp_enqueue_style('tnp-admin-fontawesome', $newsletter_url . '/vendor/fa/css/all.min.css', [], NEWSLETTER_VERSION);
459
+ wp_enqueue_style('tnp-admin-jquery-ui', $newsletter_url . '/vendor/jquery-ui/jquery-ui.min.css', [], NEWSLETTER_VERSION);
460
+ wp_enqueue_style('tnp-admin', $newsletter_url . '/admin/admin.css', [], NEWSLETTER_VERSION);
461
+ wp_enqueue_style('tnp-admin-dropdown', $newsletter_url . '/admin/dropdown.css', [], NEWSLETTER_VERSION);
462
+ wp_enqueue_style('tnp-admin-tabs', $newsletter_url . '/admin/tabs.css', [], NEWSLETTER_VERSION);
463
+ wp_enqueue_style('tnp-admin-controls', $newsletter_url . '/admin/controls.css', [], NEWSLETTER_VERSION);
464
+ wp_enqueue_style('tnp-admin-fields', $newsletter_url . '/admin/fields.css', [], NEWSLETTER_VERSION);
465
+ wp_enqueue_style('tnp-admin-widgets', $newsletter_url . '/admin/widgets.css', [], NEWSLETTER_VERSION);
466
+ wp_enqueue_style('tnp-admin-extensions', $newsletter_url . '/admin/extensions.css', [], NEWSLETTER_VERSION);
467
+
468
+ $translations_array = array(
469
+ 'save_to_update_counter' => __('Save the newsletter to update the counter!', 'newsletter')
470
+ );
471
+ wp_localize_script('tnp-admin', 'tnp_translations', $translations_array);
472
+
473
+ wp_enqueue_script('tnp-jquery-vmap', $newsletter_url . '/vendor/jqvmap/jquery.vmap.min.js', ['jquery'], NEWSLETTER_VERSION);
474
+ wp_enqueue_script('tnp-jquery-vmap-world', $newsletter_url . '/vendor/jqvmap/jquery.vmap.world.js', ['tnp-jquery-vmap'], NEWSLETTER_VERSION);
475
+ wp_enqueue_style('tnp-jquery-vmap', $newsletter_url . '/vendor/jqvmap/jqvmap.min.css', [], NEWSLETTER_VERSION);
476
+
477
+ wp_register_script('tnp-chart', $newsletter_url . '/vendor/chartjs/Chart.min.js', ['jquery'], NEWSLETTER_VERSION);
478
+
479
+ wp_enqueue_script('tnp-color-picker', $newsletter_url . '/vendor/spectrum/spectrum.min.js', ['jquery']);
480
+ wp_enqueue_style('tnp-color-picker', $newsletter_url . '/vendor/spectrum/spectrum.min.css', [], NEWSLETTER_VERSION);
481
+ }
482
+
483
+ function shortcode_newsletter_replace($attrs, $content) {
484
+ $content = do_shortcode($content);
485
+ $content = $this->replace($content, $this->get_user_from_request(), $this->get_email_from_request());
486
+ return $content;
487
+ }
488
+
489
+ function is_admin_page() {
490
+ if (!isset($_GET['page'])) {
491
+ return false;
492
+ }
493
+ $page = $_GET['page'];
494
+ return strpos($page, 'newsletter_') === 0;
495
+ }
496
+
497
+ function hook_admin_init() {
498
+ // Verificare il contesto
499
+ if (isset($_GET['page']) && $_GET['page'] === 'newsletter_main_welcome')
500
+ return;
501
+ if (get_option('newsletter_show_welcome')) {
502
+ delete_option('newsletter_show_welcome');
503
+ wp_redirect(admin_url('admin.php?page=newsletter_main_welcome'));
504
+ }
505
+ }
506
+
507
+ function hook_admin_head() {
508
+ // Small global rule for sidebar menu entries
509
+ echo '<style>';
510
+ echo '.tnp-side-menu { color: #E67E22!important; }';
511
+ echo '</style>';
512
+ }
513
+
514
+ function relink($text, $email_id, $user_id, $email_token = '') {
515
+ return NewsletterStatistics::instance()->relink($text, $email_id, $user_id, $email_token);
516
+ }
517
+
518
+ /**
519
+ * Runs every 5 minutes and look for emails that need to be processed.
520
+ */
521
+ function hook_newsletter() {
522
+
523
+ $this->logger->debug(__METHOD__ . '> Start');
524
+
525
+ if (!$this->check_transient('engine', NEWSLETTER_CRON_INTERVAL)) {
526
+ $this->logger->debug(__METHOD__ . '> Engine already active, exit');
527
+ return;
528
+ }
529
+
530
+ $emails = $this->get_results("select * from " . NEWSLETTER_EMAILS_TABLE . " where status='sending' and send_on<" . time() . " order by id asc");
531
+ $this->logger->debug(__METHOD__ . '> Emails found in sending status: ' . count($emails));
532
+
533
+ foreach ($emails as $email) {
534
+ $this->logger->debug(__METHOD__ . '> Start newsletter ' . $email->id);
535
+ $email->options = maybe_unserialize($email->options);
536
+ $r = $this->send($email);
537
+ $this->logger->debug(__METHOD__ . '> End newsletter ' . $email->id);
538
+ if (!$r) {
539
+ $this->logger->debug(__METHOD__ . '> Engine returned false, there is no more capacity');
540
+ break;
541
+ }
542
+ }
543
+ // Remove the semaphore so the delivery engine can be activated again
544
+ $this->delete_transient('engine');
545
+
546
+ $this->logger->debug(__METHOD__ . '> End');
547
+ }
548
+
549
+ function get_send_speed($email = null) {
550
+ $this->logger->debug(__METHOD__ . '> Computing delivery speed');
551
+ $mailer = $this->get_mailer();
552
+ $speed = (int) $mailer->get_speed();
553
+ if (!$speed) {
554
+ $this->logger->debug(__METHOD__ . '> Speed not set by mailer, use the default');
555
+ $speed = (int) $this->options['scheduler_max'];
556
+ } else {
557
+ $this->logger->debug(__METHOD__ . '> Speed set by mailer');
558
+ }
559
+
560
+ //$speed = (int) apply_filters('newsletter_send_speed', $speed, $email);
561
+ // Fail safe setting
562
+ $runs_per_hour = $this->get_runs_per_hour();
563
+ if (!$speed || $speed < $runs_per_hour) {
564
+ return $runs_per_hour;
565
+ }
566
+
567
+ $this->logger->debug(__METHOD__ . '> Speed: ' . $speed);
568
+ return $speed;
569
+ }
570
+
571
+ function get_send_delay() {
572
+ return 0;
573
+ }
574
+
575
+ function skip_this_run($email = null) {
576
+ return (boolean) apply_filters('newsletter_send_skip', false, $email);
577
+ }
578
+
579
+ function get_runs_per_hour() {
580
+ return (int) (3600 / NEWSLETTER_CRON_INTERVAL);
581
+ }
582
+
583
+ function get_emails_per_run() {
584
+ $speed = $this->get_send_speed();
585
+ $max = (int)($speed / $this->get_runs_per_hour());
586
+
587
+ return $max;
588
+ }
589
+
590
+ function get_max_emails($email) {
591
+ // Obsolete, here from Speed Control Addon
592
+ $max = (int) apply_filters('newsletter_send_max_emails', $this->max_emails, $email);
593
+
594
+ return min($max, $this->max_emails);
595
+ }
596
+
597
+ function fix_email($email) {
598
+ if (empty($email->query)) {
599
+ $email->query = "select * from " . NEWSLETTER_USERS_TABLE . " where status='C'";
600
+ }
601
+ if (empty($email->id)) {
602
+ $email->id = 0;
603
+ }
604
+ }
605
+
606
+ function send_setup() {
607
+ $this->logger->debug(__METHOD__ . '> Setup delivery engine');
608
+ if (is_null($this->max_emails)) {
609
+ $this->max_emails = $this->get_emails_per_run();
610
+ $this->logger->debug(__METHOD__ . '> Max emails: ' . $this->max_emails);
611
+ ignore_user_abort(true);
612
+
613
+ @set_time_limit(NEWSLETTER_CRON_INTERVAL + 30);
614
+
615
+ $max_time = (int) (@ini_get('max_execution_time') * 0.95);
616
+ if ($max_time == 0 || $max_time > NEWSLETTER_CRON_INTERVAL) {
617
+ $max_time = (int) (NEWSLETTER_CRON_INTERVAL * 0.95);
618
+ }
619
+
620
+ $this->time_limit = $this->time_start + $max_time;
621
+
622
+ $this->logger->debug(__METHOD__ . '> Max time set to ' . $max_time);
623
+ } else {
624
+ $this->logger->debug(__METHOD__ . '> Already setup');
625
+ }
626
+ }
627
+
628
+ function time_exceeded() {
629
+ if ($this->time_limit && time() > $this->time_limit) {
630
+ $this->logger->info(__METHOD__ . '> Max execution time limit reached');
631
+ return true;
632
+ }
633
+ }
634
+
635
+ /**
636
+ * Sends an email to targeted users or to given users. If a list of users is given (usually a list of test users)
637
+ * the query inside the email to retrieve users is not used.
638
+ *
639
+ * @global wpdb $wpdb
640
+ * @global type $newsletter_feed
641
+ * @param TNP_Email $email
642
+ * @param array $users
643
+ * @return boolean|WP_Error True if the process completed, false if limits was reached. On false the caller should no continue to call it with other emails.
644
+ */
645
+ function send($email, $users = null, $test = false) {
646
+ global $wpdb;
647
+
648
+ if (is_array($email)) {
649
+ $email = (object) $email;
650
+ }
651
+
652
+ $this->logger->info(__METHOD__ . '> Send email ' . $email->id);
653
+
654
+ $this->send_setup();
655
+
656
+ if ($this->max_emails <= 0) {
657
+ $this->logger->info(__METHOD__ . '> No more capacity');
658
+ return false;
659
+ }
660
+
661
+ $this->fix_email($email);
662
+
663
+ // This stops the update of last_id and sent fields since
664
+ // it's not a scheduled delivery but a test or something else (like an autoresponder)
665
+ $supplied_users = $users != null;
666
+
667
+ if (!$supplied_users) {
668
+
669
+ if ($this->skip_this_run($email)) {
670
+ return true;
671
+ }
672
+
673
+ // Speed change for specific email by Speed Control Addon
674
+ $max_emails = $this->get_max_emails($email);
675
+ if ($max_emails <= 0) {
676
+ return true;
677
+ }
678
+
679
+ $query = $email->query;
680
+ $query .= " and id>" . $email->last_id . " order by id limit " . $max_emails;
681
+
682
+ $this->logger->debug(__METHOD__ . '> Query: ' . $query);
683
+
684
+ //Retrieve subscribers
685
+ $users = $this->get_results($query);
686
+
687
+ $this->logger->debug(__METHOD__ . '> Loaded subscribers: ' . count($users));
688
+
689
+ // If there was a database error, return error
690
+ if ($users === false) {
691
+ return new WP_Error('1', 'Unable to query subscribers, check the logs');
692
+ }
693
+
694
+ if (empty($users)) {
695
+ $this->logger->info(__METHOD__ . '> No more users, set as sent');
696
+ $wpdb->query("update " . NEWSLETTER_EMAILS_TABLE . " set status='sent', total=sent where id=" . $email->id . " limit 1");
697
+ do_action('newsletter_ended_sending_newsletter', $email);
698
+ return true;
699
+ }
700
+ } else {
701
+ $this->logger->info(__METHOD__ . '> Subscribers supplied');
702
+ }
703
+
704
+ $start_time = microtime(true);
705
+ $count = 0;
706
+ $result = true;
707
+
708
+ $mailer = $this->get_mailer();
709
+
710
+ $batch_size = $mailer->get_batch_size();
711
+
712
+ $this->logger->debug(__METHOD__ . '> Batch size: ' . $batch_size);
713
+
714
+ // For batch size == 1 (normal condition) we optimize
715
+ if ($batch_size == 1) {
716
+
717
+ foreach ($users as $user) {
718
+
719
+ $this->logger->debug(__METHOD__ . '> Processing user ID: ' . $user->id);
720
+ $user = apply_filters('newsletter_send_user', $user);
721
+ $message = $this->build_message($email, $user);
722
+
723
+ // Save even test emails since people wants to see some stats even for test emails. Stats are reset upon the real "send" of a newsletter
724
+ $this->save_sent_message($message);
725
+
726
+ //Se non è un test incremento il contatore delle email spedite. Perchè incremento prima di spedire??
727
+ if (!$test) {
728
+ $wpdb->query("update " . NEWSLETTER_EMAILS_TABLE . " set sent=sent+1, last_id=" . $user->id . " where id=" . $email->id . " limit 1");
729
+ }
730
+
731
+ $r = $mailer->send($message);
732
+
733
+ if (!empty($message->error)) {
734
+ $this->logger->error($message);
735
+ $this->save_sent_message($message);
736
+ }
737
+
738
+ if (is_wp_error($r)) {
739
+ $this->logger->error($r);
740
+
741
+ // For fatal error, the newsletter status i changed to error (and the delivery stopped)
742
+ if (!$test && $r->get_error_code() == NewsletterMailer::ERROR_FATAL) {
743
+ $this->set_error_state_of_email($email, $r->get_error_message());
744
+ return $r;
745
+ }
746
+ }
747
+
748
+ if (!$supplied_users && !$test && $this->time_exceeded()) {
749
+ $result = false;
750
+ break;
751
+ }
752
+ }
753
+
754
+ $this->max_emails--;
755
+ $count++;
756
+ } else {
757
+
758
+ $chunks = array_chunk($users, $batch_size);
759
+
760
+ foreach ($chunks as $chunk) {
761
+
762
+ $messages = [];
763
+
764
+ // Peeparing a batch of messages
765
+ foreach ($chunk as $user) {
766
+ $this->logger->debug(__METHOD__ . '> Processing user ID: ' . $user->id);
767
+ $user = apply_filters('newsletter_send_user', $user);
768
+ $message = $this->build_message($email, $user);
769
+ $this->save_sent_message($message);
770
+ $messages[] = $message;
771
+
772
+ if (!$test) {
773
+ $wpdb->query("update " . NEWSLETTER_EMAILS_TABLE . " set sent=sent+1, last_id=" . $user->id . " where id=" . $email->id . " limit 1");
774
+ }
775
+ $this->max_emails--;
776
+ $count++;
777
+ }
778
+
779
+ $r = $mailer->send_batch($messages);
780
+
781
+ // Updating the status of the sent messages
782
+ foreach ($messages as $message) {
783
+ if (!empty($message->error)) {
784
+ $this->save_sent_message($message);
785
+ }
786
+ }
787
+
788
+ // The batch went in error
789
+ if (is_wp_error($r)) {
790
+ $this->logger->error($r);
791
+
792
+ if (!$test && $r->get_error_code() == NewsletterMailer::ERROR_FATAL) {
793
+ $this->set_error_state_of_email($email, $r->get_error_message());
794
+ return $r;
795
+ }
796
+ }
797
+
798
+ if (!$supplied_users && !$test && $this->time_exceeded()) {
799
+ $result = false;
800
+ break;
801
+ }
802
+ }
803
+ }
804
+
805
+ $end_time = microtime(true);
806
+
807
+ // Stats only for newsletter with enough emails in a batch (we exclude the Autoresponder since it send one email per call)
808
+ if (!$test && !$supplied_users && $count > 5) {
809
+ $this->update_send_stats($start_time, $end_time, $count, $result);
810
+ }
811
+
812
+ // Cached general statistics are reset
813
+ if (!$test) {
814
+ NewsletterStatistics::instance()->reset_stats_time($email->id);
815
+ }
816
+
817
+ $this->logger->info(__METHOD__ . '> End run for email ' . $email->id);
818
+
819
+ return $result;
820
+ }
821
+
822
+ function update_send_stats($start_time, $end_time, $count, $result) {
823
+ $send_calls = get_option('newsletter_diagnostic_send_calls', []);
824
+ $send_calls[] = [$start_time, $end_time, $count, $result];
825
+
826
+ if (count($send_calls) > 100) {
827
+ array_shift($send_calls);
828
+ }
829
+
830
+ update_option('newsletter_diagnostic_send_calls', $send_calls, false);
831
+ }
832
+
833
+ /**
834
+ * @param TNP_Email $email
835
+ */
836
+ private function set_error_state_of_email($email, $message = '') {
837
+ // Handle only message type at the moment
838
+ if ($email->type !== 'message') {
839
+ return;
840
+ }
841
+
842
+ do_action('newsletter_error_on_sending', $email, $message);
843
+
844
+ $edited_email = new TNP_Email();
845
+ $edited_email->id = $email->id;
846
+ $edited_email->status = TNP_Email::STATUS_ERROR;
847
+ $edited_email->options = $email->options;
848
+ $edited_email->options['error_message'] = $message;
849
+
850
+ $this->save_email($edited_email);
851
+ }
852
+
853
+ /**
854
+ *
855
+ * @param TNP_Email $email
856
+ * @param TNP_User $user
857
+ * @return \TNP_Mailer_Message
858
+ */
859
+ function build_message($email, $user) {
860
+
861
+ $message = new TNP_Mailer_Message();
862
+
863
+ $message->to = $user->email;
864
+
865
+ $message->headers = [];
866
+ $message->headers['Precedence'] = 'bulk';
867
+ $message->headers['X-Newsletter-Email-Id'] = $email->id;
868
+ $message->headers['X-Auto-Response-Suppress'] = 'OOF, AutoReply';
869
+ $message->headers = apply_filters('newsletter_message_headers', $message->headers, $email, $user);
870
+
871
+ $message->body = preg_replace('/data-json=".*?"/is', '', $email->message);
872
+ $message->body = preg_replace('/ +/s', ' ', $message->body);
873
+ $message->body = $this->replace($message->body, $user, $email);
874
+ if ($this->options['do_shortcodes']) {
875
+ $message->body = do_shortcode($message->body);
876
+ }
877
+ $message->body = apply_filters('newsletter_message_html', $message->body, $email, $user);
878
+
879
+ $message->body_text = $this->replace($email->message_text, $user, $email);
880
+ $message->body_text = apply_filters('newsletter_message_text', $message->body_text, $email, $user);
881
+
882
+ if ($email->track == 1) {
883
+ $message->body = $this->relink($message->body, $email->id, $user->id, $email->token);
884
+ }
885
+
886
+ $message->subject = $this->replace($email->subject, $user);
887
+ $message->subject = apply_filters('newsletter_message_subject', $message->subject, $email, $user);
888
+
889
+ if (!empty($email->options['sender_email'])) {
890
+ $message->from = $email->options['sender_email'];
891
+ } else {
892
+ $message->from = $this->options['sender_email'];
893
+ }
894
+
895
+ if (!empty($email->options['sender_name'])) {
896
+ $message->from_name = $email->options['sender_name'];
897
+ } else {
898
+ $message->from_name = $this->options['sender_name'];
899
+ }
900
+
901
+ $message->email_id = $email->id;
902
+ $message->user_id = $user->id;
903
+
904
+ return apply_filters('newsletter_message', $message, $email, $user);
905
+ }
906
+
907
+ /**
908
+ *
909
+ * @param TNP_Mailer_Message $message
910
+ * @param int $status
911
+ * @param string $error
912
+ */
913
+ function save_sent_message($message) {
914
+ global $wpdb;
915
+
916
+ if (!$message->user_id || !$message->email_id) {
917
+ return;
918
+ }
919
+ $status = empty($message->error) ? 0 : 1;
920
+
921
+ $error = mb_substr($message->error, 0, 250);
922
+
923
+ $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, $error, time(), $status, $error));
924
+ }
925
+
926
+ /**
927
+ * @deprecated since version 7.3.0
928
+ */
929
+ function limits_exceeded() {
930
+ return false;
931
+ }
932
+
933
+ /**
934
+ * @deprecated since version 6.0.0
935
+ */
936
+ function register_mail_method($callable) {
937
+ }
938
+
939
+ function register_mailer($mailer) {
940
+ if ($mailer instanceof NewsletterMailer) {
941
+ $this->mailer = $mailer;
942
+ }
943
+ }
944
+
945
+ /**
946
+ * Returns the current registered mailer which must be used to send emails.
947
+ *
948
+ * @return NewsletterMailer
949
+ */
950
+ function get_mailer() {
951
+ if ($this->mailer) {
952
+ return $this->mailer;
953
+ }
954
+
955
+ do_action('newsletter_register_mailer');
956
+
957
+ if (!$this->mailer) {
958
+ // Compatibility
959
+ $smtp = $this->get_options('smtp');
960
+ if (!empty($smtp['enabled'])) {
961
+ $this->mailer = new NewsletterDefaultSMTPMailer($smtp);
962
+ } else {
963
+ $this->mailer = new NewsletterDefaultMailer();
964
+ }
965
+ }
966
+ return $this->mailer;
967
+ }
968
+
969
+ /**
970
+ *
971
+ * @param TNP_Mailer_Message $message
972
+ * @return type
973
+ */
974
+ function deliver($message) {
975
+ $mailer = $this->get_mailer();
976
+ if (empty($message->from))
977
+ $message->from = $this->options['sender_email'];
978
+ if (empty($message->from_name))
979
+ $mailer->from_name = $this->options['sender_name'];
980
+ return $mailer->send($message);
981
+ }
982
+
983
+ /**
984
+ *
985
+ * @param type $to
986
+ * @param type $subject
987
+ * @param string|array $message If string is considered HTML, is array should contains the keys "html" and "text"
988
+ * @param type $headers
989
+ * @param type $enqueue
990
+ * @param type $from
991
+ * @return boolean
992
+ */
993
+ function mail($to, $subject, $message, $headers = array(), $enqueue = false, $from = false) {
994
+
995
+ if (empty($subject)) {
996
+ $this->logger->error('mail> Subject empty, skipped');
997
+ return true;
998
+ }
999
+
1000
+ $mailer_message = new TNP_Mailer_Message();
1001
+ $mailer_message->to = $to;
1002
+ $mailer_message->subject = $subject;
1003
+ $mailer_message->from = $this->options['sender_email'];
1004
+ $mailer_message->from_name = $this->options['sender_name'];
1005
+
1006
+ if (!empty($headers)) {
1007
+ $mailer_message->headers = $headers;
1008
+ }
1009
+ $mailer_message->headers['X-Auto-Response-Suppress'] = 'OOF, AutoReply';
1010
+
1011
+ // Message carrige returns and line feeds clean up
1012
+ if (!is_array($message)) {
1013
+ $mailer_message->body = $this->clean_eol($message);
1014
+ } else {
1015
+ if (!empty($message['text'])) {
1016
+ $mailer_message->body_text = $this->clean_eol($message['text']);
1017
+ }
1018
+
1019
+ if (!empty($message['html'])) {
1020
+ $mailer_message->body = $this->clean_eol($message['html']);
1021
+ }
1022
+ }
1023
+
1024
+ $this->logger->debug($mailer_message);
1025
+
1026
+ $mailer = $this->get_mailer();
1027
+
1028
+ $r = $mailer->send($mailer_message);
1029
+
1030
+ return !is_wp_error($r);
1031
+ }
1032
+
1033
+ function hook_deactivate() {
1034
+ wp_clear_scheduled_hook('newsletter');
1035
+ }
1036
+
1037
+ function find_file($file1, $file2) {
1038
+ if (is_file($file1))
1039
+ return $file1;
1040
+ return $file2;
1041
+ }
1042
+
1043
+ function hook_site_transient_update_plugins($value) {
1044
+ static $extra_response = array();
1045
+
1046
+ //$this->logger->debug('Update plugins transient called');
1047
+
1048
+ if (!$value || !is_object($value)) {
1049
+ //$this->logger->info('Empty object');
1050
+ return $value;
1051
+ }
1052
+
1053
+ if (!isset($value->response) || !is_array($value->response)) {
1054
+ $value->response = array();
1055
+ }
1056
+
1057
+ // Already computed? Use it! (this filter is called many times in a single request)
1058
+ if ($extra_response) {
1059
+ //$this->logger->debug('Already updated');
1060
+ $value->response = array_merge($value->response, $extra_response);
1061
+ return $value;
1062
+ }
1063
+
1064
+ $extensions = $this->getTnpExtensions();
1065
+
1066
+ // Ops...
1067
+ if (!$extensions) {
1068
+ return $value;
1069
+ }
1070
+
1071
+ foreach ($extensions as $extension) {
1072
+ unset($value->response[$extension->wp_slug]);
1073
+ unset($value->no_update[$extension->wp_slug]);
1074
+ }
1075
+
1076
+ // Someone doesn't want our addons updated, let respect it (this constant should be defined in wp-config.php)
1077
+ if (!NEWSLETTER_EXTENSION_UPDATE) {
1078
+ //$this->logger->info('Updates disabled');
1079
+ return $value;
1080
+ }
1081
+
1082
+ include_once(ABSPATH . 'wp-admin/includes/plugin.php');
1083
+
1084
+ // Ok, that is really bad (should we remove it? is there a minimum WP version?)
1085
+ if (!function_exists('get_plugin_data')) {
1086
+ //$this->logger->error('No get_plugin_data function available!');
1087
+ return $value;
1088
+ }
1089
+
1090
+ $license_key = $this->get_license_key();
1091
+
1092
+ // Here we prepare the update information BUT do not add the link to the package which is privided
1093
+ // by our Addons Manager (due to WP policies)
1094
+ foreach ($extensions as $extension) {
1095
+
1096
+ // Patch for names convention
1097
+ $extension->plugin = $extension->wp_slug;
1098
+
1099
+ //$this->logger->debug('Processing ' . $extension->plugin);
1100
+ //$this->logger->debug($extension);
1101
+
1102
+ $plugin_data = false;
1103
+ if (file_exists(WP_PLUGIN_DIR . '/' . $extension->plugin)) {
1104
+ $plugin_data = get_plugin_data(WP_PLUGIN_DIR . '/' . $extension->plugin, false, false);
1105
+ } else if (file_exists(WPMU_PLUGIN_DIR . '/' . $extension->plugin)) {
1106
+ $plugin_data = get_plugin_data(WPMU_PLUGIN_DIR . '/' . $extension->plugin, false, false);
1107
+ }
1108
+
1109
+ if (!$plugin_data) {
1110
+ //$this->logger->debug('Seems not installed');
1111
+ continue;
1112
+ }
1113
+
1114
+ $plugin = new stdClass();
1115
+ $plugin->id = $extension->id;
1116
+ $plugin->slug = $extension->slug;
1117
+ $plugin->plugin = $extension->plugin;
1118
+ $plugin->new_version = $extension->version;
1119
+ $plugin->url = $extension->url;
1120
+ if (class_exists('NewsletterExtensions')) {
1121
+ // NO filters here!
1122
+ $plugin->package = NewsletterExtensions::$instance->get_package($extension->id, $license_key);
1123
+ } else {
1124
+ $plugin->package = '';
1125
+ }
1126
+ // [banners] => Array
1127
+ // (
1128
+ // [2x] => https://ps.w.org/wp-rss-aggregator/assets/banner-1544x500.png?rev=2040548
1129
+ // [1x] => https://ps.w.org/wp-rss-aggregator/assets/banner-772x250.png?rev=2040548
1130
+ // )
1131
+ // [icons] => Array
1132
+ // (
1133
+ // [2x] => https://ps.w.org/advanced-custom-fields/assets/icon-256x256.png?rev=1082746
1134
+ // [1x] => https://ps.w.org/advanced-custom-fields/assets/icon-128x128.png?rev=1082746
1135
+ // )
1136
+ if (version_compare($extension->version, $plugin_data['Version']) > 0) {
1137
+ //$this->logger->debug('There is a new version');
1138
+ $extra_response[$extension->plugin] = $plugin;
1139
+ } else {
1140
+ // Maybe useless...
1141
+ //$this->logger->debug('There is NOT a new version');
1142
+ $value->no_update[$extension->plugin] = $plugin;
1143
+ }
1144
+ //$this->logger->debug('Added');
1145
+ }
1146
+
1147
+ $value->response = array_merge($value->response, $extra_response);
1148
+
1149
+ return $value;
1150
+ }
1151
+
1152
+ /**
1153
+ * @deprecated since version 6.1.9
1154
+ */
1155
+ function get_extension_version($extension_id) {
1156
+ return null;
1157
+ }
1158
+
1159
+ /**
1160
+ * @deprecated since version 6.1.9
1161
+ */
1162
+ function set_extension_update_data($value, $extension) {
1163
+ return $value;
1164
+ }
1165
+
1166
+ /**
1167
+ * Retrieve the extensions form the tnp site
1168
+ * @return array
1169
+ */
1170
+ function getTnpExtensions() {
1171
+
1172
+ $extensions_json = get_transient('tnp_extensions_json');
1173
+
1174
+ if (empty($extensions_json)) {
1175
+ $url = "http://www.thenewsletterplugin.com/wp-content/extensions.json?ver=" . NEWSLETTER_VERSION;
1176
+ $extensions_response = wp_remote_get($url);
1177
+
1178
+ if (is_wp_error($extensions_response)) {
1179
+ // Cache anyway for blogs which cannot connect outside
1180
+ $extensions_json = '[]';
1181
+ set_transient('tnp_extensions_json', $extensions_json, 72 * 60 * 60);
1182
+ $this->logger->error($extensions_response);
1183
+ } else {
1184
+
1185
+ $extensions_json = wp_remote_retrieve_body($extensions_response);
1186
+
1187
+ // Not clear cases
1188
+ if (empty($extensions_json) || !json_decode($extensions_json)) {
1189
+ $this->logger->error('Invalid json from thenewsletterplugin.com: retrying in 72 hours');
1190
+ $this->logger->error('JSON: ' . $extensions_json);
1191
+ $extensions_json = '[]';
1192
+ }
1193
+ set_transient('tnp_extensions_json', $extensions_json, 72 * 60 * 60);
1194
+ }
1195
+ }
1196
+
1197
+ $extensions = json_decode($extensions_json);
1198
+
1199
+ return $extensions;
1200
+ }
1201
+
1202
+ function clear_extensions_cache() {
1203
+ delete_transient('tnp_extensions_json');
1204
+ }
1205
+
1206
+ var $panels = array();
1207
+
1208
+ function add_panel($key, $panel) {
1209
+ if (!isset($this->panels[$key]))
1210
+ $this->panels[$key] = array();
1211
+ if (!isset($panel['id']))
1212
+ $panel['id'] = sanitize_key($panel['label']);
1213
+ $this->panels[$key][] = $panel;
1214
+ }
1215
+
1216
+ function has_license() {
1217
+ return !empty($this->options['contract_key']);
1218
+ }
1219
+
1220
+ function get_sender_name() {
1221
+ return $this->options['sender_name'];
1222
+ }
1223
+
1224
+ function get_sender_email() {
1225
+ return $this->options['sender_email'];
1226
+ }
1227
+
1228
+ /**
1229
+ *
1230
+ * @return int
1231
+ */
1232
+ function get_newsletter_page_id() {
1233
+ return (int) $this->options['page'];
1234
+ }
1235
+
1236
+ /**
1237
+ *
1238
+ * @return WP_Post
1239
+ */
1240
+ function get_newsletter_page() {
1241
+ return get_post($this->get_newsletter_page_id());
1242
+ }
1243
+
1244
+ /**
1245
+ * Returns the Newsletter dedicated page URL or an alternative URL if that page if not
1246
+ * configured or not available.
1247
+ *
1248
+ * @staticvar string $url
1249
+ * @return string
1250
+ */
1251
+ function get_newsletter_page_url($language = '') {
1252
+
1253
+ $page = $this->get_newsletter_page();
1254
+
1255
+ if (!$page || $page->post_status !== 'publish') {
1256
+ return $this->build_action_url('m');
1257
+ }
1258
+
1259
+ $newsletter_page_url = get_permalink($page->ID);
1260
+ if ($language && $newsletter_page_url) {
1261
+ if (class_exists('SitePress')) {
1262
+ $newsletter_page_url = apply_filters('wpml_permalink', $newsletter_page_url, $language, true);
1263
+ }
1264
+ if (function_exists('pll_get_post')) {
1265
+ $translated_page = get_permalink(pll_get_post($page->ID, $language));
1266
+ if ($translated_page) {
1267
+ $newsletter_page_url = $translated_page;
1268
+ }
1269
+ }
1270
+ }
1271
+
1272
+ return $newsletter_page_url;
1273
+ }
1274
+
1275
+ function get_license_key() {
1276
+ if (defined('NEWSLETTER_LICENSE_KEY')) {
1277
+ return NEWSLETTER_LICENSE_KEY;
1278
+ } else {
1279
+ if (!empty($this->options['contract_key'])) {
1280
+ return trim($this->options['contract_key']);
1281
+ }
1282
+ }
1283
+ return false;
1284
+ }
1285
+
1286
+ /**
1287
+ * Get the data connected to the specified license code on man settings.
1288
+ *
1289
+ * - false if no license is present
1290
+ * - WP_Error if something went wrong if getting the license data
1291
+ * - object with expiration and addons list
1292
+ *
1293
+ * @param boolean $refresh
1294
+ * @return \WP_Error|boolean|object
1295
+ */
1296
+ function get_license_data($refresh = false) {
1297
+
1298
+ $this->logger->debug('Getting license data');
1299
+
1300
+ $license_key = $this->get_license_key();
1301
+ if (empty($license_key)) {
1302
+ $this->logger->debug('License was empty');
1303
+ delete_transient('newsletter_license_data');
1304
+ return false;
1305
+ }
1306
+
1307
+ if (!$refresh) {
1308
+ $license_data = get_transient('newsletter_license_data');
1309
+ if ($license_data !== false && is_object($license_data)) {
1310
+ $this->logger->debug('License data found on cache');
1311
+ return $license_data;
1312
+ }
1313
+ }
1314
+
1315
+ $this->logger->debug('Refreshing the license data');
1316
+
1317
+ $license_data_url = 'https://www.thenewsletterplugin.com/wp-content/plugins/file-commerce-pro/get-license-data.php';
1318
+
1319
+ $response = wp_remote_post($license_data_url, array(
1320
+ 'body' => array('k' => $license_key)
1321
+ ));
1322
+
1323
+ // Fall back to http...
1324
+ if (is_wp_error($response)) {
1325
+ $this->logger->error($response);
1326
+ $this->logger->error('Falling back to http');
1327
+ $license_data_url = str_replace('https', 'http', $license_data_url);
1328
+ $response = wp_remote_post($license_data_url, array(
1329
+ 'body' => array('k' => $license_key)
1330
+ ));
1331
+ if (is_wp_error($response)) {
1332
+ $this->logger->error($response);
1333
+ set_transient('newsletter_license_data', $response, DAY_IN_SECONDS);
1334
+ return $response;
1335
+ }
1336
+ }
1337
+
1338
+ $download_message = 'You can download all addons from www.thenewsletterplugin.com if your license is valid.';
1339
+
1340
+ if (wp_remote_retrieve_response_code($response) != '200') {
1341
+ $this->logger->error('license data error: ' . wp_remote_retrieve_response_code($response));
1342
+ $data = new WP_Error(wp_remote_retrieve_response_code($response), 'License validation service error. <br>' . $download_message);
1343
+ set_transient('newsletter_license_data', $data, DAY_IN_SECONDS);
1344
+ return $data;
1345
+ }
1346
+
1347
+ $json = wp_remote_retrieve_body($response);
1348
+ $data = json_decode($json);
1349
+
1350
+ if (!is_object($data)) {
1351
+ $this->logger->error($json);
1352
+ $data = new WP_Error(1, 'License validation service error. <br>' . $download_message);
1353
+ set_transient('newsletter_license_data', $data, DAY_IN_SECONDS);
1354
+ return $data;
1355
+ }
1356
+
1357
+ if (isset($data->message)) {
1358
+ $data = new WP_Error(1, $data->message . ' (check the license on Newsletter main settings)');
1359
+ set_transient('newsletter_license_data', $data, DAY_IN_SECONDS);
1360
+ return $data;
1361
+ }
1362
+
1363
+ $expiration = WEEK_IN_SECONDS;
1364
+ // If the license expires in few days, make the transient live only few days, so it will be refreshed
1365
+ if ($data->expire > time() && $data->expire - time() < WEEK_IN_SECONDS) {
1366
+ $expiration = $data->expire - time();
1367
+ }
1368
+ set_transient('newsletter_license_data', $data, $expiration);
1369
+
1370
+ return $data;
1371
+ }
1372
+
1373
+ /**
1374
+ * @deprecated
1375
+ * @param type $license_key
1376
+ * @return \WP_Error
1377
+ */
1378
+ public static function check_license($license_key) {
1379
+ $response = wp_remote_get('http://www.thenewsletterplugin.com/wp-content/plugins/file-commerce-pro/check.php?k=' . urlencode($license_key), array('sslverify' => false));
1380
+ if (is_wp_error($response)) {
1381
+ /* @var $response WP_Error */
1382
+ return new WP_Error(-1, 'It seems that your blog cannot contact the license validator. Ask your provider to unlock the HTTP/HTTPS connections to www.thenewsletterplugin.com<br>'
1383
+ . esc_html($response->get_error_code()) . ' - ' . esc_html($response->get_error_message()));
1384
+ } else if ($response['response']['code'] != 200) {
1385
+ return new WP_Error(-1, '[' . $response['response']['code'] . '] The license seems expired or not valid, please check your <a href="https://www.thenewsletterplugin.com/account">license code and status</a>, thank you.'
1386
+ . '<br>You can anyway download the professional extension from https://www.thenewsletterplugin.com.');
1387
+ } elseif ($expires = json_decode(wp_remote_retrieve_body($response))) {
1388
+ return array('expires' => $expires->expire, 'message' => 'Your license is valid and expires on ' . esc_html(date('Y-m-d', $expires->expire)));
1389
+ } else {
1390
+ return new WP_Error(-1, 'Unable to detect the license expiration. Debug data to report to the support: <code>' . esc_html(wp_remote_retrieve_body($response)) . '</code>');
1391
+ }
1392
+ }
1393
+
1394
+ function add_notice_to_chosen_profile_page_hook($post_states, $post) {
1395
+
1396
+ if ($post->ID == $this->options['page']) {
1397
+ $post_states[] = __('Newsletter plugin page, do not delete', 'newsletter');
1398
+ }
1399
+
1400
+ return $post_states;
1401
+ }
1402
+
1403
+ }
1404
+
1405
+ $newsletter = Newsletter::instance();
1406
+
1407
+ if (is_admin()) {
1408
+ require_once NEWSLETTER_DIR . '/system/system.php';
1409
+ }
1410
+
1411
+ require_once NEWSLETTER_DIR . '/subscription/subscription.php';
1412
+ require_once NEWSLETTER_DIR . '/unsubscription/unsubscription.php';
1413
+ require_once NEWSLETTER_DIR . '/profile/profile.php';
1414
+ require_once NEWSLETTER_DIR . '/emails/emails.php';
1415
+ require_once NEWSLETTER_DIR . '/users/users.php';
1416
+ require_once NEWSLETTER_DIR . '/statistics/statistics.php';
1417
+ require_once NEWSLETTER_DIR . '/widget/standard.php';
1418
+ require_once NEWSLETTER_DIR . '/widget/minimal.php';
readme.txt CHANGED
@@ -1,392 +1,407 @@
1
- === Newsletter ===
2
- Tags: newsletter, email marketing, welcome email, signup forms, contact, lead generation, marketing automation
3
- Tested up to: 5.9
4
- Stable tag: 7.3.7
5
- Contributors: satollo,webagile,michael-travan
6
- License: GPLv2 or later
7
- License URI: https://www.gnu.org/licenses/gpl-2.0.html
8
-
9
- Add a real newsletter system to your blog. For free. With unlimited newsletters and subscribers.
10
-
11
- == Description ==
12
-
13
- Newsletter is a **real newsletter and email marketing system** for your WordPress blog: perfect for list building, you can easily create, send and track e-mails, headache-free. It just works out of box!
14
-
15
- = Discover a completely rewritten composer =
16
-
17
- We redesigned our drag and drop composer to make your campaign creation even easier. Try it!
18
-
19
- = Main Features =
20
-
21
- * **Easy-to-use Drag and drop composer** to build responsive newsletters
22
- * **Unlimited subscribers** with statistics
23
- * **Unlimited newsletters** with tracking
24
- * **Subscription spam check** with domain/ip black lists, Akismet, captcha
25
- * **Delivery speed** fine control (from 12 emails per hour to as much as your blog can manage)
26
- * [WPML ready](https://www.thenewsletterplugin.com/documentation/multilanguage), [Polylang ready](https://www.thenewsletterplugin.com/documentation/multilanguage), [Translatepress ready](https://www.thenewsletterplugin.com/documentation/multilanguage)
27
- * All messages are **fully translatable** from administration panels (no .po/.mo file to edit)
28
- * [GDPR ready](https://www.thenewsletterplugin.com/documentation/gdpr-compliancy)
29
- * **Advanced targeting** with lists combinations like all in, at least one, not in and so on
30
- * Customizable **subscription widget**, **page** or **custom form**
31
- * Wordpress Users registration **seamless integration**
32
- * **Single** And **Double Opt-In** plus privacy checkbox for EU laws compliance
33
- * **Subscribers lists** to fine-target your campaigns
34
- * PHP API and REST API for coders and integrations
35
- * SMTP-Ready (with free addon)
36
- * Customizable Themes
37
- * **Status panel** to check your blog mailing capability and configuration
38
- * **Compatible with every SMTP plugin**: Post SMTP (aka Postman), WP Mail SMTP, Easy WP SMTP, Easy SMTP Mail, WP Mail Bank, ...
39
- * **Subscribers import** from file
40
- * Newsletter with Html and Text message versions
41
-
42
- = Find Us =
43
-
44
- Newsletter is a continuously evolving plugin. Stay tuned following us on [Facebook](https://www.facebook.com/thenewsletterplugin/) or [our site](https://www.thenewsletterplugin.com/).
45
-
46
- = Free Addons =
47
-
48
- Improve The Newsletter Plugin with these free addons:
49
-
50
- * [WP Registration Addon](https://www.thenewsletterplugin.com/documentation/wpusers-extension) - connects the WordPress standard and custom registration with Newsletter subscription. Optionally imports all registered users as subscribers.
51
- * [Archive Addon](https://www.thenewsletterplugin.com/documentation/archive-extension) - creates a simple blog page which lists all your sent newsletters
52
- * [Locked Content Addon](https://www.thenewsletterplugin.com/documentation/locked-content-extension) - open up your premium content only after subscription
53
- * [Newsletter REST API Addon](https://www.thenewsletterplugin.com/documentation/developers/newsletter-api-2/) - adds a tier of REST api to integrate with the Newsletter core services
54
- * [Sendinblue Addon](https://www.thenewsletterplugin.com/documentation/addons/delivery-addons/sendinblue-extension/) - deliver your newsletters with Sendinblue
55
- * [SMTP Addon](https://www.thenewsletterplugin.com/documentation/addons/delivery-addons/smtp-extension/) - deliver your newsletters with external SMTP
56
- * [Advanced Import Addon](https://www.thenewsletterplugin.com/documentation/addons/extended-features/advanced-import/) - import contact from file or copy and paste data with full mapping
57
-
58
- (*easily add them from our [Addons panel](https://www.thenewsletterplugin.com/documentation/install-extensions)*)
59
-
60
- = Addons on WordPress.org =
61
-
62
- * [RSS Composer Block](https://wordpress.org/plugins/newsletter-rss-block/) - (3rd party) a composer block which builds its content from a RSS feed
63
- * [Popup Maker Integration](https://wordpress.org/plugins/newsletter-popupmaker/) - (3rd party) integration of Newsletter forms with Popup Maker plugin
64
- * [BuddyPress integration](https://wordpress.org/plugins/newsletter-buddypress/) - subscription opt-in inside BuddyPress signup form
65
- * [WP User Manager addon for Newsletter](https://wordpress.org/plugins/wpum-newsletter/) - adds the subscription option on registration forms
66
-
67
- = Professional Addons =
68
-
69
- Need *more power*? Feel *something's missing*? The Newsletter Plugin features can be easily extended through our **premium, professional Addons**! Let us introduce just two of them : )
70
-
71
- * [Automated](https://www.thenewsletterplugin.com/automated) - generates and sends your newsletters using your blog last posts, even custom ones like events or products. Just sit and watch!
72
- * [Autoresponder](https://www.thenewsletterplugin.com/autoresponder) - creates email series to follow up your subscribers
73
- * [Extended Composer Blocks](https://www.thenewsletterplugin.com/composer) - adds new blocks to the drag & drop composer
74
- * [WooCommerce Integration](https://www.thenewsletterplugin.com/woocommerce) - subscribe customers to a mailing list and generate product newletters.
75
- * [Reports](https://www.thenewsletterplugin.com/reports) - improves the internal statistics collection system and provides better reports of data collected for each sent email. And retargeting. Neat.
76
- * [Leads](https://www.thenewsletterplugin.com/leads) adds a fancy subscription popup box or a fixed bar to your website that will boost your conversion rate
77
- * [Amazon SES and other mail providers integration](https://www.thenewsletterplugin.com/integrations) - seamlessly integrate Amazon SES and other email service providers with The Newsletter Plugin. Hassle-free.
78
- * [Contact Form 7 Integration](https://www.thenewsletterplugin.com/documentation/contact-form-7-extension) - integrate the subscription on Contact Form 7 forms
79
- * [Ninja Forms Integration](https://www.thenewsletterplugin.com/documentation/ninjaforms-extension) - integrate the subscription on Ninja Forms
80
- * [WP Forms Integration](https://www.thenewsletterplugin.com/documentation/wpforms-extension) - integrate the subscription on WP Forms
81
- * Events Manager and The Events Calendar (By Modern Tribe) integrations - easily add events to your newsletters
82
- * [Google Analytics](https://www.thenewsletterplugin.com/google-analytics) - track newsletter links with Google UTM tracking paramaters
83
- * [Subscribe on Comment](https://www.thenewsletterplugin.com/documentation/comments-extension) - adds the subscription option to your blog comment form
84
- * [Geolocation](https://www.thenewsletterplugin.com/documentation/geolocation-extension) - adds geolocation capability to target subscribers by location
85
-
86
- = GDPR =
87
-
88
- The Newsletter Plugin provides all the technical tools needed to achieve GDPR compliancy and we're continuously working to improve them and to give support even for specific use cases.
89
- The plugin does not collect users' own subscribers data, nor it has any access to those data: hence, we are not a data processor, so a data processing agreement is not needed.
90
- Anyway if you configure the plugin to use external services (usually an external mail delivery service) you should check with that service if some sort of agreement is required.
91
-
92
- = Support =
93
-
94
- We provide support for our plugin on [Wordpress.org forums](https://wordpress.org/support/plugin/newsletter) and through our [official forum](https://www.thenewsletterplugin.com/forums).
95
-
96
- Premium Users with an active license have access to one-to-one support via our [ticketing system](https://www.thenewsletterplugin.com/support-ticket).
97
-
98
- = Follow Us =
99
-
100
- * **Our Official Website** - [https://www.thenewsletterplugin.com/](https://www.thenewsletterplugin.com/)
101
- * **LinkedIn** - [https://www.linkedin.com/company/the-newsletter-plugin](https://www.linkedin.com/company/the-newsletter-plugin)
102
- * **Our Facebook Page** - [https://www.facebook.com/thenewsletterplugin](https://www.facebook.com/thenewsletterplugin)
103
- * **Our Twitter Account** - [https://twitter.com/newsletterwp](https://twitter.com/newsletterwp)
104
-
105
- == Frequently Asked Questions ==
106
-
107
- See the [Newsletter Forum](https://www.thenewsletterplugin.com/forums) to ask for help.
108
-
109
- For documentation start from [Newsletter documentation](https://www.thenewsletterplugin.com/documentation).
110
-
111
- Thank you, The Newsletter Team
112
-
113
- == Screenshots ==
114
-
115
- 1. The responsive email Drag & Drop composer
116
- 2. The plugin dashboard
117
- 3. The Reports extension
118
-
119
- == Changelog ==
120
-
121
- = 7.3.7 =
122
-
123
- * Fixed unwanted redirects on subscription errors
124
- * Fixed composer page HTML
125
- * Minor fixes on PHP, CSS
126
- * Fixed notice on image block
127
-
128
- = 7.3.6 =
129
-
130
- * Improved composer reusability in other contexts
131
- * Removed obsolete composer code
132
- * Fixed default tracking for old theme-based neewsletters
133
- * Forced enconding on export (attempt)
134
- * WP 5.9 check
135
-
136
- = 7.3.5 =
137
-
138
- * WP 5.8.3 compatibility check
139
- * Fixed 2021 max year in date picker
140
- * Typos
141
-
142
- = 7.3.4 =
143
-
144
- * Fixed delivery fatal error management
145
- * Fixed link to the schduler dianostica panel
146
-
147
- = 7.3.3 =
148
-
149
- * Added "complained" status to subscriber filters
150
- * Fixed some links bringing to a "not allowed" page
151
- * Fixed a notice on delivery diagnostic page
152
- * Fixed logo width notice on header block
153
-
154
- = 7.3.2 =
155
-
156
- * Fixed the remote ip retrieval and clean up
157
- * Fixed header link to status page
158
- * Fixed database error with too long IPs
159
- * Fixed the subscription of cancelled addresses
160
- * Fixed sender and name customization
161
-
162
- = 7.3.1 =
163
-
164
- * Dropped old mailers support
165
- * Improved sending process and limits checking
166
- * Removed obsolete notifications
167
- * Fixed the wrong report on single email delivery speed
168
- * Added support for custom sending speed by addons
169
- * Improved excerpt generation (but it still depends on plugins and themes...)
170
- * Support for building button option on composer blocks
171
-
172
- = 7.3.0 =
173
-
174
- * Fixed header block layout with (logo only layout)
175
- * Check for conflicts on newsletter saving
176
- * Added the subscriber complained status (actually not managed automatically)
177
-
178
- = 7.2.9 =
179
-
180
- * Fixed generic action button confirmation popup not showing the message
181
- * [SECURITY] Pre parsing of IP addresses on security panel
182
- * [SECURITY] Comments allowed on IP address list on security panel
183
- * [COMPOSER] Fixed preset name/subject
184
- * Improved generated forms for accessibility
185
-
186
- = 7.2.8 =
187
-
188
- * Fixed the print_date() when no time is provided
189
- * Fixed date alignment on posts block
190
- * Folders reorganization
191
- * Social block with a new set of icons
192
- * Boosted performances of the lists management page (for big databases)
193
- * Added a new scheduler diagnostic panel
194
- * Seriously improved the cron statistics and diagnostic panel (check it out!)
195
- * Removed obsolete migration code from ancient versions
196
-
197
- = 7.2.7 =
198
-
199
- * Fixed JS error on composer sometimes preventing the correct initialization
200
-
201
- = 7.2.6 =
202
-
203
- * Fixed links on test emails sent to a free email address
204
- * Added attachment explanation
205
- * Added link to explain the use of the snippet
206
-
207
- = 7.2.5 =
208
-
209
- * Fixed subject not saved under specific circumstance
210
-
211
- = 7.2.4 =
212
-
213
- * Fixed the composer not starting for blog with SSL plugin but still HTTP configured on main WP settings
214
- * Changed labels on subscriber maintenance panel
215
- * Updated requirements for WP version
216
-
217
- = 7.2.3 =
218
-
219
- * [COMPOSER] Added approx. indicators of the subsject visibile part in Apple and Android clients (experimental)
220
- * [COMPOSER] New mobile version view directly while composing (experimental)
221
- * [COMPOSER] New test email to test subscribers or to specific email address
222
- * [COMPOSER] Fixed missing background when creating a new message from a preset
223
- * [COMPOSER] Added media selector to the CTA block
224
- * [COMPOSER] Added reference to the tags on HTML and Text blocks
225
- * [COMPOSER] Move the snippet (preheader) field near the subject
226
- * [COMPOSER] Footer block with three link options: unsubscribe, manage and view online
227
- * [COMPOSER] Improve font coherence between blocks (by default)
228
- * [ANTISPAM] Improved the antispam checks on subscription
229
- * [GENERAL] Removed obsolete folders and code
230
- * [NEWSLETTERS] Refactored subject ideas selector
231
- * [SUBSCRIPTION] Inverted extra profile fields and lists on standard subscription form
232
- * [GENERAL] IP address extracted checking proxy variables
233
- * [GENERAL] Improved sending stats collection and display for the delivery engine (not related to click/open stats)
234
-
235
- = 7.2.2 =
236
-
237
- * [COMPOSER] Posts block excerpt removed when set to 0-length
238
- * [GENERAL]Added special characters on test message
239
- * [GENERAL]Added more specific error for action calls on System/Status panel
240
- * [SUBSCRIPTION] Check for the _wp_amp_action_xhr_converted parameter by AMP plugin
241
-
242
- = 7.2.1 =
243
-
244
- * [GENERAL] Added more detailed admin logging
245
- * [NEWSLETTERS] Fixed scheduled date sometimes reset to 1/1/1970
246
-
247
- = 7.2.0 =
248
-
249
- * [PROFILE] Fixed activation email on profile change
250
- * [NEWSLETTERS] Extended year selection on newsletter scheduling
251
- * [DELIVERY] Breaking change: old enqueue() and flush() methods have been removed
252
- * [GENERAL] Fixed alert message on some buttons
253
- * [SUBSCRIPTION] Fixed error message on multiple subscriptions (when not allowed)
254
- * [GENERAL] Fixed erratic error log line on main log
255
-
256
- = 7.1.9 =
257
-
258
- * [GENERAL] Removed the encodign defatlt to Base 64 when not specified since it seems incompatible with some SMTP plugins
259
- * [GENERAL] Review some controls layout and behavior
260
- * [DEBUG] Improved logging on database errors
261
- * [GENERAL] Added TikTok, Discord and Twitch socials
262
- * [GENERAL] Fixed odd error reported related to the cron call statistics collection
263
- * [DEBUG] Added a delivery diagnostic panel
264
-
265
- = 7.1.8 =
266
-
267
- * [COMPOSER] Fixed alignment of single big image on Outlook Android
268
-
269
- = 7.1.7 =
270
-
271
- * [GENERAL] Fix of permalink onm email with multilanguage plugins
272
-
273
- = 7.1.6 =
274
-
275
- * [COMPOSER] Fixed one column big image Read more links
276
-
277
- = 7.1.5 =
278
-
279
- * [COMPOSER] Improve buttons on posts layout
280
- * [COMPOSER] Improved header layout and logo
281
- * [COMPOSER] Generally improved block spacing
282
-
283
- = 7.1.4 =
284
-
285
- * [COMPOSER] Fixed image block for Outlook
286
- * [GENERAL] Fix undefined values in Gutenberg block
287
-
288
- = 7.1.3 =
289
-
290
- * [COMPOSER] Improvements on blocks layout compatibility
291
- * [COMPOSER] Fixed preset global options saving
292
- * [COMPOSER] Content regeneration on preset selection
293
- * [GENERAL] Added to System menu the Site Health link, a not well known native page of WordPress with system information
294
- * [GENERAL] Added sending statistics reset button on status panel
295
-
296
- = 7.1.2 =
297
-
298
- * [ADDONS] Fixed the addons list
299
-
300
- = 7.1.1 =
301
-
302
- * [GENERAL] Improved profile related functions
303
- * [GENERAL] Fixed check on field names (thanks Peter P.)
304
- * [COMPOSER] Fix on preset selection
305
- * [GENERAL] Fix ajax subscription on error
306
-
307
- = 7.1.0 =
308
-
309
- * [COMPOSER] Added link to tags documentation to inject subscriber's data
310
- * [COMPOSER] Fixed layout of posts block for Outlook 365
311
- * [GENERAL] Improved caching of addons json (even on error)
312
- * [GENERAL] Status menu changed to System/Status and System/Logs
313
- * [API] Fixed the subscriber status management (the API Addon should be updated as well)
314
- * [GENERAL] Fixed management of fatal errors on sending
315
- * [GENERAL] Limited error string per message to 250 chars
316
- * [GENERAL] Fixed check on field names (thanks Peter P.)
317
-
318
-
319
- = 7.0.9 =
320
-
321
- * [CAPTCHA] Fixed button label translation
322
- * [DELIVERY] Mailing fatal error management with newsletter stop and reporting
323
- * [SMTP] Marked obsolete the internal SMTP and made available the free SMTP addon
324
- * [DELIVERY] Better management of delivery fatal errors with a new "error" status for newsletters
325
- * [GENERAL] New log files panel
326
- * [IMPORT] Old import panel replaced by the new (really better) import addon (file, copy and paste, bounced addresses import)
327
- * [NEWSLETTERS] It's now possible to specify the sender name and email per newsletter (thanks to Matthew S.)
328
-
329
- = 7.0.8 =
330
-
331
- * [SUBSCRIBERS] Changed action buttons
332
- * [GENERAL] Reorganization of CSS and removal of unused files
333
- * [DASHBOARD] New window open for links and fix of invalid URLs
334
- * [NEWSLETTERS] New action buttons
335
- * [GENERAL] Minor fixes and optimizations
336
- * [COMPOSER] Fixed rare size error on gif images
337
-
338
- = 7.0.7 =
339
-
340
- * [COMPOSER] Fixed a warning in some inline editable blocks
341
- * [NEWSLETTERS] Fixed style which made list labels badly readable
342
- * [NEWSLETTERS] Fixed style which made bullet lists white (not on delivered newsletters)
343
- * [GENERAL] Added some references to the not working scheduler warning
344
-
345
- = 7.0.6 =
346
-
347
- * [COMPOSER] CTA block not grabbing settings from the "old" blocks
348
- * [COMPOSER] CSS issue on button settings group
349
- * [COMPOSER] Posts block two columns layout (author and padding)
350
- * [IMPORT] Removed the old low-featured import (the free import addon has everything needed!)
351
- * [GENERAL] Compatibility check with WP 5.7
352
-
353
- = 7.0.5 =
354
-
355
- * [COMPOSER] Hero CTA button not working
356
- * Fixed to the hero block button
357
- * Added support for the SMTP addon
358
-
359
- = 7.0.4 =
360
-
361
- * [COMPOSER] Redesigned drag and drop composer
362
- * [COMPOSER] NEW! Save drag and drop composed newsletters as templates to reuse easily
363
- * Redesigned dashboard
364
- * Several bug and fixes
365
-
366
- = 7.0.3 =
367
-
368
- * Option to choose between unsubscription and profile link in the footer block
369
- * Direct image src URL for image block
370
- * New media selector for blocks
371
- * Minor fixes
372
- * Updated codemirror
373
- * Updated default theme
374
- * Fixed tag filter on posts block (when tags have parathesis or like)
375
- * Fixed composer visualization of bullet points
376
-
377
- = 7.0.2 =
378
-
379
- * Fixed media 2x resize
380
-
381
- = 7.0.1 =
382
-
383
- * Fixed enforced lists by language with Polylang
384
-
385
- = 7.0.0 =
386
-
387
- * Added multiple newsletter selection for deletion
388
- * Added text part on welcome and activation email
389
- * Added the attribute "show_form" to "newsletter" shortcode
390
- * Added filter on subscriber saving (from external systems) with wrong list field values
391
- * Added index.html on log folder
392
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ === Newsletter ===
2
+ Tags: newsletter, email marketing, welcome email, signup forms, contact, lead generation, marketing automation
3
+ Tested up to: 5.9
4
+ Stable tag: 7.3.8
5
+ Contributors: satollo,webagile,michael-travan
6
+ License: GPLv2 or later
7
+ License URI: https://www.gnu.org/licenses/gpl-2.0.html
8
+
9
+ Add a real newsletter system to your blog. For free. With unlimited newsletters and subscribers.
10
+
11
+ == Description ==
12
+
13
+ Newsletter is a **real newsletter and email marketing system** for your WordPress blog: perfect for list building, you can easily create, send and track e-mails, headache-free. It just works out of box!
14
+
15
+ = Discover a completely rewritten composer =
16
+
17
+ We redesigned our drag and drop composer to make your campaign creation even easier. Try it!
18
+
19
+ = Main Features =
20
+
21
+ * **Easy-to-use Drag and drop composer** to build responsive newsletters
22
+ * **Unlimited subscribers** with statistics
23
+ * **Unlimited newsletters** with tracking
24
+ * **Subscription spam check** with domain/ip black lists, Akismet, captcha
25
+ * **Delivery speed** fine control (from 12 emails per hour to as much as your blog can manage)
26
+ * [WPML ready](https://www.thenewsletterplugin.com/documentation/multilanguage), [Polylang ready](https://www.thenewsletterplugin.com/documentation/multilanguage), [Translatepress ready](https://www.thenewsletterplugin.com/documentation/multilanguage)
27
+ * All messages are **fully translatable** from administration panels (no .po/.mo file to edit)
28
+ * [GDPR ready](https://www.thenewsletterplugin.com/documentation/gdpr-compliancy)
29
+ * **Advanced targeting** with lists combinations like all in, at least one, not in and so on
30
+ * Customizable **subscription widget**, **page** or **custom form**
31
+ * Wordpress Users registration **seamless integration**
32
+ * **Single** And **Double Opt-In** plus privacy checkbox for EU laws compliance
33
+ * **Subscribers lists** to fine-target your campaigns
34
+ * PHP API and REST API for coders and integrations
35
+ * SMTP-Ready (with free addon)
36
+ * Customizable Themes
37
+ * **Status panel** to check your blog mailing capability and configuration
38
+ * **Compatible with every SMTP plugin**: Post SMTP (aka Postman), WP Mail SMTP, Easy WP SMTP, Easy SMTP Mail, WP Mail Bank, ...
39
+ * **Subscribers import** from file
40
+ * Newsletter with Html and Text message versions
41
+
42
+ = Find Us =
43
+
44
+ Newsletter is a continuously evolving plugin. Stay tuned following us on [Facebook](https://www.facebook.com/thenewsletterplugin/) or [our site](https://www.thenewsletterplugin.com/).
45
+
46
+ = Free Addons =
47
+
48
+ Improve The Newsletter Plugin with these free addons:
49
+
50
+ * [WP Registration Addon](https://www.thenewsletterplugin.com/documentation/wpusers-extension) - connects the WordPress standard and custom registration with Newsletter subscription. Optionally imports all registered users as subscribers.
51
+ * [Archive Addon](https://www.thenewsletterplugin.com/documentation/archive-extension) - creates a simple blog page which lists all your sent newsletters
52
+ * [Locked Content Addon](https://www.thenewsletterplugin.com/documentation/locked-content-extension) - open up your premium content only after subscription
53
+ * [Newsletter REST API Addon](https://www.thenewsletterplugin.com/documentation/developers/newsletter-api-2/) - adds a tier of REST api to integrate with the Newsletter core services
54
+ * [Sendinblue Addon](https://www.thenewsletterplugin.com/documentation/addons/delivery-addons/sendinblue-extension/) - deliver your newsletters with Sendinblue
55
+ * [SMTP Addon](https://www.thenewsletterplugin.com/documentation/addons/delivery-addons/smtp-extension/) - deliver your newsletters with external SMTP
56
+ * [Advanced Import Addon](https://www.thenewsletterplugin.com/documentation/addons/extended-features/advanced-import/) - import contact from file or copy and paste data with full mapping
57
+
58
+ (*easily add them from our [Addons panel](https://www.thenewsletterplugin.com/documentation/install-extensions)*)
59
+
60
+ = Addons on WordPress.org =
61
+
62
+ * [RSS Composer Block](https://wordpress.org/plugins/newsletter-rss-block/) - (3rd party) a composer block which builds its content from a RSS feed
63
+ * [Popup Maker Integration](https://wordpress.org/plugins/newsletter-popupmaker/) - (3rd party) integration of Newsletter forms with Popup Maker plugin
64
+ * [BuddyPress integration](https://wordpress.org/plugins/newsletter-buddypress/) - subscription opt-in inside BuddyPress signup form
65
+ * [WP User Manager addon for Newsletter](https://wordpress.org/plugins/wpum-newsletter/) - adds the subscription option on registration forms
66
+
67
+ = Professional Addons =
68
+
69
+ Need *more power*? Feel *something's missing*? The Newsletter Plugin features can be easily extended through our **premium, professional Addons**! Let us introduce just two of them : )
70
+
71
+ * [Automated](https://www.thenewsletterplugin.com/automated) - generates and sends your newsletters using your blog last posts, even custom ones like events or products. Just sit and watch!
72
+ * [Autoresponder](https://www.thenewsletterplugin.com/autoresponder) - creates email series to follow up your subscribers
73
+ * [Extended Composer Blocks](https://www.thenewsletterplugin.com/composer) - adds new blocks to the drag & drop composer
74
+ * [WooCommerce Integration](https://www.thenewsletterplugin.com/woocommerce) - subscribe customers to a mailing list and generate product newletters.
75
+ * [Reports](https://www.thenewsletterplugin.com/reports) - improves the internal statistics collection system and provides better reports of data collected for each sent email. And retargeting. Neat.
76
+ * [Leads](https://www.thenewsletterplugin.com/leads) adds a fancy subscription popup box or a fixed bar to your website that will boost your conversion rate
77
+ * [Amazon SES and other mail providers integration](https://www.thenewsletterplugin.com/integrations) - seamlessly integrate Amazon SES and other email service providers with The Newsletter Plugin. Hassle-free.
78
+ * [Contact Form 7 Integration](https://www.thenewsletterplugin.com/documentation/contact-form-7-extension) - integrate the subscription on Contact Form 7 forms
79
+ * [Ninja Forms Integration](https://www.thenewsletterplugin.com/documentation/ninjaforms-extension) - integrate the subscription on Ninja Forms
80
+ * [WP Forms Integration](https://www.thenewsletterplugin.com/documentation/wpforms-extension) - integrate the subscription on WP Forms
81
+ * Events Manager and The Events Calendar (By Modern Tribe) integrations - easily add events to your newsletters
82
+ * [Google Analytics](https://www.thenewsletterplugin.com/google-analytics) - track newsletter links with Google UTM tracking paramaters
83
+ * [Subscribe on Comment](https://www.thenewsletterplugin.com/documentation/comments-extension) - adds the subscription option to your blog comment form
84
+ * [Geolocation](https://www.thenewsletterplugin.com/documentation/geolocation-extension) - adds geolocation capability to target subscribers by location
85
+
86
+ = GDPR =
87
+
88
+ The Newsletter Plugin provides all the technical tools needed to achieve GDPR compliancy and we're continuously working to improve them and to give support even for specific use cases.
89
+ The plugin does not collect users' own subscribers data, nor it has any access to those data: hence, we are not a data processor, so a data processing agreement is not needed.
90
+ Anyway if you configure the plugin to use external services (usually an external mail delivery service) you should check with that service if some sort of agreement is required.
91
+
92
+ = Support =
93
+
94
+ We provide support for our plugin on [Wordpress.org forums](https://wordpress.org/support/plugin/newsletter) and through our [official forum](https://www.thenewsletterplugin.com/forums).
95
+
96
+ Premium Users with an active license have access to one-to-one support via our [ticketing system](https://www.thenewsletterplugin.com/support-ticket).
97
+
98
+ = Developers =
99
+
100
+ We have a [documentation section](https://www.thenewsletterplugin.com/documentation/developers/) dedicated to who want to develop with Newsletter.
101
+
102
+ You can find us on [GitHub](https://github.com/TheNewsletterPlugin) with some examples of addons.
103
+
104
+ = Follow Us =
105
+
106
+ * **Our Official Website** - [https://www.thenewsletterplugin.com/](https://www.thenewsletterplugin.com/)
107
+ * **GitHub** - [https://github.com/TheNewsletterPlugin](https://github.com/TheNewsletterPlugin)
108
+ * **LinkedIn** - [https://www.linkedin.com/company/the-newsletter-plugin](https://www.linkedin.com/company/the-newsletter-plugin)
109
+ * **Our Facebook Page** - [https://www.facebook.com/thenewsletterplugin](https://www.facebook.com/thenewsletterplugin)
110
+ * **Our Twitter Account** - [https://twitter.com/newsletterwp](https://twitter.com/newsletterwp)
111
+
112
+ == Frequently Asked Questions ==
113
+
114
+ See the [Newsletter Forum](https://www.thenewsletterplugin.com/forums) to ask for help.
115
+
116
+ For documentation start from [Newsletter documentation](https://www.thenewsletterplugin.com/documentation).
117
+
118
+ Thank you, The Newsletter Team
119
+
120
+ == Screenshots ==
121
+
122
+ 1. The responsive email Drag & Drop composer
123
+ 2. The plugin dashboard
124
+ 3. The Reports extension
125
+
126
+ == Changelog ==
127
+
128
+ = 7.3.8 =
129
+
130
+ * Fixed graph scale on System/Scheduler panel
131
+ * Fixed untraslated labels on subscriber management panels
132
+ * Fixed the "toggle" private/public status on sent newsletter
133
+ * Removed the "action call test" from the status panel since it does not work with some providers but does not affect the correct working of Newsletter
134
+ * Added developer information on this readme
135
+
136
+ = 7.3.7 =
137
+
138
+ * Fixed unwanted redirects on subscription errors
139
+ * Fixed composer page HTML
140
+ * Minor fixes on PHP, CSS
141
+ * Fixed notice on image block
142
+
143
+ = 7.3.6 =
144
+
145
+ * Improved composer reusability in other contexts
146
+ * Removed obsolete composer code
147
+ * Fixed default tracking for old theme-based neewsletters
148
+ * Forced enconding on export (attempt)
149
+ * WP 5.9 check
150
+
151
+ = 7.3.5 =
152
+
153
+ * WP 5.8.3 compatibility check
154
+ * Fixed 2021 max year in date picker
155
+ * Typos
156
+
157
+ = 7.3.4 =
158
+
159
+ * Fixed delivery fatal error management
160
+ * Fixed link to the schduler dianostica panel
161
+
162
+ = 7.3.3 =
163
+
164
+ * Added "complained" status to subscriber filters
165
+ * Fixed some links bringing to a "not allowed" page
166
+ * Fixed a notice on delivery diagnostic page
167
+ * Fixed logo width notice on header block
168
+
169
+ = 7.3.2 =
170
+
171
+ * Fixed the remote ip retrieval and clean up
172
+ * Fixed header link to status page
173
+ * Fixed database error with too long IPs
174
+ * Fixed the subscription of cancelled addresses
175
+ * Fixed sender and name customization
176
+
177
+ = 7.3.1 =
178
+
179
+ * Dropped old mailers support
180
+ * Improved sending process and limits checking
181
+ * Removed obsolete notifications
182
+ * Fixed the wrong report on single email delivery speed
183
+ * Added support for custom sending speed by addons
184
+ * Improved excerpt generation (but it still depends on plugins and themes...)
185
+ * Support for building button option on composer blocks
186
+
187
+ = 7.3.0 =
188
+
189
+ * Fixed header block layout with (logo only layout)
190
+ * Check for conflicts on newsletter saving
191
+ * Added the subscriber complained status (actually not managed automatically)
192
+
193
+ = 7.2.9 =
194
+
195
+ * Fixed generic action button confirmation popup not showing the message
196
+ * [SECURITY] Pre parsing of IP addresses on security panel
197
+ * [SECURITY] Comments allowed on IP address list on security panel
198
+ * [COMPOSER] Fixed preset name/subject
199
+ * Improved generated forms for accessibility
200
+
201
+ = 7.2.8 =
202
+
203
+ * Fixed the print_date() when no time is provided
204
+ * Fixed date alignment on posts block
205
+ * Folders reorganization
206
+ * Social block with a new set of icons
207
+ * Boosted performances of the lists management page (for big databases)
208
+ * Added a new scheduler diagnostic panel
209
+ * Seriously improved the cron statistics and diagnostic panel (check it out!)
210
+ * Removed obsolete migration code from ancient versions
211
+
212
+ = 7.2.7 =
213
+
214
+ * Fixed JS error on composer sometimes preventing the correct initialization
215
+
216
+ = 7.2.6 =
217
+
218
+ * Fixed links on test emails sent to a free email address
219
+ * Added attachment explanation
220
+ * Added link to explain the use of the snippet
221
+
222
+ = 7.2.5 =
223
+
224
+ * Fixed subject not saved under specific circumstance
225
+
226
+ = 7.2.4 =
227
+
228
+ * Fixed the composer not starting for blog with SSL plugin but still HTTP configured on main WP settings
229
+ * Changed labels on subscriber maintenance panel
230
+ * Updated requirements for WP version
231
+
232
+ = 7.2.3 =
233
+
234
+ * [COMPOSER] Added approx. indicators of the subsject visibile part in Apple and Android clients (experimental)
235
+ * [COMPOSER] New mobile version view directly while composing (experimental)
236
+ * [COMPOSER] New test email to test subscribers or to specific email address
237
+ * [COMPOSER] Fixed missing background when creating a new message from a preset
238
+ * [COMPOSER] Added media selector to the CTA block
239
+ * [COMPOSER] Added reference to the tags on HTML and Text blocks
240
+ * [COMPOSER] Move the snippet (preheader) field near the subject
241
+ * [COMPOSER] Footer block with three link options: unsubscribe, manage and view online
242
+ * [COMPOSER] Improve font coherence between blocks (by default)
243
+ * [ANTISPAM] Improved the antispam checks on subscription
244
+ * [GENERAL] Removed obsolete folders and code
245
+ * [NEWSLETTERS] Refactored subject ideas selector
246
+ * [SUBSCRIPTION] Inverted extra profile fields and lists on standard subscription form
247
+ * [GENERAL] IP address extracted checking proxy variables
248
+ * [GENERAL] Improved sending stats collection and display for the delivery engine (not related to click/open stats)
249
+
250
+ = 7.2.2 =
251
+
252
+ * [COMPOSER] Posts block excerpt removed when set to 0-length
253
+ * [GENERAL]Added special characters on test message
254
+ * [GENERAL]Added more specific error for action calls on System/Status panel
255
+ * [SUBSCRIPTION] Check for the _wp_amp_action_xhr_converted parameter by AMP plugin
256
+
257
+ = 7.2.1 =
258
+
259
+ * [GENERAL] Added more detailed admin logging
260
+ * [NEWSLETTERS] Fixed scheduled date sometimes reset to 1/1/1970
261
+
262
+ = 7.2.0 =
263
+
264
+ * [PROFILE] Fixed activation email on profile change
265
+ * [NEWSLETTERS] Extended year selection on newsletter scheduling
266
+ * [DELIVERY] Breaking change: old enqueue() and flush() methods have been removed
267
+ * [GENERAL] Fixed alert message on some buttons
268
+ * [SUBSCRIPTION] Fixed error message on multiple subscriptions (when not allowed)
269
+ * [GENERAL] Fixed erratic error log line on main log
270
+
271
+ = 7.1.9 =
272
+
273
+ * [GENERAL] Removed the encodign defatlt to Base 64 when not specified since it seems incompatible with some SMTP plugins
274
+ * [GENERAL] Review some controls layout and behavior
275
+ * [DEBUG] Improved logging on database errors
276
+ * [GENERAL] Added TikTok, Discord and Twitch socials
277
+ * [GENERAL] Fixed odd error reported related to the cron call statistics collection
278
+ * [DEBUG] Added a delivery diagnostic panel
279
+
280
+ = 7.1.8 =
281
+
282
+ * [COMPOSER] Fixed alignment of single big image on Outlook Android
283
+
284
+ = 7.1.7 =
285
+
286
+ * [GENERAL] Fix of permalink onm email with multilanguage plugins
287
+
288
+ = 7.1.6 =
289
+
290
+ * [COMPOSER] Fixed one column big image Read more links
291
+
292
+ = 7.1.5 =
293
+
294
+ * [COMPOSER] Improve buttons on posts layout
295
+ * [COMPOSER] Improved header layout and logo
296
+ * [COMPOSER] Generally improved block spacing
297
+
298
+ = 7.1.4 =
299
+
300
+ * [COMPOSER] Fixed image block for Outlook
301
+ * [GENERAL] Fix undefined values in Gutenberg block
302
+
303
+ = 7.1.3 =
304
+
305
+ * [COMPOSER] Improvements on blocks layout compatibility
306
+ * [COMPOSER] Fixed preset global options saving
307
+ * [COMPOSER] Content regeneration on preset selection
308
+ * [GENERAL] Added to System menu the Site Health link, a not well known native page of WordPress with system information
309
+ * [GENERAL] Added sending statistics reset button on status panel
310
+
311
+ = 7.1.2 =
312
+
313
+ * [ADDONS] Fixed the addons list
314
+
315
+ = 7.1.1 =
316
+
317
+ * [GENERAL] Improved profile related functions
318
+ * [GENERAL] Fixed check on field names (thanks Peter P.)
319
+ * [COMPOSER] Fix on preset selection
320
+ * [GENERAL] Fix ajax subscription on error
321
+
322
+ = 7.1.0 =
323
+
324
+ * [COMPOSER] Added link to tags documentation to inject subscriber's data
325
+ * [COMPOSER] Fixed layout of posts block for Outlook 365
326
+ * [GENERAL] Improved caching of addons json (even on error)
327
+ * [GENERAL] Status menu changed to System/Status and System/Logs
328
+ * [API] Fixed the subscriber status management (the API Addon should be updated as well)
329
+ * [GENERAL] Fixed management of fatal errors on sending
330
+ * [GENERAL] Limited error string per message to 250 chars
331
+ * [GENERAL] Fixed check on field names (thanks Peter P.)
332
+
333
+
334
+ = 7.0.9 =
335
+
336
+ * [CAPTCHA] Fixed button label translation
337
+ * [DELIVERY] Mailing fatal error management with newsletter stop and reporting
338
+ * [SMTP] Marked obsolete the internal SMTP and made available the free SMTP addon
339
+ * [DELIVERY] Better management of delivery fatal errors with a new "error" status for newsletters
340
+ * [GENERAL] New log files panel
341
+ * [IMPORT] Old import panel replaced by the new (really better) import addon (file, copy and paste, bounced addresses import)
342
+ * [NEWSLETTERS] It's now possible to specify the sender name and email per newsletter (thanks to Matthew S.)
343
+
344
+ = 7.0.8 =
345
+
346
+ * [SUBSCRIBERS] Changed action buttons
347
+ * [GENERAL] Reorganization of CSS and removal of unused files
348
+ * [DASHBOARD] New window open for links and fix of invalid URLs
349
+ * [NEWSLETTERS] New action buttons
350
+ * [GENERAL] Minor fixes and optimizations
351
+ * [COMPOSER] Fixed rare size error on gif images
352
+
353
+ = 7.0.7 =
354
+
355
+ * [COMPOSER] Fixed a warning in some inline editable blocks
356
+ * [NEWSLETTERS] Fixed style which made list labels badly readable
357
+ * [NEWSLETTERS] Fixed style which made bullet lists white (not on delivered newsletters)
358
+ * [GENERAL] Added some references to the not working scheduler warning
359
+
360
+ = 7.0.6 =
361
+
362
+ * [COMPOSER] CTA block not grabbing settings from the "old" blocks
363
+ * [COMPOSER] CSS issue on button settings group
364
+ * [COMPOSER] Posts block two columns layout (author and padding)
365
+ * [IMPORT] Removed the old low-featured import (the free import addon has everything needed!)
366
+ * [GENERAL] Compatibility check with WP 5.7
367
+
368
+ = 7.0.5 =
369
+
370
+ * [COMPOSER] Hero CTA button not working
371
+ * Fixed to the hero block button
372
+ * Added support for the SMTP addon
373
+
374
+ = 7.0.4 =
375
+
376
+ * [COMPOSER] Redesigned drag and drop composer
377
+ * [COMPOSER] NEW! Save drag and drop composed newsletters as templates to reuse easily
378
+ * Redesigned dashboard
379
+ * Several bug and fixes
380
+
381
+ = 7.0.3 =
382
+
383
+ * Option to choose between unsubscription and profile link in the footer block
384
+ * Direct image src URL for image block
385
+ * New media selector for blocks
386
+ * Minor fixes
387
+ * Updated codemirror
388
+ * Updated default theme
389
+ * Fixed tag filter on posts block (when tags have parathesis or like)
390
+ * Fixed composer visualization of bullet points
391
+
392
+ = 7.0.2 =
393
+
394
+ * Fixed media 2x resize
395
+
396
+ = 7.0.1 =
397
+
398
+ * Fixed enforced lists by language with Polylang
399
+
400
+ = 7.0.0 =
401
+
402
+ * Added multiple newsletter selection for deletion
403
+ * Added text part on welcome and activation email
404
+ * Added the attribute "show_form" to "newsletter" shortcode
405
+ * Added filter on subscriber saving (from external systems) with wrong list field values
406
+ * Added index.html on log folder
407
+
system/scheduler.php CHANGED
@@ -162,7 +162,7 @@ if ($controls->is_action('test')) {
162
  datasets: [
163
  {
164
  label: "Batch Average Time",
165
- data: <?php echo json_encode($stats->deltas) ?>,
166
  borderColor: '#2980b9',
167
  fill: false
168
  }]
162
  datasets: [
163
  {
164
  label: "Batch Average Time",
165
+ data: <?php echo json_encode(array_map(function ($v) {return $v/1000;}, $stats->deltas)) ?>,
166
  borderColor: '#2980b9',
167
  fill: false
168
  }]
system/status.php CHANGED
@@ -143,7 +143,7 @@ $tnp_wpdb = new TNP_WPDB(DB_USER, DB_PASSWORD, DB_NAME, DB_HOST);
143
  $stats = $this->get_send_stats();
144
 
145
  if ($stats) {
146
- $condition = $stats->mean > 2 ? 2 : 1;
147
  ?>
148
  <tr>
149
  <td id="tnp-speed">
@@ -155,8 +155,8 @@ $tnp_wpdb = new TNP_WPDB(DB_USER, DB_PASSWORD, DB_NAME, DB_HOST);
155
  </td>
156
  <td>
157
  <?php if ($condition == 2) { ?>
158
- <strong>Sending an email is taking more than 1 second, rather slow.</strong>
159
- <a href="https://www.thenewsletterplugin.com/documentation/status-panel#status-performance" target="_blank">Read more</a>.
160
  <br>
161
  <?php } ?>
162
  Average time to send an email: <?php echo $stats->mean ?> seconds<br>
@@ -388,44 +388,6 @@ $tnp_wpdb = new TNP_WPDB(DB_USER, DB_PASSWORD, DB_NAME, DB_HOST);
388
 
389
  </tr>
390
 
391
-
392
- <?php
393
- $res = 0;
394
- $response = wp_remote_post(home_url('/') . '?na=test');
395
- if (is_wp_error($response)) {
396
- $res = 1;
397
- $message = $response->get_error_message();
398
- } else if (wp_remote_retrieve_response_code($response) != 200) {
399
- $res = 1;
400
- $message = wp_remote_retrieve_response_message($response);
401
- } else if (wp_remote_retrieve_body($response) !== 'ok') {
402
- $res = 2;
403
- }
404
- ?>
405
- <tr>
406
- <td>
407
- Action call
408
- </td>
409
- <td>
410
- <?php if (!$res) { ?>
411
- <span class="tnp-ko">KO</span>
412
- <?php } else { ?>
413
- <span class="tnp-ok">OK</span>
414
- <?php } ?>
415
- </td>
416
- <td>
417
- <?php if ($res === 1) { ?>
418
- The blog is not responding to Newsletter URLs: ask the provider or your IT consultant to check this problem. Report the URL and error below<br>
419
- Error: <?php echo esc_html($message) ?><br>
420
- <?php } else if ($res === 2) { ?>
421
- The response does not contain the "ok" text: probably a caching/optimization plugin or a server configuration is forcing the blog to ignore
422
- the URL's query string. Reported that to your system administrator.
423
- <?php } ?>
424
- Url: <?php echo esc_html(home_url('/') . '?na=test') ?><br>
425
- </td>
426
- </tr>
427
-
428
-
429
  <tr>
430
  <?php
431
  $res = true;
143
  $stats = $this->get_send_stats();
144
 
145
  if ($stats) {
146
+ $condition = $stats->mean > 5 ? 2 : 1;
147
  ?>
148
  <tr>
149
  <td id="tnp-speed">
155
  </td>
156
  <td>
157
  <?php if ($condition == 2) { ?>
158
+ <strong>Sending an email is taking more than 5 seconds (by mean), rather slow.</strong>
159
+ <a href="https://www.thenewsletterplugin.com/documentation/installation/status-panel/#email-speed" target="_blank">Read more</a>.
160
  <br>
161
  <?php } ?>
162
  Average time to send an email: <?php echo $stats->mean ?> seconds<br>
388
 
389
  </tr>
390
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
391
  <tr>
392
  <?php
393
  $res = true;
users/users.php CHANGED
@@ -97,13 +97,13 @@ class NewsletterUsers extends NewsletterModule {
97
  }
98
 
99
  function admin_menu() {
100
- $this->add_menu_page('index', 'Subscribers');
101
- $this->add_admin_page('new', 'New subscriber');
102
- $this->add_admin_page('edit', 'Subscribers Edit');
103
- $this->add_admin_page('massive', 'Massive Management');
104
- $this->add_admin_page('export', 'Export');
105
- $this->add_admin_page('import', 'Import');
106
- $this->add_admin_page('statistics', 'Statistics');
107
  }
108
 
109
  function export($options = null) {
97
  }
98
 
99
  function admin_menu() {
100
+ $this->add_menu_page('index', __('Subscribers', 'newsletter'));
101
+ $this->add_admin_page('new', __('New subscriber', 'newsletter'));
102
+ $this->add_admin_page('edit', __('Subscriber Edit', 'newsletter'));
103
+ $this->add_admin_page('massive', __('Subscribers Maintenance', 'newsletter'));
104
+ $this->add_admin_page('export', __('Export', 'newsletter'));
105
+ $this->add_admin_page('import', __('Import', 'newsletter'));
106
+ $this->add_admin_page('statistics', __('Statistics', 'newsletter'));
107
  }
108
 
109
  function export($options = null) {