Version Description
- Fixed generic action button confirmation popup not showing the message
- [SECURITY] Pre parsing of IP addresses on security panel
- [SECURITY] Comments allowed on IP address list on security panel
- [COMPOSER] Fixed preset name/subject
- Improved generated forms for accessibility
Download this release
Release Info
Developer | satollo |
Plugin | Newsletter |
Version | 7.2.9 |
Comparing to | |
See all releases |
Code changes from version 7.2.8 to 7.2.9
- emails/blocks/posts/layout-two.php +22 -93
- emails/tnp-composer/_css/newsletter-builder-v2.css +1 -1
- emails/tnp-composer/_scripts/newsletter-builder-v2.js +5 -6
- emails/tnp-composer/css/backend.css +6 -2
- emails/tnp-composer/css/newsletter.css +11 -11
- emails/tnp-composer/index-v2.php +4 -3
- includes/antispam.php +198 -195
- includes/composer.php +879 -863
- includes/controls.php +2 -5
- includes/helper.php +395 -352
- includes/system.php +263 -263
- main/delivery.php +220 -220
- main/scheduler.php +412 -411
- plugin.php +2 -2
- readme.txt +9 -1
- subscription/antibot.php +183 -156
- subscription/subscription.php +20 -10
- tnp-header.php +340 -340
- users/massive.php +2 -2
emails/blocks/posts/layout-two.php
CHANGED
@@ -5,6 +5,8 @@ $column_width = $total_width / 2 - 20;
|
|
5 |
|
6 |
$title_style = TNP_Composer::get_style($options, 'title', $composer, 'title', ['scale' => .8]);
|
7 |
$text_style = TNP_Composer::get_style($options, '', $composer, 'text');
|
|
|
|
|
8 |
?>
|
9 |
<style>
|
10 |
.title {
|
@@ -48,34 +50,33 @@ $text_style = TNP_Composer::get_style($options, '', $composer, 'text');
|
|
48 |
|
49 |
</style>
|
50 |
|
51 |
-
<table cellspacing="0" cellpadding="0" border="0" width="100%">
|
52 |
|
53 |
-
<?php foreach (
|
54 |
<?php
|
55 |
$media = null;
|
56 |
if ($show_image) {
|
57 |
-
$media = tnp_composer_block_posts_get_media($
|
58 |
-
$media->link = tnp_post_permalink($
|
59 |
$media->set_width($column_width);
|
60 |
}
|
61 |
|
62 |
$meta = [];
|
63 |
|
64 |
if ($show_date) {
|
65 |
-
$meta[] = tnp_post_date($
|
66 |
}
|
67 |
|
68 |
if ($show_author) {
|
69 |
-
$author_object = get_user_by('id', $
|
70 |
if ($author_object) {
|
71 |
$meta[] = $author_object->display_name;
|
72 |
}
|
73 |
}
|
74 |
|
75 |
-
$button_options['button_url'] = tnp_post_permalink($
|
|
|
76 |
?>
|
77 |
-
|
78 |
-
<td inline-class="column-left" width="50%" valign="top" class="responsive">
|
79 |
|
80 |
|
81 |
<table cellpadding="0" cellspacing="0" border="0" width="100%">
|
@@ -87,11 +88,11 @@ $text_style = TNP_Composer::get_style($options, '', $composer, 'text');
|
|
87 |
</tr>
|
88 |
<?php } ?>
|
89 |
<tr>
|
90 |
-
<td align="center" inline-class="title" class="title tnpc-row-edit tnpc-inline-editable" data-type="title" data-id="<?php echo $
|
91 |
<?php
|
92 |
-
echo TNP_Composer::is_post_field_edited_inline($options['inline_edits'], 'title', $
|
93 |
-
TNP_Composer::get_edited_inline_post_field($options['inline_edits'], 'title', $
|
94 |
-
tnp_post_title($
|
95 |
?>
|
96 |
</td>
|
97 |
</tr>
|
@@ -106,11 +107,11 @@ $text_style = TNP_Composer::get_style($options, '', $composer, 'text');
|
|
106 |
|
107 |
<?php if ($excerpt_length) { ?>
|
108 |
<tr>
|
109 |
-
<td align="center" inline-class="excerpt" class="title tnpc-row-edit tnpc-inline-editable" data-type="text" data-id="<?php echo $
|
110 |
<?php
|
111 |
-
echo TNP_Composer::is_post_field_edited_inline($options['inline_edits'], 'text', $
|
112 |
-
TNP_Composer::get_edited_inline_post_field($options['inline_edits'], 'text', $
|
113 |
-
tnp_post_excerpt($
|
114 |
?>
|
115 |
</td>
|
116 |
</tr>
|
@@ -124,85 +125,13 @@ $text_style = TNP_Composer::get_style($options, '', $composer, 'text');
|
|
124 |
</tr>
|
125 |
<?php } ?>
|
126 |
</table>
|
127 |
-
</td>
|
128 |
-
|
129 |
-
<td inline-class="column-right" width="50%" valign="top" class="responsive">
|
130 |
<?php
|
131 |
-
|
132 |
-
|
133 |
-
|
134 |
-
if ($show_image) {
|
135 |
-
$media = tnp_composer_block_posts_get_media($row[1], $size, $image_placeholder_url);
|
136 |
-
$media->link = tnp_post_permalink($row[1]);
|
137 |
-
$media->set_width($column_width);
|
138 |
-
}
|
139 |
-
|
140 |
-
$meta = [];
|
141 |
-
|
142 |
-
if ($show_date) {
|
143 |
-
$meta[] = tnp_post_date($row[1]);
|
144 |
-
}
|
145 |
-
|
146 |
-
if ($show_author) {
|
147 |
-
$author_object = get_user_by('id', $row[1]->post_author);
|
148 |
-
if ($author_object) {
|
149 |
-
$meta[] = $author_object->display_name;
|
150 |
-
}
|
151 |
-
}
|
152 |
-
|
153 |
-
$button_options['button_url'] = tnp_post_permalink($row[1]);
|
154 |
-
?>
|
155 |
-
|
156 |
-
|
157 |
-
<table cellpadding="0" cellspacing="0" border="0" width="100%">
|
158 |
-
<?php if ($media) { ?>
|
159 |
-
<tr>
|
160 |
-
<td align="center" valign="middle">
|
161 |
-
<?php echo TNP_Composer::image($media, ['class' => 'fluid']) ?>
|
162 |
-
</td>
|
163 |
-
</tr>
|
164 |
-
<?php } ?>
|
165 |
-
<tr>
|
166 |
-
<td align="center" inline-class="title" class="tnpc-row-edit tnpc-inline-editable" data-type="title" data-id="<?php echo $row[1]->ID ?>">
|
167 |
-
<?php
|
168 |
-
echo TNP_Composer::is_post_field_edited_inline($options['inline_edits'], 'title', $row[1]->ID) ?
|
169 |
-
TNP_Composer::get_edited_inline_post_field($options['inline_edits'], 'title', $row[1]->ID) :
|
170 |
-
tnp_post_title($row[1])
|
171 |
-
?>
|
172 |
-
</td>
|
173 |
-
</tr>
|
174 |
-
<?php if ($meta) { ?>
|
175 |
-
<tr>
|
176 |
-
<td inline-class="meta">
|
177 |
-
<?php echo esc_html(implode(' - ', $meta)) ?>
|
178 |
-
</td>
|
179 |
-
</tr>
|
180 |
-
<?php } ?>
|
181 |
-
|
182 |
-
<tr>
|
183 |
-
<td align="center" inline-class="excerpt" class="tnpc-row-edit tnpc-inline-editable" data-type="text" data-id="<?php echo $row[1]->ID ?>">
|
184 |
-
<?php
|
185 |
-
echo TNP_Composer::is_post_field_edited_inline($options['inline_edits'], 'text', $row[1]->ID) ?
|
186 |
-
TNP_Composer::get_edited_inline_post_field($options['inline_edits'], 'text', $row[1]->ID) :
|
187 |
-
tnp_post_excerpt($row[1], $excerpt_length)
|
188 |
-
?>
|
189 |
-
</td>
|
190 |
-
</tr>
|
191 |
-
<?php if ($show_read_more_button) { ?>
|
192 |
-
<tr>
|
193 |
-
<td align="center" inline-class="button">
|
194 |
-
<?php echo TNP_Composer::button($button_options) ?>
|
195 |
-
</td>
|
196 |
-
</tr>
|
197 |
-
<?php } ?>
|
198 |
-
</table>
|
199 |
-
<?php } ?>
|
200 |
|
201 |
|
202 |
-
|
203 |
-
</tr>
|
204 |
|
205 |
-
<?php } ?>
|
206 |
|
207 |
-
</table>
|
208 |
|
5 |
|
6 |
$title_style = TNP_Composer::get_style($options, 'title', $composer, 'title', ['scale' => .8]);
|
7 |
$text_style = TNP_Composer::get_style($options, '', $composer, 'text');
|
8 |
+
|
9 |
+
$items = [];
|
10 |
?>
|
11 |
<style>
|
12 |
.title {
|
50 |
|
51 |
</style>
|
52 |
|
|
|
53 |
|
54 |
+
<?php foreach ($posts AS $p) { ?>
|
55 |
<?php
|
56 |
$media = null;
|
57 |
if ($show_image) {
|
58 |
+
$media = tnp_composer_block_posts_get_media($p, $size, $image_placeholder_url);
|
59 |
+
$media->link = tnp_post_permalink($p);
|
60 |
$media->set_width($column_width);
|
61 |
}
|
62 |
|
63 |
$meta = [];
|
64 |
|
65 |
if ($show_date) {
|
66 |
+
$meta[] = tnp_post_date($p);
|
67 |
}
|
68 |
|
69 |
if ($show_author) {
|
70 |
+
$author_object = get_user_by('id', $p->post_author);
|
71 |
if ($author_object) {
|
72 |
$meta[] = $author_object->display_name;
|
73 |
}
|
74 |
}
|
75 |
|
76 |
+
$button_options['button_url'] = tnp_post_permalink($p);
|
77 |
+
ob_start();
|
78 |
?>
|
79 |
+
|
|
|
80 |
|
81 |
|
82 |
<table cellpadding="0" cellspacing="0" border="0" width="100%">
|
88 |
</tr>
|
89 |
<?php } ?>
|
90 |
<tr>
|
91 |
+
<td align="center" inline-class="title" class="title tnpc-row-edit tnpc-inline-editable" data-type="title" data-id="<?php echo $p->ID ?>">
|
92 |
<?php
|
93 |
+
echo TNP_Composer::is_post_field_edited_inline($options['inline_edits'], 'title', $p->ID) ?
|
94 |
+
TNP_Composer::get_edited_inline_post_field($options['inline_edits'], 'title', $p->ID) :
|
95 |
+
tnp_post_title($p)
|
96 |
?>
|
97 |
</td>
|
98 |
</tr>
|
107 |
|
108 |
<?php if ($excerpt_length) { ?>
|
109 |
<tr>
|
110 |
+
<td align="center" inline-class="excerpt" class="title tnpc-row-edit tnpc-inline-editable" data-type="text" data-id="<?php echo $p->ID ?>">
|
111 |
<?php
|
112 |
+
echo TNP_Composer::is_post_field_edited_inline($options['inline_edits'], 'text', $p->ID) ?
|
113 |
+
TNP_Composer::get_edited_inline_post_field($options['inline_edits'], 'text', $p->ID) :
|
114 |
+
tnp_post_excerpt($p, $excerpt_length)
|
115 |
?>
|
116 |
</td>
|
117 |
</tr>
|
125 |
</tr>
|
126 |
<?php } ?>
|
127 |
</table>
|
|
|
|
|
|
|
128 |
<?php
|
129 |
+
$items[] = ob_get_clean();
|
130 |
+
|
131 |
+
} ?>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
132 |
|
133 |
|
134 |
+
<?php echo TNP_Composer::grid($items, ['width'=>$total_width, 'responsive'=>true, 'padding'=>0])?>
|
|
|
135 |
|
|
|
136 |
|
|
|
137 |
|
emails/tnp-composer/_css/newsletter-builder-v2.css
CHANGED
@@ -16,7 +16,7 @@
|
|
16 |
overflow: hidden;
|
17 |
box-sizing: border-box;
|
18 |
max-width: 1380px;
|
19 |
-
margin: 0 auto
|
20 |
}
|
21 |
|
22 |
/* Contains the newsletter editing area */
|
16 |
overflow: hidden;
|
17 |
box-sizing: border-box;
|
18 |
max-width: 1380px;
|
19 |
+
/*margin: 0 auto;*/
|
20 |
}
|
21 |
|
22 |
/* Contains the newsletter editing area */
|
emails/tnp-composer/_scripts/newsletter-builder-v2.js
CHANGED
@@ -542,7 +542,7 @@ function tnpc_load_preset(id, subject, isEditMode) {
|
|
542 |
}
|
543 |
|
544 |
if (subject && subject.length > 0) {
|
545 |
-
jQuery('#options-subject').val(tnpc_remove_double_quotes_escape_from(subject));
|
546 |
}
|
547 |
},
|
548 |
});
|
@@ -562,8 +562,7 @@ function tnpc_load_preset(id, subject, isEditMode) {
|
|
562 |
}
|
563 |
|
564 |
function tnpc_save_preset(form) {
|
565 |
-
|
566 |
-
const presetName = tnpc_remove_double_quotes_from(document.querySelector('#options-subject').value);
|
567 |
|
568 |
const presetNameModal = new TNPModal({
|
569 |
title: 'Choose a preset name',
|
@@ -572,7 +571,7 @@ function tnpc_save_preset(form) {
|
|
572 |
clickConfirmOnPressEnter: true,
|
573 |
onConfirm: function () {
|
574 |
const inputEl = document.querySelector('#preset_name');
|
575 |
-
document.querySelector('#options-subject').value = inputEl.value;
|
576 |
tnpc_save(form);
|
577 |
form.submit();
|
578 |
}
|
@@ -656,7 +655,7 @@ function tnpc_remove_double_quotes_from(str) {
|
|
656 |
|
657 |
function tnpc_update_preset(form) {
|
658 |
|
659 |
-
const presetName =
|
660 |
|
661 |
const presetNameModal = new TNPModal({
|
662 |
title: 'Choose a preset name',
|
@@ -665,7 +664,7 @@ function tnpc_update_preset(form) {
|
|
665 |
clickConfirmOnPressEnter: true,
|
666 |
onConfirm: function () {
|
667 |
const inputEl = document.querySelector('#preset_name');
|
668 |
-
document.querySelector('#options-subject').value = inputEl.value;
|
669 |
tnpc_save(form);
|
670 |
form.submit();
|
671 |
}
|
542 |
}
|
543 |
|
544 |
if (subject && subject.length > 0) {
|
545 |
+
jQuery('#options-subject-subject').val(tnpc_remove_double_quotes_escape_from(subject));
|
546 |
}
|
547 |
},
|
548 |
});
|
562 |
}
|
563 |
|
564 |
function tnpc_save_preset(form) {
|
565 |
+
const presetName = document.getElementById('options-subject-subject').value.replace('"', '');
|
|
|
566 |
|
567 |
const presetNameModal = new TNPModal({
|
568 |
title: 'Choose a preset name',
|
571 |
clickConfirmOnPressEnter: true,
|
572 |
onConfirm: function () {
|
573 |
const inputEl = document.querySelector('#preset_name');
|
574 |
+
document.querySelector('#options-subject-subject').value = inputEl.value;
|
575 |
tnpc_save(form);
|
576 |
form.submit();
|
577 |
}
|
655 |
|
656 |
function tnpc_update_preset(form) {
|
657 |
|
658 |
+
const presetName = document.getElementById('options-subject-subject').value.replace('"', '');
|
659 |
|
660 |
const presetNameModal = new TNPModal({
|
661 |
title: 'Choose a preset name',
|
664 |
clickConfirmOnPressEnter: true,
|
665 |
onConfirm: function () {
|
666 |
const inputEl = document.querySelector('#preset_name');
|
667 |
+
document.querySelector('#options-subject-subject').value = inputEl.value;
|
668 |
tnpc_save(form);
|
669 |
form.submit();
|
670 |
}
|
emails/tnp-composer/css/backend.css
CHANGED
@@ -1,7 +1,7 @@
|
|
1 |
/* Contains some rules to simulate device layout on backend preview */
|
2 |
|
3 |
#newsletter-builder-area-center-frame-content.tnp-view-mobile table[class="responsive"],
|
4 |
-
#newsletter-builder-area-center-frame-content.tnp-view-mobile table.responsive
|
5 |
{
|
6 |
width:100%!important;
|
7 |
float: none;
|
@@ -23,7 +23,7 @@
|
|
23 |
#newsletter-builder-area-center-frame-content.tnp-view-mobile img.responsive
|
24 |
{
|
25 |
max-width: 100%!important;
|
26 |
-
}
|
27 |
|
28 |
#newsletter-builder-area-center-frame-content.tnp-view-mobile img[class="fluid"]{
|
29 |
width: 100%;
|
@@ -41,3 +41,7 @@
|
|
41 |
#newsletter-builder-area-center-frame-content.tnp-view-mobile .tnp-grid-column {
|
42 |
max-width: 100%!important;
|
43 |
}
|
|
|
|
|
|
|
|
1 |
/* Contains some rules to simulate device layout on backend preview */
|
2 |
|
3 |
#newsletter-builder-area-center-frame-content.tnp-view-mobile table[class="responsive"],
|
4 |
+
#newsletter-builder-area-center-frame-content.tnp-view-mobile table.responsive
|
5 |
{
|
6 |
width:100%!important;
|
7 |
float: none;
|
23 |
#newsletter-builder-area-center-frame-content.tnp-view-mobile img.responsive
|
24 |
{
|
25 |
max-width: 100%!important;
|
26 |
+
}
|
27 |
|
28 |
#newsletter-builder-area-center-frame-content.tnp-view-mobile img[class="fluid"]{
|
29 |
width: 100%;
|
41 |
#newsletter-builder-area-center-frame-content.tnp-view-mobile .tnp-grid-column {
|
42 |
max-width: 100%!important;
|
43 |
}
|
44 |
+
|
45 |
+
#newsletter-builder-area-center-frame-content.tnp-view-mobile td[data-responsive-image="true"] {
|
46 |
+
height: auto !important;
|
47 |
+
}
|
emails/tnp-composer/css/newsletter.css
CHANGED
@@ -8,31 +8,31 @@ img { border: 0; height: auto; line-height: 100%; outline: none; text-decoration
|
|
8 |
img.aligncenter { display: block; margin: 0 auto;}
|
9 |
|
10 |
@media screen and (max-width: 525px) {
|
11 |
-
.pt-1 { padding-top: 15px!important; }
|
12 |
-
.pb-1 { padding-bottom: 15px!important; }
|
13 |
.responsive { width:100%!important; }
|
14 |
table.responsive { width:100%!important; float: none; display: table; padding-left: 0; padding-right: 0; }
|
15 |
table[class="responsive"] { width:100%!important; float: none; display: table; padding-left: 0; padding-right: 0; }
|
16 |
-
img[class="responsive"] { max-width: 100%!important; }
|
|
|
17 |
.fluid { max-width: 100%!important; width: auto; }
|
18 |
img[class="fluid"] { max-width: 100%!important; width: auto; }
|
19 |
|
20 |
.block { display: block; }
|
21 |
|
22 |
-
td[class="responsive"]{
|
23 |
-
|
24 |
-
max-width: 100%!important;
|
25 |
-
display: block;
|
26 |
-
padding-left: 0 !important;
|
27 |
-
padding-right: 0 !important;
|
28 |
-
float: none;
|
29 |
-
}
|
30 |
|
31 |
td[class="section-padding-bottom-image"]{
|
32 |
padding: 50px 15px 0 15px !important;
|
33 |
}
|
34 |
|
|
|
|
|
|
|
35 |
.tnp-grid-column {
|
36 |
max-width: 100%!important;
|
37 |
}
|
|
|
38 |
}
|
|
8 |
img.aligncenter { display: block; margin: 0 auto;}
|
9 |
|
10 |
@media screen and (max-width: 525px) {
|
11 |
+
.pt-1, .padding-top-15 { padding-top: 15px!important; }
|
12 |
+
.pb-1, .padding-bottom-15 { padding-bottom: 15px!important; }
|
13 |
.responsive { width:100%!important; }
|
14 |
table.responsive { width:100%!important; float: none; display: table; padding-left: 0; padding-right: 0; }
|
15 |
table[class="responsive"] { width:100%!important; float: none; display: table; padding-left: 0; padding-right: 0; }
|
16 |
+
img[class="responsive"] { max-width: 100%!important; }
|
17 |
+
/* "width: auto" restores the natural dimensions forced with attributes for Outlook which blocks the expansion on mobile */
|
18 |
.fluid { max-width: 100%!important; width: auto; }
|
19 |
img[class="fluid"] { max-width: 100%!important; width: auto; }
|
20 |
|
21 |
.block { display: block; }
|
22 |
|
23 |
+
td[class="responsive"]{width:100%!important; max-width: 100%!important; display: block; padding-left: 0 !important; padding-right: 0!important; float: none; }
|
24 |
+
td.responsive { width:100%!important; max-width: 100%!important; display: block; padding-left: 0 !important; padding-right: 0!important; float: none; }
|
|
|
|
|
|
|
|
|
|
|
|
|
25 |
|
26 |
td[class="section-padding-bottom-image"]{
|
27 |
padding: 50px 15px 0 15px !important;
|
28 |
}
|
29 |
|
30 |
+
.max-width-100 { max-width: 100%!important; }
|
31 |
+
|
32 |
+
/* Obsolete */
|
33 |
.tnp-grid-column {
|
34 |
max-width: 100%!important;
|
35 |
}
|
36 |
+
|
37 |
}
|
38 |
+
|
emails/tnp-composer/index-v2.php
CHANGED
@@ -31,9 +31,10 @@ $rev_dir = is_rtl() ? 'ltr' : 'rlt';
|
|
31 |
|
32 |
?>
|
33 |
<script type="text/javascript">
|
34 |
-
|
35 |
-
|
36 |
-
|
|
|
37 |
function tnp_view(type) {
|
38 |
if (type === 'mobile') {
|
39 |
jQuery('#newsletter-builder-area-center-frame-content').addClass('tnp-view-mobile');
|
31 |
|
32 |
?>
|
33 |
<script type="text/javascript">
|
34 |
+
if (window.innerWidth < 1550) {
|
35 |
+
document.body.classList.add('folded');
|
36 |
+
}
|
37 |
+
|
38 |
function tnp_view(type) {
|
39 |
if (type === 'mobile') {
|
40 |
jQuery('#newsletter-builder-area-center-frame-content').addClass('tnp-view-mobile');
|
includes/antispam.php
CHANGED
@@ -1,195 +1,198 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
class NewsletterAntispam {
|
4 |
-
|
5 |
-
var $options;
|
6 |
-
var $logger;
|
7 |
-
|
8 |
-
public static function instance() {
|
9 |
-
static $instance;
|
10 |
-
if (!$instance) {
|
11 |
-
$instance = new NewsletterAntispam();
|
12 |
-
}
|
13 |
-
return $instance;
|
14 |
-
}
|
15 |
-
|
16 |
-
public function __construct() {
|
17 |
-
$this->options = NewsletterSubscription::instance()->get_options('antibot');
|
18 |
-
$this->logger = new NewsletterLogger('antispam');
|
19 |
-
}
|
20 |
-
|
21 |
-
/**
|
22 |
-
* $email must be cleaned using the is_email() function.
|
23 |
-
*
|
24 |
-
* @param TNP_Subscription $subscription
|
25 |
-
*/
|
26 |
-
function is_spam($subscription) {
|
27 |
-
|
28 |
-
$email = $subscription->data->email;
|
29 |
-
$ip = $subscription->data->ip;
|
30 |
-
|
31 |
-
|
32 |
-
$full_name = $subscription->data->name . ' ' . $subscription->data->surname;
|
33 |
-
if ($this->is_spam_text($full_name)) {
|
34 |
-
$this->logger->fatal($email . ' - ' . $ip . ' - Name with http: ' . $full_name);
|
35 |
-
return true;
|
36 |
-
}
|
37 |
-
|
38 |
-
if ($this->is_ip_blacklisted($ip)) {
|
39 |
-
$this->logger->fatal($email . ' - ' . $ip . ' - IP blacklisted');
|
40 |
-
return true;
|
41 |
-
}
|
42 |
-
|
43 |
-
if ($this->is_address_blacklisted($email)) {
|
44 |
-
$this->logger->fatal($email . ' - ' . $ip . ' - Address blacklisted');
|
45 |
-
return true;
|
46 |
-
}
|
47 |
-
|
48 |
-
// Akismet check
|
49 |
-
$user_agent = isset( $_SERVER['HTTP_USER_AGENT'] ) ? $_SERVER['HTTP_USER_AGENT'] : '';
|
50 |
-
$referrer = isset( $_SERVER['HTTP_REFERER'] ) ? $_SERVER['HTTP_REFERER'] : '';
|
51 |
-
if ( $this->is_spam_by_akismet( $email, $full_name, $ip, $user_agent, $referrer ) ) {
|
52 |
-
$this->logger->fatal( $email . ' - ' . $ip . ' - Akismet blocked' );
|
53 |
-
|
54 |
-
return true;
|
55 |
-
}
|
56 |
-
|
57 |
-
// Flood check
|
58 |
-
if ($this->is_flood($email, $ip)) {
|
59 |
-
$this->logger->fatal($email . ' - ' . $ip . ' - Antiflood triggered');
|
60 |
-
return true;
|
61 |
-
}
|
62 |
-
|
63 |
-
// if ($this->is_missing_domain_mx($email)) {
|
64 |
-
// $this->logger->fatal($email . ' - ' . $ip . ' - MX check failed');
|
65 |
-
// header("HTTP/1.0 404 Not Found");
|
66 |
-
// return true;
|
67 |
-
// }
|
68 |
-
|
69 |
-
return false;
|
70 |
-
}
|
71 |
-
|
72 |
-
function is_address_blacklisted($email) {
|
73 |
-
|
74 |
-
if (empty($this->options['address_blacklist'])) {
|
75 |
-
return false;
|
76 |
-
}
|
77 |
-
|
78 |
-
$this->logger->debug('Address blacklist check');
|
79 |
-
$rev_email = strrev($email);
|
80 |
-
foreach ($this->options['address_blacklist'] as $item) {
|
81 |
-
if (strpos($rev_email, strrev($item)) === 0) {
|
82 |
-
return true;
|
83 |
-
}
|
84 |
-
}
|
85 |
-
return false;
|
86 |
-
}
|
87 |
-
|
88 |
-
function is_ip_blacklisted($ip) {
|
89 |
-
|
90 |
-
if (empty($this->options['ip_blacklist'])) {
|
91 |
-
return false;
|
92 |
-
}
|
93 |
-
$this->logger->debug('IP blacklist check');
|
94 |
-
foreach ($this->options['ip_blacklist'] as $item) {
|
95 |
-
if (
|
96 |
-
|
97 |
-
}
|
98 |
-
|
99 |
-
|
100 |
-
|
101 |
-
|
102 |
-
|
103 |
-
|
104 |
-
|
105 |
-
|
106 |
-
|
107 |
-
|
108 |
-
|
109 |
-
|
110 |
-
|
111 |
-
|
112 |
-
|
113 |
-
$
|
114 |
-
|
115 |
-
|
116 |
-
|
117 |
-
|
118 |
-
|
119 |
-
|
120 |
-
|
121 |
-
|
122 |
-
|
123 |
-
|
124 |
-
|
125 |
-
|
126 |
-
|
127 |
-
|
128 |
-
|
129 |
-
|
130 |
-
|
131 |
-
|
132 |
-
|
133 |
-
|
134 |
-
|
135 |
-
|
136 |
-
|
137 |
-
|
138 |
-
|
139 |
-
|
140 |
-
|
141 |
-
|
142 |
-
if (stripos($text, '
|
143 |
-
return true;
|
144 |
-
}
|
145 |
-
if (
|
146 |
-
return true;
|
147 |
-
}
|
148 |
-
|
149 |
-
|
150 |
-
|
151 |
-
|
152 |
-
|
153 |
-
|
154 |
-
|
155 |
-
|
156 |
-
|
157 |
-
|
158 |
-
|
159 |
-
|
160 |
-
|
161 |
-
|
162 |
-
|
163 |
-
|
164 |
-
|
165 |
-
|
166 |
-
|
167 |
-
'&
|
168 |
-
|
169 |
-
|
170 |
-
|
171 |
-
|
172 |
-
|
173 |
-
|
174 |
-
|
175 |
-
|
176 |
-
|
177 |
-
|
178 |
-
|
179 |
-
|
180 |
-
|
181 |
-
|
182 |
-
|
183 |
-
|
184 |
-
|
185 |
-
|
186 |
-
|
187 |
-
$
|
188 |
-
$
|
189 |
-
|
190 |
-
|
191 |
-
|
192 |
-
|
193 |
-
|
194 |
-
|
195 |
-
}
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
class NewsletterAntispam {
|
4 |
+
|
5 |
+
var $options;
|
6 |
+
var $logger;
|
7 |
+
|
8 |
+
public static function instance() {
|
9 |
+
static $instance;
|
10 |
+
if (!$instance) {
|
11 |
+
$instance = new NewsletterAntispam();
|
12 |
+
}
|
13 |
+
return $instance;
|
14 |
+
}
|
15 |
+
|
16 |
+
public function __construct() {
|
17 |
+
$this->options = NewsletterSubscription::instance()->get_options('antibot');
|
18 |
+
$this->logger = new NewsletterLogger('antispam');
|
19 |
+
}
|
20 |
+
|
21 |
+
/**
|
22 |
+
* $email must be cleaned using the is_email() function.
|
23 |
+
*
|
24 |
+
* @param TNP_Subscription $subscription
|
25 |
+
*/
|
26 |
+
function is_spam($subscription) {
|
27 |
+
|
28 |
+
$email = $subscription->data->email;
|
29 |
+
$ip = $subscription->data->ip;
|
30 |
+
|
31 |
+
|
32 |
+
$full_name = $subscription->data->name . ' ' . $subscription->data->surname;
|
33 |
+
if ($this->is_spam_text($full_name)) {
|
34 |
+
$this->logger->fatal($email . ' - ' . $ip . ' - Name with http: ' . $full_name);
|
35 |
+
return true;
|
36 |
+
}
|
37 |
+
|
38 |
+
if ($this->is_ip_blacklisted($ip)) {
|
39 |
+
$this->logger->fatal($email . ' - ' . $ip . ' - IP blacklisted');
|
40 |
+
return true;
|
41 |
+
}
|
42 |
+
|
43 |
+
if ($this->is_address_blacklisted($email)) {
|
44 |
+
$this->logger->fatal($email . ' - ' . $ip . ' - Address blacklisted');
|
45 |
+
return true;
|
46 |
+
}
|
47 |
+
|
48 |
+
// Akismet check
|
49 |
+
$user_agent = isset( $_SERVER['HTTP_USER_AGENT'] ) ? $_SERVER['HTTP_USER_AGENT'] : '';
|
50 |
+
$referrer = isset( $_SERVER['HTTP_REFERER'] ) ? $_SERVER['HTTP_REFERER'] : '';
|
51 |
+
if ( $this->is_spam_by_akismet( $email, $full_name, $ip, $user_agent, $referrer ) ) {
|
52 |
+
$this->logger->fatal( $email . ' - ' . $ip . ' - Akismet blocked' );
|
53 |
+
|
54 |
+
return true;
|
55 |
+
}
|
56 |
+
|
57 |
+
// Flood check
|
58 |
+
if ($this->is_flood($email, $ip)) {
|
59 |
+
$this->logger->fatal($email . ' - ' . $ip . ' - Antiflood triggered');
|
60 |
+
return true;
|
61 |
+
}
|
62 |
+
|
63 |
+
// if ($this->is_missing_domain_mx($email)) {
|
64 |
+
// $this->logger->fatal($email . ' - ' . $ip . ' - MX check failed');
|
65 |
+
// header("HTTP/1.0 404 Not Found");
|
66 |
+
// return true;
|
67 |
+
// }
|
68 |
+
|
69 |
+
return false;
|
70 |
+
}
|
71 |
+
|
72 |
+
function is_address_blacklisted($email) {
|
73 |
+
|
74 |
+
if (empty($this->options['address_blacklist'])) {
|
75 |
+
return false;
|
76 |
+
}
|
77 |
+
|
78 |
+
$this->logger->debug('Address blacklist check');
|
79 |
+
$rev_email = strrev($email);
|
80 |
+
foreach ($this->options['address_blacklist'] as $item) {
|
81 |
+
if (strpos($rev_email, strrev($item)) === 0) {
|
82 |
+
return true;
|
83 |
+
}
|
84 |
+
}
|
85 |
+
return false;
|
86 |
+
}
|
87 |
+
|
88 |
+
function is_ip_blacklisted($ip) {
|
89 |
+
|
90 |
+
if (empty($this->options['ip_blacklist'])) {
|
91 |
+
return false;
|
92 |
+
}
|
93 |
+
$this->logger->debug('IP blacklist check');
|
94 |
+
foreach ($this->options['ip_blacklist'] as $item) {
|
95 |
+
if (substr($item, 0, 1) === '#') {
|
96 |
+
continue;
|
97 |
+
}
|
98 |
+
if ($this->ip_match($ip, $item)) {
|
99 |
+
return true;
|
100 |
+
}
|
101 |
+
}
|
102 |
+
return false;
|
103 |
+
}
|
104 |
+
|
105 |
+
function is_missing_domain_mx($email) {
|
106 |
+
// Actually not fully implemented
|
107 |
+
return false;
|
108 |
+
|
109 |
+
if (empty($this->options['domain_check'])) {
|
110 |
+
return false;
|
111 |
+
}
|
112 |
+
|
113 |
+
$this->logger->debug('Domain MX check');
|
114 |
+
list($local, $domain) = explode('@', $email);
|
115 |
+
|
116 |
+
$hosts = array();
|
117 |
+
if (!getmxrr($domain, $hosts)) {
|
118 |
+
return true;
|
119 |
+
}
|
120 |
+
return false;
|
121 |
+
}
|
122 |
+
|
123 |
+
function is_flood($email, $ip) {
|
124 |
+
global $wpdb;
|
125 |
+
|
126 |
+
if (empty($this->options['antiflood'])) {
|
127 |
+
return false;
|
128 |
+
}
|
129 |
+
|
130 |
+
$this->logger->debug('Antiflood check');
|
131 |
+
|
132 |
+
$updated = $wpdb->get_var($wpdb->prepare("select updated from " . NEWSLETTER_USERS_TABLE . " where ip=%s or email=%s order by updated desc limit 1", $ip, $email));
|
133 |
+
|
134 |
+
if ($updated && time() - $updated < $this->options['antiflood']) {
|
135 |
+
return true;
|
136 |
+
}
|
137 |
+
|
138 |
+
return false;
|
139 |
+
}
|
140 |
+
|
141 |
+
function is_spam_text($text) {
|
142 |
+
if (stripos($text, 'http:') !== false || stripos($text, 'https:') !== false) {
|
143 |
+
return true;
|
144 |
+
}
|
145 |
+
if (stripos($text, 'www.') !== false) {
|
146 |
+
return true;
|
147 |
+
}
|
148 |
+
if (preg_match('|[^\s\.]+\.[^\s\.]+\.[^\s\.]{2,}|', $text)) {
|
149 |
+
return true;
|
150 |
+
}
|
151 |
+
|
152 |
+
return false;
|
153 |
+
}
|
154 |
+
|
155 |
+
function is_spam_by_akismet($email, $name, $ip, $agent, $referrer) {
|
156 |
+
|
157 |
+
if (!class_exists('Akismet')) {
|
158 |
+
return false;
|
159 |
+
}
|
160 |
+
|
161 |
+
if (empty($this->options['akismet'])) {
|
162 |
+
return false;
|
163 |
+
}
|
164 |
+
|
165 |
+
$this->logger->debug('Akismet check');
|
166 |
+
$request = 'blog=' . urlencode(home_url()) . '&referrer=' . urlencode($referrer) .
|
167 |
+
'&user_agent=' . urlencode($agent) .
|
168 |
+
'&comment_type=signup' .
|
169 |
+
'&comment_author_email=' . urlencode($email) .
|
170 |
+
'&user_ip=' . urlencode($ip);
|
171 |
+
if (!empty($name)) {
|
172 |
+
$request .= '&comment_author=' . urlencode($name);
|
173 |
+
}
|
174 |
+
|
175 |
+
$response = Akismet::http_post($request, 'comment-check');
|
176 |
+
|
177 |
+
if ($response && $response[1] == 'true') {
|
178 |
+
return true;
|
179 |
+
}
|
180 |
+
return false;
|
181 |
+
}
|
182 |
+
|
183 |
+
function ip_match($ip, $range) {
|
184 |
+
if (empty($ip))
|
185 |
+
return false;
|
186 |
+
if (strpos($range, '/')) {
|
187 |
+
list ($subnet, $bits) = explode('/', $range);
|
188 |
+
$ip = ip2long($ip);
|
189 |
+
$subnet = ip2long($subnet);
|
190 |
+
$mask = -1 << (32 - $bits);
|
191 |
+
$subnet &= $mask; # nb: in case the supplied subnet wasn't correctly aligned
|
192 |
+
return ($ip & $mask) == $subnet;
|
193 |
+
} else {
|
194 |
+
return strpos($range, $ip) === 0;
|
195 |
+
}
|
196 |
+
}
|
197 |
+
|
198 |
+
}
|
includes/composer.php
CHANGED
@@ -1,863 +1,879 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
/** For old style coders */
|
4 |
-
function tnp_register_block($dir) {
|
5 |
-
return TNP_Composer::register_block($dir);
|
6 |
-
}
|
7 |
-
|
8 |
-
/**
|
9 |
-
* Generates and HTML button for email using the values found on $options and
|
10 |
-
* prefixed by $prefix, with the standard syntax of NewsletterFields::button().
|
11 |
-
*
|
12 |
-
* @param array $options
|
13 |
-
* @param string $prefix
|
14 |
-
* @return string
|
15 |
-
*/
|
16 |
-
function tnpc_button($options, $prefix = 'button') {
|
17 |
-
return TNP_Composer::button($options, $prefix);
|
18 |
-
}
|
19 |
-
|
20 |
-
class TNP_Composer {
|
21 |
-
|
22 |
-
static $block_dirs = array();
|
23 |
-
|
24 |
-
static function register_block($dir) {
|
25 |
-
// Checks
|
26 |
-
$dir = realpath($dir);
|
27 |
-
if (!$dir) {
|
28 |
-
$error = new WP_Error('1', 'Seems not a valid path: ' . $dir);
|
29 |
-
NewsletterEmails::instance()->logger->error($error);
|
30 |
-
return $error;
|
31 |
-
}
|
32 |
-
|
33 |
-
$dir = wp_normalize_path($dir);
|
34 |
-
|
35 |
-
if (!file_exists($dir . '/block.php')) {
|
36 |
-
$error = new WP_Error('1', 'block.php missing on folder ' . $dir);
|
37 |
-
NewsletterEmails::instance()->logger->error($error);
|
38 |
-
return $error;
|
39 |
-
}
|
40 |
-
|
41 |
-
self::$block_dirs[] = $dir;
|
42 |
-
return true;
|
43 |
-
}
|
44 |
-
|
45 |
-
/**
|
46 |
-
* @param string $open
|
47 |
-
* @param string $inner
|
48 |
-
* @param string $close
|
49 |
-
* @param string[] $markers
|
50 |
-
*
|
51 |
-
* @return string
|
52 |
-
*/
|
53 |
-
static function wrap_html_element($open, $inner, $close, $markers = array('<!-- tnp -->', '<!-- /tnp -->')) {
|
54 |
-
|
55 |
-
return $open . $markers[0] . $inner . $markers[1] . $close;
|
56 |
-
}
|
57 |
-
|
58 |
-
/**
|
59 |
-
* @param string $block
|
60 |
-
* @param string[] $markers
|
61 |
-
*
|
62 |
-
* @return string
|
63 |
-
*/
|
64 |
-
static function unwrap_html_element($block, $markers = array('<!-- tnp -->', '<!-- /tnp -->')) {
|
65 |
-
if (self::_has_markers($block, $markers)) {
|
66 |
-
self::_escape_markers($markers);
|
67 |
-
$pattern = sprintf('/%s(.*?)%s/s', $markers[0], $markers[1]);
|
68 |
-
|
69 |
-
$matches = array();
|
70 |
-
preg_match($pattern, $block, $matches);
|
71 |
-
|
72 |
-
return $matches[1];
|
73 |
-
}
|
74 |
-
|
75 |
-
return $block;
|
76 |
-
}
|
77 |
-
|
78 |
-
/**
|
79 |
-
* @param string $block
|
80 |
-
* @param string[] $markers
|
81 |
-
*
|
82 |
-
* @return bool
|
83 |
-
*/
|
84 |
-
private static function _has_markers($block, $markers = array('<!-- tnp -->', '<!-- /tnp -->')) {
|
85 |
-
|
86 |
-
self::_escape_markers($markers);
|
87 |
-
|
88 |
-
$pattern = sprintf('/%s(.*?)%s/s', $markers[0], $markers[1]);
|
89 |
-
|
90 |
-
return preg_match($pattern, $block);
|
91 |
-
}
|
92 |
-
|
93 |
-
/**
|
94 |
-
* Sources:
|
95 |
-
* - https://webdesign.tutsplus.com/tutorials/creating-a-future-proof-responsive-email-without-media-queries--cms-23919
|
96 |
-
*
|
97 |
-
* @param type $email
|
98 |
-
* @return type
|
99 |
-
*/
|
100 |
-
static function get_html_open($email) {
|
101 |
-
$open = "<!DOCTYPE html>\n";
|
102 |
-
$open .= "<html xmlns=\"https://www.w3.org/1999/xhtml\" xmlns:o=\"urn:schemas-microsoft-com:office:office\">\n<head>\n<title>{email_subject}</title>\n";
|
103 |
-
$open .= "<meta charset=\"utf-8\">\n<meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\n";
|
104 |
-
|
105 |
-
$open .= '<!--[if !mso]><!-->' . "\n";
|
106 |
-
$open .= '<meta http-equiv="X-UA-Compatible" content="IE=edge" />' . "\n";
|
107 |
-
$open .= '<!--<![endif]-->' . "\n";
|
108 |
-
|
109 |
-
$open .= '<!--[if mso]>' . "\n";
|
110 |
-
;
|
111 |
-
$open .= '<style type="text/css">';
|
112 |
-
$open .= 'table {border-collapse:collapse;border-spacing:0;margin:0;}';
|
113 |
-
$open .= 'div, td {padding:0;}';
|
114 |
-
$open .= 'div {margin:0 !important;}';
|
115 |
-
$open .= '</style>';
|
116 |
-
$open .= "\n";
|
117 |
-
$open .= '<noscript>';
|
118 |
-
$open .= '<xml>';
|
119 |
-
$open .= '<o:OfficeDocumentSettings>';
|
120 |
-
$open .= '<o:PixelsPerInch>96</o:PixelsPerInch>';
|
121 |
-
$open .= '</o:OfficeDocumentSettings>';
|
122 |
-
$open .= '</xml>';
|
123 |
-
$open .= '</noscript>';
|
124 |
-
$open .= "\n";
|
125 |
-
$open .= '<![endif]-->';
|
126 |
-
$open .= "\n";
|
127 |
-
$open .= "<style type=\"text/css\">\n";
|
128 |
-
$open .= NewsletterEmails::instance()->get_composer_css();
|
129 |
-
$open .= "\n</style>\n";
|
130 |
-
$open .= "</head>\n";
|
131 |
-
$open .= '<body style="margin: 0; padding: 0; line-height: normal; word-spacing: normal;" dir="' . (is_rtl() ? 'rtl' : 'ltr') . '">';
|
132 |
-
$open .= "\n";
|
133 |
-
$open .= self::get_html_preheader($email);
|
134 |
-
|
135 |
-
return $open;
|
136 |
-
}
|
137 |
-
|
138 |
-
static private function get_html_preheader($email) {
|
139 |
-
|
140 |
-
if (empty($email->options['preheader'])) {
|
141 |
-
return "";
|
142 |
-
}
|
143 |
-
|
144 |
-
$preheader_text = $email->options['preheader'];
|
145 |
-
$html = "<div style=\"display:none;font-size:1px;color:#ffffff;line-height:1px;max-height:0px;max-width:0px;opacity:0;overflow:hidden;\">$preheader_text</div>";
|
146 |
-
$html .= "\n";
|
147 |
-
|
148 |
-
return $html;
|
149 |
-
}
|
150 |
-
|
151 |
-
static function get_html_close($email) {
|
152 |
-
return "</body>\n</html>";
|
153 |
-
}
|
154 |
-
|
155 |
-
/**
|
156 |
-
*
|
157 |
-
* @param TNP_Email $email
|
158 |
-
* @return string
|
159 |
-
*/
|
160 |
-
static function get_main_wrapper_open($email) {
|
161 |
-
if (!isset($email->options['composer_background']) || $email->options['composer_background'] == 'inherit') {
|
162 |
-
$bgcolor = '';
|
163 |
-
} else {
|
164 |
-
$bgcolor = $email->options['composer_background'];
|
165 |
-
}
|
166 |
-
|
167 |
-
return "\n<table cellpadding='0' cellspacing='0' border='0' width='100%'>\n" .
|
168 |
-
"<tr>\n" .
|
169 |
-
"<td bgcolor='$bgcolor' valign='top'><!-- tnp -->";
|
170 |
-
}
|
171 |
-
|
172 |
-
/**
|
173 |
-
*
|
174 |
-
* @param TNP_Email $email
|
175 |
-
* @return string
|
176 |
-
*/
|
177 |
-
static function get_main_wrapper_close($email) {
|
178 |
-
return "\n<!-- /tnp -->\n" .
|
179 |
-
"</td>\n" .
|
180 |
-
"</tr>\n" .
|
181 |
-
"</table>\n\n";
|
182 |
-
}
|
183 |
-
|
184 |
-
/**
|
185 |
-
* Remove <doctype>, <body> and unnecessary envelopes for editing with composer
|
186 |
-
*
|
187 |
-
* @param string $html_email
|
188 |
-
*
|
189 |
-
* @return string
|
190 |
-
*/
|
191 |
-
static function unwrap_email($html_email) {
|
192 |
-
|
193 |
-
if (self::_has_markers($html_email)) {
|
194 |
-
$html_email = self::unwrap_html_element($html_email);
|
195 |
-
} else {
|
196 |
-
//KEEP FOR OLD EMAIL COMPATIBILITY
|
197 |
-
// Extracts only the body part
|
198 |
-
$x = strpos($html_email, '<body');
|
199 |
-
if ($x) {
|
200 |
-
$x = strpos($html_email, '>', $x);
|
201 |
-
$y = strpos($html_email, '</body>');
|
202 |
-
$html_email = substr($html_email, $x + 1, $y - $x - 1);
|
203 |
-
}
|
204 |
-
|
205 |
-
/* Cleans up uncorrectly stored newsletter bodies */
|
206 |
-
$html_email = preg_replace('/<style\s+.*?>.*?<\\/style>/is', '', $html_email);
|
207 |
-
$html_email = preg_replace('/<meta.*?>/', '', $html_email);
|
208 |
-
$html_email = preg_replace('/<title\s+.*?>.*?<\\/title>/i', '', $html_email);
|
209 |
-
$html_email = trim($html_email);
|
210 |
-
}
|
211 |
-
|
212 |
-
// Required since esc_html DOES NOT escape the HTML entities (apparently)
|
213 |
-
$html_email = str_replace('&', '&', $html_email);
|
214 |
-
$html_email = str_replace('"', '"', $html_email);
|
215 |
-
$html_email = str_replace('<', '<', $html_email);
|
216 |
-
$html_email = str_replace('>', '>', $html_email);
|
217 |
-
|
218 |
-
return $html_email;
|
219 |
-
}
|
220 |
-
|
221 |
-
private static function _escape_markers(&$markers) {
|
222 |
-
$markers[0] = str_replace('/', '\/', $markers[0]);
|
223 |
-
$markers[1] = str_replace('/', '\/', $markers[1]);
|
224 |
-
}
|
225 |
-
|
226 |
-
/**
|
227 |
-
* Using the data collected inside $controls (and submitted by a form containing the
|
228 |
-
* composer fields), updates the email. The message body is completed with doctype,
|
229 |
-
* head, style and the main wrapper.
|
230 |
-
*
|
231 |
-
* @param TNP_Email $email
|
232 |
-
* @param NewsletterControls $controls
|
233 |
-
*/
|
234 |
-
static function update_email($email, $controls) {
|
235 |
-
if (isset($controls->data['subject'])) {
|
236 |
-
$email->subject = $controls->data['subject'];
|
237 |
-
}
|
238 |
-
|
239 |
-
// They should be only composer options
|
240 |
-
foreach ($controls->data as $name => $value) {
|
241 |
-
if (strpos($name, 'options_') === 0) {
|
242 |
-
$email->options[substr($name, 8)] = $value;
|
243 |
-
}
|
244 |
-
}
|
245 |
-
|
246 |
-
//if (isset($controls->data['preheader'])) {
|
247 |
-
// $email->options['preheader'] = $controls->data['preheader'];
|
248 |
-
//}
|
249 |
-
|
250 |
-
$email->editor = NewsletterEmails::EDITOR_COMPOSER;
|
251 |
-
|
252 |
-
$email->message = self::get_html_open($email) . self::get_main_wrapper_open($email) .
|
253 |
-
$controls->data['message'] . self::get_main_wrapper_close($email) . self::get_html_close($email);
|
254 |
-
}
|
255 |
-
|
256 |
-
/**
|
257 |
-
* Prepares a controls object injecting the relevant fields from an email
|
258 |
-
* which cannot be directly used by controls. If $email is null or missing,
|
259 |
-
* $controls is prepared with default values.
|
260 |
-
*
|
261 |
-
* @param NewsletterControls $controls
|
262 |
-
* @param TNP_Email $email
|
263 |
-
*/
|
264 |
-
static function prepare_controls($controls, $email = null) {
|
265 |
-
|
266 |
-
// Controls for a new email (which actually does not exist yet
|
267 |
-
if (!empty($email)) {
|
268 |
-
|
269 |
-
foreach ($email->options as $name => $value) {
|
270 |
-
$controls->data['options_' . $name] = $value;
|
271 |
-
}
|
272 |
-
|
273 |
-
$controls->data['message'] = TNP_Composer::unwrap_email($email->message);
|
274 |
-
$controls->data['subject'] = $email->subject;
|
275 |
-
}
|
276 |
-
|
277 |
-
if (!empty($email->options['sender_email'])) {
|
278 |
-
$controls->data['sender_email'] = $email->options['sender_email'];
|
279 |
-
} else {
|
280 |
-
$controls->data['sender_email'] = Newsletter::instance()->options['sender_email'];
|
281 |
-
}
|
282 |
-
|
283 |
-
if (!empty($email->options['sender_name'])) {
|
284 |
-
$controls->data['sender_name'] = $email->options['sender_name'];
|
285 |
-
} else {
|
286 |
-
$controls->data['sender_name'] = Newsletter::instance()->options['sender_name'];
|
287 |
-
}
|
288 |
-
|
289 |
-
$controls->data = array_merge(TNP_Composer::get_global_style_defaults(), $controls->data);
|
290 |
-
}
|
291 |
-
|
292 |
-
/**
|
293 |
-
* Extract inline edited post field from inline_edit_list[]
|
294 |
-
*
|
295 |
-
* @param array $inline_edit_list
|
296 |
-
* @param string $field_type
|
297 |
-
* @param int $post_id
|
298 |
-
*
|
299 |
-
* @return string
|
300 |
-
*/
|
301 |
-
static function get_edited_inline_post_field($inline_edit_list, $field_type, $post_id) {
|
302 |
-
|
303 |
-
foreach ($inline_edit_list as $edit) {
|
304 |
-
if ($edit['type'] == $field_type && $edit['post_id'] == $post_id) {
|
305 |
-
return $edit['content'];
|
306 |
-
}
|
307 |
-
}
|
308 |
-
|
309 |
-
return '';
|
310 |
-
}
|
311 |
-
|
312 |
-
/**
|
313 |
-
* Check if inline_edit_list[] have inline edit field for specific post
|
314 |
-
*
|
315 |
-
* @param array $inline_edit_list
|
316 |
-
* @param string $field_type
|
317 |
-
* @param int $post_id
|
318 |
-
*
|
319 |
-
* @return bool
|
320 |
-
*/
|
321 |
-
static function is_post_field_edited_inline($inline_edit_list, $field_type, $post_id) {
|
322 |
-
if (empty($inline_edit_list) || !is_array($inline_edit_list)) {
|
323 |
-
return false;
|
324 |
-
}
|
325 |
-
foreach ($inline_edit_list as $edit) {
|
326 |
-
if ($edit['type'] == $field_type && $edit['post_id'] == $post_id) {
|
327 |
-
return true;
|
328 |
-
}
|
329 |
-
}
|
330 |
-
|
331 |
-
return false;
|
332 |
-
}
|
333 |
-
|
334 |
-
/**
|
335 |
-
* Creates the HTML for a button extrating from the options, with the provided prefix, the button attributes:
|
336 |
-
*
|
337 |
-
* - [prefix]_url The button URL
|
338 |
-
* - [prefix]_font_family
|
339 |
-
* - [prefix]_font_size
|
340 |
-
* - [prefix]_font_weight
|
341 |
-
* - [prefix]_label
|
342 |
-
* - [prefix]_font_color The label color
|
343 |
-
* - [prefix]_background The button color
|
344 |
-
*
|
345 |
-
* TODO: Add radius and possiblt the alignment
|
346 |
-
*
|
347 |
-
* @param array $options
|
348 |
-
* @param string $prefix
|
349 |
-
* @return string
|
350 |
-
*/
|
351 |
-
static function button($options, $prefix = 'button') {
|
352 |
-
|
353 |
-
if (empty($options[$prefix . '_label'])) {
|
354 |
-
return;
|
355 |
-
}
|
356 |
-
$defaults = [
|
357 |
-
$prefix . '_url' => '#',
|
358 |
-
$prefix . '_font_family' => 'Helvetica, Arial, sans-serif',
|
359 |
-
$prefix . '_font_color' => '#ffffff',
|
360 |
-
$prefix . '_font_weight' => 'bold',
|
361 |
-
$prefix . '_font_size' => 20,
|
362 |
-
$prefix . '_background' => '#256F9C',
|
363 |
-
$prefix . '_align' => 'center'
|
364 |
-
];
|
365 |
-
|
366 |
-
$options = array_merge($defaults, array_filter($options));
|
367 |
-
|
368 |
-
$b = '<table border="0" cellpadding="0" cellspacing="0" role="presentation" style="margin: 0 auto"';
|
369 |
-
if (!empty($options[$prefix . '_align'])) {
|
370 |
-
$b .= ' align="' . esc_attr($options[$prefix . '_align']) . '"';
|
371 |
-
}
|
372 |
-
if (!empty($options[$prefix . '_width'])) {
|
373 |
-
$b .= ' width="' . esc_attr($options[$prefix . '_width']) . '"';
|
374 |
-
}
|
375 |
-
$b .= '>';
|
376 |
-
$b .= '<tr>';
|
377 |
-
$b .= '<td align="center" bgcolor="' . $options[$prefix . '_background'] . '" role="presentation" style="border:none;border-radius:3px;cursor:auto;mso-padding-alt:10px 25px;background:' . $options[$prefix . '_background'] . '" valign="middle">';
|
378 |
-
$b .= '<a href="' . $options[$prefix . '_url'] . '"';
|
379 |
-
$b .= ' style="display:inline-block;background:' . $options[$prefix . '_background'] . ';color:' . $options[$prefix . '_font_color'] . ';font-family:' . $options[$prefix . '_font_family'] . ';font-size:' . $options[$prefix . '_font_size'] . 'px;font-weight:' . $options[$prefix . '_font_weight'] . ';line-height:120%;margin:0;text-decoration:none;text-transform:none;padding:10px 25px;mso-padding-alt:0px;border-radius:3px;"';
|
380 |
-
$b .= ' target="_blank">';
|
381 |
-
$b .= $options[$prefix . '_label'];
|
382 |
-
$b .= '</a>';
|
383 |
-
$b .= '</td></tr></table>';
|
384 |
-
return $b;
|
385 |
-
}
|
386 |
-
|
387 |
-
/**
|
388 |
-
* Generates an IMG tag, linked if the media has an URL.
|
389 |
-
*
|
390 |
-
* @param TNP_Media $media
|
391 |
-
* @param string $style
|
392 |
-
* @return string
|
393 |
-
*/
|
394 |
-
static function image($media, $attr = []) {
|
395 |
-
|
396 |
-
$default_attrs = [
|
397 |
-
'style' => 'max-width: 100%; height: auto; display: inline-block',
|
398 |
-
'class' => '',
|
399 |
-
'link-style' => 'text-decoration: none; display: inline-block',
|
400 |
-
'link-class' => null,
|
401 |
-
];
|
402 |
-
|
403 |
-
$attr = array_merge($default_attrs, $attr);
|
404 |
-
|
405 |
-
//Class and style attribute are mutually exclusive.
|
406 |
-
//Class take priority to style because classes will transform to inline style inside block rendering operation
|
407 |
-
if (!empty($attr['inline-class'])) {
|
408 |
-
$styling = ' inline-class="' . esc_attr($attr['inline-class']) . '" ';
|
409 |
-
} else {
|
410 |
-
$styling = ' style="' . esc_attr($attr['style']) . '" ';
|
411 |
-
}
|
412 |
-
|
413 |
-
if (!empty($attr['class'])) {
|
414 |
-
$styling .= ' class="' . esc_attr($attr['class']) . '" ';
|
415 |
-
}
|
416 |
-
|
417 |
-
//Class and style attribute are mutually exclusive.
|
418 |
-
//Class take priority to style because classes will transform to inline style inside block rendering operation
|
419 |
-
if (!empty($attr['link-class'])) {
|
420 |
-
$link_styling = ' inline-class="' . esc_attr($attr['link-class']) . '" ';
|
421 |
-
} else {
|
422 |
-
$link_styling = ' style="' . esc_attr($attr['link-style']) . '" ';
|
423 |
-
}
|
424 |
-
|
425 |
-
$b = '';
|
426 |
-
if ($media->link) {
|
427 |
-
$b .= '<a href="' . esc_attr($media->link) . '" target="_blank" rel="noopener nofollow" style="display: inline-block; font-size: 0; text-decoration: none; line-height: normal!important">';
|
428 |
-
} else {
|
429 |
-
// The span grants images are not upscaled when fluid (two columns posts block)
|
430 |
-
$b .= '<span style="display: inline-block; font-size: 0; text-decoration: none; line-height: normal!important">';
|
431 |
-
}
|
432 |
-
if ($media) {
|
433 |
-
$b .= '<img src="' . esc_attr($media->url) . '" width="' . esc_attr($media->width) . '"';
|
434 |
-
if ($media->height) {
|
435 |
-
$b .= ' height="' . esc_attr($media->height) . '"';
|
436 |
-
}
|
437 |
-
$b .= ' alt="' . esc_attr($media->alt) . '"'
|
438 |
-
. ' border="0"'
|
439 |
-
. ' style="display: inline-block; max-width: 100%!important; padding: 0; border: 0;"'
|
440 |
-
. ' class="' . esc_attr($attr['class']) . '" '
|
441 |
-
. '>';
|
442 |
-
}
|
443 |
-
|
444 |
-
if ($media->link) {
|
445 |
-
$b .= '</a>';
|
446 |
-
} else {
|
447 |
-
$b .= '</span>';
|
448 |
-
}
|
449 |
-
|
450 |
-
return $b;
|
451 |
-
}
|
452 |
-
|
453 |
-
/**
|
454 |
-
* Returns a WP media ID for the specified post (or false if nothing can be found)
|
455 |
-
* looking for the featured image or, if missing, taking the first media in the gallery and
|
456 |
-
* if again missing, searching the first reference to a media in the post content.
|
457 |
-
*
|
458 |
-
* The media ID is not checked for real existance of the associated attachment.
|
459 |
-
*
|
460 |
-
* @param int $post_id
|
461 |
-
* @return int
|
462 |
-
*/
|
463 |
-
static function get_post_thumbnail_id($post_id) {
|
464 |
-
if (is_object($post_id)) {
|
465 |
-
$post_id = $post_id->ID;
|
466 |
-
}
|
467 |
-
|
468 |
-
// Find a media id to be used as featured image
|
469 |
-
$media_id = get_post_thumbnail_id($post_id);
|
470 |
-
if (!empty($media_id)) {
|
471 |
-
return $media_id;
|
472 |
-
}
|
473 |
-
|
474 |
-
$attachments = get_children(array('numberpost' => 1, 'post_parent' => $post_id, 'post_status' => 'inherit', 'post_type' => 'attachment', 'post_mime_type' => 'image', 'order' => 'ASC', 'orderby' => 'menu_order'));
|
475 |
-
if (!empty($attachments)) {
|
476 |
-
foreach ($attachments as $id => &$attachment) {
|
477 |
-
return $id;
|
478 |
-
}
|
479 |
-
}
|
480 |
-
|
481 |
-
$post = get_post($post_id);
|
482 |
-
|
483 |
-
$r = preg_match('/wp-image-(\d+)/', $post->post_content, $matches);
|
484 |
-
if ($matches) {
|
485 |
-
return (int) $matches[1];
|
486 |
-
}
|
487 |
-
|
488 |
-
return false;
|
489 |
-
}
|
490 |
-
|
491 |
-
/**
|
492 |
-
* Builds a TNP_Media object to be used in newsletters from a WP media/attachement ID. The returned
|
493 |
-
* media has a size which best match the one requested (this is the standard WP behavior, plugins
|
494 |
-
* could change it).
|
495 |
-
*
|
496 |
-
* @param int $media_id
|
497 |
-
* @param array $size
|
498 |
-
* @return \TNP_Media
|
499 |
-
*/
|
500 |
-
function get_media($media_id, $size) {
|
501 |
-
$src = wp_get_attachment_image_src($media_id, $size);
|
502 |
-
if (!$src) {
|
503 |
-
return null;
|
504 |
-
}
|
505 |
-
$media = new TNP_Media();
|
506 |
-
$media->id = $media_id;
|
507 |
-
$media->url = $src[0];
|
508 |
-
$media->width = $src[1];
|
509 |
-
$media->height = $src[2];
|
510 |
-
return $media;
|
511 |
-
}
|
512 |
-
|
513 |
-
static function post_content($post) {
|
514 |
-
$content = $post->post_content;
|
515 |
-
$content = wpautop($content);
|
516 |
-
if (true || $options['enable shortcodes']) {
|
517 |
-
remove_shortcode('gallery');
|
518 |
-
add_shortcode('gallery', 'tnp_gallery_shortcode');
|
519 |
-
$content = do_shortcode($content);
|
520 |
-
}
|
521 |
-
$content = str_replace('<p>', '<p class="paragraph">', $content);
|
522 |
-
|
523 |
-
$selected_images = array();
|
524 |
-
if (preg_match_all('/<img [^>]+>/', $content, $matches)) {
|
525 |
-
foreach ($matches[0] as $image) {
|
526 |
-
if (preg_match('/wp-image-([0-9]+)/i', $image, $class_id) && ( $attachment_id = absint($class_id[1]) )) {
|
527 |
-
$selected_images[$image] = $attachment_id;
|
528 |
-
}
|
529 |
-
}
|
530 |
-
}
|
531 |
-
|
532 |
-
foreach ($selected_images as $image => $attachment_id) {
|
533 |
-
$src = tnp_media_resize($attachment_id, array(600, 0));
|
534 |
-
if (is_wp_error($src)) {
|
535 |
-
continue;
|
536 |
-
}
|
537 |
-
$content = str_replace($image, '<img src="' . $src . '" width="600" style="max-width: 100%">', $content);
|
538 |
-
}
|
539 |
-
|
540 |
-
return $content;
|
541 |
-
}
|
542 |
-
|
543 |
-
static function get_global_style_defaults() {
|
544 |
-
return [
|
545 |
-
'options_composer_title_font_family' => 'Verdana, Geneva, sans-serif',
|
546 |
-
'options_composer_title_font_size' => 32,
|
547 |
-
'options_composer_title_font_weight' => 'normal',
|
548 |
-
'options_composer_title_font_color' => '#222222',
|
549 |
-
'options_composer_text_font_family' => 'Verdana, Geneva, sans-serif',
|
550 |
-
'options_composer_text_font_size' => 16,
|
551 |
-
'options_composer_text_font_weight' => 'normal',
|
552 |
-
'options_composer_text_font_color' => '#222222',
|
553 |
-
'options_composer_button_font_family' => 'Verdana, Geneva, sans-serif',
|
554 |
-
'options_composer_button_font_size' => 16,
|
555 |
-
'options_composer_button_font_weight' => 'normal',
|
556 |
-
'options_composer_button_font_color' => '#FFFFFF',
|
557 |
-
'options_composer_button_background_color' => '#256F9C',
|
558 |
-
'options_composer_background' => '#FFFFFF',
|
559 |
-
'options_composer_block_background' => '#FFFFFF',
|
560 |
-
];
|
561 |
-
}
|
562 |
-
|
563 |
-
/**
|
564 |
-
* Inspired by: https://webdesign.tutsplus.com/tutorials/creating-a-future-proof-responsive-email-without-media-queries--cms-23919
|
565 |
-
* @param string[] $items
|
566 |
-
* @param array $attrs
|
567 |
-
* @return string
|
568 |
-
*/
|
569 |
-
static function grid($items = [], $attrs = []) {
|
570 |
-
$attrs = wp_parse_args($attrs, ['width' => 600, 'columns' => 2, 'padding' => 10]);
|
571 |
-
$width = (int) $attrs['width'];
|
572 |
-
$columns = (int) $attrs['columns'];
|
573 |
-
$padding = (int) $attrs['padding'];
|
574 |
-
$column_width = $width / $columns;
|
575 |
-
$td_width = 100 / $columns;
|
576 |
-
$chunks = array_chunk($items, $columns);
|
577 |
-
|
578 |
-
$
|
579 |
-
|
580 |
-
|
581 |
-
$
|
582 |
-
|
583 |
-
$e .= '<!--[if mso]><
|
584 |
-
|
585 |
-
|
586 |
-
|
587 |
-
|
588 |
-
|
589 |
-
|
590 |
-
|
591 |
-
|
592 |
-
|
593 |
-
|
594 |
-
|
595 |
-
|
596 |
-
|
597 |
-
|
598 |
-
|
599 |
-
|
600 |
-
|
601 |
-
|
602 |
-
|
603 |
-
|
604 |
-
|
605 |
-
|
606 |
-
|
607 |
-
|
608 |
-
|
609 |
-
|
610 |
-
|
611 |
-
|
612 |
-
|
613 |
-
|
614 |
-
}
|
615 |
-
|
616 |
-
|
617 |
-
|
618 |
-
|
619 |
-
|
620 |
-
|
621 |
-
|
622 |
-
|
623 |
-
|
624 |
-
|
625 |
-
|
626 |
-
|
627 |
-
|
628 |
-
|
629 |
-
|
630 |
-
|
631 |
-
|
632 |
-
|
633 |
-
|
634 |
-
|
635 |
-
|
636 |
-
|
637 |
-
|
638 |
-
|
639 |
-
|
640 |
-
|
641 |
-
|
642 |
-
|
643 |
-
|
644 |
-
|
645 |
-
|
646 |
-
|
647 |
-
|
648 |
-
|
649 |
-
|
650 |
-
|
651 |
-
|
652 |
-
|
653 |
-
|
654 |
-
|
655 |
-
|
656 |
-
|
657 |
-
|
658 |
-
|
659 |
-
|
660 |
-
|
661 |
-
|
662 |
-
|
663 |
-
|
664 |
-
|
665 |
-
|
666 |
-
|
667 |
-
|
668 |
-
|
669 |
-
|
670 |
-
*
|
671 |
-
|
672 |
-
|
673 |
-
|
674 |
-
|
675 |
-
|
676 |
-
|
677 |
-
|
678 |
-
|
679 |
-
|
680 |
-
|
681 |
-
|
682 |
-
|
683 |
-
|
684 |
-
|
685 |
-
*
|
686 |
-
*
|
687 |
-
|
688 |
-
|
689 |
-
|
690 |
-
|
691 |
-
|
692 |
-
|
693 |
-
|
694 |
-
|
695 |
-
|
696 |
-
$this->
|
697 |
-
}
|
698 |
-
|
699 |
-
|
700 |
-
|
701 |
-
|
702 |
-
|
703 |
-
|
704 |
-
|
705 |
-
|
706 |
-
|
707 |
-
$
|
708 |
-
}
|
709 |
-
|
710 |
-
|
711 |
-
|
712 |
-
|
713 |
-
}
|
714 |
-
|
715 |
-
|
716 |
-
|
717 |
-
|
718 |
-
|
719 |
-
|
720 |
-
|
721 |
-
|
722 |
-
|
723 |
-
|
724 |
-
|
725 |
-
|
726 |
-
|
727 |
-
|
728 |
-
|
729 |
-
|
730 |
-
|
731 |
-
|
732 |
-
|
733 |
-
|
734 |
-
|
735 |
-
|
736 |
-
|
737 |
-
|
738 |
-
|
739 |
-
|
740 |
-
|
741 |
-
|
742 |
-
|
743 |
-
|
744 |
-
|
745 |
-
|
746 |
-
|
747 |
-
|
748 |
-
|
749 |
-
|
750 |
-
|
751 |
-
|
752 |
-
|
753 |
-
|
754 |
-
}
|
755 |
-
|
756 |
-
|
757 |
-
|
758 |
-
|
759 |
-
|
760 |
-
|
761 |
-
|
762 |
-
|
763 |
-
|
764 |
-
|
765 |
-
|
766 |
-
|
767 |
-
|
768 |
-
|
769 |
-
|
770 |
-
|
771 |
-
|
772 |
-
|
773 |
-
|
774 |
-
|
775 |
-
|
776 |
-
|
777 |
-
|
778 |
-
|
779 |
-
|
780 |
-
|
781 |
-
|
782 |
-
|
783 |
-
|
784 |
-
|
785 |
-
|
786 |
-
|
787 |
-
|
788 |
-
|
789 |
-
|
790 |
-
|
791 |
-
|
792 |
-
|
793 |
-
|
794 |
-
|
795 |
-
|
796 |
-
|
797 |
-
|
798 |
-
|
799 |
-
|
800 |
-
|
801 |
-
|
802 |
-
|
803 |
-
|
804 |
-
|
805 |
-
|
806 |
-
|
807 |
-
|
808 |
-
|
809 |
-
|
810 |
-
|
811 |
-
|
812 |
-
|
813 |
-
|
814 |
-
|
815 |
-
|
816 |
-
|
817 |
-
|
818 |
-
|
819 |
-
|
820 |
-
|
821 |
-
|
822 |
-
|
823 |
-
|
824 |
-
|
825 |
-
|
826 |
-
|
827 |
-
|
828 |
-
|
829 |
-
|
830 |
-
|
831 |
-
|
832 |
-
private
|
833 |
-
|
834 |
-
|
835 |
-
|
836 |
-
|
837 |
-
|
838 |
-
|
839 |
-
|
840 |
-
|
841 |
-
|
842 |
-
|
843 |
-
|
844 |
-
|
845 |
-
|
846 |
-
|
847 |
-
|
848 |
-
|
849 |
-
|
850 |
-
|
851 |
-
|
852 |
-
|
853 |
-
|
854 |
-
|
855 |
-
function
|
856 |
-
|
857 |
-
}
|
858 |
-
|
859 |
-
function
|
860 |
-
|
861 |
-
}
|
862 |
-
|
863 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/** For old style coders */
|
4 |
+
function tnp_register_block($dir) {
|
5 |
+
return TNP_Composer::register_block($dir);
|
6 |
+
}
|
7 |
+
|
8 |
+
/**
|
9 |
+
* Generates and HTML button for email using the values found on $options and
|
10 |
+
* prefixed by $prefix, with the standard syntax of NewsletterFields::button().
|
11 |
+
*
|
12 |
+
* @param array $options
|
13 |
+
* @param string $prefix
|
14 |
+
* @return string
|
15 |
+
*/
|
16 |
+
function tnpc_button($options, $prefix = 'button') {
|
17 |
+
return TNP_Composer::button($options, $prefix);
|
18 |
+
}
|
19 |
+
|
20 |
+
class TNP_Composer {
|
21 |
+
|
22 |
+
static $block_dirs = array();
|
23 |
+
|
24 |
+
static function register_block($dir) {
|
25 |
+
// Checks
|
26 |
+
$dir = realpath($dir);
|
27 |
+
if (!$dir) {
|
28 |
+
$error = new WP_Error('1', 'Seems not a valid path: ' . $dir);
|
29 |
+
NewsletterEmails::instance()->logger->error($error);
|
30 |
+
return $error;
|
31 |
+
}
|
32 |
+
|
33 |
+
$dir = wp_normalize_path($dir);
|
34 |
+
|
35 |
+
if (!file_exists($dir . '/block.php')) {
|
36 |
+
$error = new WP_Error('1', 'block.php missing on folder ' . $dir);
|
37 |
+
NewsletterEmails::instance()->logger->error($error);
|
38 |
+
return $error;
|
39 |
+
}
|
40 |
+
|
41 |
+
self::$block_dirs[] = $dir;
|
42 |
+
return true;
|
43 |
+
}
|
44 |
+
|
45 |
+
/**
|
46 |
+
* @param string $open
|
47 |
+
* @param string $inner
|
48 |
+
* @param string $close
|
49 |
+
* @param string[] $markers
|
50 |
+
*
|
51 |
+
* @return string
|
52 |
+
*/
|
53 |
+
static function wrap_html_element($open, $inner, $close, $markers = array('<!-- tnp -->', '<!-- /tnp -->')) {
|
54 |
+
|
55 |
+
return $open . $markers[0] . $inner . $markers[1] . $close;
|
56 |
+
}
|
57 |
+
|
58 |
+
/**
|
59 |
+
* @param string $block
|
60 |
+
* @param string[] $markers
|
61 |
+
*
|
62 |
+
* @return string
|
63 |
+
*/
|
64 |
+
static function unwrap_html_element($block, $markers = array('<!-- tnp -->', '<!-- /tnp -->')) {
|
65 |
+
if (self::_has_markers($block, $markers)) {
|
66 |
+
self::_escape_markers($markers);
|
67 |
+
$pattern = sprintf('/%s(.*?)%s/s', $markers[0], $markers[1]);
|
68 |
+
|
69 |
+
$matches = array();
|
70 |
+
preg_match($pattern, $block, $matches);
|
71 |
+
|
72 |
+
return $matches[1];
|
73 |
+
}
|
74 |
+
|
75 |
+
return $block;
|
76 |
+
}
|
77 |
+
|
78 |
+
/**
|
79 |
+
* @param string $block
|
80 |
+
* @param string[] $markers
|
81 |
+
*
|
82 |
+
* @return bool
|
83 |
+
*/
|
84 |
+
private static function _has_markers($block, $markers = array('<!-- tnp -->', '<!-- /tnp -->')) {
|
85 |
+
|
86 |
+
self::_escape_markers($markers);
|
87 |
+
|
88 |
+
$pattern = sprintf('/%s(.*?)%s/s', $markers[0], $markers[1]);
|
89 |
+
|
90 |
+
return preg_match($pattern, $block);
|
91 |
+
}
|
92 |
+
|
93 |
+
/**
|
94 |
+
* Sources:
|
95 |
+
* - https://webdesign.tutsplus.com/tutorials/creating-a-future-proof-responsive-email-without-media-queries--cms-23919
|
96 |
+
*
|
97 |
+
* @param type $email
|
98 |
+
* @return type
|
99 |
+
*/
|
100 |
+
static function get_html_open($email) {
|
101 |
+
$open = "<!DOCTYPE html>\n";
|
102 |
+
$open .= "<html xmlns=\"https://www.w3.org/1999/xhtml\" xmlns:o=\"urn:schemas-microsoft-com:office:office\">\n<head>\n<title>{email_subject}</title>\n";
|
103 |
+
$open .= "<meta charset=\"utf-8\">\n<meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\n";
|
104 |
+
|
105 |
+
$open .= '<!--[if !mso]><!-->' . "\n";
|
106 |
+
$open .= '<meta http-equiv="X-UA-Compatible" content="IE=edge" />' . "\n";
|
107 |
+
$open .= '<!--<![endif]-->' . "\n";
|
108 |
+
|
109 |
+
$open .= '<!--[if mso]>' . "\n";
|
110 |
+
;
|
111 |
+
$open .= '<style type="text/css">';
|
112 |
+
$open .= 'table {border-collapse:collapse;border-spacing:0;margin:0;}';
|
113 |
+
$open .= 'div, td {padding:0;}';
|
114 |
+
$open .= 'div {margin:0 !important;}';
|
115 |
+
$open .= '</style>';
|
116 |
+
$open .= "\n";
|
117 |
+
$open .= '<noscript>';
|
118 |
+
$open .= '<xml>';
|
119 |
+
$open .= '<o:OfficeDocumentSettings>';
|
120 |
+
$open .= '<o:PixelsPerInch>96</o:PixelsPerInch>';
|
121 |
+
$open .= '</o:OfficeDocumentSettings>';
|
122 |
+
$open .= '</xml>';
|
123 |
+
$open .= '</noscript>';
|
124 |
+
$open .= "\n";
|
125 |
+
$open .= '<![endif]-->';
|
126 |
+
$open .= "\n";
|
127 |
+
$open .= "<style type=\"text/css\">\n";
|
128 |
+
$open .= NewsletterEmails::instance()->get_composer_css();
|
129 |
+
$open .= "\n</style>\n";
|
130 |
+
$open .= "</head>\n";
|
131 |
+
$open .= '<body style="margin: 0; padding: 0; line-height: normal; word-spacing: normal;" dir="' . (is_rtl() ? 'rtl' : 'ltr') . '">';
|
132 |
+
$open .= "\n";
|
133 |
+
$open .= self::get_html_preheader($email);
|
134 |
+
|
135 |
+
return $open;
|
136 |
+
}
|
137 |
+
|
138 |
+
static private function get_html_preheader($email) {
|
139 |
+
|
140 |
+
if (empty($email->options['preheader'])) {
|
141 |
+
return "";
|
142 |
+
}
|
143 |
+
|
144 |
+
$preheader_text = $email->options['preheader'];
|
145 |
+
$html = "<div style=\"display:none;font-size:1px;color:#ffffff;line-height:1px;max-height:0px;max-width:0px;opacity:0;overflow:hidden;\">$preheader_text</div>";
|
146 |
+
$html .= "\n";
|
147 |
+
|
148 |
+
return $html;
|
149 |
+
}
|
150 |
+
|
151 |
+
static function get_html_close($email) {
|
152 |
+
return "</body>\n</html>";
|
153 |
+
}
|
154 |
+
|
155 |
+
/**
|
156 |
+
*
|
157 |
+
* @param TNP_Email $email
|
158 |
+
* @return string
|
159 |
+
*/
|
160 |
+
static function get_main_wrapper_open($email) {
|
161 |
+
if (!isset($email->options['composer_background']) || $email->options['composer_background'] == 'inherit') {
|
162 |
+
$bgcolor = '';
|
163 |
+
} else {
|
164 |
+
$bgcolor = $email->options['composer_background'];
|
165 |
+
}
|
166 |
+
|
167 |
+
return "\n<table cellpadding='0' cellspacing='0' border='0' width='100%'>\n" .
|
168 |
+
"<tr>\n" .
|
169 |
+
"<td bgcolor='$bgcolor' valign='top'><!-- tnp -->";
|
170 |
+
}
|
171 |
+
|
172 |
+
/**
|
173 |
+
*
|
174 |
+
* @param TNP_Email $email
|
175 |
+
* @return string
|
176 |
+
*/
|
177 |
+
static function get_main_wrapper_close($email) {
|
178 |
+
return "\n<!-- /tnp -->\n" .
|
179 |
+
"</td>\n" .
|
180 |
+
"</tr>\n" .
|
181 |
+
"</table>\n\n";
|
182 |
+
}
|
183 |
+
|
184 |
+
/**
|
185 |
+
* Remove <doctype>, <body> and unnecessary envelopes for editing with composer
|
186 |
+
*
|
187 |
+
* @param string $html_email
|
188 |
+
*
|
189 |
+
* @return string
|
190 |
+
*/
|
191 |
+
static function unwrap_email($html_email) {
|
192 |
+
|
193 |
+
if (self::_has_markers($html_email)) {
|
194 |
+
$html_email = self::unwrap_html_element($html_email);
|
195 |
+
} else {
|
196 |
+
//KEEP FOR OLD EMAIL COMPATIBILITY
|
197 |
+
// Extracts only the body part
|
198 |
+
$x = strpos($html_email, '<body');
|
199 |
+
if ($x) {
|
200 |
+
$x = strpos($html_email, '>', $x);
|
201 |
+
$y = strpos($html_email, '</body>');
|
202 |
+
$html_email = substr($html_email, $x + 1, $y - $x - 1);
|
203 |
+
}
|
204 |
+
|
205 |
+
/* Cleans up uncorrectly stored newsletter bodies */
|
206 |
+
$html_email = preg_replace('/<style\s+.*?>.*?<\\/style>/is', '', $html_email);
|
207 |
+
$html_email = preg_replace('/<meta.*?>/', '', $html_email);
|
208 |
+
$html_email = preg_replace('/<title\s+.*?>.*?<\\/title>/i', '', $html_email);
|
209 |
+
$html_email = trim($html_email);
|
210 |
+
}
|
211 |
+
|
212 |
+
// Required since esc_html DOES NOT escape the HTML entities (apparently)
|
213 |
+
$html_email = str_replace('&', '&', $html_email);
|
214 |
+
$html_email = str_replace('"', '"', $html_email);
|
215 |
+
$html_email = str_replace('<', '<', $html_email);
|
216 |
+
$html_email = str_replace('>', '>', $html_email);
|
217 |
+
|
218 |
+
return $html_email;
|
219 |
+
}
|
220 |
+
|
221 |
+
private static function _escape_markers(&$markers) {
|
222 |
+
$markers[0] = str_replace('/', '\/', $markers[0]);
|
223 |
+
$markers[1] = str_replace('/', '\/', $markers[1]);
|
224 |
+
}
|
225 |
+
|
226 |
+
/**
|
227 |
+
* Using the data collected inside $controls (and submitted by a form containing the
|
228 |
+
* composer fields), updates the email. The message body is completed with doctype,
|
229 |
+
* head, style and the main wrapper.
|
230 |
+
*
|
231 |
+
* @param TNP_Email $email
|
232 |
+
* @param NewsletterControls $controls
|
233 |
+
*/
|
234 |
+
static function update_email($email, $controls) {
|
235 |
+
if (isset($controls->data['subject'])) {
|
236 |
+
$email->subject = $controls->data['subject'];
|
237 |
+
}
|
238 |
+
|
239 |
+
// They should be only composer options
|
240 |
+
foreach ($controls->data as $name => $value) {
|
241 |
+
if (strpos($name, 'options_') === 0) {
|
242 |
+
$email->options[substr($name, 8)] = $value;
|
243 |
+
}
|
244 |
+
}
|
245 |
+
|
246 |
+
//if (isset($controls->data['preheader'])) {
|
247 |
+
// $email->options['preheader'] = $controls->data['preheader'];
|
248 |
+
//}
|
249 |
+
|
250 |
+
$email->editor = NewsletterEmails::EDITOR_COMPOSER;
|
251 |
+
|
252 |
+
$email->message = self::get_html_open($email) . self::get_main_wrapper_open($email) .
|
253 |
+
$controls->data['message'] . self::get_main_wrapper_close($email) . self::get_html_close($email);
|
254 |
+
}
|
255 |
+
|
256 |
+
/**
|
257 |
+
* Prepares a controls object injecting the relevant fields from an email
|
258 |
+
* which cannot be directly used by controls. If $email is null or missing,
|
259 |
+
* $controls is prepared with default values.
|
260 |
+
*
|
261 |
+
* @param NewsletterControls $controls
|
262 |
+
* @param TNP_Email $email
|
263 |
+
*/
|
264 |
+
static function prepare_controls($controls, $email = null) {
|
265 |
+
|
266 |
+
// Controls for a new email (which actually does not exist yet
|
267 |
+
if (!empty($email)) {
|
268 |
+
|
269 |
+
foreach ($email->options as $name => $value) {
|
270 |
+
$controls->data['options_' . $name] = $value;
|
271 |
+
}
|
272 |
+
|
273 |
+
$controls->data['message'] = TNP_Composer::unwrap_email($email->message);
|
274 |
+
$controls->data['subject'] = $email->subject;
|
275 |
+
}
|
276 |
+
|
277 |
+
if (!empty($email->options['sender_email'])) {
|
278 |
+
$controls->data['sender_email'] = $email->options['sender_email'];
|
279 |
+
} else {
|
280 |
+
$controls->data['sender_email'] = Newsletter::instance()->options['sender_email'];
|
281 |
+
}
|
282 |
+
|
283 |
+
if (!empty($email->options['sender_name'])) {
|
284 |
+
$controls->data['sender_name'] = $email->options['sender_name'];
|
285 |
+
} else {
|
286 |
+
$controls->data['sender_name'] = Newsletter::instance()->options['sender_name'];
|
287 |
+
}
|
288 |
+
|
289 |
+
$controls->data = array_merge(TNP_Composer::get_global_style_defaults(), $controls->data);
|
290 |
+
}
|
291 |
+
|
292 |
+
/**
|
293 |
+
* Extract inline edited post field from inline_edit_list[]
|
294 |
+
*
|
295 |
+
* @param array $inline_edit_list
|
296 |
+
* @param string $field_type
|
297 |
+
* @param int $post_id
|
298 |
+
*
|
299 |
+
* @return string
|
300 |
+
*/
|
301 |
+
static function get_edited_inline_post_field($inline_edit_list, $field_type, $post_id) {
|
302 |
+
|
303 |
+
foreach ($inline_edit_list as $edit) {
|
304 |
+
if ($edit['type'] == $field_type && $edit['post_id'] == $post_id) {
|
305 |
+
return $edit['content'];
|
306 |
+
}
|
307 |
+
}
|
308 |
+
|
309 |
+
return '';
|
310 |
+
}
|
311 |
+
|
312 |
+
/**
|
313 |
+
* Check if inline_edit_list[] have inline edit field for specific post
|
314 |
+
*
|
315 |
+
* @param array $inline_edit_list
|
316 |
+
* @param string $field_type
|
317 |
+
* @param int $post_id
|
318 |
+
*
|
319 |
+
* @return bool
|
320 |
+
*/
|
321 |
+
static function is_post_field_edited_inline($inline_edit_list, $field_type, $post_id) {
|
322 |
+
if (empty($inline_edit_list) || !is_array($inline_edit_list)) {
|
323 |
+
return false;
|
324 |
+
}
|
325 |
+
foreach ($inline_edit_list as $edit) {
|
326 |
+
if ($edit['type'] == $field_type && $edit['post_id'] == $post_id) {
|
327 |
+
return true;
|
328 |
+
}
|
329 |
+
}
|
330 |
+
|
331 |
+
return false;
|
332 |
+
}
|
333 |
+
|
334 |
+
/**
|
335 |
+
* Creates the HTML for a button extrating from the options, with the provided prefix, the button attributes:
|
336 |
+
*
|
337 |
+
* - [prefix]_url The button URL
|
338 |
+
* - [prefix]_font_family
|
339 |
+
* - [prefix]_font_size
|
340 |
+
* - [prefix]_font_weight
|
341 |
+
* - [prefix]_label
|
342 |
+
* - [prefix]_font_color The label color
|
343 |
+
* - [prefix]_background The button color
|
344 |
+
*
|
345 |
+
* TODO: Add radius and possiblt the alignment
|
346 |
+
*
|
347 |
+
* @param array $options
|
348 |
+
* @param string $prefix
|
349 |
+
* @return string
|
350 |
+
*/
|
351 |
+
static function button($options, $prefix = 'button') {
|
352 |
+
|
353 |
+
if (empty($options[$prefix . '_label'])) {
|
354 |
+
return;
|
355 |
+
}
|
356 |
+
$defaults = [
|
357 |
+
$prefix . '_url' => '#',
|
358 |
+
$prefix . '_font_family' => 'Helvetica, Arial, sans-serif',
|
359 |
+
$prefix . '_font_color' => '#ffffff',
|
360 |
+
$prefix . '_font_weight' => 'bold',
|
361 |
+
$prefix . '_font_size' => 20,
|
362 |
+
$prefix . '_background' => '#256F9C',
|
363 |
+
$prefix . '_align' => 'center'
|
364 |
+
];
|
365 |
+
|
366 |
+
$options = array_merge($defaults, array_filter($options));
|
367 |
+
|
368 |
+
$b = '<table border="0" cellpadding="0" cellspacing="0" role="presentation" style="margin: 0 auto"';
|
369 |
+
if (!empty($options[$prefix . '_align'])) {
|
370 |
+
$b .= ' align="' . esc_attr($options[$prefix . '_align']) . '"';
|
371 |
+
}
|
372 |
+
if (!empty($options[$prefix . '_width'])) {
|
373 |
+
$b .= ' width="' . esc_attr($options[$prefix . '_width']) . '"';
|
374 |
+
}
|
375 |
+
$b .= '>';
|
376 |
+
$b .= '<tr>';
|
377 |
+
$b .= '<td align="center" bgcolor="' . $options[$prefix . '_background'] . '" role="presentation" style="border:none;border-radius:3px;cursor:auto;mso-padding-alt:10px 25px;background:' . $options[$prefix . '_background'] . '" valign="middle">';
|
378 |
+
$b .= '<a href="' . $options[$prefix . '_url'] . '"';
|
379 |
+
$b .= ' style="display:inline-block;background:' . $options[$prefix . '_background'] . ';color:' . $options[$prefix . '_font_color'] . ';font-family:' . $options[$prefix . '_font_family'] . ';font-size:' . $options[$prefix . '_font_size'] . 'px;font-weight:' . $options[$prefix . '_font_weight'] . ';line-height:120%;margin:0;text-decoration:none;text-transform:none;padding:10px 25px;mso-padding-alt:0px;border-radius:3px;"';
|
380 |
+
$b .= ' target="_blank">';
|
381 |
+
$b .= $options[$prefix . '_label'];
|
382 |
+
$b .= '</a>';
|
383 |
+
$b .= '</td></tr></table>';
|
384 |
+
return $b;
|
385 |
+
}
|
386 |
+
|
387 |
+
/**
|
388 |
+
* Generates an IMG tag, linked if the media has an URL.
|
389 |
+
*
|
390 |
+
* @param TNP_Media $media
|
391 |
+
* @param string $style
|
392 |
+
* @return string
|
393 |
+
*/
|
394 |
+
static function image($media, $attr = []) {
|
395 |
+
|
396 |
+
$default_attrs = [
|
397 |
+
'style' => 'max-width: 100%; height: auto; display: inline-block',
|
398 |
+
'class' => '',
|
399 |
+
'link-style' => 'text-decoration: none; display: inline-block',
|
400 |
+
'link-class' => null,
|
401 |
+
];
|
402 |
+
|
403 |
+
$attr = array_merge($default_attrs, $attr);
|
404 |
+
|
405 |
+
//Class and style attribute are mutually exclusive.
|
406 |
+
//Class take priority to style because classes will transform to inline style inside block rendering operation
|
407 |
+
if (!empty($attr['inline-class'])) {
|
408 |
+
$styling = ' inline-class="' . esc_attr($attr['inline-class']) . '" ';
|
409 |
+
} else {
|
410 |
+
$styling = ' style="' . esc_attr($attr['style']) . '" ';
|
411 |
+
}
|
412 |
+
|
413 |
+
if (!empty($attr['class'])) {
|
414 |
+
$styling .= ' class="' . esc_attr($attr['class']) . '" ';
|
415 |
+
}
|
416 |
+
|
417 |
+
//Class and style attribute are mutually exclusive.
|
418 |
+
//Class take priority to style because classes will transform to inline style inside block rendering operation
|
419 |
+
if (!empty($attr['link-class'])) {
|
420 |
+
$link_styling = ' inline-class="' . esc_attr($attr['link-class']) . '" ';
|
421 |
+
} else {
|
422 |
+
$link_styling = ' style="' . esc_attr($attr['link-style']) . '" ';
|
423 |
+
}
|
424 |
+
|
425 |
+
$b = '';
|
426 |
+
if ($media->link) {
|
427 |
+
$b .= '<a href="' . esc_attr($media->link) . '" target="_blank" rel="noopener nofollow" style="display: inline-block; font-size: 0; text-decoration: none; line-height: normal!important">';
|
428 |
+
} else {
|
429 |
+
// The span grants images are not upscaled when fluid (two columns posts block)
|
430 |
+
$b .= '<span style="display: inline-block; font-size: 0; text-decoration: none; line-height: normal!important">';
|
431 |
+
}
|
432 |
+
if ($media) {
|
433 |
+
$b .= '<img src="' . esc_attr($media->url) . '" width="' . esc_attr($media->width) . '"';
|
434 |
+
if ($media->height) {
|
435 |
+
$b .= ' height="' . esc_attr($media->height) . '"';
|
436 |
+
}
|
437 |
+
$b .= ' alt="' . esc_attr($media->alt) . '"'
|
438 |
+
. ' border="0"'
|
439 |
+
. ' style="display: inline-block; max-width: 100%!important; padding: 0; border: 0;"'
|
440 |
+
. ' class="' . esc_attr($attr['class']) . '" '
|
441 |
+
. '>';
|
442 |
+
}
|
443 |
+
|
444 |
+
if ($media->link) {
|
445 |
+
$b .= '</a>';
|
446 |
+
} else {
|
447 |
+
$b .= '</span>';
|
448 |
+
}
|
449 |
+
|
450 |
+
return $b;
|
451 |
+
}
|
452 |
+
|
453 |
+
/**
|
454 |
+
* Returns a WP media ID for the specified post (or false if nothing can be found)
|
455 |
+
* looking for the featured image or, if missing, taking the first media in the gallery and
|
456 |
+
* if again missing, searching the first reference to a media in the post content.
|
457 |
+
*
|
458 |
+
* The media ID is not checked for real existance of the associated attachment.
|
459 |
+
*
|
460 |
+
* @param int $post_id
|
461 |
+
* @return int
|
462 |
+
*/
|
463 |
+
static function get_post_thumbnail_id($post_id) {
|
464 |
+
if (is_object($post_id)) {
|
465 |
+
$post_id = $post_id->ID;
|
466 |
+
}
|
467 |
+
|
468 |
+
// Find a media id to be used as featured image
|
469 |
+
$media_id = get_post_thumbnail_id($post_id);
|
470 |
+
if (!empty($media_id)) {
|
471 |
+
return $media_id;
|
472 |
+
}
|
473 |
+
|
474 |
+
$attachments = get_children(array('numberpost' => 1, 'post_parent' => $post_id, 'post_status' => 'inherit', 'post_type' => 'attachment', 'post_mime_type' => 'image', 'order' => 'ASC', 'orderby' => 'menu_order'));
|
475 |
+
if (!empty($attachments)) {
|
476 |
+
foreach ($attachments as $id => &$attachment) {
|
477 |
+
return $id;
|
478 |
+
}
|
479 |
+
}
|
480 |
+
|
481 |
+
$post = get_post($post_id);
|
482 |
+
|
483 |
+
$r = preg_match('/wp-image-(\d+)/', $post->post_content, $matches);
|
484 |
+
if ($matches) {
|
485 |
+
return (int) $matches[1];
|
486 |
+
}
|
487 |
+
|
488 |
+
return false;
|
489 |
+
}
|
490 |
+
|
491 |
+
/**
|
492 |
+
* Builds a TNP_Media object to be used in newsletters from a WP media/attachement ID. The returned
|
493 |
+
* media has a size which best match the one requested (this is the standard WP behavior, plugins
|
494 |
+
* could change it).
|
495 |
+
*
|
496 |
+
* @param int $media_id
|
497 |
+
* @param array $size
|
498 |
+
* @return \TNP_Media
|
499 |
+
*/
|
500 |
+
function get_media($media_id, $size) {
|
501 |
+
$src = wp_get_attachment_image_src($media_id, $size);
|
502 |
+
if (!$src) {
|
503 |
+
return null;
|
504 |
+
}
|
505 |
+
$media = new TNP_Media();
|
506 |
+
$media->id = $media_id;
|
507 |
+
$media->url = $src[0];
|
508 |
+
$media->width = $src[1];
|
509 |
+
$media->height = $src[2];
|
510 |
+
return $media;
|
511 |
+
}
|
512 |
+
|
513 |
+
static function post_content($post) {
|
514 |
+
$content = $post->post_content;
|
515 |
+
$content = wpautop($content);
|
516 |
+
if (true || $options['enable shortcodes']) {
|
517 |
+
remove_shortcode('gallery');
|
518 |
+
add_shortcode('gallery', 'tnp_gallery_shortcode');
|
519 |
+
$content = do_shortcode($content);
|
520 |
+
}
|
521 |
+
$content = str_replace('<p>', '<p class="paragraph">', $content);
|
522 |
+
|
523 |
+
$selected_images = array();
|
524 |
+
if (preg_match_all('/<img [^>]+>/', $content, $matches)) {
|
525 |
+
foreach ($matches[0] as $image) {
|
526 |
+
if (preg_match('/wp-image-([0-9]+)/i', $image, $class_id) && ( $attachment_id = absint($class_id[1]) )) {
|
527 |
+
$selected_images[$image] = $attachment_id;
|
528 |
+
}
|
529 |
+
}
|
530 |
+
}
|
531 |
+
|
532 |
+
foreach ($selected_images as $image => $attachment_id) {
|
533 |
+
$src = tnp_media_resize($attachment_id, array(600, 0));
|
534 |
+
if (is_wp_error($src)) {
|
535 |
+
continue;
|
536 |
+
}
|
537 |
+
$content = str_replace($image, '<img src="' . $src . '" width="600" style="max-width: 100%">', $content);
|
538 |
+
}
|
539 |
+
|
540 |
+
return $content;
|
541 |
+
}
|
542 |
+
|
543 |
+
static function get_global_style_defaults() {
|
544 |
+
return [
|
545 |
+
'options_composer_title_font_family' => 'Verdana, Geneva, sans-serif',
|
546 |
+
'options_composer_title_font_size' => 32,
|
547 |
+
'options_composer_title_font_weight' => 'normal',
|
548 |
+
'options_composer_title_font_color' => '#222222',
|
549 |
+
'options_composer_text_font_family' => 'Verdana, Geneva, sans-serif',
|
550 |
+
'options_composer_text_font_size' => 16,
|
551 |
+
'options_composer_text_font_weight' => 'normal',
|
552 |
+
'options_composer_text_font_color' => '#222222',
|
553 |
+
'options_composer_button_font_family' => 'Verdana, Geneva, sans-serif',
|
554 |
+
'options_composer_button_font_size' => 16,
|
555 |
+
'options_composer_button_font_weight' => 'normal',
|
556 |
+
'options_composer_button_font_color' => '#FFFFFF',
|
557 |
+
'options_composer_button_background_color' => '#256F9C',
|
558 |
+
'options_composer_background' => '#FFFFFF',
|
559 |
+
'options_composer_block_background' => '#FFFFFF',
|
560 |
+
];
|
561 |
+
}
|
562 |
+
|
563 |
+
/**
|
564 |
+
* Inspired by: https://webdesign.tutsplus.com/tutorials/creating-a-future-proof-responsive-email-without-media-queries--cms-23919
|
565 |
+
* @param string[] $items
|
566 |
+
* @param array $attrs
|
567 |
+
* @return string
|
568 |
+
*/
|
569 |
+
static function grid($items = [], $attrs = []) {
|
570 |
+
$attrs = wp_parse_args($attrs, ['width' => 600, 'columns' => 2, 'padding' => 10, 'responsive' => true]);
|
571 |
+
$width = (int) $attrs['width'];
|
572 |
+
$columns = (int) $attrs['columns'];
|
573 |
+
$padding = (int) $attrs['padding'];
|
574 |
+
$column_width = $width / $columns;
|
575 |
+
$td_width = 100 / $columns;
|
576 |
+
$chunks = array_chunk($items, $columns);
|
577 |
+
|
578 |
+
if ($attrs['responsive']) {
|
579 |
+
|
580 |
+
$e = '<div style="text-align:center;font-size:0;">';
|
581 |
+
foreach ($chunks as &$chunk) {
|
582 |
+
|
583 |
+
$e .= '<!--[if mso]><table role="presentation" width="100%"><tr><![endif]-->';
|
584 |
+
foreach ($chunk as &$item) {
|
585 |
+
$e .= '<!--[if mso]><td width="' . $td_width . '%" style="width:' . $td_width . '%;padding:' . $padding . 'px" valign="top"><![endif]-->';
|
586 |
+
|
587 |
+
$e .= '<div class="max-width-100" style="width:100%;max-width:' . $column_width . 'px;display:inline-block;vertical-align: top;box-sizing: border-box;">';
|
588 |
+
|
589 |
+
// This element to add padding without deal with border-box not well supported
|
590 |
+
$e .= '<div style="padding:' . $padding . 'px;">';
|
591 |
+
$e .= $item;
|
592 |
+
$e .= '</div>';
|
593 |
+
$e .= '</div>';
|
594 |
+
|
595 |
+
$e .= '<!--[if mso]></td><![endif]-->';
|
596 |
+
}
|
597 |
+
$e .= '<!--[if mso]></tr></table><![endif]-->';
|
598 |
+
$e .= '</div>';
|
599 |
+
}
|
600 |
+
return $e;
|
601 |
+
} else {
|
602 |
+
$e = '<table role="presentation" width="100%" cellspacing="0" cellpadding="0" border="0" style="width: 100%; max-width: 100%!important">';
|
603 |
+
foreach ($chunks as &$chunk) {
|
604 |
+
$e .= '<tr>';
|
605 |
+
foreach ($chunk as &$item) {
|
606 |
+
$e .= '<td width="' . $td_width . '%" style="width:' . $td_width . '%; padding:' . $padding . 'px" valign="top">';
|
607 |
+
$e .= $item;
|
608 |
+
$e .= '</td>';
|
609 |
+
}
|
610 |
+
$e .= '</tr>';
|
611 |
+
}
|
612 |
+
$e .= '</table>';
|
613 |
+
return $e;
|
614 |
+
}
|
615 |
+
}
|
616 |
+
|
617 |
+
static function get_text_style($options, $prefix, $composer, $attrs = []) {
|
618 |
+
return self::get_style($options, $prefix, $composer, 'text', $attrs);
|
619 |
+
}
|
620 |
+
|
621 |
+
static function get_title_style($options, $prefix, $composer, $attrs = []) {
|
622 |
+
return self::get_style($options, $prefix, $composer, 'title', $attrs);
|
623 |
+
}
|
624 |
+
|
625 |
+
static function get_style($options, $prefix, $composer, $type = 'text', $attrs = []) {
|
626 |
+
$style = new TNP_Style();
|
627 |
+
$scale = 1.0;
|
628 |
+
if (!empty($attrs['scale'])) {
|
629 |
+
$scale = (float) $attrs['scale'];
|
630 |
+
}
|
631 |
+
if (!empty($prefix))
|
632 |
+
$prefix .= '_';
|
633 |
+
|
634 |
+
$style->font_family = empty($options[$prefix . 'font_family']) ? $composer[$type . '_font_family'] : $options[$prefix . 'font_family'];
|
635 |
+
$style->font_size = empty($options[$prefix . 'font_size']) ? round($composer[$type . '_font_size'] * $scale) : $options[$prefix . 'font_size'];
|
636 |
+
$style->font_color = empty($options[$prefix . 'font_color']) ? $composer[$type . '_font_color'] : $options[$prefix . 'font_color'];
|
637 |
+
$style->font_weight = empty($options[$prefix . 'font_weight']) ? $composer[$type . '_font_weight'] : $options[$prefix . 'font_weight'];
|
638 |
+
if ($type === 'button') {
|
639 |
+
$style->background = empty($options[$prefix . 'background']) ? $composer[$type . '_background_color'] : $options[$prefix . 'background'];
|
640 |
+
}
|
641 |
+
return $style;
|
642 |
+
}
|
643 |
+
|
644 |
+
}
|
645 |
+
|
646 |
+
class TNP_Style {
|
647 |
+
|
648 |
+
var $font_family;
|
649 |
+
var $font_size;
|
650 |
+
var $font_weight;
|
651 |
+
var $font_color;
|
652 |
+
var $background;
|
653 |
+
|
654 |
+
function echo_css($scale = 1.0) {
|
655 |
+
echo 'font-size: ', round($this->font_size * $scale), 'px;';
|
656 |
+
echo 'font-family: ', $this->font_family, ';';
|
657 |
+
echo 'font-weight: ', $this->font_weight, ';';
|
658 |
+
echo 'color: ', $this->font_color, ';';
|
659 |
+
}
|
660 |
+
|
661 |
+
}
|
662 |
+
|
663 |
+
/**
|
664 |
+
* Generate multicolumn and responsive html template for email.
|
665 |
+
* Initialize class with max columns per row and start to add cells.
|
666 |
+
*/
|
667 |
+
class TNP_Composer_Grid_System {
|
668 |
+
|
669 |
+
/**
|
670 |
+
* @var TNP_Composer_Grid_Row[]
|
671 |
+
*/
|
672 |
+
private $rows;
|
673 |
+
|
674 |
+
/**
|
675 |
+
* @var int
|
676 |
+
*/
|
677 |
+
private $cells_per_row;
|
678 |
+
|
679 |
+
/**
|
680 |
+
* @var int
|
681 |
+
*/
|
682 |
+
private $cells_counter;
|
683 |
+
|
684 |
+
/**
|
685 |
+
* TNP_Composer_Grid_System constructor.
|
686 |
+
*
|
687 |
+
* @param int $columns_per_row Max columns per row
|
688 |
+
*/
|
689 |
+
public function __construct($columns_per_row) {
|
690 |
+
$this->cells_per_row = $columns_per_row;
|
691 |
+
$this->cells_counter = 0;
|
692 |
+
$this->rows = [];
|
693 |
+
}
|
694 |
+
|
695 |
+
public function __toString() {
|
696 |
+
return $this->render();
|
697 |
+
}
|
698 |
+
|
699 |
+
/**
|
700 |
+
* Add cell to grid
|
701 |
+
*
|
702 |
+
* @param TNP_Composer_Grid_Cell $cell
|
703 |
+
*/
|
704 |
+
public function add_cell($cell) {
|
705 |
+
|
706 |
+
if ($this->cells_counter % $this->cells_per_row === 0) {
|
707 |
+
$this->add_row(new TNP_Composer_Grid_Row());
|
708 |
+
}
|
709 |
+
|
710 |
+
$row_idx = (int) floor($this->cells_counter / $this->cells_per_row);
|
711 |
+
$this->rows[$row_idx]->add_cell($cell);
|
712 |
+
$this->cells_counter++;
|
713 |
+
}
|
714 |
+
|
715 |
+
private function add_row($row) {
|
716 |
+
$this->rows[] = $row;
|
717 |
+
}
|
718 |
+
|
719 |
+
public function render() {
|
720 |
+
|
721 |
+
$str = '';
|
722 |
+
foreach ($this->rows as $row) {
|
723 |
+
$str .= $row->render();
|
724 |
+
}
|
725 |
+
|
726 |
+
return $str;
|
727 |
+
}
|
728 |
+
|
729 |
+
}
|
730 |
+
|
731 |
+
/**
|
732 |
+
* Class TNP_Composer_Grid_Row
|
733 |
+
*/
|
734 |
+
class TNP_Composer_Grid_Row {
|
735 |
+
|
736 |
+
/**
|
737 |
+
* @var TNP_Composer_Grid_Cell[]
|
738 |
+
*/
|
739 |
+
private $cells;
|
740 |
+
|
741 |
+
public function __construct(...$cells) {
|
742 |
+
if (!empty($cells)) {
|
743 |
+
foreach ($cells as $cell) {
|
744 |
+
$this->add_cell($cell);
|
745 |
+
}
|
746 |
+
}
|
747 |
+
}
|
748 |
+
|
749 |
+
/**
|
750 |
+
* @param TNP_Composer_Grid_Cell $cell
|
751 |
+
*/
|
752 |
+
public function add_cell($cell) {
|
753 |
+
$this->cells[] = $cell;
|
754 |
+
}
|
755 |
+
|
756 |
+
public function render() {
|
757 |
+
$rendered_cells = '';
|
758 |
+
$column_percentage_width = round(100 / $this->cells_count(), 0, PHP_ROUND_HALF_DOWN) . '%';
|
759 |
+
foreach ($this->cells as $cell) {
|
760 |
+
$rendered_cells .= $cell->render(['width' => $column_percentage_width]);
|
761 |
+
}
|
762 |
+
|
763 |
+
$row_template = $this->get_template();
|
764 |
+
|
765 |
+
return str_replace('TNP_ROW_CONTENT_PH', $rendered_cells, $row_template);
|
766 |
+
}
|
767 |
+
|
768 |
+
private function cells_count() {
|
769 |
+
return count($this->cells);
|
770 |
+
}
|
771 |
+
|
772 |
+
private function get_template() {
|
773 |
+
return "<table border='0' cellpadding='0' cellspacing='0' width='100%'><tbody><tr><td>TNP_ROW_CONTENT_PH</td></tr></tbody></table>";
|
774 |
+
}
|
775 |
+
|
776 |
+
}
|
777 |
+
|
778 |
+
/**
|
779 |
+
* Class TNP_Composer_Grid_Cell
|
780 |
+
*/
|
781 |
+
class TNP_Composer_Grid_Cell {
|
782 |
+
|
783 |
+
/**
|
784 |
+
* @var string
|
785 |
+
*/
|
786 |
+
private $content;
|
787 |
+
|
788 |
+
/**
|
789 |
+
* @var array
|
790 |
+
*/
|
791 |
+
public $args;
|
792 |
+
|
793 |
+
public function __construct($content = null, $args = []) {
|
794 |
+
$default_args = [
|
795 |
+
'width' => '100%',
|
796 |
+
'class' => '',
|
797 |
+
'align' => 'left',
|
798 |
+
'valign' => 'top'
|
799 |
+
];
|
800 |
+
|
801 |
+
$this->args = array_merge($default_args, $args);
|
802 |
+
|
803 |
+
$this->content = $content ? $content : '';
|
804 |
+
}
|
805 |
+
|
806 |
+
public function add_content($content) {
|
807 |
+
$this->content .= $content;
|
808 |
+
}
|
809 |
+
|
810 |
+
public function render($args) {
|
811 |
+
$this->args = array_merge($this->args, $args);
|
812 |
+
|
813 |
+
$column_template = $this->get_template();
|
814 |
+
$column = str_replace(
|
815 |
+
[
|
816 |
+
'TNP_ALIGN_PH',
|
817 |
+
'TNP_VALIGN_PH',
|
818 |
+
'TNP_WIDTH_PH',
|
819 |
+
'TNP_CLASS_PH',
|
820 |
+
'TNP_COLUMN_CONTENT_PH'
|
821 |
+
], [
|
822 |
+
$this->args['align'],
|
823 |
+
$this->args['valign'],
|
824 |
+
$this->args['width'],
|
825 |
+
$this->args['class'],
|
826 |
+
$this->content
|
827 |
+
], $column_template);
|
828 |
+
|
829 |
+
return $column;
|
830 |
+
}
|
831 |
+
|
832 |
+
private function get_template() {
|
833 |
+
return "<table border='0' cellpadding='0' cellspacing='0' width='TNP_WIDTH_PH' align='left' style='table-layout: fixed;' class='responsive'>
|
834 |
+
<tbody>
|
835 |
+
<tr>
|
836 |
+
<td border='0' style='padding: 20px 10px 40px;' align='TNP_ALIGN_PH' valign='TNP_VALIGN_PH' class='TNP_CLASS_PH'>
|
837 |
+
TNP_COLUMN_CONTENT_PH
|
838 |
+
</td>
|
839 |
+
</tr>
|
840 |
+
</tbody>
|
841 |
+
</table>";
|
842 |
+
}
|
843 |
+
|
844 |
+
}
|
845 |
+
|
846 |
+
class TNP_Composer_Component_Factory {
|
847 |
+
|
848 |
+
private $options;
|
849 |
+
|
850 |
+
/**
|
851 |
+
* TNP_Composer_Component_Factory constructor.
|
852 |
+
*
|
853 |
+
* @param Controller$controller
|
854 |
+
*/
|
855 |
+
public function __construct($controller) {
|
856 |
+
|
857 |
+
}
|
858 |
+
|
859 |
+
function heading() {
|
860 |
+
|
861 |
+
}
|
862 |
+
|
863 |
+
function paragraph() {
|
864 |
+
|
865 |
+
}
|
866 |
+
|
867 |
+
function link() {
|
868 |
+
|
869 |
+
}
|
870 |
+
|
871 |
+
function button() {
|
872 |
+
|
873 |
+
}
|
874 |
+
|
875 |
+
function image() {
|
876 |
+
|
877 |
+
}
|
878 |
+
|
879 |
+
}
|
includes/controls.php
CHANGED
@@ -1044,11 +1044,8 @@ class NewsletterControls {
|
|
1044 |
echo '<button class="button-primary" onclick="this.form.act.value=\'' . esc_attr($action) . '\'; return true;"/>', $label, '</button>';
|
1045 |
}
|
1046 |
}
|
1047 |
-
|
1048 |
-
|
1049 |
-
* @deprecated
|
1050 |
-
*/
|
1051 |
-
function button_confirm($action, $label, $message = '', $data = '') {
|
1052 |
$this->btn($action, $label, ['data' => $data, 'confirm' => $message]);
|
1053 |
}
|
1054 |
|
1044 |
echo '<button class="button-primary" onclick="this.form.act.value=\'' . esc_attr($action) . '\'; return true;"/>', $label, '</button>';
|
1045 |
}
|
1046 |
}
|
1047 |
+
|
1048 |
+
function button_confirm($action, $label, $message = true, $data = '') {
|
|
|
|
|
|
|
1049 |
$this->btn($action, $label, ['data' => $data, 'confirm' => $message]);
|
1050 |
}
|
1051 |
|
includes/helper.php
CHANGED
@@ -1,352 +1,395 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
defined('ABSPATH') || exit;
|
4 |
-
|
5 |
-
function tnp_post_thumbnail_src($post, $size = 'thumbnail', $alternative = '') {
|
6 |
-
if (is_object($post)) {
|
7 |
-
$post = $post->ID;
|
8 |
-
}
|
9 |
-
|
10 |
-
// Find a media id to be used as featured image
|
11 |
-
$media_id = get_post_thumbnail_id($post);
|
12 |
-
if (empty($media_id)) {
|
13 |
-
$attachments = get_children(array('numberpost' => 1, 'post_parent' => $post, 'post_status' => 'inherit', 'post_type' => 'attachment', 'post_mime_type' => 'image', 'order' => 'ASC', 'orderby' => 'menu_order'));
|
14 |
-
if (!empty($attachments)) {
|
15 |
-
foreach ($attachments as $id => &$attachment) {
|
16 |
-
$media_id = $id;
|
17 |
-
break;
|
18 |
-
}
|
19 |
-
}
|
20 |
-
}
|
21 |
-
|
22 |
-
if (!$media_id) {
|
23 |
-
return $alternative;
|
24 |
-
}
|
25 |
-
|
26 |
-
if (!defined('NEWSLETTER_MEDIA_RESIZE') || NEWSLETTER_MEDIA_RESIZE) {
|
27 |
-
if (is_array($size)) {
|
28 |
-
$src = tnp_media_resize($media_id, $size);
|
29 |
-
if (is_wp_error($src)) {
|
30 |
-
Newsletter::instance()->logger->error($src);
|
31 |
-
return $alternative;
|
32 |
-
} else {
|
33 |
-
return $src;
|
34 |
-
}
|
35 |
-
}
|
36 |
-
}
|
37 |
-
|
38 |
-
$media = wp_get_attachment_image_src($media_id, $size);
|
39 |
-
if (strpos($media[0], 'http') !== 0) {
|
40 |
-
$media[0] = 'http:' . $media[0];
|
41 |
-
}
|
42 |
-
return $media[0];
|
43 |
-
}
|
44 |
-
|
45 |
-
/**
|
46 |
-
* @param WP_Post $post
|
47 |
-
* @param int $length
|
48 |
-
*
|
49 |
-
* @return string
|
50 |
-
*/
|
51 |
-
function tnp_post_excerpt($post, $length = 30) {
|
52 |
-
$excerpt = tnp_delete_all_shordcodes_tags(get_the_excerpt($post->ID));
|
53 |
-
$excerpt = wp_trim_words($excerpt, $length);
|
54 |
-
|
55 |
-
|
56 |
-
|
57 |
-
|
58 |
-
|
59 |
-
|
60 |
-
|
61 |
-
|
62 |
-
|
63 |
-
|
64 |
-
|
65 |
-
|
66 |
-
|
67 |
-
|
68 |
-
|
69 |
-
|
70 |
-
|
71 |
-
|
72 |
-
|
73 |
-
|
74 |
-
|
75 |
-
|
76 |
-
|
77 |
-
|
78 |
-
|
79 |
-
|
80 |
-
|
81 |
-
|
82 |
-
|
83 |
-
|
84 |
-
|
85 |
-
|
86 |
-
|
87 |
-
|
88 |
-
*
|
89 |
-
*
|
90 |
-
*
|
91 |
-
*
|
92 |
-
*
|
93 |
-
*
|
94 |
-
* @param
|
95 |
-
* @
|
96 |
-
|
97 |
-
|
98 |
-
|
99 |
-
|
100 |
-
|
101 |
-
|
102 |
-
|
103 |
-
|
104 |
-
|
105 |
-
|
106 |
-
|
107 |
-
|
108 |
-
$
|
109 |
-
$
|
110 |
-
|
111 |
-
|
112 |
-
|
113 |
-
|
114 |
-
|
115 |
-
|
116 |
-
|
117 |
-
//
|
118 |
-
|
119 |
-
|
120 |
-
$relative_file =
|
121 |
-
|
122 |
-
|
123 |
-
|
124 |
-
|
125 |
-
|
126 |
-
$
|
127 |
-
|
128 |
-
|
129 |
-
|
130 |
-
|
131 |
-
|
132 |
-
|
133 |
-
|
134 |
-
|
135 |
-
$
|
136 |
-
|
137 |
-
|
138 |
-
|
139 |
-
|
140 |
-
|
141 |
-
|
142 |
-
|
143 |
-
|
144 |
-
|
145 |
-
}
|
146 |
-
|
147 |
-
$
|
148 |
-
if ($
|
149 |
-
$src = wp_get_attachment_image_src($media_id, 'full');
|
150 |
-
return $src[0];
|
151 |
-
|
152 |
-
|
153 |
-
|
154 |
-
|
155 |
-
|
156 |
-
if (
|
157 |
-
$src = wp_get_attachment_image_src($media_id, 'full');
|
158 |
-
return $src[0];
|
159 |
-
}
|
160 |
-
|
161 |
-
$
|
162 |
-
|
163 |
-
|
164 |
-
|
165 |
-
|
166 |
-
|
167 |
-
}
|
168 |
-
|
169 |
-
|
170 |
-
|
171 |
-
|
172 |
-
|
173 |
-
|
174 |
-
|
175 |
-
|
176 |
-
|
177 |
-
|
178 |
-
|
179 |
-
|
180 |
-
|
181 |
-
|
182 |
-
|
183 |
-
$
|
184 |
-
|
185 |
-
|
186 |
-
|
187 |
-
|
188 |
-
$
|
189 |
-
|
190 |
-
|
191 |
-
|
192 |
-
$media
|
193 |
-
|
194 |
-
|
195 |
-
|
196 |
-
$
|
197 |
-
|
198 |
-
|
199 |
-
|
200 |
-
|
201 |
-
|
202 |
-
|
203 |
-
|
204 |
-
|
205 |
-
|
206 |
-
|
207 |
-
|
208 |
-
|
209 |
-
|
210 |
-
|
211 |
-
|
212 |
-
|
213 |
-
|
214 |
-
|
215 |
-
|
216 |
-
|
217 |
-
|
218 |
-
|
219 |
-
|
220 |
-
|
221 |
-
|
222 |
-
if (
|
223 |
-
|
224 |
-
|
225 |
-
|
226 |
-
|
227 |
-
|
228 |
-
|
229 |
-
|
230 |
-
if (
|
231 |
-
$
|
232 |
-
|
233 |
-
|
234 |
-
|
235 |
-
|
236 |
-
|
237 |
-
|
238 |
-
|
239 |
-
|
240 |
-
|
241 |
-
|
242 |
-
|
243 |
-
|
244 |
-
|
245 |
-
$
|
246 |
-
if ($
|
247 |
-
|
248 |
-
}
|
249 |
-
$
|
250 |
-
|
251 |
-
|
252 |
-
|
253 |
-
|
254 |
-
|
255 |
-
|
256 |
-
|
257 |
-
|
258 |
-
|
259 |
-
|
260 |
-
|
261 |
-
|
262 |
-
|
263 |
-
|
264 |
-
|
265 |
-
|
266 |
-
|
267 |
-
|
268 |
-
|
269 |
-
|
270 |
-
|
271 |
-
|
272 |
-
|
273 |
-
|
274 |
-
$
|
275 |
-
|
276 |
-
|
277 |
-
|
278 |
-
|
279 |
-
|
280 |
-
|
281 |
-
$
|
282 |
-
|
283 |
-
|
284 |
-
Newsletter::instance()->logger->error($
|
285 |
-
|
286 |
-
|
287 |
-
|
288 |
-
|
289 |
-
$
|
290 |
-
|
291 |
-
|
292 |
-
|
293 |
-
|
294 |
-
$
|
295 |
-
|
296 |
-
|
297 |
-
$
|
298 |
-
|
299 |
-
|
300 |
-
|
301 |
-
|
302 |
-
|
303 |
-
$
|
304 |
-
$
|
305 |
-
|
306 |
-
|
307 |
-
|
308 |
-
|
309 |
-
|
310 |
-
|
311 |
-
|
312 |
-
|
313 |
-
|
314 |
-
|
315 |
-
|
316 |
-
|
317 |
-
|
318 |
-
|
319 |
-
|
320 |
-
|
321 |
-
|
322 |
-
|
323 |
-
|
324 |
-
|
325 |
-
|
326 |
-
*
|
327 |
-
*
|
328 |
-
|
329 |
-
|
330 |
-
|
331 |
-
|
332 |
-
|
333 |
-
|
334 |
-
|
335 |
-
|
336 |
-
|
337 |
-
|
338 |
-
|
339 |
-
|
340 |
-
|
341 |
-
|
342 |
-
|
343 |
-
|
344 |
-
|
345 |
-
|
346 |
-
|
347 |
-
|
348 |
-
|
349 |
-
|
350 |
-
|
351 |
-
|
352 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
defined('ABSPATH') || exit;
|
4 |
+
|
5 |
+
function tnp_post_thumbnail_src($post, $size = 'thumbnail', $alternative = '') {
|
6 |
+
if (is_object($post)) {
|
7 |
+
$post = $post->ID;
|
8 |
+
}
|
9 |
+
|
10 |
+
// Find a media id to be used as featured image
|
11 |
+
$media_id = get_post_thumbnail_id($post);
|
12 |
+
if (empty($media_id)) {
|
13 |
+
$attachments = get_children(array('numberpost' => 1, 'post_parent' => $post, 'post_status' => 'inherit', 'post_type' => 'attachment', 'post_mime_type' => 'image', 'order' => 'ASC', 'orderby' => 'menu_order'));
|
14 |
+
if (!empty($attachments)) {
|
15 |
+
foreach ($attachments as $id => &$attachment) {
|
16 |
+
$media_id = $id;
|
17 |
+
break;
|
18 |
+
}
|
19 |
+
}
|
20 |
+
}
|
21 |
+
|
22 |
+
if (!$media_id) {
|
23 |
+
return $alternative;
|
24 |
+
}
|
25 |
+
|
26 |
+
if (!defined('NEWSLETTER_MEDIA_RESIZE') || NEWSLETTER_MEDIA_RESIZE) {
|
27 |
+
if (is_array($size)) {
|
28 |
+
$src = tnp_media_resize($media_id, $size);
|
29 |
+
if (is_wp_error($src)) {
|
30 |
+
Newsletter::instance()->logger->error($src);
|
31 |
+
return $alternative;
|
32 |
+
} else {
|
33 |
+
return $src;
|
34 |
+
}
|
35 |
+
}
|
36 |
+
}
|
37 |
+
|
38 |
+
$media = wp_get_attachment_image_src($media_id, $size);
|
39 |
+
if (strpos($media[0], 'http') !== 0) {
|
40 |
+
$media[0] = 'http:' . $media[0];
|
41 |
+
}
|
42 |
+
return $media[0];
|
43 |
+
}
|
44 |
+
|
45 |
+
/**
|
46 |
+
* @param WP_Post $post
|
47 |
+
* @param int $length
|
48 |
+
*
|
49 |
+
* @return string
|
50 |
+
*/
|
51 |
+
function tnp_post_excerpt($post, $length = 30) {
|
52 |
+
$excerpt = tnp_delete_all_shordcodes_tags(get_the_excerpt($post->ID));
|
53 |
+
$excerpt = wp_trim_words($excerpt, $length);
|
54 |
+
$excerpt = str_replace(' ', '', $excerpt);
|
55 |
+
|
56 |
+
return $excerpt;
|
57 |
+
}
|
58 |
+
|
59 |
+
function tnp_delete_all_shordcodes_tags($post_content = '') {
|
60 |
+
//Delete open tags
|
61 |
+
$post_content = preg_replace("/\[[a-zA-Z0-9_-]*?(\s.*?)?\]/", '', $post_content);
|
62 |
+
//Delete close tags
|
63 |
+
$post_content = preg_replace("/\[\/[a-zA-Z0-9_-]*?\]/", '', $post_content);
|
64 |
+
|
65 |
+
return $post_content;
|
66 |
+
}
|
67 |
+
|
68 |
+
function tnp_post_permalink($post) {
|
69 |
+
return get_permalink($post->ID);
|
70 |
+
}
|
71 |
+
|
72 |
+
function tnp_post_content($post) {
|
73 |
+
return $post->post_content;
|
74 |
+
}
|
75 |
+
|
76 |
+
function tnp_post_title($post) {
|
77 |
+
return $post->post_title;
|
78 |
+
}
|
79 |
+
|
80 |
+
function tnp_post_date($post, $format = null) {
|
81 |
+
if (empty($format)) {
|
82 |
+
$format = get_option('date_format');
|
83 |
+
}
|
84 |
+
return mysql2date($format, $post->post_date);
|
85 |
+
}
|
86 |
+
|
87 |
+
/**
|
88 |
+
* Tries to create a resized version of a media uploaded to the media library.
|
89 |
+
* Returns an empty string if the media does not exists or generally if the attached file
|
90 |
+
* cannot be found. If the resize fails for whatever reason, fall backs to the
|
91 |
+
* standard image source returned by WP which is usually not exactly the
|
92 |
+
* requested size.
|
93 |
+
*
|
94 |
+
* @param int $media_id
|
95 |
+
* @param array $size
|
96 |
+
* @return string
|
97 |
+
*/
|
98 |
+
function tnp_media_resize($media_id, $size) {
|
99 |
+
if (empty($media_id)) {
|
100 |
+
return '';
|
101 |
+
}
|
102 |
+
|
103 |
+
$relative_file = get_post_meta($media_id, '_wp_attached_file', true);
|
104 |
+
if (empty($relative_file)) {
|
105 |
+
return '';
|
106 |
+
}
|
107 |
+
|
108 |
+
$width = $size[0];
|
109 |
+
$height = $size[1];
|
110 |
+
$crop = false;
|
111 |
+
if (isset($size[2])) {
|
112 |
+
$crop = (boolean) $size[2];
|
113 |
+
}
|
114 |
+
|
115 |
+
$uploads = wp_upload_dir();
|
116 |
+
|
117 |
+
// Based on _wp_relative_upload_path() function for blog which store the
|
118 |
+
// full patch of media files
|
119 |
+
if (0 === strpos($relative_file, $uploads['basedir'])) {
|
120 |
+
$relative_file = str_replace($uploads['basedir'], '', $relative_file);
|
121 |
+
$relative_file = ltrim($relative_file, '/');
|
122 |
+
}
|
123 |
+
|
124 |
+
$absolute_file = $uploads['basedir'] . '/' . $relative_file;
|
125 |
+
// Relative and absolute name of the thumbnail.
|
126 |
+
$pathinfo = pathinfo($relative_file);
|
127 |
+
|
128 |
+
// We don't know why, but on some systems files with non-ascii characters loose the file name (grrr...)
|
129 |
+
if (empty($pathinfo['filename'])) {
|
130 |
+
$src = wp_get_attachment_image_src($media_id, 'full');
|
131 |
+
return $src[0];
|
132 |
+
}
|
133 |
+
|
134 |
+
$relative_thumb = $pathinfo['dirname'] . '/' . $pathinfo['filename'] . '-' . $width . 'x' .
|
135 |
+
$height . ($crop ? '-c' : '') . '.' . $pathinfo['extension'];
|
136 |
+
$absolute_thumb = $uploads['basedir'] . '/newsletter/thumbnails/' . $relative_thumb;
|
137 |
+
|
138 |
+
// Thumbnail generation if needed.
|
139 |
+
if (!file_exists($absolute_thumb) || filemtime($absolute_thumb) < filemtime($absolute_file)) {
|
140 |
+
$r = wp_mkdir_p($uploads['basedir'] . '/newsletter/thumbnails/' . $pathinfo['dirname']);
|
141 |
+
|
142 |
+
if (!$r) {
|
143 |
+
$src = wp_get_attachment_image_src($media_id, 'full');
|
144 |
+
return $src[0];
|
145 |
+
}
|
146 |
+
|
147 |
+
$editor = wp_get_image_editor($absolute_file);
|
148 |
+
if (is_wp_error($editor)) {
|
149 |
+
$src = wp_get_attachment_image_src($media_id, 'full');
|
150 |
+
return $src[0];
|
151 |
+
//return $editor;
|
152 |
+
//return $uploads['baseurl'] . '/' . $relative_file;
|
153 |
+
}
|
154 |
+
|
155 |
+
$original_size = $editor->get_size();
|
156 |
+
if ($width > $original_size['width'] || $height > $original_size['height']) {
|
157 |
+
$src = wp_get_attachment_image_src($media_id, 'full');
|
158 |
+
return $src[0];
|
159 |
+
}
|
160 |
+
|
161 |
+
$editor->set_quality(80);
|
162 |
+
$resized = $editor->resize($width, $height, $crop);
|
163 |
+
|
164 |
+
if (is_wp_error($resized)) {
|
165 |
+
$src = wp_get_attachment_image_src($media_id, 'full');
|
166 |
+
return $src[0];
|
167 |
+
}
|
168 |
+
|
169 |
+
$saved = $editor->save($absolute_thumb);
|
170 |
+
if (is_wp_error($saved)) {
|
171 |
+
$src = wp_get_attachment_image_src($media_id, 'full');
|
172 |
+
return $src[0];
|
173 |
+
//return $saved;
|
174 |
+
//return $uploads['baseurl'] . '/' . $relative_file;
|
175 |
+
}
|
176 |
+
}
|
177 |
+
|
178 |
+
return $uploads['baseurl'] . '/newsletter/thumbnails/' . $relative_thumb;
|
179 |
+
}
|
180 |
+
|
181 |
+
function _tnp_get_default_media($media_id, $size) {
|
182 |
+
|
183 |
+
$src = wp_get_attachment_image_src($media_id, $size);
|
184 |
+
if (!$src) {
|
185 |
+
return null;
|
186 |
+
}
|
187 |
+
$media = new TNP_Media();
|
188 |
+
$media->id = $media_id;
|
189 |
+
$media->url = $src[0];
|
190 |
+
$media->width = $src[1];
|
191 |
+
$media->height = $src[2];
|
192 |
+
return $media;
|
193 |
+
}
|
194 |
+
|
195 |
+
function tnp_get_media($media_id, $size) {
|
196 |
+
$src = wp_get_attachment_image_src($media_id, $size);
|
197 |
+
if (!$src) {
|
198 |
+
return null;
|
199 |
+
}
|
200 |
+
$media = new TNP_Media();
|
201 |
+
$media->id = $media_id;
|
202 |
+
$media->url = $src[0];
|
203 |
+
$media->width = $src[1];
|
204 |
+
$media->height = $src[2];
|
205 |
+
return $media;
|
206 |
+
}
|
207 |
+
|
208 |
+
/**
|
209 |
+
* Create a resized version of the media stored in the WP media library.
|
210 |
+
*
|
211 |
+
* @param int $media_id
|
212 |
+
* @param array $size
|
213 |
+
* @return TNP_Media
|
214 |
+
*/
|
215 |
+
function tnp_resize($media_id, $size) {
|
216 |
+
if (empty($media_id)) {
|
217 |
+
return null;
|
218 |
+
}
|
219 |
+
|
220 |
+
$relative_file = get_post_meta($media_id, '_wp_attached_file', true);
|
221 |
+
|
222 |
+
if (empty($relative_file)) {
|
223 |
+
return null;
|
224 |
+
}
|
225 |
+
|
226 |
+
$uploads = wp_upload_dir();
|
227 |
+
|
228 |
+
// Based on _wp_relative_upload_path() function for blog which store the
|
229 |
+
// full patch of media files
|
230 |
+
if (0 === strpos($relative_file, $uploads['basedir'])) {
|
231 |
+
$relative_file = str_replace($uploads['basedir'], '', $relative_file);
|
232 |
+
$relative_file = ltrim($relative_file, '/');
|
233 |
+
}
|
234 |
+
|
235 |
+
$width = $size[0];
|
236 |
+
$height = $size[1];
|
237 |
+
$crop = false;
|
238 |
+
if (isset($size[2])) {
|
239 |
+
$crop = (boolean) $size[2];
|
240 |
+
}
|
241 |
+
|
242 |
+
$absolute_file = $uploads['basedir'] . '/' . $relative_file;
|
243 |
+
|
244 |
+
if (substr($relative_file, -4) === '.gif') {
|
245 |
+
$editor = wp_get_image_editor($absolute_file);
|
246 |
+
if (is_wp_error($editor)) {
|
247 |
+
return _tnp_get_default_media($media_id, $size);
|
248 |
+
}
|
249 |
+
$new_size = $editor->get_size();
|
250 |
+
$media = new TNP_Media();
|
251 |
+
$media->id = $media_id;
|
252 |
+
$media->width = $new_size['width'];
|
253 |
+
$media->height = $new_size['height'];
|
254 |
+
if ($media->width > $width) {
|
255 |
+
$media->set_width($width);
|
256 |
+
}
|
257 |
+
$media->url = $uploads['baseurl'] . '/' . $relative_file;
|
258 |
+
return $media;
|
259 |
+
}
|
260 |
+
|
261 |
+
// Relative and absolute name of the thumbnail.
|
262 |
+
$pathinfo = pathinfo($relative_file);
|
263 |
+
|
264 |
+
// We don't know why, but on some systems files with non-ascii characters loose the file name (grrr...)
|
265 |
+
if (empty($pathinfo['filename'])) {
|
266 |
+
return _tnp_get_default_media($media_id, $size);
|
267 |
+
}
|
268 |
+
|
269 |
+
$relative_thumb = $pathinfo['dirname'] . '/' . $pathinfo['filename'] . '-' . $width . 'x' . $height . ($crop ? '-c' : '') . '.' . $pathinfo['extension'];
|
270 |
+
$absolute_thumb = $uploads['basedir'] . '/newsletter/thumbnails/' . $relative_thumb;
|
271 |
+
|
272 |
+
// Thumbnail generation if needed.
|
273 |
+
if (!file_exists($absolute_thumb) || filemtime($absolute_thumb) < filemtime($absolute_file)) {
|
274 |
+
$r = wp_mkdir_p($uploads['basedir'] . '/newsletter/thumbnails/' . $pathinfo['dirname']);
|
275 |
+
|
276 |
+
if (!$r) {
|
277 |
+
Newsletter::instance()->logger->error('Unable to create dir ' . $uploads['basedir'] . '/newsletter/thumbnails/' . $pathinfo['dirname']);
|
278 |
+
return _tnp_get_default_media($media_id, $size);
|
279 |
+
}
|
280 |
+
|
281 |
+
$editor = wp_get_image_editor($absolute_file);
|
282 |
+
if (is_wp_error($editor)) {
|
283 |
+
Newsletter::instance()->logger->error($editor);
|
284 |
+
Newsletter::instance()->logger->error('File: ' . $absolute_file);
|
285 |
+
return _tnp_get_default_media($media_id, $size);
|
286 |
+
}
|
287 |
+
|
288 |
+
$original_size = $editor->get_size();
|
289 |
+
if ($width > $original_size['width'] && $height > $original_size['height']) {
|
290 |
+
Newsletter::instance()->logger->error('Requested size larger than the original one');
|
291 |
+
return _tnp_get_default_media($media_id, $size);
|
292 |
+
}
|
293 |
+
|
294 |
+
$editor->set_quality(85);
|
295 |
+
$resized = $editor->resize($width, $height, $crop);
|
296 |
+
|
297 |
+
if (is_wp_error($resized)) {
|
298 |
+
Newsletter::instance()->logger->error($resized);
|
299 |
+
Newsletter::instance()->logger->error('File: ' . $absolute_file);
|
300 |
+
return _tnp_get_default_media($media_id, $size);
|
301 |
+
}
|
302 |
+
|
303 |
+
$saved = $editor->save($absolute_thumb);
|
304 |
+
if (is_wp_error($saved)) {
|
305 |
+
Newsletter::instance()->logger->error($saved);
|
306 |
+
return _tnp_get_default_media($media_id, $size);
|
307 |
+
}
|
308 |
+
$new_size = $editor->get_size();
|
309 |
+
|
310 |
+
$media = new TNP_Media();
|
311 |
+
$media->width = $new_size['width'];
|
312 |
+
$media->height = $new_size['height'];
|
313 |
+
$media->url = $uploads['baseurl'] . '/newsletter/thumbnails/' . $relative_thumb;
|
314 |
+
} else {
|
315 |
+
$media = new TNP_Media();
|
316 |
+
$new_size = getimagesize($absolute_thumb);
|
317 |
+
$media->width = $new_size[0];
|
318 |
+
$media->height = $new_size[1];
|
319 |
+
$media->url = $uploads['baseurl'] . '/newsletter/thumbnails/' . $relative_thumb;
|
320 |
+
}
|
321 |
+
|
322 |
+
return $media;
|
323 |
+
}
|
324 |
+
|
325 |
+
function tnp_resize_2x($media_id, $size) {
|
326 |
+
$size[0] = $size[0] * 2;
|
327 |
+
$size[1] = $size[1] * 2;
|
328 |
+
$media = tnp_resize($media_id, $size);
|
329 |
+
if (!$media) return $media;
|
330 |
+
$media->set_width( $size[0] / 2 );
|
331 |
+
return $media;
|
332 |
+
}
|
333 |
+
|
334 |
+
/**
|
335 |
+
* @param TNP_Media[] $images
|
336 |
+
*
|
337 |
+
* @return int
|
338 |
+
*/
|
339 |
+
function tnp_get_max_height_of( $images ) {
|
340 |
+
$max_height = 0;
|
341 |
+
foreach ( $images as $image ) {
|
342 |
+
$max_height = $image->height > $max_height ? $image->height : $max_height;
|
343 |
+
}
|
344 |
+
|
345 |
+
return $max_height;
|
346 |
+
}
|
347 |
+
|
348 |
+
/**
|
349 |
+
* @param WP_Post[] $product_list
|
350 |
+
* @param array $size
|
351 |
+
*
|
352 |
+
* @return TNP_Media[]
|
353 |
+
*/
|
354 |
+
function tnp_resize_product_list_featured_image( $product_list, $size ) {
|
355 |
+
$images = [];
|
356 |
+
foreach ( $product_list as $p ) {
|
357 |
+
$images[ $p->ID ] = tnp_resize_2x( TNP_Composer::get_post_thumbnail_id( $p->ID ), $size );
|
358 |
+
}
|
359 |
+
|
360 |
+
return $images;
|
361 |
+
}
|
362 |
+
|
363 |
+
/**
|
364 |
+
* Get media for "posts" composer block
|
365 |
+
*
|
366 |
+
* @param WP_Post post
|
367 |
+
* @param array $size
|
368 |
+
* @param string $default_image_url
|
369 |
+
*
|
370 |
+
* @return TNP_Media
|
371 |
+
*/
|
372 |
+
function tnp_composer_block_posts_get_media($post, $size, $default_image_url = null) {
|
373 |
+
$post_thumbnail_id = TNP_Composer::get_post_thumbnail_id($post);
|
374 |
+
|
375 |
+
$media = null;
|
376 |
+
|
377 |
+
if (!empty($post_thumbnail_id)) {
|
378 |
+
$media = tnp_resize($post_thumbnail_id, array_values($size));
|
379 |
+
} else if ($default_image_url) {
|
380 |
+
Newsletter::instance()->logger->error('Thumbnail id not found');
|
381 |
+
$media = new TNP_Media();
|
382 |
+
$media->url = $default_image_url;
|
383 |
+
$media->width = $size['width'];
|
384 |
+
$media->height = $size['height'];
|
385 |
+
}
|
386 |
+
return $media;
|
387 |
+
}
|
388 |
+
|
389 |
+
function tnp_outlook_wrapper_open($width = 600) {
|
390 |
+
return NewsletterEmails::get_outlook_wrapper_open($width);
|
391 |
+
}
|
392 |
+
|
393 |
+
function tnp_outlook_wrapper_close() {
|
394 |
+
return NewsletterEmails::get_outlook_wrapper_close();
|
395 |
+
}
|
includes/system.php
CHANGED
@@ -1,263 +1,263 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
defined('ABSPATH') || exit;
|
4 |
-
|
5 |
-
class NewsletterSystem {
|
6 |
-
|
7 |
-
static $instance;
|
8 |
-
|
9 |
-
const JOB_OK = 0;
|
10 |
-
const JOB_MISSING = 2;
|
11 |
-
const JOB_LATE = 1;
|
12 |
-
const JOB_SKIPPED = 3;
|
13 |
-
|
14 |
-
/**
|
15 |
-
* @return NewsletterSystem
|
16 |
-
*/
|
17 |
-
static function instance() {
|
18 |
-
if (self::$instance == null) {
|
19 |
-
self::$instance = new NewsletterSystem();
|
20 |
-
}
|
21 |
-
return self::$instance;
|
22 |
-
}
|
23 |
-
|
24 |
-
function __construct() {
|
25 |
-
|
26 |
-
}
|
27 |
-
|
28 |
-
function reset_cron_stats() {
|
29 |
-
update_option('newsletter_diagnostic_cron_calls', [], false);
|
30 |
-
}
|
31 |
-
|
32 |
-
/**
|
33 |
-
*
|
34 |
-
* @param type $calls
|
35 |
-
* @return \TNP_Cron_Stats
|
36 |
-
*/
|
37 |
-
function get_cron_stats() {
|
38 |
-
$calls = get_option('newsletter_diagnostic_cron_calls', []);
|
39 |
-
|
40 |
-
// Not enough data
|
41 |
-
if (count($calls) < 12) {
|
42 |
-
return null;
|
43 |
-
}
|
44 |
-
|
45 |
-
$stats = new TNP_Cron_Stats();
|
46 |
-
|
47 |
-
for ($i = 1; $i < count($calls); $i++) {
|
48 |
-
$delta = $calls[$i] - $calls[$i - 1];
|
49 |
-
$stats->deltas[] = $delta;
|
50 |
-
if ($stats->min > $delta) {
|
51 |
-
$stats->min = $delta;
|
52 |
-
}
|
53 |
-
if ($stats->max < $delta) {
|
54 |
-
$stats->max = $delta;
|
55 |
-
}
|
56 |
-
}
|
57 |
-
$stats->avg = round(array_sum($stats->deltas) / count($stats->deltas));
|
58 |
-
$stats->good = $stats->avg < NEWSLETTER_CRON_INTERVAL * 1.1; // 10% error
|
59 |
-
return $stats;
|
60 |
-
}
|
61 |
-
|
62 |
-
function get_last_cron_call() {
|
63 |
-
$calls = get_option('newsletter_diagnostic_cron_calls', []);
|
64 |
-
if (empty($calls))
|
65 |
-
return 0;
|
66 |
-
return end($calls);
|
67 |
-
}
|
68 |
-
|
69 |
-
function has_newsletter_schedule() {
|
70 |
-
$schedules = wp_get_schedules();
|
71 |
-
if (!empty($schedules)) {
|
72 |
-
foreach ($schedules as $key => $data) {
|
73 |
-
if ($key == 'newsletter') {
|
74 |
-
return true;
|
75 |
-
}
|
76 |
-
}
|
77 |
-
}
|
78 |
-
return false;
|
79 |
-
}
|
80 |
-
|
81 |
-
/**
|
82 |
-
*
|
83 |
-
* @return boolean|int
|
84 |
-
*/
|
85 |
-
function get_job_delay() {
|
86 |
-
$x = wp_next_scheduled('newsletter');
|
87 |
-
return $x === false ? false : time() - $x;
|
88 |
-
}
|
89 |
-
|
90 |
-
function get_job_schedule() {
|
91 |
-
return wp_next_scheduled('newsletter');
|
92 |
-
}
|
93 |
-
|
94 |
-
function get_cache_job_status($refresh = false) {
|
95 |
-
$status = get_transient('newsletter_job_status');
|
96 |
-
if ($status === false || $refresh) {
|
97 |
-
$status = $this->get_job_status();
|
98 |
-
set_transient('newsletter_job_status', $status, DAY_IN_SECONDS);
|
99 |
-
}
|
100 |
-
return $status;
|
101 |
-
}
|
102 |
-
|
103 |
-
function get_job_status() {
|
104 |
-
|
105 |
-
$x = wp_next_scheduled('newsletter');
|
106 |
-
if ($x === false) {
|
107 |
-
return self::JOB_MISSING;
|
108 |
-
}
|
109 |
-
|
110 |
-
// Special case: the scheduler has been triggered but the job not executed
|
111 |
-
$calls = get_option('newsletter_diagnostic_cron_calls', []);
|
112 |
-
if (!empty($calls)) {
|
113 |
-
$last = end($calls);
|
114 |
-
if ($last > $x) {
|
115 |
-
return self::JOB_SKIPPED;
|
116 |
-
}
|
117 |
-
}
|
118 |
-
|
119 |
-
if (time() - $x > 900) {
|
120 |
-
return self::JOB_LATE;
|
121 |
-
}
|
122 |
-
return self::JOB_OK;
|
123 |
-
}
|
124 |
-
|
125 |
-
function reset_send_stats() {
|
126 |
-
update_option('newsletter_diagnostic_send_calls', [], false);
|
127 |
-
}
|
128 |
-
|
129 |
-
function get_send_stats() {
|
130 |
-
// Send calls stats
|
131 |
-
$send_calls = get_option('newsletter_diagnostic_send_calls', []);
|
132 |
-
if (!$send_calls) {
|
133 |
-
return null;
|
134 |
-
}
|
135 |
-
$send_max = 0;
|
136 |
-
$send_min = PHP_INT_MAX;
|
137 |
-
$send_total_time = 0;
|
138 |
-
$send_total_emails = 0;
|
139 |
-
$send_completed = 0;
|
140 |
-
$stats = new TNP_Send_stats();
|
141 |
-
|
142 |
-
// Batches
|
143 |
-
for ($i = 0; $i < count($send_calls); $i++) {
|
144 |
-
// 0 - batch start time
|
145 |
-
// 1 - batch end time
|
146 |
-
// 2 - number of sent email in this batch
|
147 |
-
// 3 - 0: prematurely stopped, 1: completed
|
148 |
-
if (empty($send_calls[$i][2])) {
|
149 |
-
continue;
|
150 |
-
}
|
151 |
-
if ($send_calls[$i][2] <= 1) {
|
152 |
-
continue;
|
153 |
-
}
|
154 |
-
|
155 |
-
$delta = $send_calls[$i][1] - $send_calls[$i][0];
|
156 |
-
$send_total_time += $delta;
|
157 |
-
$send_total_emails += $send_calls[$i][2];
|
158 |
-
|
159 |
-
$send_mean = $delta / $send_calls[$i][2];
|
160 |
-
$stats->means[] = $send_mean;
|
161 |
-
$stats->sizes[] = $send_calls[$i][2];
|
162 |
-
if ($send_min > $send_mean) {
|
163 |
-
$send_min = $send_mean;
|
164 |
-
}
|
165 |
-
if ($send_max < $send_mean) {
|
166 |
-
$send_max = $send_mean;
|
167 |
-
}
|
168 |
-
if (isset($send_calls[$i][3]) && $send_calls[$i][3]) {
|
169 |
-
$send_completed++;
|
170 |
-
}
|
171 |
-
}
|
172 |
-
|
173 |
-
if (empty($stats->means)) {
|
174 |
-
return null;
|
175 |
-
}
|
176 |
-
$send_mean = $send_total_time / $send_total_emails;
|
177 |
-
|
178 |
-
$stats->min = round($send_min, 2);
|
179 |
-
$stats->max = round($send_max, 2);
|
180 |
-
$stats->mean = round($send_mean, 2);
|
181 |
-
$stats->total_time = round($send_total_time);
|
182 |
-
$stats->total_emails = $send_total_emails;
|
183 |
-
$stats->total_runs = count($stats->means);
|
184 |
-
|
185 |
-
$stats->completed = $send_completed;
|
186 |
-
$stats->interrupted = $stats->total_runs - $stats->completed;
|
187 |
-
return $stats;
|
188 |
-
}
|
189 |
-
|
190 |
-
/**
|
191 |
-
* Returns a list of functions attached to the prvoded filter or action name.
|
192 |
-
*
|
193 |
-
* @global array $wp_filter
|
194 |
-
* @param string $tag
|
195 |
-
* @return string
|
196 |
-
*/
|
197 |
-
function get_hook_functions($tag) {
|
198 |
-
global $wp_filter;
|
199 |
-
|
200 |
-
|
201 |
-
foreach ($wp_filter[$tag]->callbacks as $priority => $functions) {
|
202 |
-
|
203 |
-
foreach ($functions as $function) {
|
204 |
-
$b .= '[' . $priority . '] ';
|
205 |
-
if (is_array($function['function'])) {
|
206 |
-
if (is_object($function['function'][0])) {
|
207 |
-
$b .= get_class($function['function'][0]) . '::' . $function['function'][1];
|
208 |
-
} else {
|
209 |
-
$b .= $function['function'][0] . '::' . $function['function'][1];
|
210 |
-
}
|
211 |
-
} else {
|
212 |
-
if (is_object($function['function'])) {
|
213 |
-
$fn = new ReflectionFunction($function['function']);
|
214 |
-
$b .= get_class($fn->getClosureThis()) . '(closure)';
|
215 |
-
} else {
|
216 |
-
$b .= $function['function'];
|
217 |
-
}
|
218 |
-
}
|
219 |
-
$b .= "<br>";
|
220 |
-
}
|
221 |
-
}
|
222 |
-
}
|
223 |
-
return $b;
|
224 |
-
}
|
225 |
-
|
226 |
-
}
|
227 |
-
|
228 |
-
class TNP_Cron_Stats {
|
229 |
-
|
230 |
-
var $min = PHP_INT_MAX;
|
231 |
-
var $max = 0;
|
232 |
-
var $avg = 0;
|
233 |
-
/* List of intervals between cron calls */
|
234 |
-
var $deltas = [];
|
235 |
-
/* If the cron is triggered enough often */
|
236 |
-
var $good = true;
|
237 |
-
|
238 |
-
}
|
239 |
-
|
240 |
-
class TNP_Send_Stats {
|
241 |
-
|
242 |
-
/* Emails sent */
|
243 |
-
var $total_emails;
|
244 |
-
/* Total batches collected (1 sized-batch by Autoresponder are ignored) */
|
245 |
-
var $total_runs;
|
246 |
-
/* Total sending time of the collected batches */
|
247 |
-
var $total_time;
|
248 |
-
/* Batch completed without timeout or max emails limit */
|
249 |
-
var $completed;
|
250 |
-
/* Batches interrupted due to reached limits */
|
251 |
-
var $interrupted;
|
252 |
-
/* Min time to send an email */
|
253 |
-
var $min = PHP_INT_MAX;
|
254 |
-
/* Max time to send an email */
|
255 |
-
var $max = 0;
|
256 |
-
/* Average time to send all collected emails */
|
257 |
-
var $mean = 0;
|
258 |
-
/* List of single batches average per email sending time */
|
259 |
-
var $means = [];
|
260 |
-
/* Number of emails in the single batches */
|
261 |
-
var $sizes = [];
|
262 |
-
|
263 |
-
}
|
1 |
+
<?php
|
2 |
+
|
3 |
+
defined('ABSPATH') || exit;
|
4 |
+
|
5 |
+
class NewsletterSystem {
|
6 |
+
|
7 |
+
static $instance;
|
8 |
+
|
9 |
+
const JOB_OK = 0;
|
10 |
+
const JOB_MISSING = 2;
|
11 |
+
const JOB_LATE = 1;
|
12 |
+
const JOB_SKIPPED = 3;
|
13 |
+
|
14 |
+
/**
|
15 |
+
* @return NewsletterSystem
|
16 |
+
*/
|
17 |
+
static function instance() {
|
18 |
+
if (self::$instance == null) {
|
19 |
+
self::$instance = new NewsletterSystem();
|
20 |
+
}
|
21 |
+
return self::$instance;
|
22 |
+
}
|
23 |
+
|
24 |
+
function __construct() {
|
25 |
+
|
26 |
+
}
|
27 |
+
|
28 |
+
function reset_cron_stats() {
|
29 |
+
update_option('newsletter_diagnostic_cron_calls', [], false);
|
30 |
+
}
|
31 |
+
|
32 |
+
/**
|
33 |
+
*
|
34 |
+
* @param type $calls
|
35 |
+
* @return \TNP_Cron_Stats
|
36 |
+
*/
|
37 |
+
function get_cron_stats() {
|
38 |
+
$calls = get_option('newsletter_diagnostic_cron_calls', []);
|
39 |
+
|
40 |
+
// Not enough data
|
41 |
+
if (count($calls) < 12) {
|
42 |
+
return null;
|
43 |
+
}
|
44 |
+
|
45 |
+
$stats = new TNP_Cron_Stats();
|
46 |
+
|
47 |
+
for ($i = 1; $i < count($calls); $i++) {
|
48 |
+
$delta = $calls[$i] - $calls[$i - 1];
|
49 |
+
$stats->deltas[] = $delta;
|
50 |
+
if ($stats->min > $delta) {
|
51 |
+
$stats->min = $delta;
|
52 |
+
}
|
53 |
+
if ($stats->max < $delta) {
|
54 |
+
$stats->max = $delta;
|
55 |
+
}
|
56 |
+
}
|
57 |
+
$stats->avg = round(array_sum($stats->deltas) / count($stats->deltas));
|
58 |
+
$stats->good = $stats->avg < NEWSLETTER_CRON_INTERVAL * 1.1; // 10% error
|
59 |
+
return $stats;
|
60 |
+
}
|
61 |
+
|
62 |
+
function get_last_cron_call() {
|
63 |
+
$calls = get_option('newsletter_diagnostic_cron_calls', []);
|
64 |
+
if (empty($calls))
|
65 |
+
return 0;
|
66 |
+
return end($calls);
|
67 |
+
}
|
68 |
+
|
69 |
+
function has_newsletter_schedule() {
|
70 |
+
$schedules = wp_get_schedules();
|
71 |
+
if (!empty($schedules)) {
|
72 |
+
foreach ($schedules as $key => $data) {
|
73 |
+
if ($key == 'newsletter') {
|
74 |
+
return true;
|
75 |
+
}
|
76 |
+
}
|
77 |
+
}
|
78 |
+
return false;
|
79 |
+
}
|
80 |
+
|
81 |
+
/**
|
82 |
+
*
|
83 |
+
* @return boolean|int
|
84 |
+
*/
|
85 |
+
function get_job_delay() {
|
86 |
+
$x = wp_next_scheduled('newsletter');
|
87 |
+
return $x === false ? false : time() - $x;
|
88 |
+
}
|
89 |
+
|
90 |
+
function get_job_schedule() {
|
91 |
+
return wp_next_scheduled('newsletter');
|
92 |
+
}
|
93 |
+
|
94 |
+
function get_cache_job_status($refresh = false) {
|
95 |
+
$status = get_transient('newsletter_job_status');
|
96 |
+
if ($status === false || $refresh) {
|
97 |
+
$status = $this->get_job_status();
|
98 |
+
set_transient('newsletter_job_status', $status, DAY_IN_SECONDS);
|
99 |
+
}
|
100 |
+
return $status;
|
101 |
+
}
|
102 |
+
|
103 |
+
function get_job_status() {
|
104 |
+
|
105 |
+
$x = wp_next_scheduled('newsletter');
|
106 |
+
if ($x === false) {
|
107 |
+
return self::JOB_MISSING;
|
108 |
+
}
|
109 |
+
|
110 |
+
// Special case: the scheduler has been triggered but the job not executed
|
111 |
+
$calls = get_option('newsletter_diagnostic_cron_calls', []);
|
112 |
+
if (!empty($calls)) {
|
113 |
+
$last = end($calls);
|
114 |
+
if ($last > $x) {
|
115 |
+
return self::JOB_SKIPPED;
|
116 |
+
}
|
117 |
+
}
|
118 |
+
|
119 |
+
if (time() - $x > 900) {
|
120 |
+
return self::JOB_LATE;
|
121 |
+
}
|
122 |
+
return self::JOB_OK;
|
123 |
+
}
|
124 |
+
|
125 |
+
function reset_send_stats() {
|
126 |
+
update_option('newsletter_diagnostic_send_calls', [], false);
|
127 |
+
}
|
128 |
+
|
129 |
+
function get_send_stats() {
|
130 |
+
// Send calls stats
|
131 |
+
$send_calls = get_option('newsletter_diagnostic_send_calls', []);
|
132 |
+
if (!$send_calls) {
|
133 |
+
return null;
|
134 |
+
}
|
135 |
+
$send_max = 0;
|
136 |
+
$send_min = PHP_INT_MAX;
|
137 |
+
$send_total_time = 0;
|
138 |
+
$send_total_emails = 0;
|
139 |
+
$send_completed = 0;
|
140 |
+
$stats = new TNP_Send_stats();
|
141 |
+
|
142 |
+
// Batches
|
143 |
+
for ($i = 0; $i < count($send_calls); $i++) {
|
144 |
+
// 0 - batch start time
|
145 |
+
// 1 - batch end time
|
146 |
+
// 2 - number of sent email in this batch
|
147 |
+
// 3 - 0: prematurely stopped, 1: completed
|
148 |
+
if (empty($send_calls[$i][2])) {
|
149 |
+
continue;
|
150 |
+
}
|
151 |
+
if ($send_calls[$i][2] <= 1) {
|
152 |
+
continue;
|
153 |
+
}
|
154 |
+
|
155 |
+
$delta = $send_calls[$i][1] - $send_calls[$i][0];
|
156 |
+
$send_total_time += $delta;
|
157 |
+
$send_total_emails += $send_calls[$i][2];
|
158 |
+
|
159 |
+
$send_mean = $delta / $send_calls[$i][2];
|
160 |
+
$stats->means[] = $send_mean;
|
161 |
+
$stats->sizes[] = $send_calls[$i][2];
|
162 |
+
if ($send_min > $send_mean) {
|
163 |
+
$send_min = $send_mean;
|
164 |
+
}
|
165 |
+
if ($send_max < $send_mean) {
|
166 |
+
$send_max = $send_mean;
|
167 |
+
}
|
168 |
+
if (isset($send_calls[$i][3]) && $send_calls[$i][3]) {
|
169 |
+
$send_completed++;
|
170 |
+
}
|
171 |
+
}
|
172 |
+
|
173 |
+
if (empty($stats->means)) {
|
174 |
+
return null;
|
175 |
+
}
|
176 |
+
$send_mean = $send_total_time / $send_total_emails;
|
177 |
+
|
178 |
+
$stats->min = round($send_min, 2);
|
179 |
+
$stats->max = round($send_max, 2);
|
180 |
+
$stats->mean = round($send_mean, 2);
|
181 |
+
$stats->total_time = round($send_total_time);
|
182 |
+
$stats->total_emails = $send_total_emails;
|
183 |
+
$stats->total_runs = count($stats->means);
|
184 |
+
|
185 |
+
$stats->completed = $send_completed;
|
186 |
+
$stats->interrupted = $stats->total_runs - $stats->completed;
|
187 |
+
return $stats;
|
188 |
+
}
|
189 |
+
|
190 |
+
/**
|
191 |
+
* Returns a list of functions attached to the prvoded filter or action name.
|
192 |
+
*
|
193 |
+
* @global array $wp_filter
|
194 |
+
* @param string $tag
|
195 |
+
* @return string
|
196 |
+
*/
|
197 |
+
function get_hook_functions($tag) {
|
198 |
+
global $wp_filter;
|
199 |
+
$b = '';
|
200 |
+
if (isset($wp_filter[$tag])) {
|
201 |
+
foreach ($wp_filter[$tag]->callbacks as $priority => $functions) {
|
202 |
+
|
203 |
+
foreach ($functions as $function) {
|
204 |
+
$b .= '[' . $priority . '] ';
|
205 |
+
if (is_array($function['function'])) {
|
206 |
+
if (is_object($function['function'][0])) {
|
207 |
+
$b .= get_class($function['function'][0]) . '::' . $function['function'][1];
|
208 |
+
} else {
|
209 |
+
$b .= $function['function'][0] . '::' . $function['function'][1];
|
210 |
+
}
|
211 |
+
} else {
|
212 |
+
if (is_object($function['function'])) {
|
213 |
+
$fn = new ReflectionFunction($function['function']);
|
214 |
+
$b .= get_class($fn->getClosureThis()) . '(closure)';
|
215 |
+
} else {
|
216 |
+
$b .= $function['function'];
|
217 |
+
}
|
218 |
+
}
|
219 |
+
$b .= "<br>";
|
220 |
+
}
|
221 |
+
}
|
222 |
+
}
|
223 |
+
return $b;
|
224 |
+
}
|
225 |
+
|
226 |
+
}
|
227 |
+
|
228 |
+
class TNP_Cron_Stats {
|
229 |
+
|
230 |
+
var $min = PHP_INT_MAX;
|
231 |
+
var $max = 0;
|
232 |
+
var $avg = 0;
|
233 |
+
/* List of intervals between cron calls */
|
234 |
+
var $deltas = [];
|
235 |
+
/* If the cron is triggered enough often */
|
236 |
+
var $good = true;
|
237 |
+
|
238 |
+
}
|
239 |
+
|
240 |
+
class TNP_Send_Stats {
|
241 |
+
|
242 |
+
/* Emails sent */
|
243 |
+
var $total_emails;
|
244 |
+
/* Total batches collected (1 sized-batch by Autoresponder are ignored) */
|
245 |
+
var $total_runs;
|
246 |
+
/* Total sending time of the collected batches */
|
247 |
+
var $total_time;
|
248 |
+
/* Batch completed without timeout or max emails limit */
|
249 |
+
var $completed;
|
250 |
+
/* Batches interrupted due to reached limits */
|
251 |
+
var $interrupted;
|
252 |
+
/* Min time to send an email */
|
253 |
+
var $min = PHP_INT_MAX;
|
254 |
+
/* Max time to send an email */
|
255 |
+
var $max = 0;
|
256 |
+
/* Average time to send all collected emails */
|
257 |
+
var $mean = 0;
|
258 |
+
/* List of single batches average per email sending time */
|
259 |
+
var $means = [];
|
260 |
+
/* Number of emails in the single batches */
|
261 |
+
var $sizes = [];
|
262 |
+
|
263 |
+
}
|
main/delivery.php
CHANGED
@@ -1,220 +1,220 @@
|
|
1 |
-
<?php
|
2 |
-
/* @var $this Newsletter */
|
3 |
-
/* @var $wpdb wpdb */
|
4 |
-
|
5 |
-
defined('ABSPATH') || exit;
|
6 |
-
|
7 |
-
include_once NEWSLETTER_INCLUDES_DIR . '/controls.php';
|
8 |
-
$controls = new NewsletterControls();
|
9 |
-
|
10 |
-
if ($controls->is_action('test')) {
|
11 |
-
|
12 |
-
if (!NewsletterModule::is_email($controls->data['test_email'])) {
|
13 |
-
$controls->errors = 'The test email address is not set or is not correct.';
|
14 |
-
}
|
15 |
-
|
16 |
-
if (empty($controls->errors)) {
|
17 |
-
|
18 |
-
$options = $controls->data;
|
19 |
-
|
20 |
-
if ($controls->data['test_email'] == $this->options['sender_email']) {
|
21 |
-
$controls->messages .= '<strong>Warning:</strong> you are using as test email the same address configured as sender in main configuration. Test can fail because of that.<br>';
|
22 |
-
}
|
23 |
-
|
24 |
-
$message = NewsletterMailerAddon::get_test_message($controls->data['test_email'], 'Newsletter test email at ' . date(DATE_ISO8601));
|
25 |
-
|
26 |
-
$r = $this->deliver($message);
|
27 |
-
|
28 |
-
if (!is_wp_error($r)) {
|
29 |
-
$options['mail'] = 1;
|
30 |
-
$controls->messages .= '<strong>SUCCESS</strong><br>';
|
31 |
-
$controls->messages .= 'Anyway if the message does not appear the mailbox (check even the spam folder) you can ';
|
32 |
-
$controls->messages .= '<a href="https://www.thenewsletterplugin.com/documentation/?p=15170" target="_blank"><strong>read more here</strong></a>.';
|
33 |
-
} else {
|
34 |
-
$options['mail'] = 0;
|
35 |
-
$options['mail_error'] = $r->get_error_message();
|
36 |
-
|
37 |
-
$controls->errors .= '<strong>FAILED</strong> (' . $r->get_error_message() . ')<br>';
|
38 |
-
|
39 |
-
if (!empty($this->options['return_path'])) {
|
40 |
-
$controls->errors .= '- Try to remove the return path on main settings.<br>';
|
41 |
-
}
|
42 |
-
|
43 |
-
$controls->errors .= '<a href="https://www.thenewsletterplugin.com/documentation/?p=15170" target="_blank"><strong>' . __('Read more', 'newsletter') . '</strong></a>.';
|
44 |
-
|
45 |
-
$parts = explode('@', $this->options['sender_email']);
|
46 |
-
$sitename = strtolower($_SERVER['SERVER_NAME']);
|
47 |
-
if (substr($sitename, 0, 4) == 'www.') {
|
48 |
-
$sitename = substr($sitename, 4);
|
49 |
-
}
|
50 |
-
if (strtolower($sitename) != strtolower($parts[1])) {
|
51 |
-
$controls->errors .= '- Try to set on main setting a sender address with the same domain of your blog: ' . $sitename . ' (you are using ' . $this->options['sender_email'] . ')<br>';
|
52 |
-
}
|
53 |
-
}
|
54 |
-
$this->save_options($options, 'status');
|
55 |
-
}
|
56 |
-
}
|
57 |
-
|
58 |
-
$options = $this->get_options('status');
|
59 |
-
|
60 |
-
$mailer = Newsletter::instance()->get_mailer();
|
61 |
-
$functions = tnp_get_hook_functions('phpmailer_init');
|
62 |
-
$icon = 'fas fa-plug';
|
63 |
-
if ($mailer instanceof NewsletterDefaultMailer) {
|
64 |
-
$mailer_name = 'Wordpress';
|
65 |
-
$service_name = 'Hosting Provider';
|
66 |
-
if (!empty($functions)) {
|
67 |
-
$mailer_name .= '<br>(see below)';
|
68 |
-
$service_name .= '<br>(see below)';
|
69 |
-
}
|
70 |
-
$icon = 'fab fa-wordpress';
|
71 |
-
} else if ($mailer instanceof NewsletterDefaultSMTPMailer) {
|
72 |
-
$mailer_name = 'Internal SMTP';
|
73 |
-
$service_name = 'SMTP Provider';
|
74 |
-
} else {
|
75 |
-
$mailer_name = 'Unknown';
|
76 |
-
$service_name = 'Unknown';
|
77 |
-
if (is_object($mailer)) {
|
78 |
-
if (method_exists($mailer, 'get_description')) {
|
79 |
-
$mailer_name = esc_html($mailer->get_description());
|
80 |
-
$service_name = esc_html(ucfirst($mailer->get_name()));
|
81 |
-
} else {
|
82 |
-
$mailer_name = esc_html(get_class($mailer));
|
83 |
-
$service_name = $mailer_name;
|
84 |
-
}
|
85 |
-
}
|
86 |
-
}
|
87 |
-
|
88 |
-
function tnp_get_hook_functions($tag) {
|
89 |
-
global $wp_filter;
|
90 |
-
if (isset($wp_filter)) {
|
91 |
-
$b = '';
|
92 |
-
foreach ($wp_filter[$tag]->callbacks as $priority => $functions) {
|
93 |
-
|
94 |
-
foreach ($functions as $function) {
|
95 |
-
$b .= '[' . $priority . '] ';
|
96 |
-
if (is_array($function['function'])) {
|
97 |
-
if (is_object($function['function'][0])) {
|
98 |
-
$b .= get_class($function['function'][0]) . '::' . $function['function'][1];
|
99 |
-
} else {
|
100 |
-
$b .= $function['function'][0] . '::' . $function['function'][1];
|
101 |
-
}
|
102 |
-
} else {
|
103 |
-
if (is_object($function['function'])) {
|
104 |
-
$fn = new ReflectionFunction($function['function']);
|
105 |
-
$b .= get_class($fn->getClosureThis()) . '(closure)';
|
106 |
-
} else {
|
107 |
-
$b .= $function['function'];
|
108 |
-
}
|
109 |
-
}
|
110 |
-
$b .= "<br>";
|
111 |
-
}
|
112 |
-
}
|
113 |
-
}
|
114 |
-
return $b;
|
115 |
-
}
|
116 |
-
|
117 |
-
$speed = Newsletter::$instance->options['scheduler_max'];
|
118 |
-
?>
|
119 |
-
<style>
|
120 |
-
.tnp-flow {
|
121 |
-
margin-top: 30px;
|
122 |
-
}
|
123 |
-
.tnp-flow div {
|
124 |
-
display: inline-block;
|
125 |
-
vertical-align: middle;
|
126 |
-
color: #fff;
|
127 |
-
text-align: center;
|
128 |
-
margin: 0 20px;
|
129 |
-
padding: 1em;
|
130 |
-
}
|
131 |
-
.tnp-flow div i {
|
132 |
-
font-size: 50px;
|
133 |
-
}
|
134 |
-
.tnp-flow div.tnp-arrow {
|
135 |
-
font-size: 40px;
|
136 |
-
color: #bbb;
|
137 |
-
padding: 0;
|
138 |
-
margin: 0;
|
139 |
-
}
|
140 |
-
.tnp-mail, .tnp-addon, .tnp-service {
|
141 |
-
height: 150px;
|
142 |
-
width: 150px;
|
143 |
-
border: 1px solid #fff;
|
144 |
-
}
|
145 |
-
</style>
|
146 |
-
|
147 |
-
<div class="wrap tnp-main-status" id="tnp-wrap">
|
148 |
-
|
149 |
-
<?php include NEWSLETTER_DIR . '/tnp-header.php'; ?>
|
150 |
-
|
151 |
-
<div id="tnp-heading">
|
152 |
-
|
153 |
-
<h2><?php _e('Email Delivery', 'newsletter') ?></h2>
|
154 |
-
|
155 |
-
</div>
|
156 |
-
|
157 |
-
<div id="tnp-body">
|
158 |
-
<form method="post" action="">
|
159 |
-
<?php $controls->init(); ?>
|
160 |
-
<h3>Mailing test</h3>
|
161 |
-
|
162 |
-
<p>
|
163 |
-
<?php $controls->text_email('test_email') ?> <?php $controls->button('test', __('Send a test message')) ?>
|
164 |
-
<?php if (empty($options['mail'])) { ?>
|
165 |
-
<span class="tnp-ko">KO</span>
|
166 |
-
<?php } else { ?>
|
167 |
-
<span class="tnp-ok">OK</span>
|
168 |
-
<?php } ?>
|
169 |
-
</p>
|
170 |
-
|
171 |
-
<p>
|
172 |
-
<?php if (empty($options['mail'])) { ?>
|
173 |
-
<?php if (empty($options['mail_error'])) { ?>
|
174 |
-
<p>A test has never run.</p>
|
175 |
-
<?php } else { ?>
|
176 |
-
<p>Last test failed with error "<?php echo esc_html($options['mail_error']) ?>".</p>
|
177 |
-
|
178 |
-
<?php } ?>
|
179 |
-
<?php } else { ?>
|
180 |
-
<p>Last test was successful. If you didn't receive the test email:</p>
|
181 |
-
<ol style="color: #fff">
|
182 |
-
<li>If you're using an third party SMTP plugin, do a test from that plugin configuration panel</li>
|
183 |
-
<li>If you're using a Newsletter Delivery Addon, do a test from that addon configuration panel</li>
|
184 |
-
<li>If previous points do not apply to you, ask for support to your provider reporting the emails from your blog are not delivered</li>
|
185 |
-
</ol>
|
186 |
-
<?php } ?>
|
187 |
-
<p><a href="https://www.thenewsletterplugin.com/documentation/email-sending-issues" target="_blank">Read more to solve your issues, if any</a></p>
|
188 |
-
|
189 |
-
|
190 |
-
</form>
|
191 |
-
|
192 |
-
<h3>
|
193 |
-
How are messages delivered by Newsletter to your subscribers?
|
194 |
-
</h3>
|
195 |
-
|
196 |
-
<div class="tnp-flow">
|
197 |
-
<div class="tnp-mail"><i class="fas fa-envelope"></i><br><br>Messages<br>
|
198 |
-
(max: <?php echo esc_html($speed) ?> emails per hour)
|
199 |
-
</div>
|
200 |
-
<div class="tnp-arrow">→</div>
|
201 |
-
<div class="tnp-addon"><i class="<?php echo $icon ?>"></i><br><br><?php echo $mailer_name ?></div>
|
202 |
-
<div class="tnp-arrow">→</div>
|
203 |
-
<div class="tnp-service"><i class="fas fa-cog"></i><br><br>
|
204 |
-
<?php echo $service_name ?>
|
205 |
-
</div>
|
206 |
-
<div class="tnp-arrow">→</div>
|
207 |
-
<div class="tnp-user"><i class="fas fa-user"></i></div>
|
208 |
-
</div>
|
209 |
-
|
210 |
-
|
211 |
-
<?php if (!empty($functions)) { ?>
|
212 |
-
<br><br>
|
213 |
-
<h3>Functions that are changing the default WordPress delivery system</h3>
|
214 |
-
<p><?php echo $functions ?></p>
|
215 |
-
<?php } ?>
|
216 |
-
|
217 |
-
|
218 |
-
</div>
|
219 |
-
<?php include NEWSLETTER_DIR . '/tnp-footer.php'; ?>
|
220 |
-
</div>
|
1 |
+
<?php
|
2 |
+
/* @var $this Newsletter */
|
3 |
+
/* @var $wpdb wpdb */
|
4 |
+
|
5 |
+
defined('ABSPATH') || exit;
|
6 |
+
|
7 |
+
include_once NEWSLETTER_INCLUDES_DIR . '/controls.php';
|
8 |
+
$controls = new NewsletterControls();
|
9 |
+
|
10 |
+
if ($controls->is_action('test')) {
|
11 |
+
|
12 |
+
if (!NewsletterModule::is_email($controls->data['test_email'])) {
|
13 |
+
$controls->errors = 'The test email address is not set or is not correct.';
|
14 |
+
}
|
15 |
+
|
16 |
+
if (empty($controls->errors)) {
|
17 |
+
|
18 |
+
$options = $controls->data;
|
19 |
+
|
20 |
+
if ($controls->data['test_email'] == $this->options['sender_email']) {
|
21 |
+
$controls->messages .= '<strong>Warning:</strong> you are using as test email the same address configured as sender in main configuration. Test can fail because of that.<br>';
|
22 |
+
}
|
23 |
+
|
24 |
+
$message = NewsletterMailerAddon::get_test_message($controls->data['test_email'], 'Newsletter test email at ' . date(DATE_ISO8601));
|
25 |
+
|
26 |
+
$r = $this->deliver($message);
|
27 |
+
|
28 |
+
if (!is_wp_error($r)) {
|
29 |
+
$options['mail'] = 1;
|
30 |
+
$controls->messages .= '<strong>SUCCESS</strong><br>';
|
31 |
+
$controls->messages .= 'Anyway if the message does not appear the mailbox (check even the spam folder) you can ';
|
32 |
+
$controls->messages .= '<a href="https://www.thenewsletterplugin.com/documentation/?p=15170" target="_blank"><strong>read more here</strong></a>.';
|
33 |
+
} else {
|
34 |
+
$options['mail'] = 0;
|
35 |
+
$options['mail_error'] = $r->get_error_message();
|
36 |
+
|
37 |
+
$controls->errors .= '<strong>FAILED</strong> (' . $r->get_error_message() . ')<br>';
|
38 |
+
|
39 |
+
if (!empty($this->options['return_path'])) {
|
40 |
+
$controls->errors .= '- Try to remove the return path on main settings.<br>';
|
41 |
+
}
|
42 |
+
|
43 |
+
$controls->errors .= '<a href="https://www.thenewsletterplugin.com/documentation/?p=15170" target="_blank"><strong>' . __('Read more', 'newsletter') . '</strong></a>.';
|
44 |
+
|
45 |
+
$parts = explode('@', $this->options['sender_email']);
|
46 |
+
$sitename = strtolower($_SERVER['SERVER_NAME']);
|
47 |
+
if (substr($sitename, 0, 4) == 'www.') {
|
48 |
+
$sitename = substr($sitename, 4);
|
49 |
+
}
|
50 |
+
if (strtolower($sitename) != strtolower($parts[1])) {
|
51 |
+
$controls->errors .= '- Try to set on main setting a sender address with the same domain of your blog: ' . $sitename . ' (you are using ' . $this->options['sender_email'] . ')<br>';
|
52 |
+
}
|
53 |
+
}
|
54 |
+
$this->save_options($options, 'status');
|
55 |
+
}
|
56 |
+
}
|
57 |
+
|
58 |
+
$options = $this->get_options('status');
|
59 |
+
|
60 |
+
$mailer = Newsletter::instance()->get_mailer();
|
61 |
+
$functions = tnp_get_hook_functions('phpmailer_init');
|
62 |
+
$icon = 'fas fa-plug';
|
63 |
+
if ($mailer instanceof NewsletterDefaultMailer) {
|
64 |
+
$mailer_name = 'Wordpress';
|
65 |
+
$service_name = 'Hosting Provider';
|
66 |
+
if (!empty($functions)) {
|
67 |
+
$mailer_name .= '<br>(see below)';
|
68 |
+
$service_name .= '<br>(see below)';
|
69 |
+
}
|
70 |
+
$icon = 'fab fa-wordpress';
|
71 |
+
} else if ($mailer instanceof NewsletterDefaultSMTPMailer) {
|
72 |
+
$mailer_name = 'Internal SMTP';
|
73 |
+
$service_name = 'SMTP Provider';
|
74 |
+
} else {
|
75 |
+
$mailer_name = 'Unknown';
|
76 |
+
$service_name = 'Unknown';
|
77 |
+
if (is_object($mailer)) {
|
78 |
+
if (method_exists($mailer, 'get_description')) {
|
79 |
+
$mailer_name = esc_html($mailer->get_description());
|
80 |
+
$service_name = esc_html(ucfirst($mailer->get_name()));
|
81 |
+
} else {
|
82 |
+
$mailer_name = esc_html(get_class($mailer));
|
83 |
+
$service_name = $mailer_name;
|
84 |
+
}
|
85 |
+
}
|
86 |
+
}
|
87 |
+
|
88 |
+
function tnp_get_hook_functions($tag) {
|
89 |
+
global $wp_filter;
|
90 |
+
if (isset($wp_filter)) {
|
91 |
+
$b = '';
|
92 |
+
foreach ($wp_filter[$tag]->callbacks as $priority => $functions) {
|
93 |
+
|
94 |
+
foreach ($functions as $function) {
|
95 |
+
$b .= '[' . $priority . '] ';
|
96 |
+
if (is_array($function['function'])) {
|
97 |
+
if (is_object($function['function'][0])) {
|
98 |
+
$b .= get_class($function['function'][0]) . '::' . $function['function'][1];
|
99 |
+
} else {
|
100 |
+
$b .= $function['function'][0] . '::' . $function['function'][1];
|
101 |
+
}
|
102 |
+
} else {
|
103 |
+
if (is_object($function['function'])) {
|
104 |
+
$fn = new ReflectionFunction($function['function']);
|
105 |
+
$b .= get_class($fn->getClosureThis()) . '(closure)';
|
106 |
+
} else {
|
107 |
+
$b .= $function['function'];
|
108 |
+
}
|
109 |
+
}
|
110 |
+
$b .= "<br>";
|
111 |
+
}
|
112 |
+
}
|
113 |
+
}
|
114 |
+
return $b;
|
115 |
+
}
|
116 |
+
|
117 |
+
$speed = Newsletter::$instance->options['scheduler_max'];
|
118 |
+
?>
|
119 |
+
<style>
|
120 |
+
.tnp-flow {
|
121 |
+
margin-top: 30px;
|
122 |
+
}
|
123 |
+
.tnp-flow div {
|
124 |
+
display: inline-block;
|
125 |
+
vertical-align: middle;
|
126 |
+
color: #fff;
|
127 |
+
text-align: center;
|
128 |
+
margin: 0 20px;
|
129 |
+
padding: 1em;
|
130 |
+
}
|
131 |
+
.tnp-flow div i {
|
132 |
+
font-size: 50px;
|
133 |
+
}
|
134 |
+
.tnp-flow div.tnp-arrow {
|
135 |
+
font-size: 40px;
|
136 |
+
color: #bbb;
|
137 |
+
padding: 0;
|
138 |
+
margin: 0;
|
139 |
+
}
|
140 |
+
.tnp-mail, .tnp-addon, .tnp-service {
|
141 |
+
height: 150px;
|
142 |
+
width: 150px;
|
143 |
+
border: 1px solid #fff;
|
144 |
+
}
|
145 |
+
</style>
|
146 |
+
|
147 |
+
<div class="wrap tnp-main-status" id="tnp-wrap">
|
148 |
+
|
149 |
+
<?php include NEWSLETTER_DIR . '/tnp-header.php'; ?>
|
150 |
+
|
151 |
+
<div id="tnp-heading">
|
152 |
+
|
153 |
+
<h2><?php _e('Email Delivery', 'newsletter') ?></h2>
|
154 |
+
|
155 |
+
</div>
|
156 |
+
|
157 |
+
<div id="tnp-body">
|
158 |
+
<form method="post" action="">
|
159 |
+
<?php $controls->init(); ?>
|
160 |
+
<h3>Mailing test</h3>
|
161 |
+
|
162 |
+
<p>
|
163 |
+
<?php $controls->text_email('test_email') ?> <?php $controls->button('test', __('Send a test message')) ?>
|
164 |
+
<?php if (empty($options['mail'])) { ?>
|
165 |
+
<span class="tnp-ko">KO</span>
|
166 |
+
<?php } else { ?>
|
167 |
+
<span class="tnp-ok">OK</span>
|
168 |
+
<?php } ?>
|
169 |
+
</p>
|
170 |
+
|
171 |
+
<p>
|
172 |
+
<?php if (empty($options['mail'])) { ?>
|
173 |
+
<?php if (empty($options['mail_error'])) { ?>
|
174 |
+
<p>A test has never run.</p>
|
175 |
+
<?php } else { ?>
|
176 |
+
<p>Last test failed with error "<?php echo esc_html($options['mail_error']) ?>".</p>
|
177 |
+
|
178 |
+
<?php } ?>
|
179 |
+
<?php } else { ?>
|
180 |
+
<p>Last test was successful. If you didn't receive the test email:</p>
|
181 |
+
<ol style="color: #fff">
|
182 |
+
<li>If you're using an third party SMTP plugin, do a test from that plugin configuration panel</li>
|
183 |
+
<li>If you're using a Newsletter Delivery Addon, do a test from that addon configuration panel</li>
|
184 |
+
<li>If previous points do not apply to you, ask for support to your provider reporting the emails from your blog are not delivered</li>
|
185 |
+
</ol>
|
186 |
+
<?php } ?>
|
187 |
+
<p><a href="https://www.thenewsletterplugin.com/documentation/email-sending-issues" target="_blank">Read more to solve your issues, if any</a></p>
|
188 |
+
|
189 |
+
|
190 |
+
</form>
|
191 |
+
|
192 |
+
<h3>
|
193 |
+
How are messages delivered by Newsletter to your subscribers?
|
194 |
+
</h3>
|
195 |
+
|
196 |
+
<div class="tnp-flow">
|
197 |
+
<div class="tnp-mail"><i class="fas fa-envelope"></i><br><br>Messages<br>
|
198 |
+
(max: <?php echo esc_html($speed) ?> emails per hour)
|
199 |
+
</div>
|
200 |
+
<div class="tnp-arrow">→</div>
|
201 |
+
<div class="tnp-addon"><i class="<?php echo $icon ?>"></i><br><br><?php echo $mailer_name ?></div>
|
202 |
+
<div class="tnp-arrow">→</div>
|
203 |
+
<div class="tnp-service"><i class="fas fa-cog"></i><br><br>
|
204 |
+
<?php echo $service_name ?>
|
205 |
+
</div>
|
206 |
+
<div class="tnp-arrow">→</div>
|
207 |
+
<div class="tnp-user"><i class="fas fa-user"></i></div>
|
208 |
+
</div>
|
209 |
+
|
210 |
+
|
211 |
+
<?php if (!empty($functions)) { ?>
|
212 |
+
<br><br>
|
213 |
+
<h3>Functions that are changing the default WordPress delivery system</h3>
|
214 |
+
<p><?php echo $functions ?></p>
|
215 |
+
<?php } ?>
|
216 |
+
|
217 |
+
|
218 |
+
</div>
|
219 |
+
<?php include NEWSLETTER_DIR . '/tnp-footer.php'; ?>
|
220 |
+
</div>
|
main/scheduler.php
CHANGED
@@ -1,411 +1,412 @@
|
|
1 |
-
<?php
|
2 |
-
/* @var $this Newsletter */
|
3 |
-
/* @var $wpdb wpdb */
|
4 |
-
|
5 |
-
defined('ABSPATH') || exit;
|
6 |
-
|
7 |
-
wp_enqueue_script('tnp-chart');
|
8 |
-
|
9 |
-
include_once NEWSLETTER_INCLUDES_DIR . '/controls.php';
|
10 |
-
$controls = new NewsletterControls();
|
11 |
-
$system = NewsletterSystem::instance();
|
12 |
-
|
13 |
-
if ($controls->is_action('reset')) {
|
14 |
-
$system->reset_cron_stats();
|
15 |
-
$controls->add_message_done();
|
16 |
-
}
|
17 |
-
|
18 |
-
if ($controls->is_action('reschedule')) {
|
19 |
-
wp_clear_scheduled_hook('newsletter');
|
20 |
-
wp_schedule_event(time() + 30, 'newsletter', 'newsletter');
|
21 |
-
$controls->add_message_done();
|
22 |
-
}
|
23 |
-
|
24 |
-
if ($controls->is_action('trigger')) {
|
25 |
-
wp_clear_scheduled_hook('newsletter');
|
26 |
-
wp_schedule_event(time() + NEWSLETTER_CRON_INTERVAL, 'newsletter', 'newsletter');
|
27 |
-
Newsletter::instance()->hook_newsletter();
|
28 |
-
$controls->add_message_done();
|
29 |
-
}
|
30 |
-
|
31 |
-
if ($controls->is_action('test')) {
|
32 |
-
$response = wp_remote_get(site_url('/wp-cron.php') . '?' . time());
|
33 |
-
if (is_wp_error($response)) {
|
34 |
-
$controls->errors = 'Test failed: ' . esc_html($response->get_error_message());
|
35 |
-
} else if (wp_remote_retrieve_response_code($response) != 200) {
|
36 |
-
$controls->errors = 'Test failed: ' . esc_html(wp_remote_retrieve_response_message($response));
|
37 |
-
} else {
|
38 |
-
$controls->add_message('Test ok');
|
39 |
-
}
|
40 |
-
|
41 |
-
if ($controls->errors) {
|
42 |
-
$controls->errors .= '<br>Report this error to your provider saying the site cannot make an HTTP call to its wp-cron.php file and copying the error message above.';
|
43 |
-
}
|
44 |
-
}
|
45 |
-
|
46 |
-
function tnp_status_print_flag($condition, $url = '') {
|
47 |
-
switch ($condition) {
|
48 |
-
case 0: echo ' <span class="tnp-ko">KO</span>';
|
49 |
-
break;
|
50 |
-
case 1: echo '<span class="tnp-ok">OK</span>';
|
51 |
-
break;
|
52 |
-
case 2: echo '<span class="tnp-maybe">MAYBE</span>';
|
53 |
-
break;
|
54 |
-
}
|
55 |
-
if ($url) {
|
56 |
-
echo '<a href="', $url, '" target="_blank">Read more</a>';
|
57 |
-
}
|
58 |
-
}
|
59 |
-
|
60 |
-
$system = NewsletterSystem::instance();
|
61 |
-
?>
|
62 |
-
|
63 |
-
<style>
|
64 |
-
#tnp-body table.widefat td {
|
65 |
-
vertical-align: top;
|
66 |
-
}
|
67 |
-
#tnp-body table.widefat td.status {
|
68 |
-
text-align: center;
|
69 |
-
}
|
70 |
-
</style>
|
71 |
-
<div class="wrap tnp-main-status" id="tnp-wrap">
|
72 |
-
|
73 |
-
<?php include NEWSLETTER_DIR . '/tnp-header.php'; ?>
|
74 |
-
|
75 |
-
<div id="tnp-heading">
|
76 |
-
|
77 |
-
<h2><?php _e('WordPress Scheduler and Newsletter Delivery Engine', 'newsletter') ?></h2>
|
78 |
-
<p>
|
79 |
-
The scheduler is a WordPress component that executes <strong>background tasks</strong>
|
80 |
-
(publish future post, run backups, send newsletters, ...).
|
81 |
-
<br>
|
82 |
-
Here some steps you can consider if the scheduler has issues.
|
83 |
-
</p>
|
84 |
-
<ul>
|
85 |
-
<li>Check the <a href="<?php echo admin_url('/site-health.php') ?>">site health panel</a> and try to solve the issues identified by WordPress in your site</li>
|
86 |
-
<li>Install the <a href="https://wordpress.org/plugins/wp-crontrol/" target="_blank">WP Crontol</a> plugin which shows all the scheduled jobs and delays</li>
|
87 |
-
<li>Configure an <a href="https://www.thenewsletterplugin.com/documentation/delivery-and-spam/newsletter-delivery-engine/" target="_blank">external cron service</a>
|
88 |
-
(if you have a license you can use our <a href="https://www.thenewsletterplugin.com/account/cron/" target="_blank">cron service</a>)</li>
|
89 |
-
</ul>
|
90 |
-
</div>
|
91 |
-
|
92 |
-
<div id="tnp-body">
|
93 |
-
|
94 |
-
|
95 |
-
<form method="post" action="">
|
96 |
-
<?php $controls->init(); ?>
|
97 |
-
|
98 |
-
<table class="widefat">
|
99 |
-
<?php
|
100 |
-
$status = $system->get_job_status();
|
101 |
-
$condition = $status == NewsletterSystem::JOB_OK ? 1 : 0;
|
102 |
-
?>
|
103 |
-
<tr>
|
104 |
-
<td>Delivery background job</td>
|
105 |
-
<td class="status">
|
106 |
-
<?php tnp_status_print_flag($condition, 'https://www.thenewsletterplugin.com/documentation/delivery-and-spam/newsletter-delivery-engine/') ?>
|
107 |
-
</td>
|
108 |
-
<td>
|
109 |
-
<?php
|
110 |
-
switch ($status) {
|
111 |
-
case NewsletterSystem::JOB_MISSING:
|
112 |
-
echo 'The engine
|
113 |
-
break;
|
114 |
-
case NewsletterSystem::JOB_LATE:
|
115 |
-
echo 'The engine
|
116 |
-
break;
|
117 |
-
case NewsletterSystem::JOB_SKIPPED:
|
118 |
-
echo 'The engine
|
119 |
-
break;
|
120 |
-
case NewsletterSystem::JOB_OK:
|
121 |
-
echo 'Everything seems fine!';
|
122 |
-
break;
|
123 |
-
}
|
124 |
-
?>
|
125 |
-
<br><br>
|
126 |
-
Next run: <?php echo $controls->print_date($system->get_job_schedule(), false, true) ?>
|
127 |
-
<br><br>
|
128 |
-
<?php
|
129 |
-
if ($status == NewsletterSystem::JOB_LATE) {
|
130 |
-
$controls->button('trigger', 'Run manually');
|
131 |
-
}
|
132 |
-
?>
|
133 |
-
</td>
|
134 |
-
</tr>
|
135 |
-
|
136 |
-
|
137 |
-
<tr>
|
138 |
-
<td>Last cron call</td>
|
139 |
-
<td class="status"> </td>
|
140 |
-
<td>
|
141 |
-
<?php echo $controls->print_date($system->get_last_cron_call()) ?>
|
142 |
-
</td>
|
143 |
-
</tr>
|
144 |
-
|
145 |
-
|
146 |
-
<tr>
|
147 |
-
<?php
|
148 |
-
$stats = NewsletterSystem::instance()->get_cron_stats();
|
149 |
-
?>
|
150 |
-
<td>
|
151 |
-
Cron call stats
|
152 |
-
</td>
|
153 |
-
<?php if ($stats == null) { ?>
|
154 |
-
<td class="status">
|
155 |
-
|
156 |
-
</td>
|
157 |
-
<td>
|
158 |
-
Not enough data, some hours are still required.
|
159 |
-
</td>
|
160 |
-
|
161 |
-
<?php } else { ?>
|
162 |
-
|
163 |
-
<?php
|
164 |
-
$condition = $stats->good ? 1 : 0;
|
165 |
-
?>
|
166 |
-
|
167 |
-
<td class="status">
|
168 |
-
<?php tnp_status_print_flag($condition, 'https://www.thenewsletterplugin.com/documentation/delivery-and-spam/newsletter-delivery-engine/') ?>
|
169 |
-
</td>
|
170 |
-
<td>
|
171 |
-
<?php if ($condition == 0) { ?>
|
172 |
-
The blog cron system is NOT triggered enough often.<br>
|
173 |
-
<?php } ?>
|
174 |
-
|
175 |
-
Samples <?php echo count($stats->deltas) ?>, average <?php echo $stats->avg ?> s, max <?php echo $stats->max ?> s, min <?php echo $stats->min ?> s
|
176 |
-
|
177 |
-
<canvas id="tnp-cron-chart" style="width: 550px; height: 180px"></canvas>
|
178 |
-
<script>
|
179 |
-
jQuery(function () {
|
180 |
-
var cronChartData = {
|
181 |
-
labels: <?php echo json_encode(range(1, count($stats->deltas))) ?>,
|
182 |
-
datasets: [
|
183 |
-
{
|
184 |
-
label: "Batch Average Time",
|
185 |
-
data: <?php echo json_encode($stats->deltas) ?>,
|
186 |
-
borderColor: '#2980b9',
|
187 |
-
fill: false
|
188 |
-
}]
|
189 |
-
};
|
190 |
-
var cronChartConfig = {
|
191 |
-
type: "line",
|
192 |
-
data: cronChartData,
|
193 |
-
options: {
|
194 |
-
responsive: false,
|
195 |
-
maintainAspectRatio: false,
|
196 |
-
scales: {
|
197 |
-
x: {
|
198 |
-
type: 'linear'
|
199 |
-
}
|
200 |
-
}
|
201 |
-
}
|
202 |
-
};
|
203 |
-
new Chart('tnp-cron-chart', cronChartConfig);
|
204 |
-
});
|
205 |
-
</script>
|
206 |
-
|
207 |
-
<?php $controls->button_reset() ?>
|
208 |
-
|
209 |
-
</td>
|
210 |
-
<?php } ?>
|
211 |
-
</tr>
|
212 |
-
|
213 |
-
<?php
|
214 |
-
$condition = $system->has_newsletter_schedule() ? 1 : 0;
|
215 |
-
$schedules = wp_get_schedules();
|
216 |
-
?>
|
217 |
-
<tr>
|
218 |
-
<td>
|
219 |
-
Newsletter engine schedule
|
220 |
-
</td>
|
221 |
-
<td class="status"><?php tnp_status_print_flag($condition) ?></td>
|
222 |
-
<td>
|
223 |
-
<?php if (!$condition) { ?>
|
224 |
-
The Newsletter schedule is not present probably another plugin is interfering with the starndard WordPress scheuling system.<br>
|
225 |
-
You can reactivate it, but is the problem persist
|
226 |
-
<?php $controls->button('reschedule', 'Reactivate') ?>
|
227 |
-
<?php } ?>
|
228 |
-
|
229 |
-
Registered recurring schedules:<br>
|
230 |
-
<ul style="margin-left: 0em;">
|
231 |
-
<?php
|
232 |
-
if (!empty($schedules)) {
|
233 |
-
foreach ($schedules as $key => $data) {
|
234 |
-
if ($key == 'newsletter') {
|
235 |
-
echo '<li style="padding: 0; margin: 0; font-weight: bold">', esc_html($key . ' - ' . $data['interval']), ' seconds</li>';
|
236 |
-
} else {
|
237 |
-
echo '<li style="padding: 0; margin: 0;">', esc_html($key . ' - ' . $data['interval']), ' seconds</li>';
|
238 |
-
}
|
239 |
-
}
|
240 |
-
}
|
241 |
-
?>
|
242 |
-
</ul>
|
243 |
-
</td>
|
244 |
-
</tr>
|
245 |
-
|
246 |
-
|
247 |
-
<tr>
|
248 |
-
<td>Cron URL</td>
|
249 |
-
<td class="status"> </td>
|
250 |
-
<td>
|
251 |
-
<strong><?php echo esc_html(site_url('/wp-cron.php')) ?></strong>
|
252 |
-
<br><br>
|
253 |
-
Can be used to trigger the WordPress scheduler from an external cron service.
|
254 |
-
</td>
|
255 |
-
</tr>
|
256 |
-
|
257 |
-
|
258 |
-
|
259 |
-
|
260 |
-
<tr>
|
261 |
-
<td>
|
262 |
-
WordPress scheduler auto trigger
|
263 |
-
</td>
|
264 |
-
<td class="status">
|
265 |
-
<?php //tnp_status_print_flag($condition) ?>
|
266 |
-
</td>
|
267 |
-
<td>
|
268 |
-
<?php $controls->button_test() ?>
|
269 |
-
</td>
|
270 |
-
</tr>
|
271 |
-
|
272 |
-
<?php
|
273 |
-
$condition = (defined('DISABLE_WP_CRON') && DISABLE_WP_CRON) ? 2 : 1;
|
274 |
-
?>
|
275 |
-
<tr>
|
276 |
-
<td>
|
277 |
-
<code>DISABLE_WP_CRON</code>
|
278 |
-
</td>
|
279 |
-
<td class="status">
|
280 |
-
<?php tnp_status_print_flag($condition) ?>
|
281 |
-
</td>
|
282 |
-
<td>
|
283 |
-
<?php if ($condition == 2) { ?>
|
284 |
-
The constant <code>DISABLE_WP_CRON</code> is set to <code>true</code> (probably in <code>wp-config.php</code>). That disables the scheduler auto triggering and it's
|
285 |
-
good ONLY if you setup an external trigger.
|
286 |
-
<?php } ?>
|
287 |
-
</td>
|
288 |
-
</tr>
|
289 |
-
|
290 |
-
<tr>
|
291 |
-
<td>
|
292 |
-
<code>ALTERNATE_WP_CRON</code>
|
293 |
-
</td>
|
294 |
-
<td class="status">
|
295 |
-
|
296 |
-
</td>
|
297 |
-
<td>
|
298 |
-
<?php if (defined('ALTERNATE_WP_CRON') && ALTERNATE_WP_CRON) { ?>
|
299 |
-
Using the alternate cron trigger. Rare configuration but should not be a problem.
|
300 |
-
<?php } else { ?>
|
301 |
-
Option not active, it's ok.
|
302 |
-
<?php } ?>
|
303 |
-
</td>
|
304 |
-
</tr>
|
305 |
-
|
306 |
-
<?php
|
307 |
-
$condition = NEWSLETTER_CRON_INTERVAL == 300 ? 1 : 2;
|
308 |
-
?>
|
309 |
-
<tr>
|
310 |
-
<td><code>NEWSLETTER_CRON_INTERVAL</code></td>
|
311 |
-
<td class="status">
|
312 |
-
<?php tnp_status_print_flag($condition) ?>
|
313 |
-
</td>
|
314 |
-
<td>
|
315 |
-
<?php echo NEWSLETTER_CRON_INTERVAL, ' seconds'; ?>
|
316 |
-
<br><br>
|
317 |
-
How often the Newsletter engine should be activated. Default 300 seconds. Different value can be set on your <code>wp-config.php</code>
|
318 |
-
(not recommended).
|
319 |
-
</td>
|
320 |
-
</tr>
|
321 |
-
|
322 |
-
|
323 |
-
<?php
|
324 |
-
$condition = WP_CRON_LOCK_TIMEOUT != MINUTE_IN_SECONDS ? 2 : 1;
|
325 |
-
?>
|
326 |
-
<tr>
|
327 |
-
<td><code>WP_CRON_LOCK_TIMEOUT</code></td>
|
328 |
-
<td class="status">
|
329 |
-
<?php tnp_status_print_flag($condition) ?>
|
330 |
-
</td>
|
331 |
-
<td>
|
332 |
-
<?php echo WP_CRON_LOCK_TIMEOUT, ' seconds'; ?>
|
333 |
-
|
334 |
-
<?php if ($condition == 2) { ?>
|
335 |
-
<br>
|
336 |
-
A non standard (<?php echo MINUTE_IN_SECONDS ?> seconds) value is specified probably in your <code>wp-config.php</code>.
|
337 |
-
<?php } ?>
|
338 |
-
</td>
|
339 |
-
</tr>
|
340 |
-
|
341 |
-
|
342 |
-
<?php
|
343 |
-
$condition = (defined('NEWSLETTER_CRON_WARNINGS') && !NEWSLETTER_CRON_WARNINGS) ? 2 : 1;
|
344 |
-
?>
|
345 |
-
<tr>
|
346 |
-
|
347 |
-
<td>
|
348 |
-
<code>NEWSLETTER_CRON_WARNINGS</code>
|
349 |
-
</td>
|
350 |
-
<td class="status">
|
351 |
-
<?php tnp_status_print_flag($condition) ?>
|
352 |
-
</td>
|
353 |
-
<td>
|
354 |
-
<?php if ($condition == 2) { ?>
|
355 |
-
Scheduler warnings are disabled in your <code>wp-config.php</code> with the constant <code>NEWSLETTER_CRON_WARNINGS</code> set to true.
|
356 |
-
<?php } else { ?>
|
357 |
-
Scheduler warnings are enabled
|
358 |
-
<?php } ?>
|
359 |
-
</td>
|
360 |
-
</tr>
|
361 |
-
|
362 |
-
<?php
|
363 |
-
$condition = has_filter('pre_reschedule_event') ? 2 : 1;
|
364 |
-
|
365 |
-
|
366 |
-
|
367 |
-
<td
|
368 |
-
|
369 |
-
|
370 |
-
|
371 |
-
|
372 |
-
|
373 |
-
|
374 |
-
|
375 |
-
|
376 |
-
|
377 |
-
|
378 |
-
|
379 |
-
|
380 |
-
|
381 |
-
|
382 |
-
|
383 |
-
|
384 |
-
|
385 |
-
<td
|
386 |
-
|
387 |
-
|
388 |
-
|
389 |
-
|
390 |
-
|
391 |
-
|
392 |
-
|
393 |
-
|
394 |
-
|
395 |
-
|
396 |
-
|
397 |
-
|
398 |
-
|
399 |
-
|
400 |
-
|
401 |
-
|
402 |
-
|
403 |
-
|
404 |
-
|
405 |
-
|
406 |
-
|
407 |
-
|
408 |
-
|
409 |
-
|
410 |
-
|
411 |
-
|
|
1 |
+
<?php
|
2 |
+
/* @var $this Newsletter */
|
3 |
+
/* @var $wpdb wpdb */
|
4 |
+
|
5 |
+
defined('ABSPATH') || exit;
|
6 |
+
|
7 |
+
wp_enqueue_script('tnp-chart');
|
8 |
+
|
9 |
+
include_once NEWSLETTER_INCLUDES_DIR . '/controls.php';
|
10 |
+
$controls = new NewsletterControls();
|
11 |
+
$system = NewsletterSystem::instance();
|
12 |
+
|
13 |
+
if ($controls->is_action('reset')) {
|
14 |
+
$system->reset_cron_stats();
|
15 |
+
$controls->add_message_done();
|
16 |
+
}
|
17 |
+
|
18 |
+
if ($controls->is_action('reschedule')) {
|
19 |
+
wp_clear_scheduled_hook('newsletter');
|
20 |
+
wp_schedule_event(time() + 30, 'newsletter', 'newsletter');
|
21 |
+
$controls->add_message_done();
|
22 |
+
}
|
23 |
+
|
24 |
+
if ($controls->is_action('trigger')) {
|
25 |
+
wp_clear_scheduled_hook('newsletter');
|
26 |
+
wp_schedule_event(time() + NEWSLETTER_CRON_INTERVAL, 'newsletter', 'newsletter');
|
27 |
+
Newsletter::instance()->hook_newsletter();
|
28 |
+
$controls->add_message_done();
|
29 |
+
}
|
30 |
+
|
31 |
+
if ($controls->is_action('test')) {
|
32 |
+
$response = wp_remote_get(site_url('/wp-cron.php') . '?' . time());
|
33 |
+
if (is_wp_error($response)) {
|
34 |
+
$controls->errors = 'Test failed: ' . esc_html($response->get_error_message());
|
35 |
+
} else if (wp_remote_retrieve_response_code($response) != 200) {
|
36 |
+
$controls->errors = 'Test failed: ' . esc_html(wp_remote_retrieve_response_message($response));
|
37 |
+
} else {
|
38 |
+
$controls->add_message('Test ok');
|
39 |
+
}
|
40 |
+
|
41 |
+
if ($controls->errors) {
|
42 |
+
$controls->errors .= '<br>Report this error to your provider saying the site cannot make an HTTP call to its wp-cron.php file and copying the error message above.';
|
43 |
+
}
|
44 |
+
}
|
45 |
+
|
46 |
+
function tnp_status_print_flag($condition, $url = '') {
|
47 |
+
switch ($condition) {
|
48 |
+
case 0: echo ' <span class="tnp-ko">KO</span>';
|
49 |
+
break;
|
50 |
+
case 1: echo '<span class="tnp-ok">OK</span>';
|
51 |
+
break;
|
52 |
+
case 2: echo '<span class="tnp-maybe">MAYBE</span>';
|
53 |
+
break;
|
54 |
+
}
|
55 |
+
if ($url) {
|
56 |
+
echo '<br><a href="', $url, '" target="_blank">Read more</a>';
|
57 |
+
}
|
58 |
+
}
|
59 |
+
|
60 |
+
$system = NewsletterSystem::instance();
|
61 |
+
?>
|
62 |
+
|
63 |
+
<style>
|
64 |
+
#tnp-body table.widefat td {
|
65 |
+
vertical-align: top;
|
66 |
+
}
|
67 |
+
#tnp-body table.widefat td.status {
|
68 |
+
text-align: center;
|
69 |
+
}
|
70 |
+
</style>
|
71 |
+
<div class="wrap tnp-main-status" id="tnp-wrap">
|
72 |
+
|
73 |
+
<?php include NEWSLETTER_DIR . '/tnp-header.php'; ?>
|
74 |
+
|
75 |
+
<div id="tnp-heading">
|
76 |
+
|
77 |
+
<h2><?php _e('WordPress Scheduler and Newsletter Delivery Engine', 'newsletter') ?></h2>
|
78 |
+
<p>
|
79 |
+
The scheduler is a WordPress component that executes <strong>background tasks</strong>
|
80 |
+
(publish future post, run backups, send newsletters, ...).
|
81 |
+
<br>
|
82 |
+
Here some steps you can consider if the scheduler has issues.
|
83 |
+
</p>
|
84 |
+
<ul>
|
85 |
+
<li>Check the <a href="<?php echo admin_url('/site-health.php') ?>">site health panel</a> and try to solve the issues identified by WordPress in your site</li>
|
86 |
+
<li>Install the <a href="https://wordpress.org/plugins/wp-crontrol/" target="_blank">WP Crontol</a> plugin which shows all the scheduled jobs and delays</li>
|
87 |
+
<li>Configure an <a href="https://www.thenewsletterplugin.com/documentation/delivery-and-spam/newsletter-delivery-engine/" target="_blank">external cron service</a>
|
88 |
+
(if you have a license you can use our <a href="https://www.thenewsletterplugin.com/account/cron/" target="_blank">cron service</a>)</li>
|
89 |
+
</ul>
|
90 |
+
</div>
|
91 |
+
|
92 |
+
<div id="tnp-body">
|
93 |
+
|
94 |
+
|
95 |
+
<form method="post" action="">
|
96 |
+
<?php $controls->init(); ?>
|
97 |
+
|
98 |
+
<table class="widefat">
|
99 |
+
<?php
|
100 |
+
$status = $system->get_job_status();
|
101 |
+
$condition = $status == NewsletterSystem::JOB_OK ? 1 : 0;
|
102 |
+
?>
|
103 |
+
<tr>
|
104 |
+
<td>Delivery background job</td>
|
105 |
+
<td class="status">
|
106 |
+
<?php tnp_status_print_flag($condition, 'https://www.thenewsletterplugin.com/documentation/delivery-and-spam/newsletter-delivery-engine/') ?>
|
107 |
+
</td>
|
108 |
+
<td>
|
109 |
+
<?php
|
110 |
+
switch ($status) {
|
111 |
+
case NewsletterSystem::JOB_MISSING:
|
112 |
+
echo 'The engine schedule is missing. Try to deactivate and reactivate the Newsletter plugin.';
|
113 |
+
break;
|
114 |
+
case NewsletterSystem::JOB_LATE:
|
115 |
+
echo 'The engine schedule is late. You probably need and external scheduler trigger.';
|
116 |
+
break;
|
117 |
+
case NewsletterSystem::JOB_SKIPPED:
|
118 |
+
echo 'The engine schedule has been skipped. The scheduler is overloaded or a job has fatal error and blocks the scheduler.';
|
119 |
+
break;
|
120 |
+
case NewsletterSystem::JOB_OK:
|
121 |
+
echo 'Everything seems fine!';
|
122 |
+
break;
|
123 |
+
}
|
124 |
+
?>
|
125 |
+
<br><br>
|
126 |
+
Next run: <?php echo $controls->print_date($system->get_job_schedule(), false, true) ?>
|
127 |
+
<br><br>
|
128 |
+
<?php
|
129 |
+
if ($status == NewsletterSystem::JOB_LATE) {
|
130 |
+
$controls->button('trigger', 'Run manually');
|
131 |
+
}
|
132 |
+
?>
|
133 |
+
</td>
|
134 |
+
</tr>
|
135 |
+
|
136 |
+
|
137 |
+
<tr>
|
138 |
+
<td>Last cron call</td>
|
139 |
+
<td class="status"> </td>
|
140 |
+
<td>
|
141 |
+
<?php echo $controls->print_date($system->get_last_cron_call()) ?>
|
142 |
+
</td>
|
143 |
+
</tr>
|
144 |
+
|
145 |
+
|
146 |
+
<tr>
|
147 |
+
<?php
|
148 |
+
$stats = NewsletterSystem::instance()->get_cron_stats();
|
149 |
+
?>
|
150 |
+
<td>
|
151 |
+
Cron call stats
|
152 |
+
</td>
|
153 |
+
<?php if ($stats == null) { ?>
|
154 |
+
<td class="status">
|
155 |
+
|
156 |
+
</td>
|
157 |
+
<td>
|
158 |
+
Not enough data, some hours are still required.
|
159 |
+
</td>
|
160 |
+
|
161 |
+
<?php } else { ?>
|
162 |
+
|
163 |
+
<?php
|
164 |
+
$condition = $stats->good ? 1 : 0;
|
165 |
+
?>
|
166 |
+
|
167 |
+
<td class="status">
|
168 |
+
<?php tnp_status_print_flag($condition, 'https://www.thenewsletterplugin.com/documentation/delivery-and-spam/newsletter-delivery-engine/') ?>
|
169 |
+
</td>
|
170 |
+
<td>
|
171 |
+
<?php if ($condition == 0) { ?>
|
172 |
+
The blog cron system is NOT triggered enough often.<br>
|
173 |
+
<?php } ?>
|
174 |
+
|
175 |
+
Samples <?php echo count($stats->deltas) ?>, average <?php echo $stats->avg ?> s, max <?php echo $stats->max ?> s, min <?php echo $stats->min ?> s
|
176 |
+
|
177 |
+
<canvas id="tnp-cron-chart" style="width: 550px; height: 180px"></canvas>
|
178 |
+
<script>
|
179 |
+
jQuery(function () {
|
180 |
+
var cronChartData = {
|
181 |
+
labels: <?php echo json_encode(range(1, count($stats->deltas))) ?>,
|
182 |
+
datasets: [
|
183 |
+
{
|
184 |
+
label: "Batch Average Time",
|
185 |
+
data: <?php echo json_encode($stats->deltas) ?>,
|
186 |
+
borderColor: '#2980b9',
|
187 |
+
fill: false
|
188 |
+
}]
|
189 |
+
};
|
190 |
+
var cronChartConfig = {
|
191 |
+
type: "line",
|
192 |
+
data: cronChartData,
|
193 |
+
options: {
|
194 |
+
responsive: false,
|
195 |
+
maintainAspectRatio: false,
|
196 |
+
scales: {
|
197 |
+
x: {
|
198 |
+
type: 'linear'
|
199 |
+
}
|
200 |
+
}
|
201 |
+
}
|
202 |
+
};
|
203 |
+
new Chart('tnp-cron-chart', cronChartConfig);
|
204 |
+
});
|
205 |
+
</script>
|
206 |
+
|
207 |
+
<?php $controls->button_reset() ?>
|
208 |
+
|
209 |
+
</td>
|
210 |
+
<?php } ?>
|
211 |
+
</tr>
|
212 |
+
|
213 |
+
<?php
|
214 |
+
$condition = $system->has_newsletter_schedule() ? 1 : 0;
|
215 |
+
$schedules = wp_get_schedules();
|
216 |
+
?>
|
217 |
+
<tr>
|
218 |
+
<td>
|
219 |
+
Newsletter engine schedule
|
220 |
+
</td>
|
221 |
+
<td class="status"><?php tnp_status_print_flag($condition) ?></td>
|
222 |
+
<td>
|
223 |
+
<?php if (!$condition) { ?>
|
224 |
+
The Newsletter schedule is not present probably another plugin is interfering with the starndard WordPress scheuling system.<br>
|
225 |
+
You can reactivate it, but is the problem persist
|
226 |
+
<?php $controls->button('reschedule', 'Reactivate') ?>
|
227 |
+
<?php } ?>
|
228 |
+
|
229 |
+
Registered recurring schedules:<br>
|
230 |
+
<ul style="margin-left: 0em;">
|
231 |
+
<?php
|
232 |
+
if (!empty($schedules)) {
|
233 |
+
foreach ($schedules as $key => $data) {
|
234 |
+
if ($key == 'newsletter') {
|
235 |
+
echo '<li style="padding: 0; margin: 0; font-weight: bold">', esc_html($key . ' - ' . $data['interval']), ' seconds</li>';
|
236 |
+
} else {
|
237 |
+
echo '<li style="padding: 0; margin: 0;">', esc_html($key . ' - ' . $data['interval']), ' seconds</li>';
|
238 |
+
}
|
239 |
+
}
|
240 |
+
}
|
241 |
+
?>
|
242 |
+
</ul>
|
243 |
+
</td>
|
244 |
+
</tr>
|
245 |
+
|
246 |
+
|
247 |
+
<tr>
|
248 |
+
<td>Cron URL</td>
|
249 |
+
<td class="status"> </td>
|
250 |
+
<td>
|
251 |
+
<strong><?php echo esc_html(site_url('/wp-cron.php')) ?></strong>
|
252 |
+
<br><br>
|
253 |
+
Can be used to trigger the WordPress scheduler from an external cron service.
|
254 |
+
</td>
|
255 |
+
</tr>
|
256 |
+
|
257 |
+
|
258 |
+
|
259 |
+
|
260 |
+
<tr>
|
261 |
+
<td>
|
262 |
+
WordPress scheduler auto trigger
|
263 |
+
</td>
|
264 |
+
<td class="status">
|
265 |
+
<?php //tnp_status_print_flag($condition) ?>
|
266 |
+
</td>
|
267 |
+
<td>
|
268 |
+
<?php $controls->button_test() ?>
|
269 |
+
</td>
|
270 |
+
</tr>
|
271 |
+
|
272 |
+
<?php
|
273 |
+
$condition = (defined('DISABLE_WP_CRON') && DISABLE_WP_CRON) ? 2 : 1;
|
274 |
+
?>
|
275 |
+
<tr>
|
276 |
+
<td>
|
277 |
+
<code>DISABLE_WP_CRON</code>
|
278 |
+
</td>
|
279 |
+
<td class="status">
|
280 |
+
<?php tnp_status_print_flag($condition) ?>
|
281 |
+
</td>
|
282 |
+
<td>
|
283 |
+
<?php if ($condition == 2) { ?>
|
284 |
+
The constant <code>DISABLE_WP_CRON</code> is set to <code>true</code> (probably in <code>wp-config.php</code>). That disables the scheduler auto triggering and it's
|
285 |
+
good ONLY if you setup an external trigger.
|
286 |
+
<?php } ?>
|
287 |
+
</td>
|
288 |
+
</tr>
|
289 |
+
|
290 |
+
<tr>
|
291 |
+
<td>
|
292 |
+
<code>ALTERNATE_WP_CRON</code>
|
293 |
+
</td>
|
294 |
+
<td class="status">
|
295 |
+
|
296 |
+
</td>
|
297 |
+
<td>
|
298 |
+
<?php if (defined('ALTERNATE_WP_CRON') && ALTERNATE_WP_CRON) { ?>
|
299 |
+
Using the alternate cron trigger. Rare configuration but should not be a problem.
|
300 |
+
<?php } else { ?>
|
301 |
+
Option not active, it's ok.
|
302 |
+
<?php } ?>
|
303 |
+
</td>
|
304 |
+
</tr>
|
305 |
+
|
306 |
+
<?php
|
307 |
+
$condition = NEWSLETTER_CRON_INTERVAL == 300 ? 1 : 2;
|
308 |
+
?>
|
309 |
+
<tr>
|
310 |
+
<td><code>NEWSLETTER_CRON_INTERVAL</code></td>
|
311 |
+
<td class="status">
|
312 |
+
<?php tnp_status_print_flag($condition) ?>
|
313 |
+
</td>
|
314 |
+
<td>
|
315 |
+
<?php echo NEWSLETTER_CRON_INTERVAL, ' seconds'; ?>
|
316 |
+
<br><br>
|
317 |
+
How often the Newsletter engine should be activated. Default 300 seconds. Different value can be set on your <code>wp-config.php</code>
|
318 |
+
(not recommended).
|
319 |
+
</td>
|
320 |
+
</tr>
|
321 |
+
|
322 |
+
|
323 |
+
<?php
|
324 |
+
$condition = WP_CRON_LOCK_TIMEOUT != MINUTE_IN_SECONDS ? 2 : 1;
|
325 |
+
?>
|
326 |
+
<tr>
|
327 |
+
<td><code>WP_CRON_LOCK_TIMEOUT</code></td>
|
328 |
+
<td class="status">
|
329 |
+
<?php tnp_status_print_flag($condition) ?>
|
330 |
+
</td>
|
331 |
+
<td>
|
332 |
+
<?php echo WP_CRON_LOCK_TIMEOUT, ' seconds'; ?>
|
333 |
+
|
334 |
+
<?php if ($condition == 2) { ?>
|
335 |
+
<br>
|
336 |
+
A non standard (<?php echo MINUTE_IN_SECONDS ?> seconds) value is specified probably in your <code>wp-config.php</code>.
|
337 |
+
<?php } ?>
|
338 |
+
</td>
|
339 |
+
</tr>
|
340 |
+
|
341 |
+
|
342 |
+
<?php
|
343 |
+
$condition = (defined('NEWSLETTER_CRON_WARNINGS') && !NEWSLETTER_CRON_WARNINGS) ? 2 : 1;
|
344 |
+
?>
|
345 |
+
<tr>
|
346 |
+
|
347 |
+
<td>
|
348 |
+
<code>NEWSLETTER_CRON_WARNINGS</code>
|
349 |
+
</td>
|
350 |
+
<td class="status">
|
351 |
+
<?php tnp_status_print_flag($condition) ?>
|
352 |
+
</td>
|
353 |
+
<td>
|
354 |
+
<?php if ($condition == 2) { ?>
|
355 |
+
Scheduler warnings are disabled in your <code>wp-config.php</code> with the constant <code>NEWSLETTER_CRON_WARNINGS</code> set to true.
|
356 |
+
<?php } else { ?>
|
357 |
+
Scheduler warnings are enabled
|
358 |
+
<?php } ?>
|
359 |
+
</td>
|
360 |
+
</tr>
|
361 |
+
|
362 |
+
<?php
|
363 |
+
$condition = has_filter('pre_reschedule_event') ? 2 : 1;
|
364 |
+
$functions = $system->get_hook_functions('pre_reschedule_event');
|
365 |
+
?>
|
366 |
+
<tr>
|
367 |
+
<td><code>pre_reschedule_event</code></td>
|
368 |
+
<td class="status">
|
369 |
+
<?php tnp_status_print_flag($condition) ?>
|
370 |
+
</td>
|
371 |
+
<td>
|
372 |
+
<?php if ($condition == 2) { ?>
|
373 |
+
One or more plugin are filtering the jobs rescheduling. If a recurrent job (like the newsletter generation with Automated) disappers
|
374 |
+
this is a good starting point.<br><br>
|
375 |
+
<?php } ?>
|
376 |
+
Attached functions:<br>
|
377 |
+
<?php echo $functions?$functions:'[none]' ?>
|
378 |
+
</td>
|
379 |
+
</tr>
|
380 |
+
|
381 |
+
<?php
|
382 |
+
$transient = get_transient('doing_cron');
|
383 |
+
?>
|
384 |
+
<tr>
|
385 |
+
<td>Transient <code>doing_cron</code></td>
|
386 |
+
<td class="status">
|
387 |
+
<?php //tnp_status_print_flag($condition) ?>
|
388 |
+
</td>
|
389 |
+
<td>
|
390 |
+
<?php if ($transient) { ?>
|
391 |
+
<?php
|
392 |
+
echo esc_html($transient);
|
393 |
+
if (is_numeric($transient)) {
|
394 |
+
echo ' (', $controls->print_date((int) $transient), ')';
|
395 |
+
}
|
396 |
+
?>
|
397 |
+
<?php } else { ?>
|
398 |
+
[unset]
|
399 |
+
<?php } ?>
|
400 |
+
<br><br>
|
401 |
+
When set it means the scheduler is executing background jobs. Install the WP Crontol plugin to have more information about
|
402 |
+
your site background jobs.
|
403 |
+
</td>
|
404 |
+
</tr>
|
405 |
+
</table>
|
406 |
+
|
407 |
+
</form>
|
408 |
+
</div>
|
409 |
+
|
410 |
+
<?php include NEWSLETTER_DIR . '/tnp-footer.php'; ?>
|
411 |
+
|
412 |
+
</div>
|
plugin.php
CHANGED
@@ -4,7 +4,7 @@
|
|
4 |
Plugin Name: Newsletter
|
5 |
Plugin URI: https://www.thenewsletterplugin.com/plugins/newsletter
|
6 |
Description: Newsletter is a cool plugin to create your own subscriber list, to send newsletters, to build your business. <strong>Before update give a look to <a href="https://www.thenewsletterplugin.com/category/release">this page</a> to know what's changed.</strong>
|
7 |
-
Version: 7.2.
|
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.
|
@@ -37,7 +37,7 @@ if (version_compare(phpversion(), '5.6', '<')) {
|
|
37 |
return;
|
38 |
}
|
39 |
|
40 |
-
define('NEWSLETTER_VERSION', '7.2.
|
41 |
|
42 |
global $newsletter, $wpdb;
|
43 |
|
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.2.9
|
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.
|
37 |
return;
|
38 |
}
|
39 |
|
40 |
+
define('NEWSLETTER_VERSION', '7.2.9');
|
41 |
|
42 |
global $newsletter, $wpdb;
|
43 |
|
readme.txt
CHANGED
@@ -1,7 +1,7 @@
|
|
1 |
=== Newsletter ===
|
2 |
Tags: newsletter, email marketing, welcome email, signup forms, contact, lead generation, marketing automation
|
3 |
Tested up to: 5.8.1
|
4 |
-
Stable tag: 7.2.
|
5 |
Contributors: satollo,webagile,michael-travan
|
6 |
License: GPLv2 or later
|
7 |
License URI: https://www.gnu.org/licenses/gpl-2.0.html
|
@@ -118,6 +118,14 @@ Thank you, The Newsletter Team
|
|
118 |
|
119 |
== Changelog ==
|
120 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
121 |
= 7.2.8 =
|
122 |
|
123 |
* Fixed the print_date() when no time is provided
|
1 |
=== Newsletter ===
|
2 |
Tags: newsletter, email marketing, welcome email, signup forms, contact, lead generation, marketing automation
|
3 |
Tested up to: 5.8.1
|
4 |
+
Stable tag: 7.2.9
|
5 |
Contributors: satollo,webagile,michael-travan
|
6 |
License: GPLv2 or later
|
7 |
License URI: https://www.gnu.org/licenses/gpl-2.0.html
|
118 |
|
119 |
== Changelog ==
|
120 |
|
121 |
+
= 7.2.9 =
|
122 |
+
|
123 |
+
* Fixed generic action button confirmation popup not showing the message
|
124 |
+
* [SECURITY] Pre parsing of IP addresses on security panel
|
125 |
+
* [SECURITY] Comments allowed on IP address list on security panel
|
126 |
+
* [COMPOSER] Fixed preset name/subject
|
127 |
+
* Improved generated forms for accessibility
|
128 |
+
|
129 |
= 7.2.8 =
|
130 |
|
131 |
* Fixed the print_date() when no time is provided
|
subscription/antibot.php
CHANGED
@@ -1,156 +1,183 @@
|
|
1 |
-
<?php
|
2 |
-
/* @var $this NewsletterSubscription */
|
3 |
-
defined('ABSPATH') || exit;
|
4 |
-
|
5 |
-
include_once NEWSLETTER_INCLUDES_DIR . '/controls.php';
|
6 |
-
$controls = new NewsletterControls();
|
7 |
-
|
8 |
-
if ($controls->is_action()) {
|
9 |
-
|
10 |
-
if ($controls->is_action('save')) {
|
11 |
-
|
12 |
-
$
|
13 |
-
$controls->data['
|
14 |
-
|
15 |
-
|
16 |
-
|
17 |
-
|
18 |
-
|
19 |
-
|
20 |
-
|
21 |
-
|
22 |
-
|
23 |
-
|
24 |
-
|
25 |
-
|
26 |
-
|
27 |
-
|
28 |
-
|
29 |
-
|
30 |
-
|
31 |
-
|
32 |
-
|
33 |
-
|
34 |
-
|
35 |
-
|
36 |
-
|
37 |
-
|
38 |
-
|
39 |
-
|
40 |
-
|
41 |
-
|
42 |
-
|
43 |
-
|
44 |
-
|
45 |
-
|
46 |
-
|
47 |
-
|
48 |
-
|
49 |
-
|
50 |
-
|
51 |
-
|
52 |
-
|
53 |
-
|
54 |
-
|
55 |
-
|
56 |
-
|
57 |
-
|
58 |
-
|
59 |
-
|
60 |
-
|
61 |
-
|
62 |
-
|
63 |
-
|
64 |
-
|
65 |
-
|
66 |
-
|
67 |
-
|
68 |
-
|
69 |
-
|
70 |
-
|
71 |
-
|
72 |
-
|
73 |
-
|
74 |
-
|
75 |
-
|
76 |
-
|
77 |
-
<tr>
|
78 |
-
<th><?php
|
79 |
-
<td>
|
80 |
-
<?php
|
81 |
-
$controls->
|
82 |
-
|
83 |
-
|
84 |
-
|
85 |
-
|
86 |
-
|
87 |
-
|
88 |
-
|
89 |
-
|
90 |
-
|
91 |
-
|
92 |
-
|
93 |
-
|
94 |
-
|
95 |
-
|
96 |
-
|
97 |
-
|
98 |
-
|
99 |
-
|
100 |
-
|
101 |
-
|
102 |
-
<td>
|
103 |
-
<?php
|
104 |
-
|
105 |
-
|
106 |
-
|
107 |
-
|
108 |
-
|
109 |
-
|
110 |
-
|
111 |
-
|
112 |
-
|
113 |
-
|
114 |
-
|
115 |
-
|
116 |
-
|
117 |
-
|
118 |
-
|
119 |
-
|
120 |
-
|
121 |
-
|
122 |
-
|
123 |
-
|
124 |
-
|
125 |
-
<
|
126 |
-
<?php $controls->
|
127 |
-
</
|
128 |
-
|
129 |
-
|
130 |
-
|
131 |
-
|
132 |
-
|
133 |
-
|
134 |
-
|
135 |
-
|
136 |
-
|
137 |
-
|
138 |
-
|
139 |
-
|
140 |
-
|
141 |
-
|
142 |
-
|
143 |
-
</div>
|
144 |
-
|
145 |
-
|
146 |
-
|
147 |
-
|
148 |
-
|
149 |
-
|
150 |
-
|
151 |
-
|
152 |
-
|
153 |
-
|
154 |
-
|
155 |
-
|
156 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/* @var $this NewsletterSubscription */
|
3 |
+
defined('ABSPATH') || exit;
|
4 |
+
|
5 |
+
include_once NEWSLETTER_INCLUDES_DIR . '/controls.php';
|
6 |
+
$controls = new NewsletterControls();
|
7 |
+
|
8 |
+
if ($controls->is_action()) {
|
9 |
+
|
10 |
+
if ($controls->is_action('save')) {
|
11 |
+
// Processing IPs
|
12 |
+
$list = $this->to_array($controls->data['ip_blacklist']);
|
13 |
+
$controls->data['ip_blacklist'] = [];
|
14 |
+
foreach ($list as $item) {
|
15 |
+
$item = trim($item);
|
16 |
+
if (substr($item, 0, 1) === '#') {
|
17 |
+
$controls->data['ip_blacklist'][] = $item;
|
18 |
+
continue;
|
19 |
+
}
|
20 |
+
$item = preg_replace( '|[^0-9a-fA-F:./]|', '', $item);
|
21 |
+
if (empty($item)) {
|
22 |
+
continue;
|
23 |
+
}
|
24 |
+
if (strpos($item, '/', 2)) {
|
25 |
+
list($ip, $bits) = explode('/', $item);
|
26 |
+
$bits = (int)$bits;
|
27 |
+
if (!$bits) continue;
|
28 |
+
$item = $ip . '/' . $bits;
|
29 |
+
} else {
|
30 |
+
|
31 |
+
}
|
32 |
+
$controls->data['ip_blacklist'][] = $item;
|
33 |
+
}
|
34 |
+
|
35 |
+
//$controls->data['ip_blacklist'] = $this->to_array($controls->data['ip_blacklist']);
|
36 |
+
$controls->data['address_blacklist'] = $this->to_array($controls->data['address_blacklist']);
|
37 |
+
|
38 |
+
$this->save_options($controls->data, 'antibot');
|
39 |
+
$controls->add_message_saved();
|
40 |
+
}
|
41 |
+
} else {
|
42 |
+
$controls->data = $this->get_options('antibot');
|
43 |
+
}
|
44 |
+
?>
|
45 |
+
|
46 |
+
<div class="wrap" id="tnp-wrap">
|
47 |
+
|
48 |
+
<?php include NEWSLETTER_DIR . '/tnp-header.php'; ?>
|
49 |
+
|
50 |
+
<div id="tnp-heading">
|
51 |
+
|
52 |
+
<h2><?php _e('Security', 'newsletter') ?></h2>
|
53 |
+
<?php $controls->page_help('https://www.thenewsletterplugin.com/documentation/subscription/antiflood') ?>
|
54 |
+
|
55 |
+
</div>
|
56 |
+
|
57 |
+
<div id="tnp-body">
|
58 |
+
|
59 |
+
<form method="post" action="">
|
60 |
+
<?php $controls->init(); ?>
|
61 |
+
|
62 |
+
|
63 |
+
<p>
|
64 |
+
<?php $controls->button_save() ?>
|
65 |
+
</p>
|
66 |
+
|
67 |
+
<div id="tabs">
|
68 |
+
<ul>
|
69 |
+
<li><a href="#tabs-general"><?php _e('Security', 'newsletter') ?></a></li>
|
70 |
+
<li><a href="#tabs-blacklists"><?php _e('Blacklists', 'newsletter') ?></a></li>
|
71 |
+
</ul>
|
72 |
+
|
73 |
+
<div id="tabs-general">
|
74 |
+
|
75 |
+
|
76 |
+
<table class="form-table">
|
77 |
+
<tr>
|
78 |
+
<th><?php _e('Disable antibot', 'newsletter') ?></th>
|
79 |
+
<td>
|
80 |
+
<?php $controls->yesno('disabled'); ?>
|
81 |
+
<?php $controls->help('https://www.thenewsletterplugin.com/documentation/subscription/antiflood') ?>
|
82 |
+
<p class="description">
|
83 |
+
<?php _e('Disable for ajax form submission', 'newsletter'); ?>
|
84 |
+
</p>
|
85 |
+
</td>
|
86 |
+
</tr>
|
87 |
+
|
88 |
+
<tr>
|
89 |
+
<th><?php $controls->field_label('Akismet', '/documentation/subscription/antiflood#akismet')?></th>
|
90 |
+
<td>
|
91 |
+
<?php
|
92 |
+
$controls->select('akismet', array(
|
93 |
+
0 => __('Disabled', 'newsletter'),
|
94 |
+
1 => __('Enabled', 'newsletter')
|
95 |
+
));
|
96 |
+
?>
|
97 |
+
</td>
|
98 |
+
</tr>
|
99 |
+
|
100 |
+
<tr>
|
101 |
+
<th><?php $controls->field_label(__('Antiflood', 'newsletter'), '/documentation/subscription/antiflood#antiflood') ?></th>
|
102 |
+
<td>
|
103 |
+
<?php
|
104 |
+
$controls->select('antiflood', array(
|
105 |
+
0 => __('Disabled', 'newsletter'),
|
106 |
+
5 => '5 ' . __('seconds', 'newsletter'),
|
107 |
+
10 => '10 ' . __('seconds', 'newsletter'),
|
108 |
+
15 => '15 ' . __('seconds', 'newsletter'),
|
109 |
+
30 => '30 ' . __('seconds', 'newsletter'),
|
110 |
+
60 => '1 ' . __('minute', 'newsletter'),
|
111 |
+
120 => '2 ' . __('minutes', 'newsletter'),
|
112 |
+
300 => '5 ' . __('minutes', 'newsletter'),
|
113 |
+
600 => '10 ' . __('minutes', 'newsletter'),
|
114 |
+
900 => '15 ' . __('minutes', 'newsletter'),
|
115 |
+
1800 => '30 ' . __('minutes', 'newsletter'),
|
116 |
+
360 => '60 ' . __('minutes', 'newsletter')
|
117 |
+
));
|
118 |
+
?>
|
119 |
+
</td>
|
120 |
+
</tr>
|
121 |
+
<tr>
|
122 |
+
<th>
|
123 |
+
<?php $controls->field_label(__('Captcha', 'newsletter'), '/documentation/subscription/antiflood/#captcha') ?>
|
124 |
+
</th>
|
125 |
+
<td>
|
126 |
+
<?php $controls->enabled('captcha'); ?>
|
127 |
+
</td>
|
128 |
+
</tr>
|
129 |
+
<?php /*
|
130 |
+
<tr>
|
131 |
+
<th><?php _e('Domain check', 'newsletter') ?></th>
|
132 |
+
<td>
|
133 |
+
<?php
|
134 |
+
$controls->yesno('domain_check');
|
135 |
+
?>
|
136 |
+
</td>
|
137 |
+
</tr>
|
138 |
+
*/ ?>
|
139 |
+
|
140 |
+
</table>
|
141 |
+
|
142 |
+
|
143 |
+
</div>
|
144 |
+
|
145 |
+
<div id="tabs-blacklists">
|
146 |
+
<table class="form-table">
|
147 |
+
<tr>
|
148 |
+
<th>
|
149 |
+
<?php $controls->field_label(__('IP black list', 'newsletter'), '/documentation/subscription/antiflood/#ip-blacklist') ?>
|
150 |
+
</th>
|
151 |
+
<td>
|
152 |
+
<?php $controls->textarea('ip_blacklist'); ?>
|
153 |
+
<p class="description">
|
154 |
+
<?php _e('One per line', 'newsletter') ?>
|
155 |
+
IPv4 (aaa.bbb.ccc.ddd) supported. IPv6 supported. CIDR supported only for IPv4. Lines starting with # are
|
156 |
+
considered comments.
|
157 |
+
</p>
|
158 |
+
</td>
|
159 |
+
</tr>
|
160 |
+
<tr>
|
161 |
+
<th>
|
162 |
+
<?php $controls->field_label(__('Address black list', 'newsletter'), '/documentation/subscription/antiflood/#email-blacklist') ?>
|
163 |
+
</th>
|
164 |
+
<td>
|
165 |
+
<?php $controls->textarea('address_blacklist'); ?>
|
166 |
+
<p class="description"><?php _e('One per line', 'newsletter') ?></p>
|
167 |
+
</td>
|
168 |
+
</tr>
|
169 |
+
</table>
|
170 |
+
</div>
|
171 |
+
|
172 |
+
</div>
|
173 |
+
|
174 |
+
<p>
|
175 |
+
<?php $controls->button_save() ?>
|
176 |
+
</p>
|
177 |
+
|
178 |
+
</form>
|
179 |
+
</div>
|
180 |
+
|
181 |
+
<?php include NEWSLETTER_DIR . '/tnp-footer.php'; ?>
|
182 |
+
|
183 |
+
</div>
|
subscription/subscription.php
CHANGED
@@ -1285,7 +1285,7 @@ class NewsletterSubscription extends NewsletterModule {
|
|
1285 |
if (!$suffix) {
|
1286 |
$suffix = $name;
|
1287 |
}
|
1288 |
-
$buffer = '<label for="
|
1289 |
if (isset($attrs['label'])) {
|
1290 |
if (empty($attrs['label'])) {
|
1291 |
return;
|
@@ -1316,6 +1316,12 @@ class NewsletterSubscription extends NewsletterModule {
|
|
1316 |
}
|
1317 |
|
1318 |
function shortcode_newsletter_field($attrs, $content = '') {
|
|
|
|
|
|
|
|
|
|
|
|
|
1319 |
$this->setup_form_options();
|
1320 |
$language = $this->get_current_language();
|
1321 |
|
@@ -1325,9 +1331,10 @@ class NewsletterSubscription extends NewsletterModule {
|
|
1325 |
|
1326 |
if ($name == 'email') {
|
1327 |
$buffer .= '<div class="tnp-field tnp-field-email">';
|
|
|
1328 |
$buffer .= $this->_shortcode_label('email', $attrs);
|
1329 |
|
1330 |
-
$buffer .= '<input class="tnp-email" type="email" name="ne" value=""';
|
1331 |
if (isset($attrs['placeholder'])) {
|
1332 |
$buffer .= ' placeholder="' . esc_attr($attrs['placeholder']) . '"';
|
1333 |
}
|
@@ -1348,7 +1355,7 @@ class NewsletterSubscription extends NewsletterModule {
|
|
1348 |
$buffer .= '<div class="tnp-field tnp-field-firstname">';
|
1349 |
$buffer .= $this->_shortcode_label('name', $attrs);
|
1350 |
|
1351 |
-
$buffer .= '<input class="tnp-name" type="text" name="nn" value=""';
|
1352 |
if (isset($attrs['placeholder'])) {
|
1353 |
$buffer .= ' placeholder="' . esc_attr($attrs['placeholder']) . '"';
|
1354 |
}
|
@@ -1364,7 +1371,7 @@ class NewsletterSubscription extends NewsletterModule {
|
|
1364 |
$buffer .= '<div class="tnp-field tnp-field-surname">';
|
1365 |
$buffer .= $this->_shortcode_label('surname', $attrs);
|
1366 |
|
1367 |
-
$buffer .= '<input class="tnp-surname" type="text" name="ns" value=""';
|
1368 |
if (isset($attrs['placeholder'])) {
|
1369 |
$buffer .= ' placeholder="' . esc_attr($attrs['placeholder']) . '"';
|
1370 |
}
|
@@ -1395,8 +1402,9 @@ class NewsletterSubscription extends NewsletterModule {
|
|
1395 |
return '<input type="hidden" name="nl[]" value="' . esc_attr($list->id) . '">';
|
1396 |
}
|
1397 |
|
1398 |
-
$
|
1399 |
-
$buffer .= '<
|
|
|
1400 |
if (isset($attrs['checked'])) {
|
1401 |
$buffer .= ' checked';
|
1402 |
}
|
@@ -1435,8 +1443,9 @@ class NewsletterSubscription extends NewsletterModule {
|
|
1435 |
} else {
|
1436 |
|
1437 |
foreach ($lists as $list) {
|
1438 |
-
$
|
1439 |
-
$buffer .= '<
|
|
|
1440 |
if ($list->checked) {
|
1441 |
$buffer .= ' checked';
|
1442 |
}
|
@@ -1531,8 +1540,9 @@ class NewsletterSubscription extends NewsletterModule {
|
|
1531 |
|
1532 |
$buffer .= '<div class="tnp-field tnp-field-checkbox tnp-field-privacy">';
|
1533 |
|
1534 |
-
$
|
1535 |
-
$buffer .= '<
|
|
|
1536 |
if (!empty($attrs['url'])) {
|
1537 |
$buffer .= '<a target="_blank" href="' . esc_attr($attrs['url']) . '">';
|
1538 |
}
|
1285 |
if (!$suffix) {
|
1286 |
$suffix = $name;
|
1287 |
}
|
1288 |
+
$buffer = '<label for="' . esc_attr($attrs['id']) . '">';
|
1289 |
if (isset($attrs['label'])) {
|
1290 |
if (empty($attrs['label'])) {
|
1291 |
return;
|
1316 |
}
|
1317 |
|
1318 |
function shortcode_newsletter_field($attrs, $content = '') {
|
1319 |
+
// Counter to create unique ID for checkbox and labels
|
1320 |
+
static $idx = 0;
|
1321 |
+
|
1322 |
+
$idx++;
|
1323 |
+
$attrs['id'] = 'tnp-' . $idx;
|
1324 |
+
|
1325 |
$this->setup_form_options();
|
1326 |
$language = $this->get_current_language();
|
1327 |
|
1331 |
|
1332 |
if ($name == 'email') {
|
1333 |
$buffer .= '<div class="tnp-field tnp-field-email">';
|
1334 |
+
|
1335 |
$buffer .= $this->_shortcode_label('email', $attrs);
|
1336 |
|
1337 |
+
$buffer .= '<input class="tnp-email" type="email" name="ne" id="'. esc_attr($attrs['id']) . '" value=""';
|
1338 |
if (isset($attrs['placeholder'])) {
|
1339 |
$buffer .= ' placeholder="' . esc_attr($attrs['placeholder']) . '"';
|
1340 |
}
|
1355 |
$buffer .= '<div class="tnp-field tnp-field-firstname">';
|
1356 |
$buffer .= $this->_shortcode_label('name', $attrs);
|
1357 |
|
1358 |
+
$buffer .= '<input class="tnp-name" type="text" name="nn" id="'. esc_attr($attrs['id']) . '" value=""';
|
1359 |
if (isset($attrs['placeholder'])) {
|
1360 |
$buffer .= ' placeholder="' . esc_attr($attrs['placeholder']) . '"';
|
1361 |
}
|
1371 |
$buffer .= '<div class="tnp-field tnp-field-surname">';
|
1372 |
$buffer .= $this->_shortcode_label('surname', $attrs);
|
1373 |
|
1374 |
+
$buffer .= '<input class="tnp-surname" type="text" name="ns" id="'. esc_attr($attrs['id']) . '" value=""';
|
1375 |
if (isset($attrs['placeholder'])) {
|
1376 |
$buffer .= ' placeholder="' . esc_attr($attrs['placeholder']) . '"';
|
1377 |
}
|
1402 |
return '<input type="hidden" name="nl[]" value="' . esc_attr($list->id) . '">';
|
1403 |
}
|
1404 |
|
1405 |
+
$idx++;
|
1406 |
+
$buffer .= '<div class="tnp-field tnp-field-checkbox tnp-field-list"><label for="tnp-' . $idx . '">';
|
1407 |
+
$buffer .= '<input type="checkbox" id="tnp-' . $idx . '" name="nl[]" value="' . esc_attr($list->id) . '"';
|
1408 |
if (isset($attrs['checked'])) {
|
1409 |
$buffer .= ' checked';
|
1410 |
}
|
1443 |
} else {
|
1444 |
|
1445 |
foreach ($lists as $list) {
|
1446 |
+
$idx++;
|
1447 |
+
$buffer .= '<div class="tnp-field tnp-field-checkbox tnp-field-list"><label for="nl' . $idx . '">';
|
1448 |
+
$buffer .= '<input type="checkbox" id="nl' . $idx . '" name="nl[]" value="' . $list->id . '"';
|
1449 |
if ($list->checked) {
|
1450 |
$buffer .= ' checked';
|
1451 |
}
|
1540 |
|
1541 |
$buffer .= '<div class="tnp-field tnp-field-checkbox tnp-field-privacy">';
|
1542 |
|
1543 |
+
$idx++;
|
1544 |
+
$buffer .= '<input type="checkbox" name="ny" required class="tnp-privacy" id="tnp-' . $idx . '"> ';
|
1545 |
+
$buffer .= '<label for="tnp-' . $idx . '">';
|
1546 |
if (!empty($attrs['url'])) {
|
1547 |
$buffer .= '<a target="_blank" href="' . esc_attr($attrs['url']) . '">';
|
1548 |
}
|
tnp-header.php
CHANGED
@@ -1,340 +1,340 @@
|
|
1 |
-
<?php
|
2 |
-
global $current_user, $wpdb;
|
3 |
-
|
4 |
-
defined('ABSPATH') || exit;
|
5 |
-
|
6 |
-
$dismissed = get_option('newsletter_dismissed', []);
|
7 |
-
|
8 |
-
$user_count = Newsletter::instance()->get_user_count();
|
9 |
-
|
10 |
-
$is_administrator = current_user_can('administrator');
|
11 |
-
|
12 |
-
function newsletter_print_entries($group) {
|
13 |
-
$entries = apply_filters('newsletter_menu_' . $group, array());
|
14 |
-
if (!$entries) {
|
15 |
-
return;
|
16 |
-
}
|
17 |
-
|
18 |
-
foreach ($entries as &$entry) {
|
19 |
-
echo '<li><a href="', $entry['url'], '">', $entry['label'];
|
20 |
-
if (!empty($entry['description'])) {
|
21 |
-
echo '<small>', $entry['description'], '</small>';
|
22 |
-
}
|
23 |
-
echo '</a></li>';
|
24 |
-
}
|
25 |
-
}
|
26 |
-
|
27 |
-
// Check the status to show a warning if needed
|
28 |
-
$status_options = Newsletter::instance()->get_options('status');
|
29 |
-
$warning = false;
|
30 |
-
|
31 |
-
$warning |= empty($status_options['mail']);
|
32 |
-
?>
|
33 |
-
<script>
|
34 |
-
function tnp_close_promotion() {
|
35 |
-
jQuery.post(ajaxurl + "?action=tnp_hide_promotion", {id: 'june-2020'});
|
36 |
-
document.getElementById('tnp-promotion-bar').style.display = 'none';
|
37 |
-
}
|
38 |
-
</script>
|
39 |
-
|
40 |
-
<?php if (get_option('newsletter_promotion') !== 'june-2020' && time() < gmmktime(0, 0, 0, 7, 15, 2020)) { ?>
|
41 |
-
<div id="tnp-promotion-bar">
|
42 |
-
<a href="https://www.thenewsletterplugin.com/premium?utm_source=plugin-bar&utm_campaign=june-2020" onclick="tnp_close_promotion(); return true;" target="_blank">50% discount offer until July, 15. Check it out.</a>
|
43 |
-
|
44 |
-
<a href="javascript:void(tnp_close_promotion('june-2020'))">No, thank you!</a>
|
45 |
-
</div>
|
46 |
-
<?php } ?>
|
47 |
-
|
48 |
-
|
49 |
-
<div class="tnp-drowpdown" id="tnp-header">
|
50 |
-
<a href="?page=newsletter_main_index"><img src="<?php echo plugins_url('newsletter'); ?>/admin/images/logo-red.png" class="tnp-header-logo" style="vertical-align: bottom;"></a>
|
51 |
-
<ul>
|
52 |
-
<li><a href="#"><i class="fas fa-users"></i> <?php _e('Subscribers', 'newsletter') ?> <i class="fas fa-chevron-down"></i></a>
|
53 |
-
<ul>
|
54 |
-
<li>
|
55 |
-
<a href="?page=newsletter_users_index"><i class="fas fa-search"></i> <?php _e('Search And Edit', 'newsletter') ?>
|
56 |
-
<small><?php _e('Add, edit, search', 'newsletter') ?></small></a>
|
57 |
-
</li>
|
58 |
-
|
59 |
-
<li>
|
60 |
-
<a href="?page=newsletter_profile_index"><i class="fas fa-user-circle"></i> <?php _e('Profile page', 'newsletter') ?>
|
61 |
-
<small><?php _e('The subscriber personal profile editing panel', 'newsletter') ?></small></a>
|
62 |
-
</li>
|
63 |
-
|
64 |
-
<?php if (!class_exists('NewsletterImport')) { ?>
|
65 |
-
<li>
|
66 |
-
<a href="?page=newsletter_users_import"><i class="fas fa-upload"></i> <?php _e('Import', 'newsletter') ?>
|
67 |
-
<small><?php _e('Import from external sources', 'newsletter') ?></small></a>
|
68 |
-
</li>
|
69 |
-
<?php } ?>
|
70 |
-
|
71 |
-
<li>
|
72 |
-
<a href="?page=newsletter_users_export"><i class="fas fa-download"></i> <?php _e('Export', 'newsletter') ?>
|
73 |
-
<small><?php _e('Export your subscribers list', 'newsletter') ?></small></a>
|
74 |
-
</li>
|
75 |
-
|
76 |
-
<li>
|
77 |
-
<a href="?page=newsletter_users_massive"><i class="fas fa-wrench"></i> <?php _e('Maintenance', 'newsletter') ?>
|
78 |
-
<small><?php _e('Massive actions: change list, clean up, ...', 'newsletter') ?></small></a>
|
79 |
-
</li>
|
80 |
-
|
81 |
-
<li>
|
82 |
-
<a href="?page=newsletter_users_statistics"><i class="fas fa-chart-bar"></i> <?php _e('Statistics', 'newsletter') ?>
|
83 |
-
<small><?php _e('All about your subscribers', 'newsletter') ?></small></a>
|
84 |
-
</li>
|
85 |
-
|
86 |
-
<?php newsletter_print_entries('subscribers') ?>
|
87 |
-
</ul>
|
88 |
-
</li>
|
89 |
-
<li><a href="#"><i class="fas fa-list"></i> <?php _e('List Building', 'newsletter') ?> <i class="fas fa-chevron-down"></i></a>
|
90 |
-
<ul>
|
91 |
-
<li>
|
92 |
-
<a href="?page=newsletter_subscription_profile"><i class="fas fa-check-square"></i> <?php _e('Subscription Form Fields, Buttons, Labels', 'newsletter') ?>
|
93 |
-
<small><?php _e('When and what data to collect', 'newsletter') ?></small></a>
|
94 |
-
</li>
|
95 |
-
|
96 |
-
<li>
|
97 |
-
<a href="?page=newsletter_subscription_options"><i class="fas fa-sign-in-alt"></i> <?php _e('Subscription', 'newsletter') ?>
|
98 |
-
<small><?php _e('The subscription process in detail', 'newsletter') ?></small></a>
|
99 |
-
</li>
|
100 |
-
|
101 |
-
<li>
|
102 |
-
<a href="?page=newsletter_subscription_lists"><i class="fas fa-th-list"></i> <?php _e('Lists', 'newsletter') ?>
|
103 |
-
<small><?php _e('Profile the subscribers for a better targeting', 'newsletter') ?></small></a>
|
104 |
-
</li>
|
105 |
-
|
106 |
-
<li>
|
107 |
-
<a href="?page=newsletter_subscription_antibot"><i class="fas fa-lock"></i> <?php _e('Security', 'newsletter') ?>
|
108 |
-
<small><?php _e('Spam subscriptions control', 'newsletter') ?></small></a>
|
109 |
-
</li>
|
110 |
-
|
111 |
-
<li>
|
112 |
-
<a href="?page=newsletter_unsubscription_index"><i class="fas fa-sign-out-alt"></i> <?php _e('Unsubscription', 'newsletter') ?>
|
113 |
-
<small><?php _e('How to give the last goodbye (or avoid it!)', 'newsletter') ?></small></a>
|
114 |
-
</li>
|
115 |
-
|
116 |
-
<?php
|
117 |
-
newsletter_print_entries('subscription');
|
118 |
-
?>
|
119 |
-
</ul>
|
120 |
-
</li>
|
121 |
-
|
122 |
-
<li>
|
123 |
-
<a href="#"><i class="fas fa-newspaper"></i> <?php _e('Newsletters', 'newsletter') ?> <i class="fas fa-chevron-down"></i></a>
|
124 |
-
<ul>
|
125 |
-
<li>
|
126 |
-
<a href="?page=newsletter_emails_composer"><i class="fas fa-plus"></i> <?php _e('Create newsletter', 'newsletter') ?>
|
127 |
-
<small><?php _e('Start your new campaign', 'newsletter') ?></small></a>
|
128 |
-
</li>
|
129 |
-
|
130 |
-
<li>
|
131 |
-
<a href="?page=newsletter_emails_index"><i class="fas fa-newspaper"></i> <?php _e('Newsletters', 'newsletter') ?>
|
132 |
-
<small><?php _e('The classic "write & send" newsletters', 'newsletter') ?></small></a>
|
133 |
-
</li>
|
134 |
-
|
135 |
-
<li>
|
136 |
-
<a href="<?php echo NewsletterStatistics::instance()->get_index_url() ?>"><i class="fas fa-chart-bar"></i> <?php _e('Statistics', 'newsletter') ?>
|
137 |
-
<small><?php _e('Tracking configuration and basic data', 'newsletter') ?></small></a>
|
138 |
-
</li>
|
139 |
-
<?php
|
140 |
-
newsletter_print_entries('newsletters');
|
141 |
-
?>
|
142 |
-
</ul>
|
143 |
-
</li>
|
144 |
-
|
145 |
-
<li>
|
146 |
-
<a href="#"><i class="fas fa-cog"></i> <?php _e('Settings', 'newsletter') ?> <i class="fas fa-chevron-down"></i></a>
|
147 |
-
<ul>
|
148 |
-
<?php if ($is_administrator) { ?>
|
149 |
-
<li>
|
150 |
-
<a href="?page=newsletter_main_main"><i class="fas fa-cogs"></i> <?php _e('General Settings', 'newsletter') ?>
|
151 |
-
<small><?php _e('Delivery speed, sender details, ...', 'newsletter') ?></small></a>
|
152 |
-
</li>
|
153 |
-
<?php if (!class_exists('NewsletterSmtp')) { ?>
|
154 |
-
<li>
|
155 |
-
<a href="?page=newsletter_main_smtp"><i class="fas fa-server"></i> <?php _e('SMTP', 'newsletter') ?>
|
156 |
-
<small><?php _e('External mail server', 'newsletter') ?></small>
|
157 |
-
</a>
|
158 |
-
</li>
|
159 |
-
<?php } ?>
|
160 |
-
<?php } ?>
|
161 |
-
|
162 |
-
<li>
|
163 |
-
<a href="?page=newsletter_main_info"><i class="fas fa-info"></i> <?php _e('Company Info', 'newsletter') ?>
|
164 |
-
<small><?php _e('Social, address, logo and general info', 'newsletter') ?></small></a>
|
165 |
-
</li>
|
166 |
-
|
167 |
-
<li>
|
168 |
-
<a href="?page=newsletter_subscription_template"><i class="fas fa-file-alt"></i> <?php _e('Messages Template', 'newsletter') ?>
|
169 |
-
<small><?php _e('Change the look of your service emails', 'newsletter') ?></small></a>
|
170 |
-
</li>
|
171 |
-
|
172 |
-
<?php
|
173 |
-
newsletter_print_entries('settings');
|
174 |
-
?>
|
175 |
-
</ul>
|
176 |
-
</li>
|
177 |
-
|
178 |
-
<?php if ($is_administrator) { ?>
|
179 |
-
<li>
|
180 |
-
<a href="#"><i class="fas fa-thermometer"></i> <?php _e('System', 'newsletter') ?>
|
181 |
-
<?php if ($warning) { ?>
|
182 |
-
<i class="fas fa-exclamation-triangle" style="color: red;"></i>
|
183 |
-
<?php } ?>
|
184 |
-
</a>
|
185 |
-
<ul>
|
186 |
-
<li>
|
187 |
-
<a href="<?php echo admin_url('site-health.php') ?> "><i class="fas fa-file"></i> <?php _e('Site health') ?>
|
188 |
-
<small><?php _e('WP native site health checks', 'newsletter') ?></small></a>
|
189 |
-
</li>
|
190 |
-
<li>
|
191 |
-
<a href="?page=newsletter_main_delivery"><i class="fas fa-file"></i> <?php _e('Delivery Diagnostic', 'newsletter') ?>
|
192 |
-
<small><?php _e('Delivery analysis and test', 'newsletter') ?></small></a>
|
193 |
-
</li>
|
194 |
-
<li>
|
195 |
-
<a href="?page=newsletter_main_scheduler"><i class="fas fa-robot"></i> <?php _e('Scheduler', 'newsletter') ?>
|
196 |
-
<small><?php _e('', 'newsletter') ?></small></a>
|
197 |
-
</li>
|
198 |
-
<li>
|
199 |
-
<a href="?page=newsletter_main_status"><i class="fas fa-file"></i> <?php _e('Status', 'newsletter') ?>
|
200 |
-
<small><?php _e('Checks and parameters', 'newsletter') ?></small></a>
|
201 |
-
</li>
|
202 |
-
|
203 |
-
<li>
|
204 |
-
<a href="?page=newsletter_main_logs"><i class="fas fa-file"></i> <?php _e('Logs', 'newsletter') ?>
|
205 |
-
<small><?php _e('Plugin and addons logs', 'newsletter') ?></small></a>
|
206 |
-
</li>
|
207 |
-
</ul>
|
208 |
-
</li>
|
209 |
-
<?php } ?>
|
210 |
-
|
211 |
-
<?php
|
212 |
-
$license_data = Newsletter::instance()->get_license_data();
|
213 |
-
$premium_url = 'https://www.thenewsletterplugin.com/premium?utm_source=plugin&utm_medium=link&utm_campaign=header&utm_content=' . urlencode($_GET['page']);
|
214 |
-
?>
|
215 |
-
|
216 |
-
<?php if (empty($license_data)) { ?>
|
217 |
-
<li class="tnp-professional-extensions-button"><a href="<?php echo $premium_url ?>" target="_blank">
|
218 |
-
<i class="fas fa-trophy"></i> <?php _e('Get Professional Addons', 'newsletter') ?></a>
|
219 |
-
</li>
|
220 |
-
<?php } elseif (is_wp_error($license_data)) { ?>
|
221 |
-
<li class="tnp-professional-extensions-button-red">
|
222 |
-
<a href="?page=newsletter_main_main"><i class="fas fa-hand-paper" style="color: white"></i> <?php _e('Unable to check', 'newsletter') ?></a>
|
223 |
-
</li>
|
224 |
-
|
225 |
-
<?php } elseif ($license_data->expire == 0) { ?>
|
226 |
-
|
227 |
-
<li class="tnp-professional-extensions-button"><a href="<?php echo $premium_url ?>" target="_blank">
|
228 |
-
<i class="fas fa-trophy"></i> <?php _e('Get Professional Addons', 'newsletter') ?></a>
|
229 |
-
</li>
|
230 |
-
|
231 |
-
<?php } elseif ($license_data->expire < time()) { ?>
|
232 |
-
|
233 |
-
<li class="tnp-professional-extensions-button-red">
|
234 |
-
<a href="?page=newsletter_main_main"><i class="fas fa-hand-paper" style="color: white"></i> <?php _e('License expired', 'newsletter') ?></a>
|
235 |
-
</li>
|
236 |
-
|
237 |
-
<?php } elseif ($license_data->expire >= time()) { ?>
|
238 |
-
|
239 |
-
<?php $p = class_exists('NewsletterExtensions') ? 'newsletter_extensions_index' : 'newsletter_main_extensions'; ?>
|
240 |
-
<li class="tnp-professional-extensions-button">
|
241 |
-
<a href="?page=<?php echo $p ?>"><i class="fas fa-check-square"></i> <?php _e('License active', 'newsletter') ?></a>
|
242 |
-
</li>
|
243 |
-
|
244 |
-
|
245 |
-
<?php } ?>
|
246 |
-
</ul>
|
247 |
-
</div>
|
248 |
-
|
249 |
-
<?php if (isset($_GET['debug']) || !isset($dismissed['newsletter-shortcode'])) { ?>
|
250 |
-
<?php
|
251 |
-
// Check of Newsletter dedicated page
|
252 |
-
if (!empty(Newsletter::instance()->options['page'])) {
|
253 |
-
if (get_post_status(Newsletter::instance()->options['page']) === 'publish') {
|
254 |
-
$content = get_post_field('post_content', Newsletter::instance()->options['page']);
|
255 |
-
// With and without attributes
|
256 |
-
if (strpos($content, '[newsletter]') === false && strpos($content, '[newsletter ') === false) {
|
257 |
-
?>
|
258 |
-
<div class="tnp-notice">
|
259 |
-
<a href="<?php echo $_SERVER['REQUEST_URI'] . '&noheader=1&dismiss=newsletter-shortcode' ?>" class="tnp-dismiss">×</a>
|
260 |
-
The Newsletter dedicated page does not contain the [newsletter] shortcode. If you're using a visual composer it could be ok.
|
261 |
-
<a href="<?php echo site_url('/wp-admin/post.php') ?>?post=<?php echo esc_attr(Newsletter::instance()->options['page']) ?>&action=edit"><strong>Edit the page</strong></a>.
|
262 |
-
|
263 |
-
</div>
|
264 |
-
<?php
|
265 |
-
}
|
266 |
-
}
|
267 |
-
}
|
268 |
-
?>
|
269 |
-
<?php } ?>
|
270 |
-
|
271 |
-
<?php if (isset($_GET['debug']) || !isset($dismissed['rate']) && $user_count > 300) { ?>
|
272 |
-
<div class="tnp-notice">
|
273 |
-
<a href="<?php echo $_SERVER['REQUEST_URI'] . '&noheader=1&dismiss=rate' ?>" class="tnp-dismiss">×</a>
|
274 |
-
|
275 |
-
We never asked before and we're curious: <a href="http://wordpress.org/plugins/newsletter/" target="_blank">would you rate this plugin</a>?
|
276 |
-
(few seconds required - account on WordPress.org required, every blog owner should have one...). <strong>Really appreciated, The Newsletter Team</strong>.
|
277 |
-
|
278 |
-
</div>
|
279 |
-
<?php } ?>
|
280 |
-
|
281 |
-
<?php if (isset($_GET['debug']) || !isset($dismissed['newsletter-page']) && empty(Newsletter::instance()->options['page'])) { ?>
|
282 |
-
<div class="tnp-notice">
|
283 |
-
<a href="<?php echo $_SERVER['REQUEST_URI'] . '&noheader=1&dismiss=newsletter-page' ?>" class="tnp-dismiss">×</a>
|
284 |
-
|
285 |
-
You should create a blog page to show the subscription form and the subscription messages. Go to the
|
286 |
-
<a href="?page=newsletter_main_main">general settings panel</a> to configure it.
|
287 |
-
|
288 |
-
</div>
|
289 |
-
<?php } ?>
|
290 |
-
|
291 |
-
<?php if (isset($_GET['debug']) || !isset($dismissed['newsletter-subscribe']) && get_option('newsletter_install_time') && get_option('newsletter_install_time') < time() - 86400 * 15) { ?>
|
292 |
-
<div class="tnp-notice">
|
293 |
-
<a href="<?php echo $_SERVER['REQUEST_URI'] . '&noheader=1&dismiss=newsletter-subscribe' ?>" class="tnp-dismiss">×</a>
|
294 |
-
If you want to be informed of important updates of Newsletter, you may want to subscribe to our newsletter<br>
|
295 |
-
<form action="https://www.thenewsletterplugin.com/?na=s" target="_blank" method="post">
|
296 |
-
<input type="hidden" value="plugin-header" name="nr">
|
297 |
-
<input type="hidden" value="3" name="nl[]">
|
298 |
-
<input type="hidden" value="single" name="optin">
|
299 |
-
<input type="email" name="ne" value="<?php echo esc_attr(get_option('admin_email')) ?>">
|
300 |
-
<input type="submit" value="<?php esc_attr_e('Subscribe', 'newsletter') ?>">
|
301 |
-
</form>
|
302 |
-
</div>
|
303 |
-
<?php } ?>
|
304 |
-
|
305 |
-
<?php
|
306 |
-
if (!defined('NEWSLETTER_CRON_WARNINGS') || NEWSLETTER_CRON_WARNINGS) {
|
307 |
-
$x = NewsletterSystem::instance()->get_job_status();
|
308 |
-
if ($x !== NewsletterSystem::JOB_OK) {
|
309 |
-
echo '<div class="tnpc-warning">The are issues with the delivery engine. Please <a href="?page=newsletter_main_scheduler">check them here</a>.</div>';
|
310 |
-
}
|
311 |
-
}
|
312 |
-
?>
|
313 |
-
|
314 |
-
<?php
|
315 |
-
if ($_GET['page'] !== 'newsletter_emails_edit') {
|
316 |
-
|
317 |
-
$last_failed_newsletters = Newsletter::instance()->get_emails_by_field('status', TNP_Email::STATUS_ERROR);
|
318 |
-
|
319 |
-
foreach ($last_failed_newsletters as $newsletter) {
|
320 |
-
echo '<div class="tnpc-error">';
|
321 |
-
printf(__('Newsletter "%s" stopped by fatal error.', 'newsletter'), esc_html($newsletter->subject));
|
322 |
-
echo ' ';
|
323 |
-
$c = new NewsletterControls();
|
324 |
-
$c->btn_link('?page=newsletter_emails_edit&id=' . $newsletter->id, __('Check', 'newsletter'));
|
325 |
-
echo '</div>';
|
326 |
-
}
|
327 |
-
}
|
328 |
-
?>
|
329 |
-
|
330 |
-
<div id="tnp-notification">
|
331 |
-
<?php
|
332 |
-
if (isset($controls)) {
|
333 |
-
$controls->show();
|
334 |
-
$controls->messages = '';
|
335 |
-
$controls->errors = '';
|
336 |
-
}
|
337 |
-
?>
|
338 |
-
</div>
|
339 |
-
|
340 |
-
|
1 |
+
<?php
|
2 |
+
global $current_user, $wpdb;
|
3 |
+
|
4 |
+
defined('ABSPATH') || exit;
|
5 |
+
|
6 |
+
$dismissed = get_option('newsletter_dismissed', []);
|
7 |
+
|
8 |
+
$user_count = Newsletter::instance()->get_user_count();
|
9 |
+
|
10 |
+
$is_administrator = current_user_can('administrator');
|
11 |
+
|
12 |
+
function newsletter_print_entries($group) {
|
13 |
+
$entries = apply_filters('newsletter_menu_' . $group, array());
|
14 |
+
if (!$entries) {
|
15 |
+
return;
|
16 |
+
}
|
17 |
+
|
18 |
+
foreach ($entries as &$entry) {
|
19 |
+
echo '<li><a href="', $entry['url'], '">', $entry['label'];
|
20 |
+
if (!empty($entry['description'])) {
|
21 |
+
echo '<small>', $entry['description'], '</small>';
|
22 |
+
}
|
23 |
+
echo '</a></li>';
|
24 |
+
}
|
25 |
+
}
|
26 |
+
|
27 |
+
// Check the status to show a warning if needed
|
28 |
+
$status_options = Newsletter::instance()->get_options('status');
|
29 |
+
$warning = false;
|
30 |
+
|
31 |
+
$warning |= empty($status_options['mail']);
|
32 |
+
?>
|
33 |
+
<script>
|
34 |
+
function tnp_close_promotion() {
|
35 |
+
jQuery.post(ajaxurl + "?action=tnp_hide_promotion", {id: 'june-2020'});
|
36 |
+
document.getElementById('tnp-promotion-bar').style.display = 'none';
|
37 |
+
}
|
38 |
+
</script>
|
39 |
+
|
40 |
+
<?php if (get_option('newsletter_promotion') !== 'june-2020' && time() < gmmktime(0, 0, 0, 7, 15, 2020)) { ?>
|
41 |
+
<div id="tnp-promotion-bar">
|
42 |
+
<a href="https://www.thenewsletterplugin.com/premium?utm_source=plugin-bar&utm_campaign=june-2020" onclick="tnp_close_promotion(); return true;" target="_blank">50% discount offer until July, 15. Check it out.</a>
|
43 |
+
|
44 |
+
<a href="javascript:void(tnp_close_promotion('june-2020'))">No, thank you!</a>
|
45 |
+
</div>
|
46 |
+
<?php } ?>
|
47 |
+
|
48 |
+
|
49 |
+
<div class="tnp-drowpdown" id="tnp-header">
|
50 |
+
<a href="?page=newsletter_main_index"><img src="<?php echo plugins_url('newsletter'); ?>/admin/images/logo-red.png" class="tnp-header-logo" style="vertical-align: bottom;"></a>
|
51 |
+
<ul>
|
52 |
+
<li><a href="#"><i class="fas fa-users"></i> <?php _e('Subscribers', 'newsletter') ?> <i class="fas fa-chevron-down"></i></a>
|
53 |
+
<ul>
|
54 |
+
<li>
|
55 |
+
<a href="?page=newsletter_users_index"><i class="fas fa-search"></i> <?php _e('Search And Edit', 'newsletter') ?>
|
56 |
+
<small><?php _e('Add, edit, search', 'newsletter') ?></small></a>
|
57 |
+
</li>
|
58 |
+
|
59 |
+
<li>
|
60 |
+
<a href="?page=newsletter_profile_index"><i class="fas fa-user-circle"></i> <?php _e('Profile page', 'newsletter') ?>
|
61 |
+
<small><?php _e('The subscriber personal profile editing panel', 'newsletter') ?></small></a>
|
62 |
+
</li>
|
63 |
+
|
64 |
+
<?php if (!class_exists('NewsletterImport')) { ?>
|
65 |
+
<li>
|
66 |
+
<a href="?page=newsletter_users_import"><i class="fas fa-upload"></i> <?php _e('Import', 'newsletter') ?>
|
67 |
+
<small><?php _e('Import from external sources', 'newsletter') ?></small></a>
|
68 |
+
</li>
|
69 |
+
<?php } ?>
|
70 |
+
|
71 |
+
<li>
|
72 |
+
<a href="?page=newsletter_users_export"><i class="fas fa-download"></i> <?php _e('Export', 'newsletter') ?>
|
73 |
+
<small><?php _e('Export your subscribers list', 'newsletter') ?></small></a>
|
74 |
+
</li>
|
75 |
+
|
76 |
+
<li>
|
77 |
+
<a href="?page=newsletter_users_massive"><i class="fas fa-wrench"></i> <?php _e('Maintenance', 'newsletter') ?>
|
78 |
+
<small><?php _e('Massive actions: change list, clean up, ...', 'newsletter') ?></small></a>
|
79 |
+
</li>
|
80 |
+
|
81 |
+
<li>
|
82 |
+
<a href="?page=newsletter_users_statistics"><i class="fas fa-chart-bar"></i> <?php _e('Statistics', 'newsletter') ?>
|
83 |
+
<small><?php _e('All about your subscribers', 'newsletter') ?></small></a>
|
84 |
+
</li>
|
85 |
+
|
86 |
+
<?php newsletter_print_entries('subscribers') ?>
|
87 |
+
</ul>
|
88 |
+
</li>
|
89 |
+
<li><a href="#"><i class="fas fa-list"></i> <?php _e('List Building', 'newsletter') ?> <i class="fas fa-chevron-down"></i></a>
|
90 |
+
<ul>
|
91 |
+
<li>
|
92 |
+
<a href="?page=newsletter_subscription_profile"><i class="fas fa-check-square"></i> <?php _e('Subscription Form Fields, Buttons, Labels', 'newsletter') ?>
|
93 |
+
<small><?php _e('When and what data to collect', 'newsletter') ?></small></a>
|
94 |
+
</li>
|
95 |
+
|
96 |
+
<li>
|
97 |
+
<a href="?page=newsletter_subscription_options"><i class="fas fa-sign-in-alt"></i> <?php _e('Subscription', 'newsletter') ?>
|
98 |
+
<small><?php _e('The subscription process in detail', 'newsletter') ?></small></a>
|
99 |
+
</li>
|
100 |
+
|
101 |
+
<li>
|
102 |
+
<a href="?page=newsletter_subscription_lists"><i class="fas fa-th-list"></i> <?php _e('Lists', 'newsletter') ?>
|
103 |
+
<small><?php _e('Profile the subscribers for a better targeting', 'newsletter') ?></small></a>
|
104 |
+
</li>
|
105 |
+
|
106 |
+
<li>
|
107 |
+
<a href="?page=newsletter_subscription_antibot"><i class="fas fa-lock"></i> <?php _e('Security', 'newsletter') ?>
|
108 |
+
<small><?php _e('Spam subscriptions control', 'newsletter') ?></small></a>
|
109 |
+
</li>
|
110 |
+
|
111 |
+
<li>
|
112 |
+
<a href="?page=newsletter_unsubscription_index"><i class="fas fa-sign-out-alt"></i> <?php _e('Unsubscription', 'newsletter') ?>
|
113 |
+
<small><?php _e('How to give the last goodbye (or avoid it!)', 'newsletter') ?></small></a>
|
114 |
+
</li>
|
115 |
+
|
116 |
+
<?php
|
117 |
+
newsletter_print_entries('subscription');
|
118 |
+
?>
|
119 |
+
</ul>
|
120 |
+
</li>
|
121 |
+
|
122 |
+
<li>
|
123 |
+
<a href="#"><i class="fas fa-newspaper"></i> <?php _e('Newsletters', 'newsletter') ?> <i class="fas fa-chevron-down"></i></a>
|
124 |
+
<ul>
|
125 |
+
<li>
|
126 |
+
<a href="?page=newsletter_emails_composer"><i class="fas fa-plus"></i> <?php _e('Create newsletter', 'newsletter') ?>
|
127 |
+
<small><?php _e('Start your new campaign', 'newsletter') ?></small></a>
|
128 |
+
</li>
|
129 |
+
|
130 |
+
<li>
|
131 |
+
<a href="?page=newsletter_emails_index"><i class="fas fa-newspaper"></i> <?php _e('Newsletters', 'newsletter') ?>
|
132 |
+
<small><?php _e('The classic "write & send" newsletters', 'newsletter') ?></small></a>
|
133 |
+
</li>
|
134 |
+
|
135 |
+
<li>
|
136 |
+
<a href="<?php echo NewsletterStatistics::instance()->get_index_url() ?>"><i class="fas fa-chart-bar"></i> <?php _e('Statistics', 'newsletter') ?>
|
137 |
+
<small><?php _e('Tracking configuration and basic data', 'newsletter') ?></small></a>
|
138 |
+
</li>
|
139 |
+
<?php
|
140 |
+
newsletter_print_entries('newsletters');
|
141 |
+
?>
|
142 |
+
</ul>
|
143 |
+
</li>
|
144 |
+
|
145 |
+
<li>
|
146 |
+
<a href="#"><i class="fas fa-cog"></i> <?php _e('Settings', 'newsletter') ?> <i class="fas fa-chevron-down"></i></a>
|
147 |
+
<ul>
|
148 |
+
<?php if ($is_administrator) { ?>
|
149 |
+
<li>
|
150 |
+
<a href="?page=newsletter_main_main"><i class="fas fa-cogs"></i> <?php _e('General Settings', 'newsletter') ?>
|
151 |
+
<small><?php _e('Delivery speed, sender details, ...', 'newsletter') ?></small></a>
|
152 |
+
</li>
|
153 |
+
<?php if (!class_exists('NewsletterSmtp')) { ?>
|
154 |
+
<li>
|
155 |
+
<a href="?page=newsletter_main_smtp"><i class="fas fa-server"></i> <?php _e('SMTP', 'newsletter') ?>
|
156 |
+
<small><?php _e('External mail server', 'newsletter') ?></small>
|
157 |
+
</a>
|
158 |
+
</li>
|
159 |
+
<?php } ?>
|
160 |
+
<?php } ?>
|
161 |
+
|
162 |
+
<li>
|
163 |
+
<a href="?page=newsletter_main_info"><i class="fas fa-info"></i> <?php _e('Company Info', 'newsletter') ?>
|
164 |
+
<small><?php _e('Social, address, logo and general info', 'newsletter') ?></small></a>
|
165 |
+
</li>
|
166 |
+
|
167 |
+
<li>
|
168 |
+
<a href="?page=newsletter_subscription_template"><i class="fas fa-file-alt"></i> <?php _e('Messages Template', 'newsletter') ?>
|
169 |
+
<small><?php _e('Change the look of your service emails', 'newsletter') ?></small></a>
|
170 |
+
</li>
|
171 |
+
|
172 |
+
<?php
|
173 |
+
newsletter_print_entries('settings');
|
174 |
+
?>
|
175 |
+
</ul>
|
176 |
+
</li>
|
177 |
+
|
178 |
+
<?php if ($is_administrator) { ?>
|
179 |
+
<li>
|
180 |
+
<a href="#"><i class="fas fa-thermometer"></i> <?php _e('System', 'newsletter') ?>
|
181 |
+
<?php if ($warning) { ?>
|
182 |
+
<i class="fas fa-exclamation-triangle" style="color: red;"></i>
|
183 |
+
<?php } ?>
|
184 |
+
</a>
|
185 |
+
<ul>
|
186 |
+
<li>
|
187 |
+
<a href="<?php echo admin_url('site-health.php') ?> "><i class="fas fa-file"></i> <?php _e('Site health') ?>
|
188 |
+
<small><?php _e('WP native site health checks', 'newsletter') ?></small></a>
|
189 |
+
</li>
|
190 |
+
<li>
|
191 |
+
<a href="?page=newsletter_main_delivery"><i class="fas fa-file"></i> <?php _e('Delivery Diagnostic', 'newsletter') ?>
|
192 |
+
<small><?php _e('Delivery analysis and test', 'newsletter') ?></small></a>
|
193 |
+
</li>
|
194 |
+
<li>
|
195 |
+
<a href="?page=newsletter_main_scheduler"><i class="fas fa-robot"></i> <?php _e('Scheduler', 'newsletter') ?>
|
196 |
+
<small><?php _e('', 'newsletter') ?></small></a>
|
197 |
+
</li>
|
198 |
+
<li>
|
199 |
+
<a href="?page=newsletter_main_status"><i class="fas fa-file"></i> <?php _e('Status', 'newsletter') ?>
|
200 |
+
<small><?php _e('Checks and parameters', 'newsletter') ?></small></a>
|
201 |
+
</li>
|
202 |
+
|
203 |
+
<li>
|
204 |
+
<a href="?page=newsletter_main_logs"><i class="fas fa-file"></i> <?php _e('Logs', 'newsletter') ?>
|
205 |
+
<small><?php _e('Plugin and addons logs', 'newsletter') ?></small></a>
|
206 |
+
</li>
|
207 |
+
</ul>
|
208 |
+
</li>
|
209 |
+
<?php } ?>
|
210 |
+
|
211 |
+
<?php
|
212 |
+
$license_data = Newsletter::instance()->get_license_data();
|
213 |
+
$premium_url = 'https://www.thenewsletterplugin.com/premium?utm_source=plugin&utm_medium=link&utm_campaign=header&utm_content=' . urlencode($_GET['page']);
|
214 |
+
?>
|
215 |
+
|
216 |
+
<?php if (empty($license_data)) { ?>
|
217 |
+
<li class="tnp-professional-extensions-button"><a href="<?php echo $premium_url ?>" target="_blank">
|
218 |
+
<i class="fas fa-trophy"></i> <?php _e('Get Professional Addons', 'newsletter') ?></a>
|
219 |
+
</li>
|
220 |
+
<?php } elseif (is_wp_error($license_data)) { ?>
|
221 |
+
<li class="tnp-professional-extensions-button-red">
|
222 |
+
<a href="?page=newsletter_main_main"><i class="fas fa-hand-paper" style="color: white"></i> <?php _e('Unable to check', 'newsletter') ?></a>
|
223 |
+
</li>
|
224 |
+
|
225 |
+
<?php } elseif ($license_data->expire == 0) { ?>
|
226 |
+
|
227 |
+
<li class="tnp-professional-extensions-button"><a href="<?php echo $premium_url ?>" target="_blank">
|
228 |
+
<i class="fas fa-trophy"></i> <?php _e('Get Professional Addons', 'newsletter') ?></a>
|
229 |
+
</li>
|
230 |
+
|
231 |
+
<?php } elseif ($license_data->expire < time()) { ?>
|
232 |
+
|
233 |
+
<li class="tnp-professional-extensions-button-red">
|
234 |
+
<a href="?page=newsletter_main_main"><i class="fas fa-hand-paper" style="color: white"></i> <?php _e('License expired', 'newsletter') ?></a>
|
235 |
+
</li>
|
236 |
+
|
237 |
+
<?php } elseif ($license_data->expire >= time()) { ?>
|
238 |
+
|
239 |
+
<?php $p = class_exists('NewsletterExtensions') ? 'newsletter_extensions_index' : 'newsletter_main_extensions'; ?>
|
240 |
+
<li class="tnp-professional-extensions-button">
|
241 |
+
<a href="?page=<?php echo $p ?>"><i class="fas fa-check-square"></i> <?php _e('License active', 'newsletter') ?></a>
|
242 |
+
</li>
|
243 |
+
|
244 |
+
|
245 |
+
<?php } ?>
|
246 |
+
</ul>
|
247 |
+
</div>
|
248 |
+
|
249 |
+
<?php if (isset($_GET['debug']) || !isset($dismissed['newsletter-shortcode'])) { ?>
|
250 |
+
<?php
|
251 |
+
// Check of Newsletter dedicated page
|
252 |
+
if (!empty(Newsletter::instance()->options['page'])) {
|
253 |
+
if (get_post_status(Newsletter::instance()->options['page']) === 'publish') {
|
254 |
+
$content = get_post_field('post_content', Newsletter::instance()->options['page']);
|
255 |
+
// With and without attributes
|
256 |
+
if (strpos($content, '[newsletter]') === false && strpos($content, '[newsletter ') === false) {
|
257 |
+
?>
|
258 |
+
<div class="tnp-notice">
|
259 |
+
<a href="<?php echo $_SERVER['REQUEST_URI'] . '&noheader=1&dismiss=newsletter-shortcode' ?>" class="tnp-dismiss">×</a>
|
260 |
+
The Newsletter dedicated page does not contain the [newsletter] shortcode. If you're using a visual composer it could be ok.
|
261 |
+
<a href="<?php echo site_url('/wp-admin/post.php') ?>?post=<?php echo esc_attr(Newsletter::instance()->options['page']) ?>&action=edit"><strong>Edit the page</strong></a>.
|
262 |
+
|
263 |
+
</div>
|
264 |
+
<?php
|
265 |
+
}
|
266 |
+
}
|
267 |
+
}
|
268 |
+
?>
|
269 |
+
<?php } ?>
|
270 |
+
|
271 |
+
<?php if (isset($_GET['debug']) || !isset($dismissed['rate']) && $user_count > 300) { ?>
|
272 |
+
<div class="tnp-notice">
|
273 |
+
<a href="<?php echo $_SERVER['REQUEST_URI'] . '&noheader=1&dismiss=rate' ?>" class="tnp-dismiss">×</a>
|
274 |
+
|
275 |
+
We never asked before and we're curious: <a href="http://wordpress.org/plugins/newsletter/" target="_blank">would you rate this plugin</a>?
|
276 |
+
(few seconds required - account on WordPress.org required, every blog owner should have one...). <strong>Really appreciated, The Newsletter Team</strong>.
|
277 |
+
|
278 |
+
</div>
|
279 |
+
<?php } ?>
|
280 |
+
|
281 |
+
<?php if (isset($_GET['debug']) || !isset($dismissed['newsletter-page']) && empty(Newsletter::instance()->options['page'])) { ?>
|
282 |
+
<div class="tnp-notice">
|
283 |
+
<a href="<?php echo $_SERVER['REQUEST_URI'] . '&noheader=1&dismiss=newsletter-page' ?>" class="tnp-dismiss">×</a>
|
284 |
+
|
285 |
+
You should create a blog page to show the subscription form and the subscription messages. Go to the
|
286 |
+
<a href="?page=newsletter_main_main">general settings panel</a> to configure it.
|
287 |
+
|
288 |
+
</div>
|
289 |
+
<?php } ?>
|
290 |
+
|
291 |
+
<?php if (isset($_GET['debug']) || !isset($dismissed['newsletter-subscribe']) && get_option('newsletter_install_time') && get_option('newsletter_install_time') < time() - 86400 * 15) { ?>
|
292 |
+
<div class="tnp-notice">
|
293 |
+
<a href="<?php echo $_SERVER['REQUEST_URI'] . '&noheader=1&dismiss=newsletter-subscribe' ?>" class="tnp-dismiss">×</a>
|
294 |
+
If you want to be informed of important updates of Newsletter, you may want to subscribe to our newsletter<br>
|
295 |
+
<form action="https://www.thenewsletterplugin.com/?na=s" target="_blank" method="post">
|
296 |
+
<input type="hidden" value="plugin-header" name="nr">
|
297 |
+
<input type="hidden" value="3" name="nl[]">
|
298 |
+
<input type="hidden" value="single" name="optin">
|
299 |
+
<input type="email" name="ne" value="<?php echo esc_attr(get_option('admin_email')) ?>">
|
300 |
+
<input type="submit" value="<?php esc_attr_e('Subscribe', 'newsletter') ?>">
|
301 |
+
</form>
|
302 |
+
</div>
|
303 |
+
<?php } ?>
|
304 |
+
|
305 |
+
<?php
|
306 |
+
if (!defined('NEWSLETTER_CRON_WARNINGS') || NEWSLETTER_CRON_WARNINGS) {
|
307 |
+
$x = NewsletterSystem::instance()->get_job_status();
|
308 |
+
if ($x !== NewsletterSystem::JOB_OK) {
|
309 |
+
echo '<div class="tnpc-warning">The are issues with the delivery engine. Please <a href="?page=newsletter_main_scheduler">check them here</a>.</div>';
|
310 |
+
}
|
311 |
+
}
|
312 |
+
?>
|
313 |
+
|
314 |
+
<?php
|
315 |
+
if ($_GET['page'] !== 'newsletter_emails_edit') {
|
316 |
+
|
317 |
+
$last_failed_newsletters = Newsletter::instance()->get_emails_by_field('status', TNP_Email::STATUS_ERROR);
|
318 |
+
|
319 |
+
foreach ($last_failed_newsletters as $newsletter) {
|
320 |
+
echo '<div class="tnpc-error">';
|
321 |
+
printf(__('Newsletter "%s" stopped by fatal error.', 'newsletter'), esc_html($newsletter->subject));
|
322 |
+
echo ' ';
|
323 |
+
$c = new NewsletterControls();
|
324 |
+
$c->btn_link('?page=newsletter_emails_edit&id=' . $newsletter->id, __('Check', 'newsletter'));
|
325 |
+
echo '</div>';
|
326 |
+
}
|
327 |
+
}
|
328 |
+
?>
|
329 |
+
|
330 |
+
<div id="tnp-notification">
|
331 |
+
<?php
|
332 |
+
if (isset($controls)) {
|
333 |
+
$controls->show();
|
334 |
+
$controls->messages = '';
|
335 |
+
$controls->errors = '';
|
336 |
+
}
|
337 |
+
?>
|
338 |
+
</div>
|
339 |
+
|
340 |
+
|
users/massive.php
CHANGED
@@ -216,7 +216,7 @@ if ($controls->is_action('update_inactive')) {
|
|
216 |
|
217 |
</td>
|
218 |
<td>
|
219 |
-
<?php $controls->
|
220 |
</td>
|
221 |
</tr>
|
222 |
|
@@ -228,7 +228,7 @@ if ($controls->is_action('update_inactive')) {
|
|
228 |
<?php $controls->language('language', false) ?> <?php _e('subscribers without a language', 'newsletter') ?>
|
229 |
</td>
|
230 |
<td>
|
231 |
-
<?php $controls->
|
232 |
</td>
|
233 |
</tr>
|
234 |
<?php } ?>
|
216 |
|
217 |
</td>
|
218 |
<td>
|
219 |
+
<?php $controls->btn('update_inactive', __('Update', 'newsletter'), ['confirm'=>true]); ?>
|
220 |
</td>
|
221 |
</tr>
|
222 |
|
228 |
<?php $controls->language('language', false) ?> <?php _e('subscribers without a language', 'newsletter') ?>
|
229 |
</td>
|
230 |
<td>
|
231 |
+
<?php $controls->btn('language', '»', ['confirm'=>true]); ?>
|
232 |
</td>
|
233 |
</tr>
|
234 |
<?php } ?>
|