Newsletter - Version 7.3.5

Version Description

  • WP 5.8.3 compatibility check
  • Fixed 2021 max year in date picker
  • Typos
Download this release

Release Info

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

Code changes from version 7.3.4 to 7.3.5

Files changed (6) hide show
  1. includes/controls.php +2112 -2112
  2. includes/helper.php +417 -412
  3. plugin.php +3 -3
  4. readme.txt +8 -2
  5. system/scheduler.php +1 -1
  6. tnp-header.php +1 -1
includes/controls.php CHANGED
@@ -1,2112 +1,2112 @@
1
- <?php
2
-
3
- defined('ABSPATH') || exit;
4
-
5
- include_once __DIR__ . '/fields.php';
6
-
7
- class NewsletterControls {
8
-
9
- var $data = [];
10
- var $action = false;
11
- var $button_data = '';
12
- var $errors = '';
13
-
14
- /**
15
- * @var string
16
- */
17
- var $messages = '';
18
-
19
- /**
20
- * @var array
21
- */
22
- var $warnings = array();
23
- var $countries = array(
24
- 'AF' => 'Afghanistan',
25
- 'AX' => 'Aland Islands',
26
- 'AL' => 'Albania',
27
- 'DZ' => 'Algeria',
28
- 'AS' => 'American Samoa',
29
- 'AD' => 'Andorra',
30
- 'AO' => 'Angola',
31
- 'AI' => 'Anguilla',
32
- 'AQ' => 'Antarctica',
33
- 'AG' => 'Antigua And Barbuda',
34
- 'AR' => 'Argentina',
35
- 'AM' => 'Armenia',
36
- 'AW' => 'Aruba',
37
- 'AU' => 'Australia',
38
- 'AT' => 'Austria',
39
- 'AZ' => 'Azerbaijan',
40
- 'BS' => 'Bahamas',
41
- 'BH' => 'Bahrain',
42
- 'BD' => 'Bangladesh',
43
- 'BB' => 'Barbados',
44
- 'BY' => 'Belarus',
45
- 'BE' => 'Belgium',
46
- 'BZ' => 'Belize',
47
- 'BJ' => 'Benin',
48
- 'BM' => 'Bermuda',
49
- 'BT' => 'Bhutan',
50
- 'BO' => 'Bolivia',
51
- 'BA' => 'Bosnia And Herzegovina',
52
- 'BW' => 'Botswana',
53
- 'BV' => 'Bouvet Island',
54
- 'BR' => 'Brazil',
55
- 'IO' => 'British Indian Ocean Territory',
56
- 'BN' => 'Brunei Darussalam',
57
- 'BG' => 'Bulgaria',
58
- 'BF' => 'Burkina Faso',
59
- 'BI' => 'Burundi',
60
- 'KH' => 'Cambodia',
61
- 'CM' => 'Cameroon',
62
- 'CA' => 'Canada',
63
- 'CV' => 'Cape Verde',
64
- 'KY' => 'Cayman Islands',
65
- 'CF' => 'Central African Republic',
66
- 'TD' => 'Chad',
67
- 'CL' => 'Chile',
68
- 'CN' => 'China',
69
- 'CX' => 'Christmas Island',
70
- 'CC' => 'Cocos (Keeling) Islands',
71
- 'CO' => 'Colombia',
72
- 'KM' => 'Comoros',
73
- 'CG' => 'Congo',
74
- 'CD' => 'Congo, Democratic Republic',
75
- 'CK' => 'Cook Islands',
76
- 'CR' => 'Costa Rica',
77
- 'CI' => 'Cote D\'Ivoire',
78
- 'HR' => 'Croatia',
79
- 'CU' => 'Cuba',
80
- 'CY' => 'Cyprus',
81
- 'CZ' => 'Czech Republic',
82
- 'DK' => 'Denmark',
83
- 'DJ' => 'Djibouti',
84
- 'DM' => 'Dominica',
85
- 'DO' => 'Dominican Republic',
86
- 'EC' => 'Ecuador',
87
- 'EG' => 'Egypt',
88
- 'SV' => 'El Salvador',
89
- 'GQ' => 'Equatorial Guinea',
90
- 'ER' => 'Eritrea',
91
- 'EE' => 'Estonia',
92
- 'ET' => 'Ethiopia',
93
- 'FK' => 'Falkland Islands (Malvinas)',
94
- 'FO' => 'Faroe Islands',
95
- 'FJ' => 'Fiji',
96
- 'FI' => 'Finland',
97
- 'FR' => 'France',
98
- 'GF' => 'French Guiana',
99
- 'PF' => 'French Polynesia',
100
- 'TF' => 'French Southern Territories',
101
- 'GA' => 'Gabon',
102
- 'GM' => 'Gambia',
103
- 'GE' => 'Georgia',
104
- 'DE' => 'Germany',
105
- 'GH' => 'Ghana',
106
- 'GI' => 'Gibraltar',
107
- 'GR' => 'Greece',
108
- 'GL' => 'Greenland',
109
- 'GD' => 'Grenada',
110
- 'GP' => 'Guadeloupe',
111
- 'GU' => 'Guam',
112
- 'GT' => 'Guatemala',
113
- 'GG' => 'Guernsey',
114
- 'GN' => 'Guinea',
115
- 'GW' => 'Guinea-Bissau',
116
- 'GY' => 'Guyana',
117
- 'HT' => 'Haiti',
118
- 'HM' => 'Heard Island & Mcdonald Islands',
119
- 'VA' => 'Holy See (Vatican City State)',
120
- 'HN' => 'Honduras',
121
- 'HK' => 'Hong Kong',
122
- 'HU' => 'Hungary',
123
- 'IS' => 'Iceland',
124
- 'IN' => 'India',
125
- 'ID' => 'Indonesia',
126
- 'IR' => 'Iran, Islamic Republic Of',
127
- 'IQ' => 'Iraq',
128
- 'IE' => 'Ireland',
129
- 'IM' => 'Isle Of Man',
130
- 'IL' => 'Israel',
131
- 'IT' => 'Italy',
132
- 'JM' => 'Jamaica',
133
- 'JP' => 'Japan',
134
- 'JE' => 'Jersey',
135
- 'JO' => 'Jordan',
136
- 'KZ' => 'Kazakhstan',
137
- 'KE' => 'Kenya',
138
- 'KI' => 'Kiribati',
139
- 'KR' => 'Korea',
140
- 'KW' => 'Kuwait',
141
- 'KG' => 'Kyrgyzstan',
142
- 'LA' => 'Lao People\'s Democratic Republic',
143
- 'LV' => 'Latvia',
144
- 'LB' => 'Lebanon',
145
- 'LS' => 'Lesotho',
146
- 'LR' => 'Liberia',
147
- 'LY' => 'Libyan Arab Jamahiriya',
148
- 'LI' => 'Liechtenstein',
149
- 'LT' => 'Lithuania',
150
- 'LU' => 'Luxembourg',
151
- 'MO' => 'Macao',
152
- 'MK' => 'Macedonia',
153
- 'MG' => 'Madagascar',
154
- 'MW' => 'Malawi',
155
- 'MY' => 'Malaysia',
156
- 'MV' => 'Maldives',
157
- 'ML' => 'Mali',
158
- 'MT' => 'Malta',
159
- 'MH' => 'Marshall Islands',
160
- 'MQ' => 'Martinique',
161
- 'MR' => 'Mauritania',
162
- 'MU' => 'Mauritius',
163
- 'YT' => 'Mayotte',
164
- 'MX' => 'Mexico',
165
- 'FM' => 'Micronesia, Federated States Of',
166
- 'MD' => 'Moldova',
167
- 'MC' => 'Monaco',
168
- 'MN' => 'Mongolia',
169
- 'ME' => 'Montenegro',
170
- 'MS' => 'Montserrat',
171
- 'MA' => 'Morocco',
172
- 'MZ' => 'Mozambique',
173
- 'MM' => 'Myanmar',
174
- 'NA' => 'Namibia',
175
- 'NR' => 'Nauru',
176
- 'NP' => 'Nepal',
177
- 'NL' => 'Netherlands',
178
- 'AN' => 'Netherlands Antilles',
179
- 'NC' => 'New Caledonia',
180
- 'NZ' => 'New Zealand',
181
- 'NI' => 'Nicaragua',
182
- 'NE' => 'Niger',
183
- 'NG' => 'Nigeria',
184
- 'NU' => 'Niue',
185
- 'NF' => 'Norfolk Island',
186
- 'MP' => 'Northern Mariana Islands',
187
- 'NO' => 'Norway',
188
- 'OM' => 'Oman',
189
- 'PK' => 'Pakistan',
190
- 'PW' => 'Palau',
191
- 'PS' => 'Palestinian Territory, Occupied',
192
- 'PA' => 'Panama',
193
- 'PG' => 'Papua New Guinea',
194
- 'PY' => 'Paraguay',
195
- 'PE' => 'Peru',
196
- 'PH' => 'Philippines',
197
- 'PN' => 'Pitcairn',
198
- 'PL' => 'Poland',
199
- 'PT' => 'Portugal',
200
- 'PR' => 'Puerto Rico',
201
- 'QA' => 'Qatar',
202
- 'RE' => 'Reunion',
203
- 'RO' => 'Romania',
204
- 'RU' => 'Russian Federation',
205
- 'RW' => 'Rwanda',
206
- 'BL' => 'Saint Barthelemy',
207
- 'SH' => 'Saint Helena',
208
- 'KN' => 'Saint Kitts And Nevis',
209
- 'LC' => 'Saint Lucia',
210
- 'MF' => 'Saint Martin',
211
- 'PM' => 'Saint Pierre And Miquelon',
212
- 'VC' => 'Saint Vincent And Grenadines',
213
- 'WS' => 'Samoa',
214
- 'SM' => 'San Marino',
215
- 'ST' => 'Sao Tome And Principe',
216
- 'SA' => 'Saudi Arabia',
217
- 'SN' => 'Senegal',
218
- 'RS' => 'Serbia',
219
- 'SC' => 'Seychelles',
220
- 'SL' => 'Sierra Leone',
221
- 'SG' => 'Singapore',
222
- 'SK' => 'Slovakia',
223
- 'SI' => 'Slovenia',
224
- 'SB' => 'Solomon Islands',
225
- 'SO' => 'Somalia',
226
- 'ZA' => 'South Africa',
227
- 'GS' => 'South Georgia And Sandwich Isl.',
228
- 'ES' => 'Spain',
229
- 'LK' => 'Sri Lanka',
230
- 'SD' => 'Sudan',
231
- 'SR' => 'Suriname',
232
- 'SJ' => 'Svalbard And Jan Mayen',
233
- 'SZ' => 'Swaziland',
234
- 'SE' => 'Sweden',
235
- 'CH' => 'Switzerland',
236
- 'SY' => 'Syrian Arab Republic',
237
- 'TW' => 'Taiwan',
238
- 'TJ' => 'Tajikistan',
239
- 'TZ' => 'Tanzania',
240
- 'TH' => 'Thailand',
241
- 'TL' => 'Timor-Leste',
242
- 'TG' => 'Togo',
243
- 'TK' => 'Tokelau',
244
- 'TO' => 'Tonga',
245
- 'TT' => 'Trinidad And Tobago',
246
- 'TN' => 'Tunisia',
247
- 'TR' => 'Turkey',
248
- 'TM' => 'Turkmenistan',
249
- 'TC' => 'Turks And Caicos Islands',
250
- 'TV' => 'Tuvalu',
251
- 'UG' => 'Uganda',
252
- 'UA' => 'Ukraine',
253
- 'AE' => 'United Arab Emirates',
254
- 'GB' => 'United Kingdom',
255
- 'US' => 'United States',
256
- 'UM' => 'United States Outlying Islands',
257
- 'UY' => 'Uruguay',
258
- 'UZ' => 'Uzbekistan',
259
- 'VU' => 'Vanuatu',
260
- 'VE' => 'Venezuela',
261
- 'VN' => 'Viet Nam',
262
- 'VG' => 'Virgin Islands, British',
263
- 'VI' => 'Virgin Islands, U.S.',
264
- 'WF' => 'Wallis And Futuna',
265
- 'EH' => 'Western Sahara',
266
- 'YE' => 'Yemen',
267
- 'ZM' => 'Zambia',
268
- 'ZW' => 'Zimbabwe',
269
- 'XX' => 'Undefined',
270
- 'CW' => 'Curaçao',
271
- 'SS' => 'South Sudan',
272
- 'EU' => 'Europe (generic)',
273
- 'A1' => 'Anonymous IP',
274
- 'A2' => 'Satellite IP'
275
- );
276
-
277
- /**
278
- *
279
- * @param array $options
280
- */
281
- function __construct($options = null) {
282
- if ($options === null) {
283
- if (isset($_POST['options'])) {
284
- $this->data = stripslashes_deep($_POST['options']);
285
- }
286
- } else {
287
- $this->data = (array) $options;
288
- }
289
-
290
- if (isset($_REQUEST['act'])) {
291
- $this->action = $_REQUEST['act'];
292
- }
293
-
294
- if (isset($_REQUEST['btn'])) {
295
- $this->button_data = $_REQUEST['btn'];
296
- }
297
- // Fields analysis
298
- if (isset($_REQUEST['tnp_fields'])) {
299
- $fields = $_REQUEST['tnp_fields'];
300
- if (is_array($fields)) {
301
- foreach ($fields as $name => $type) {
302
- if ($type == 'datetime') {
303
- // Ex. The user insert 01/07/2012 14:30 and it set the time zone to +2. We cannot use the
304
- // mktime, since it uses the time zone of the machine. We create the time as if we are on
305
- // GMT 0 and then we subtract the GMT offset (the example date and time on GMT+2 happens
306
- // "before").
307
-
308
- $time = gmmktime((int) $_REQUEST[$name . '_hour'], 0, 0, (int) $_REQUEST[$name . '_month'], (int) $_REQUEST[$name . '_day'], (int) $_REQUEST[$name . '_year']);
309
- $time -= get_option('gmt_offset') * 3600;
310
- $this->data[$name] = $time;
311
- continue;
312
- }
313
- if ($type === 'array') {
314
- if (!isset($this->data[$name]))
315
- $this->data[$name] = [];
316
- }
317
- if ($type === 'checkbox') {
318
- if (!isset($this->data[$name])) {
319
- $this->data[$name] = 0;
320
- }
321
- }
322
- }
323
- }
324
- }
325
- }
326
-
327
- function set_data($data) {
328
- if (is_array($data)) {
329
- $this->data = $data;
330
- } else if (is_object($data)) {
331
- $this->data = (array) $data;
332
- } else {
333
- $this->data = [];
334
- }
335
- }
336
-
337
- function merge($options) {
338
- if (!is_array($options))
339
- return;
340
- if ($this->data == null)
341
- $this->data = array();
342
- $this->data = array_merge($this->data, $options);
343
- }
344
-
345
- function merge_defaults($defaults) {
346
- if ($this->data == null)
347
- $this->data = $defaults;
348
- else
349
- $this->data = array_merge($defaults, $this->data);
350
- }
351
-
352
- /**
353
- * Return true is there in an asked action is no action name is specified or
354
- * true is the requested action matches the passed action.
355
- * Dies if it is not a safe call.
356
- */
357
- function is_action($action = null) {
358
- if ($action == null)
359
- return $this->action != null;
360
- if ($this->action == null)
361
- return false;
362
- if ($this->action != $action)
363
- return false;
364
- if (check_admin_referer('save'))
365
- return true;
366
- die('Invalid call');
367
- }
368
-
369
- function get_value($name, $def = null) {
370
- if (!isset($this->data[$name])) {
371
- return $def;
372
- }
373
- return $this->data[$name];
374
- }
375
-
376
- function get_value_array($name) {
377
- if (!isset($this->data[$name]) || !is_array($this->data[$name]))
378
- return array();
379
- return $this->data[$name];
380
- }
381
-
382
- function show_error($text) {
383
- echo '<div class="tnp-error">', $text, '</div>';
384
- }
385
-
386
- function show_warning($text) {
387
- echo '<div class="tnp-warning">', $text, '</div>';
388
- }
389
-
390
- function show_message($text) {
391
- echo '<div class="tnpc-message">', $text, '</div>';
392
- }
393
-
394
- /**
395
- * Show the errors and messages.
396
- */
397
- function show() {
398
- static $shown = false;
399
-
400
- if ($shown) {
401
- return;
402
- }
403
- $shown = true;
404
-
405
- if (!empty($this->errors)) {
406
- echo '<div class="tnpc-error">';
407
- echo $this->errors;
408
- echo '</div>';
409
- }
410
- if (!empty($this->warnings)) {
411
- foreach ((array) $this->warnings as $warning) {
412
- echo '<div class="tnpc-warning">';
413
- echo $warning;
414
- echo '</div>';
415
- }
416
- }
417
- if (!empty($this->messages)) {
418
- echo '<div class="tnpc-message">';
419
- echo $this->messages;
420
- echo '</div>';
421
- }
422
- }
423
-
424
- function add_message($text) {
425
- if (!empty($this->messages)) {
426
- $this->messages .= '<br><br>';
427
- }
428
- $this->messages .= $text;
429
- }
430
-
431
- function add_message_saved() {
432
- if (!empty($this->messages)) {
433
- $this->messages .= '<br><br>';
434
- }
435
- $this->messages .= __('Saved.', 'newsletter');
436
- }
437
-
438
- function add_message_deleted() {
439
- if (!empty($this->messages)) {
440
- $this->messages .= '<br><br>';
441
- }
442
- $this->messages .= __('Deleted.', 'newsletter');
443
- }
444
-
445
- function add_message_reset() {
446
- if (!empty($this->messages)) {
447
- $this->messages .= '<br><br>';
448
- }
449
- $this->messages .= __('Options reset.', 'newsletter');
450
- }
451
-
452
- function add_message_done() {
453
- if (!empty($this->messages)) {
454
- $this->messages .= '<br><br>';
455
- }
456
- $this->messages .= __('Done.', 'newsletter');
457
- }
458
-
459
- function add_language_warning() {
460
- $newsletter = Newsletter::instance();
461
- $current_language = $newsletter->get_current_language();
462
-
463
- if (!$current_language) {
464
- return;
465
- }
466
- $this->warnings[] = 'You are configuring the language <strong>' . $newsletter->get_language_label($current_language) . '</strong>. Switch to "all languages" to see all options.';
467
- }
468
-
469
- function switch_to_all_languages_notice() {
470
- echo '<div class="tnpc-languages-notice">';
471
- _e('Switch the administration side to "all languages" to set these options', 'newsletter');
472
- echo '</div>';
473
- }
474
-
475
- function hint($text, $url = '') {
476
- echo '<div class="tnpc-hint">';
477
- // Do not escape that, it can be formatted
478
- echo $text;
479
- if (!empty($url)) {
480
- echo ' <a href="' . esc_attr($url) . '" target="_blank">Read more</a>.';
481
- }
482
- echo '</div>';
483
- }
484
-
485
- function yesno($name) {
486
- $value = isset($this->data[$name]) ? (int) $this->data[$name] : 0;
487
-
488
- echo '<select style="width: 60px" name="options[', esc_attr($name), ']">';
489
- echo '<option value="0"';
490
- if ($value == 0) {
491
- echo ' selected';
492
- }
493
- echo '>', __('No', 'newsletter'), '</option>';
494
- echo '<option value="1"';
495
- if ($value == 1) {
496
- echo ' selected';
497
- }
498
- echo '>', __('Yes', 'newsletter'), '</option>';
499
- echo '</select>&nbsp;&nbsp;&nbsp;';
500
- }
501
-
502
- function enabled($name = 'enabled', $attrs = []) {
503
- $value = isset($this->data[$name]) ? (int) $this->data[$name] : 0;
504
- $name = esc_attr($name);
505
-
506
- echo '<select style="width: 100px" name="options[', $name, ']" id="options-', $name, '"';
507
- if (isset($attrs['bind_to'])) {
508
- echo ' onchange="tnp_select_toggle(this, \'', $attrs['bind_to'], '\')"';
509
- }
510
- echo '>';
511
- echo '<option value="0"';
512
- if ($value == 0) {
513
- echo ' selected';
514
- }
515
- echo '>', __('Disabled', 'newsletter'), '</option>';
516
- echo '<option value="1"';
517
- if ($value == 1) {
518
- echo ' selected';
519
- }
520
- echo '>', __('Enabled', 'newsletter'), '</option>';
521
- echo '</select>';
522
- if (isset($attrs['bind_to'])) {
523
- if ($value) {
524
- echo '<script>jQuery(function ($) {$("#options-', $attrs['bind_to'], '").show()})</script>';
525
- } else {
526
- echo '<script>jQuery(function ($) {$("#options-', $attrs['bind_to'], '").hide()})</script>';
527
- }
528
- }
529
- }
530
-
531
- function disabled($name) {
532
- $value = isset($this->data[$name]) ? (int) $this->data[$name] : 0;
533
-
534
- echo '<select style="width: 100px" name="options[' . esc_attr($name) . ']">';
535
- echo '<option value="0"';
536
- if ($value == 0) {
537
- echo ' selected';
538
- }
539
- echo '>Enabled</option>';
540
- echo '<option value="1"';
541
- if ($value == 1) {
542
- echo ' selected';
543
- }
544
- echo '>Disabled</option>';
545
- echo '</select>';
546
- }
547
-
548
- /**
549
- * Creates a set of checkbox all named as $name with values and labels extracted from
550
- * $values_labels. A checkbox will be checked if internal data under key $name is an array
551
- * and contains the value of the current (echoing) checkbox.
552
- *
553
- * On submit it produces an array under the name $name IF at least one checkbox has
554
- * been checked. Otherwise the key won't be present.
555
- *
556
- * @param array $values
557
- * @param string $name
558
- * @param array $values_labels
559
- */
560
- function checkboxes_group($name, $values_labels) {
561
- $value_array = $this->get_value_array($name);
562
-
563
- echo '<div class="tnpc-checkboxes">';
564
- foreach ($values_labels as $value => $label) {
565
- echo '<label><input type="checkbox" id="' . esc_attr($name) . '" name="options[' . esc_attr($name) . '][]" value="' . esc_attr($value) . '"';
566
- if (array_search($value, $value_array) !== false) {
567
- echo ' checked';
568
- }
569
- echo '>';
570
- if ($label != '') {
571
- echo '&nbsp;' . esc_html($label);
572
- }
573
- echo "</label>";
574
- }
575
- echo "<div style='clear: both'></div>";
576
- }
577
-
578
- /** Creates a checkbox group with all public post types.
579
- */
580
- function post_types($name = 'post_types') {
581
- $list = array();
582
- $post_types = get_post_types(array('public' => true), 'objects', 'and');
583
- foreach ($post_types as $post_type) {
584
- $list[$post_type->name] = $post_type->labels->name;
585
- }
586
-
587
- $this->checkboxes_group($name, $list);
588
- }
589
-
590
- function posts_select($name, $max = 20, $args = array()) {
591
- $args = array_merge(array(
592
- 'posts_per_page' => 5,
593
- 'offset' => 0,
594
- 'category' => '',
595
- 'category_name' => '',
596
- 'orderby' => 'date',
597
- 'order' => 'DESC',
598
- 'include' => '',
599
- 'exclude' => '',
600
- 'meta_key' => '',
601
- 'meta_value' => '',
602
- 'post_type' => 'post',
603
- 'post_mime_type' => '',
604
- 'post_parent' => '',
605
- 'author' => '',
606
- 'author_name' => '',
607
- 'post_status' => 'publish',
608
- 'suppress_filters' => true
609
- ), $args);
610
- $args['posts_per_page'] = $max;
611
-
612
- $posts = get_posts($args);
613
- $options = array();
614
- foreach ($posts as $post) {
615
- $options['' . $post->ID] = $post->post_title;
616
- }
617
-
618
- $this->select($name, $options);
619
- }
620
-
621
- function select_number($name, $min, $max) {
622
- $options = array();
623
- for ($i = $min; $i <= $max; $i++) {
624
- $options['' . $i] = $i;
625
- }
626
- $this->select($name, $options);
627
- }
628
-
629
- function page($name = 'page', $first = null, $language = '', $show_id = false) {
630
- $args = array(
631
- 'post_type' => 'page',
632
- 'posts_per_page' => 1000,
633
- 'offset' => 0,
634
- 'orderby' => 'post_title',
635
- 'post_status' => 'any',
636
- 'suppress_filters' => true
637
- );
638
-
639
- $pages = get_posts($args);
640
- //$pages = get_pages();
641
- $options = array();
642
- foreach ($pages as $page) {
643
- /* @var $page WP_Post */
644
- $label = $page->post_title;
645
- if ($page->post_status != 'publish') {
646
- $label .= ' (' . $page->post_status . ')';
647
- }
648
- if ($show_id) {
649
- $label .= ' [' . $page->ID . ']';
650
- }
651
- $options[$page->ID] = $label;
652
- }
653
- $this->select($name, $options, $first);
654
- }
655
-
656
- /** Used to create a select which is part of a group of controls identified by $name that will
657
- * produce an array of values as $_REQUEST['name'].
658
- * @param string $name
659
- * @param array $options Associative array
660
- */
661
- function select_group($name, $options) {
662
- $value_array = $this->get_value_array($name);
663
-
664
- echo '<select name="options[' . esc_attr($name) . '][]">';
665
-
666
- foreach ($options as $key => $label) {
667
- echo '<option value="' . esc_attr($key) . '"';
668
- if (array_search($key, $value_array) !== false) {
669
- echo ' selected';
670
- }
671
- echo '>' . esc_html($label) . '</option>';
672
- }
673
-
674
- echo '</select>';
675
- }
676
-
677
- function select($name, $options, $first = null, $attrs = []) {
678
- echo '<select id="options-' . esc_attr($name) . '" name="options[' . esc_attr($name) . ']"';
679
- if ($attrs) {
680
- foreach ($attrs as $key => $value) {
681
- echo ' ', $key, '="' . esc_attr($value), '"';
682
- }
683
- }
684
- echo '>';
685
- if (!empty($first)) {
686
- echo '<option value="">' . esc_html($first) . '</option>';
687
- }
688
- $value = $this->get_value($name);
689
- foreach ($options as $key => $label) {
690
- echo '<option value="' . esc_attr($key) . '"';
691
- if ($value == $key) {
692
- echo ' selected';
693
- }
694
- echo '>' . esc_html($label) . '</option>';
695
- }
696
- echo '</select>';
697
- }
698
-
699
- function select_images($name, $options, $first = null) {
700
- $value = $this->get_value($name);
701
-
702
- echo '<select id="options-' . esc_attr($name) . '" name="options[' . esc_attr($name) . ']" style="min-width: 200px">';
703
- if (!empty($first)) {
704
- echo '<option value="">' . esc_html($first) . '</option>';
705
- } else {
706
- // if (empty($value)) {
707
- // $keys = array_keys($options);
708
- // $value = $keys[0];
709
- // }
710
- }
711
- foreach ($options as $key => $data) {
712
- echo '<option value="' . esc_attr($key) . '" image="' . esc_attr($data['image']) . '"';
713
- if ($value == $key)
714
- echo ' selected';
715
- echo '>' . esc_html($data['label']) . '</option>';
716
- }
717
- echo '</select>';
718
- echo '<script>jQuery("#options-' . esc_attr($name) . '").select2({templateResult: tnp_select_images, templateSelection: tnp_select_images_selection});</script>';
719
- }
720
-
721
- function select2($name, $options, $first = null, $multiple = false, $style = null, $placeholder = '') {
722
-
723
- if ($multiple) {
724
- $option_name = "options[" . esc_attr($name) . "][]";
725
- } else {
726
- $option_name = "options[" . esc_attr($name) . "]";
727
- }
728
-
729
- if (is_null($style)) {
730
- $style = 'width: 100%';
731
- }
732
-
733
- $value = $this->get_value($name);
734
-
735
- echo '<select id="options-', esc_attr($name), '" name="', $option_name, '" style="', $style, '"',
736
- ($multiple ? ' multiple' : ''), '>';
737
- if (!empty($first)) {
738
- echo '<option value="">' . esc_html($first) . '</option>';
739
- }
740
-
741
- foreach ($options as $key => $data) {
742
- echo '<option value="' . esc_attr($key) . '"';
743
- if (is_array($value) && in_array($key, $value) || (!is_null($value) && $value == $key )) {
744
- echo ' selected';
745
- }
746
- echo '>' . esc_html($data) . '</option>';
747
- }
748
-
749
- echo '</select>';
750
- echo '<script>jQuery("#options-' . esc_attr($name) . '").select2({placeholder: "', esc_js($placeholder), '"});</script>';
751
- }
752
-
753
- function select_grouped($name, $groups) {
754
- $value = $this->get_value($name);
755
- $name = esc_attr($name);
756
- echo '<select name="options[', $name, ']">';
757
-
758
- foreach ($groups as $group) {
759
- echo '<optgroup label="' . esc_attr($group['']) . '">';
760
- if (!empty($group)) {
761
- foreach ($group as $key => $label) {
762
- if ($key == '') {
763
- continue;
764
- }
765
- echo '<option value="' . esc_attr($key) . '"';
766
- if ($value == $key) {
767
- echo ' selected';
768
- }
769
- echo '>' . esc_html($label) . '</option>';
770
- }
771
- }
772
- echo '</optgroup>';
773
- }
774
- echo '</select>';
775
- }
776
-
777
- /**
778
- * Generated a select control with all available templates. From version 3 there are
779
- * only on kind of templates, they are no more separated by type.
780
- */
781
- function themes($name, $themes, $submit_on_click = true) {
782
- foreach ($themes as $key => $data) {
783
- echo '<label style="display: block; float: left; text-align: center; margin-right: 10px;">';
784
- echo esc_html($key) . '<br>';
785
- echo '<img src="' . esc_attr($data['screenshot']) . '" width="100" height="100" style="border: 1px solid #666; padding: 5px"><br>';
786
- echo '<input style="position: relative; top: -40px" type="radio" onchange="this.form.act.value=\'theme\';this.form.submit()" name="options[' . esc_attr($name) . ']" value="' . esc_attr($key) . '"';
787
- if ($this->data[$name] == $key) {
788
- echo ' checked';
789
- }
790
- echo '>';
791
- echo '</label>';
792
- }
793
- echo '<div style="clear: both"></div>';
794
- }
795
-
796
- function value($name) {
797
- echo esc_html($this->data[$name]);
798
- }
799
-
800
- function value_date($name, $show_remaining = true) {
801
- $time = $this->get_value($name);
802
-
803
- echo gmdate(get_option('date_format') . ' ' . get_option('time_format'), $time + get_option('gmt_offset') * 3600);
804
- $delta = $time - time();
805
- if ($show_remaining && $delta > 0) {
806
- echo 'Remaining: ';
807
- $delta = $time - time();
808
- $days = floor($delta / (24 * 3600));
809
- $delta = $delta - $days * 24 * 3600;
810
- $hours = floor($delta / 3600);
811
- $delta = $delta - $hours * 3600;
812
- $minutes = floor($delta / 60);
813
-
814
- if ($days > 0) {
815
- echo $days . ' days ';
816
- }
817
- echo $hours . ' hours ';
818
- echo $minutes . ' minutes ';
819
- }
820
- }
821
-
822
- function password($name, $size = 20, $placeholder = '') {
823
- $value = $this->get_value($name);
824
- $name = esc_attr($name);
825
- echo '<input id="options-', $name, '" placeholder="' . esc_attr($placeholder) . '" name="options[', $name, ']" type="password" autocomplete="off" ';
826
- if (!empty($size)) {
827
- echo 'size="', $size, '" ';
828
- }
829
- echo 'value="', esc_attr($value), '">';
830
- }
831
-
832
- function text($name, $size = 20, $placeholder = '') {
833
- $value = $this->get_value($name);
834
- $name = esc_attr($name);
835
- echo '<input id="options-', $name, '" placeholder="' . esc_attr($placeholder) . '" title="' . esc_attr($placeholder) . '" name="options[', $name, ']" type="text" ';
836
- if (!empty($size)) {
837
- echo 'size="', esc_attr($size), '" ';
838
- }
839
- echo 'value="', esc_attr($value), '">';
840
- }
841
-
842
- function text_email($name, $attrs = []) {
843
- if (is_numeric($attrs)) {
844
- $attrs = ['size' => $attrs];
845
- }
846
- $attrs = array_merge(['placeholder' => __('Valid email address', 'newsletter'), 'size' => 40, 'required' => false], $attrs);
847
-
848
- $value = $this->get_value($name);
849
- echo '<input name="options[' . esc_attr($name) . ']" type="email" placeholder="';
850
- echo esc_attr($attrs['placeholder']);
851
- echo '" size="', esc_attr($attrs['size']), '" value="', esc_attr($value) , '"';
852
- if ($attrs['required']) {
853
- echo ' required';
854
- }
855
- echo '>';
856
- }
857
-
858
- function text_url($name, $size = 40) {
859
- $value = $this->get_value($name);
860
- echo '<input name="options[' . esc_attr($name) . ']" type="url" placeholder="http://..." size="' . esc_attr($size) . '" value="';
861
- echo esc_attr($value);
862
- echo '"/>';
863
- }
864
-
865
- function hidden($name) {
866
- $value = $this->get_value($name);
867
- echo '<input name="options[', esc_attr($name), ']" id="options-', esc_attr($name), '" type="hidden" value="', esc_attr($value), '">';
868
- }
869
-
870
- /**
871
- * General button. Attributes:
872
- * - id: the element HTML id
873
- * - confirm: if string the text is shown in a confirmation message, if true shows a standard confirm message
874
- * - icon: the font awesome icon name (fa-xxx)
875
- * - style: the CSS style
876
- * - data: free data associated to the button click ($controls->button_data) for example to pass the element ID from a list of elements
877
- *
878
- * @param string $action
879
- * @param string $label
880
- * @param array $attrs
881
- */
882
- function btn($action, $label, $attrs = []) {
883
- echo '<button class="button-primary tnpc-button"';
884
- if (isset($attrs['id'])) {
885
- echo ' id="', esc_attrs($attrs['id']), '"';
886
- }
887
- $onclick = "this.form.act.value='" . esc_attr(esc_js(trim($action))) . "';";
888
- if (!empty($attrs['data'])) {
889
- $onclick .= "this.form.btn.value='" . esc_attr(esc_js($attrs['data'])) . "';";
890
- }
891
- if (isset($attrs['confirm'])) {
892
- if (is_string($attrs['confirm'])) {
893
- $onclick .= "if (!confirm('" . esc_attr(esc_js($attrs['confirm'])) . "')) return false;";
894
- } else if ($attrs['confirm'] === true) {
895
- $onclick .= "if (!confirm('" . esc_attr(esc_js(__('Proceed?', 'newsletter'))) . "')) return false;";
896
- }
897
- }
898
- echo 'onclick="', $onclick, '"';
899
- if (!empty($attrs['title'])) {
900
- echo ' title="', esc_attr($attrs['title']), '"';
901
- }
902
- if (!empty($attrs['style'])) {
903
- echo ' style="', esc_attr($attrs['style']), '"';
904
- }
905
- echo '>';
906
- if (!empty($attrs['icon'])) {
907
- echo '<i class="fas ', esc_attr($attrs['icon']), '"></i>';
908
- if (!empty($label)) {
909
- echo '&nbsp;', esc_html($label);
910
- }
911
- } else {
912
- echo esc_html($label);
913
- }
914
- echo '</button>';
915
- }
916
-
917
- /**
918
- * Creates a link looking lie a standard button. Attributes:
919
- * - title: the link "title" HTML attribute
920
- * - target: the link "target" HTML attribute
921
- * - icon: the font awesome icon name (fa-xxx)
922
- * - style: the CSS style
923
- *
924
- * @param string $url
925
- * @param string $label
926
- * @param array $attrs
927
- */
928
- function btn_link($url, $label, $attrs = []) {
929
- echo '<a href="', esc_attr($url), '" class="button-primary tnpc-button"';
930
- if (!empty($attrs['style'])) {
931
- echo ' style="', esc_attr($attrs['style']), '"';
932
- }
933
- if (!empty($attrs['title'])) {
934
- echo ' title="', esc_attr($attrs['title']), '"';
935
- }
936
- if (!empty($attrs['target'])) {
937
- echo ' target="', esc_attr($attrs['target']), '"';
938
- }
939
- echo '>';
940
- if (!empty($attrs['icon'])) {
941
- echo '<i class="fas ', esc_attr($attrs['icon']), '"></i>';
942
- if (!empty($label)) {
943
- echo '&nbsp;', esc_html($label);
944
- }
945
- } else {
946
- echo esc_html($label);
947
- }
948
- echo '</a>';
949
- }
950
-
951
- function button($action, $label, $function = '', $id = '') {
952
- $id = !empty($id) ? " id=\"$id\" " : '';
953
- if ($function != null) {
954
- echo '<input ' . $id . ' class="button-primary tnpc-button" type="button" value="' . esc_attr($label) . '" onclick="this.form.act.value=\'' . esc_attr($action) . '\';' . esc_html($function) . '"/>';
955
- } else {
956
- echo '<input ' . $id . ' class="button-primary tnpc-button" type="submit" value="' . esc_attr($label) . '" onclick="this.form.act.value=\'' . esc_attr($action) . '\';return true;"/>';
957
- }
958
- }
959
-
960
- function action_link($action, $label, $function = null) {
961
- if ($function != null) {
962
- echo '<input class="button-link tnpc-button" type="button" value="' . esc_attr($label) . '" onclick="this.form.act.value=\'' . esc_attr($action) . '\';' . esc_html($function) . '"/>';
963
- } else {
964
- echo '<input class="button-link tnpc-button" type="submit" value="' . esc_attr($label) . '" onclick="this.form.act.value=\'' . esc_attr($action) . '\';return true;"/>';
965
- }
966
- }
967
-
968
- function button_save() {
969
- $this->btn('save', __('Save', 'newsletter'), ['icon' => 'fa-save']);
970
- }
971
-
972
- function button_reset($action = 'reset') {
973
- $this->btn($action, __('Reset', 'newsletter'), ['icon' => 'fa-reply', 'confirm' => true]);
974
- }
975
-
976
- function button_copy($data = '') {
977
- $this->btn('copy', __('Duplicate', 'newsletter'), ['data' => $data, 'icon' => 'fa-copy', 'confirm' => true]);
978
- }
979
-
980
- function button_icon_copy($data = '') {
981
- $this->btn('copy', '', ['data' => $data, 'icon' => 'fa-copy', 'confirm' => true, 'title' => __('Duplicate', 'newsletter')]);
982
- }
983
-
984
- /**
985
- * Creates a button with "delete" action.
986
- * @param type $data
987
- */
988
- function button_delete($data = '') {
989
- $this->btn('delete', __('Delete', 'newsletter'), ['data' => $data, 'icon' => 'fa-times', 'confirm' => true, 'style' => 'background-color: darkred; color: #ffffff']);
990
- }
991
-
992
- function button_icon_delete($data = '') {
993
- $this->btn('delete', '', ['data' => $data, 'icon' => 'fa-times', 'confirm' => true, 'title' => __('Delete', 'newsletter'), 'style' => 'background-color: darkred; color: #ffffff']);
994
- }
995
-
996
- function button_icon_configure($url) {
997
- $this->btn_link($url, '', ['icon' => 'fa-cog', 'title' => __('Configure', 'newsletter')]);
998
- }
999
-
1000
- function button_icon_subscribers($url) {
1001
- $this->btn_link($url, '', ['icon' => 'fa-users', 'title' => __('Subscribers', 'newsletter')]);
1002
- }
1003
-
1004
- function button_statistics($url) {
1005
- $this->btn_link($url, __('Statistics', 'newsletter'), ['icon' => 'fa-chart-bar']);
1006
- }
1007
-
1008
- function button_icon_statistics($url) {
1009
- $this->btn_link($url, '', ['icon' => 'fa-chart-bar', 'title' => __('Statistics', 'newsletter')]);
1010
- }
1011
-
1012
- function button_icon_view($url) {
1013
- $this->btn_link($url, '', ['icon' => 'fa-eye', 'title' => __('View', 'newsletter'), 'target' => '_blank']);
1014
- }
1015
-
1016
- function button_icon_newsletters($url) {
1017
- $this->btn_link($url, '', ['icon' => 'fa-file-alt', 'title' => __('Newsletters', 'newsletter')]);
1018
- }
1019
-
1020
- function button_icon_design($url) {
1021
- $this->btn_link($url, '', ['icon' => 'fa-paint-brush', 'title' => __('Design', 'newsletter')]);
1022
- }
1023
-
1024
- function button_icon_edit($url) {
1025
- $this->btn_link($url, '', ['icon' => 'fa-edit', 'title' => __('Edit', 'newsletter')]);
1026
- }
1027
-
1028
- function button_icon_back($url) {
1029
- $this->btn_link($url, '', ['icon' => 'fa-chevron-left', 'title' => __('Back', 'newsletter')]);
1030
- }
1031
-
1032
- function button_icon($action, $icon, $title = '', $data = '', $confirm = false) {
1033
- $this->btn($action, '', ['data' => $data, 'icon' => $icon, 'title' => $title, 'confirm' => $confirm]);
1034
- }
1035
-
1036
- function button_back($url) {
1037
- $this->btn_link($url, __('Back', 'newsletter'), ['icon' => 'fa-chevron-left']);
1038
- }
1039
-
1040
- function button_test($action = 'test') {
1041
- $this->btn($action, __('Test', 'newsletter'), ['icon' => 'fa-vial']);
1042
- }
1043
-
1044
- /**
1045
- * @deprecated
1046
- */
1047
- function button_primary($action, $label, $function = null) {
1048
- if ($function != null) {
1049
- echo '<button class="button-primary" onclick="this.form.act.value=\'' . esc_attr($action) . '\';' . esc_attr($function) . '">', $label, '</button>';
1050
- } else {
1051
- echo '<button class="button-primary" onclick="this.form.act.value=\'' . esc_attr($action) . '\'; return true;"/>', $label, '</button>';
1052
- }
1053
- }
1054
-
1055
- function button_confirm($action, $label, $message = true, $data = '') {
1056
- $this->btn($action, $label, ['data' => $data, 'confirm' => $message]);
1057
- }
1058
-
1059
- /**
1060
- * @deprecated
1061
- * @param string $url
1062
- * @param string $label Not escaped.
1063
- */
1064
- function button_link($url, $label = '') {
1065
- echo '<a href="', esc_attr($url), '" class="button-primary">', $label, '</a>';
1066
- }
1067
-
1068
- function editor($name, $rows = 5, $cols = 75) {
1069
- echo '<textarea class="visual" name="options[' . esc_attr($name) . ']" style="width: 100%" wrap="off" rows="' . esc_attr($rows) . '">';
1070
- echo esc_html($this->get_value($name));
1071
- echo '</textarea>';
1072
- }
1073
-
1074
- function wp_editor($name, $settings = []) {
1075
-
1076
- add_filter('mce_buttons', function ($mce_buttons) {
1077
- $mce_buttons[] = 'wp_add_media';
1078
- //$mce_buttons[] = 'wp_code';
1079
- return $mce_buttons;
1080
- });
1081
-
1082
- $settings = array_merge(['media_buttons' => false], $settings);
1083
-
1084
- $value = $this->get_value($name);
1085
- wp_editor($value, $name, array_merge(array(
1086
- 'tinymce' => array('content_css' => plugins_url('newsletter') . '/admin/wp-editor.css?ver=' . NEWSLETTER_VERSION),
1087
- 'textarea_name' => 'options[' . esc_attr($name) . ']',
1088
- 'wpautop' => false
1089
- ), $settings));
1090
- }
1091
-
1092
- function textarea($name, $width = '100%', $height = '50') {
1093
- $value = $this->get_value($name);
1094
- if (is_array($value)) {
1095
- $value = implode("\n", $value);
1096
- }
1097
- echo '<textarea id="options-' . esc_attr($name) . '" class="dynamic" name="options[' . esc_attr($name) . ']" wrap="off" style="width:' . esc_attr($width) . ';height:' . esc_attr($height) . '">';
1098
- echo esc_html($value);
1099
- echo '</textarea>';
1100
- }
1101
-
1102
- function textarea_fixed($name, $width = '100%', $height = '200') {
1103
- $value = $this->get_value($name);
1104
- $name = esc_attr($name);
1105
- echo '<textarea id="options-', $name, '" name="options[', $name, ']" wrap="off" style="width:', esc_attr($width), ';height:', esc_attr($height), 'px">';
1106
- echo esc_html($value);
1107
- echo '</textarea>';
1108
- }
1109
-
1110
- function textarea_preview($name, $width = '100%', $height = '200', $header = '', $footer = '', $switch_button = true) {
1111
- $value = $this->get_value($name);
1112
- $name = esc_attr($name);
1113
- if ($switch_button) {
1114
- echo '<input class="button-primary" type="button" onclick="newsletter_textarea_preview(\'options-', $name, '\', \'\', \'\')" value="Switch editor/preview">';
1115
- echo '<br><br>';
1116
- }
1117
- echo '<div style="box-sizing: border-box; position: relative; margin: 0; padding: 0; width:' . esc_attr($width) . '; height:' . esc_attr($height) . '">';
1118
- echo '<textarea id="options-', $name, '" name="options[', $name, ']" wrap="off" style="width:' . esc_attr($width) . ';height:' . esc_attr($height) . 'px">';
1119
- echo esc_html($value);
1120
- echo '</textarea>';
1121
- echo '<div id="options-', $name, '-preview" style="box-sizing: border-box; background-color: #eee; border: 1px solid #bbb; padding: 15px; width: auto; position: absolute; top: 20px; left: 20px; box-shadow: 0 0 20px #777; z-index: 10000; display: none">';
1122
- echo '<iframe id="options-', $name, '-iframe" class="tnp-editor-preview-desktop"></iframe>';
1123
- echo '<iframe id="options-', $name, '-iframe-phone" class="tnp-editor-preview-mobile"></iframe>';
1124
- echo '</div>';
1125
- echo '</div>';
1126
- }
1127
-
1128
- function email($prefix, $editor = null, $disable_option = false, $settings = array()) {
1129
- if ($disable_option) {
1130
- $this->disabled($prefix . '_disabled');
1131
- echo '<br>';
1132
- }
1133
-
1134
- $this->text($prefix . '_subject', 90, 'Subject');
1135
- echo '<br><br>';
1136
-
1137
- if ($editor == 'wordpress') {
1138
- $this->wp_editor($prefix . '_message', $settings);
1139
- } else if ($editor == 'textarea') {
1140
- $this->textarea($prefix . '_message');
1141
- } else {
1142
- $this->editor($prefix . '_message');
1143
- }
1144
- }
1145
-
1146
- /**
1147
- * Standard checkbox, when not checked no value is transmitted (checkbox2).
1148
- *
1149
- * @param string $name
1150
- * @param string $label
1151
- */
1152
- function checkbox($name, $label = '') {
1153
- if ($label != '') {
1154
- echo '<label>';
1155
- }
1156
- echo '<input type="checkbox" id="options-' . esc_attr($name) . '" name="options[' . esc_attr($name) . ']" value="1"';
1157
- if (!empty($this->data[$name])) {
1158
- echo ' checked';
1159
- }
1160
- echo '>';
1161
- if ($label != '') {
1162
- echo '&nbsp;' . esc_html($label) . '</label>';
1163
- }
1164
- }
1165
-
1166
- /**
1167
- * Checkbox with a hidden field to transmit 1 or 0 even when the checkbox is not checked.
1168
- *
1169
- * @param string $name
1170
- * @param string $label
1171
- */
1172
- function checkbox2($name, $label = '') {
1173
- if ($label != '') {
1174
- echo '<label>';
1175
- }
1176
- echo '<input type="checkbox" id="' . esc_attr($name) . '" onchange="document.getElementById(\'' . esc_attr($name) . '_hidden\').value=this.checked?\'1\':\'0\'"';
1177
- if (!empty($this->data[$name])) {
1178
- echo ' checked';
1179
- }
1180
- echo '>';
1181
- if ($label != '') {
1182
- echo '&nbsp;' . esc_html($label) . '</label>';
1183
- }
1184
- echo '<input type="hidden" id="' . esc_attr($name) . '_hidden" name="options[' . esc_attr($name) . ']" value="';
1185
-
1186
- echo empty($this->data[$name]) ? '0' : '1';
1187
- echo '">';
1188
- }
1189
-
1190
- function radio($name, $value, $label = '') {
1191
- if ($label != '') {
1192
- echo '<label>';
1193
- }
1194
- echo '<input type="radio" id="' . esc_attr($name) . '" name="options[' . esc_attr($name) . ']" value="' . esc_attr($value) . '"';
1195
- $v = $this->get_value($name);
1196
- if ($v == $value) {
1197
- echo ' checked';
1198
- }
1199
- echo '>';
1200
- if ($label != '') {
1201
- echo '&nbsp;' . esc_html($label) . '</label>';
1202
- }
1203
- }
1204
-
1205
- /**
1206
- * Creates a checkbox named $name and checked if the internal data contains under
1207
- * the key $name an array containig the passed value.
1208
- */
1209
- function checkbox_group($name, $value, $label = '', $attrs = []) {
1210
- $attrs = wp_parse_args($attrs, ['label_escape' => true]);
1211
- echo '<label><input type="checkbox" id="' . esc_attr($name) . '" name="options[' . esc_attr($name) . '][]" value="' . esc_attr($value) . '"';
1212
- if (isset($this->data[$name]) && is_array($this->data[$name]) && array_search($value, $this->data[$name]) !== false) {
1213
- echo ' checked';
1214
- }
1215
- echo '>';
1216
- if ($label != '') {
1217
- if ($attrs['label_escape']) {
1218
- echo esc_html($label);
1219
- } else {
1220
- echo $label;
1221
- }
1222
- }
1223
- echo '</label>';
1224
- }
1225
-
1226
- function checkboxes($name, $options) {
1227
- echo '<div class="tnpc-checkboxes">';
1228
- foreach ($options as $value => $label) {
1229
- $this->checkbox_group($name, $value, $label);
1230
- }
1231
- echo '<div style="clear: both"></div>';
1232
- echo '</div>';
1233
- }
1234
-
1235
- function color($name, $default = '') {
1236
- $value = esc_attr($this->get_value($name, $default));
1237
- $name = esc_attr($name);
1238
- echo '<input class="tnpc-color" id="options-', $name, '" name="options[', $name, ']" type="text" value="', $value, '">';
1239
- }
1240
-
1241
- /** Creates a set of checkbox named $name_[category id] (so they are posted with distinct names).
1242
- */
1243
- function categories($name = 'category') {
1244
- $categories = get_categories();
1245
- echo '<div class="tnpc-checkboxes">';
1246
- foreach ($categories as $c) {
1247
- $this->checkbox($name . '_' . $c->cat_ID, esc_html($c->cat_name));
1248
- }
1249
- echo '<div style="clear: both"></div>';
1250
- }
1251
-
1252
- /**
1253
- * Creates a set of checkbox to activate the profile preferences. Every checkbox has a DIV around to
1254
- * be formatted.
1255
- */
1256
- function categories_group($name, $show_mode = false) {
1257
- $categories = get_categories();
1258
- if ($show_mode) {
1259
- $this->select($name . '_mode', array('include' => 'To be included', 'exclude' => 'To be excluded'));
1260
- }
1261
- echo '<div class="tnpc-checkboxes">';
1262
- foreach ($categories as &$c) {
1263
- $this->checkbox_group($name, $c->cat_ID, esc_html($c->cat_name));
1264
- }
1265
- echo '<div style="clear: both"></div>';
1266
- }
1267
-
1268
- /**
1269
- * Creates a set of checkboxes named $name_[preference number] (so they are
1270
- * distinct fields).
1271
- * Empty preferences are skipped.
1272
- */
1273
- function preferences($name = 'preferences') {
1274
- $lists = Newsletter::instance()->get_lists();
1275
-
1276
- echo '<div class="tnpc-checkboxes">';
1277
- foreach ($lists as $list) {
1278
- $this->checkbox2($name . '_' . $list->id, esc_html($list->name));
1279
- }
1280
- echo '<div style="clear: both"></div>';
1281
- }
1282
-
1283
- /** A list of all lists defined each one with a checkbox to select it. An array
1284
- * of ID of all checked lists is submitted.
1285
- *
1286
- * @param string $name
1287
- */
1288
- function lists($name = 'lists') {
1289
- echo '<input type="hidden" name="tnp_fields[' . esc_attr($name) . ']" value="array">';
1290
- $this->preferences_group($name);
1291
- }
1292
-
1293
- function lists_checkboxes($name = 'lists') {
1294
- $this->preferences_group($name);
1295
- }
1296
-
1297
- /**
1298
- * Creates a set of checkboxes all names $name[] and the preference number as value
1299
- * so the selected checkboxes are retrieved as an array of values ($REQUEST[$name]
1300
- * will be an array if at east one preference is checked).
1301
- */
1302
- function preferences_group($name = 'preferences') {
1303
-
1304
- $lists = Newsletter::instance()->get_lists();
1305
-
1306
- echo '<div class="tnpc-lists">';
1307
- foreach ($lists as $list) {
1308
- $this->checkbox_group($name, $list->id, '<span>' . $list->id . '</span> ' . esc_html($list->name), ['label_escape' => false]);
1309
- }
1310
- echo '<a href="https://www.thenewsletterplugin.com/documentation/newsletter-lists" target="_blank">'
1311
- . 'Click here to read more about lists.'
1312
- . '</a>';
1313
- echo '</div>';
1314
- }
1315
-
1316
- /** Creates as many selects as the active preferences with the three values
1317
- * 'any', 'yes', 'no' corresponding to the values 0, 1, 2.
1318
- */
1319
- function preferences_selects($name = 'preferences', $skip_empty = false) {
1320
- $lists = Newsletter::instance()->get_lists();
1321
-
1322
- echo '<div class="newsletter-preferences-group">';
1323
- foreach ($lists as $list) {
1324
-
1325
- echo '<div class="newsletter-preferences-item">';
1326
-
1327
- $this->select($name . '_' . $list->id, array(0 => 'Any', 1 => 'Yes', 2 => 'No'));
1328
- echo '(' . $list->id . ') ' . esc_html($list->name);
1329
-
1330
- echo '</div>';
1331
- }
1332
- echo '<div style="clear: both"></div>';
1333
- echo '<a href="https://www.thenewsletterplugin.com/plugins/newsletter/newsletter-preferences" target="_blank">Click here know more about preferences.</a> They can be configured on Subscription/Form field panel.';
1334
- echo '</div>';
1335
- }
1336
-
1337
- /**
1338
- * Creates a single select with the active preferences.
1339
- */
1340
- function preferences_select($name = 'preference', $empty_label = null) {
1341
- $lists = $this->get_list_options($empty_label);
1342
- $this->select($name, $lists);
1343
- echo ' <a href="admin.php?page=newsletter_subscription_lists" target="_blank"><i class="fas fa-edit"></i></a>';
1344
- }
1345
-
1346
- function lists_select($name = 'list', $empty_label = null) {
1347
- $lists = $this->get_list_options($empty_label);
1348
- $this->select($name, $lists);
1349
- }
1350
-
1351
- function lists_select_with_notes($name = 'list', $empty_label = null) {
1352
-
1353
- $value = $this->get_value($name);
1354
-
1355
- $lists = Newsletter::instance()->get_lists();
1356
- $options = [];
1357
- if ($empty_label) {
1358
- $options[''] = $empty_label;
1359
- }
1360
-
1361
- foreach ($lists as $list) {
1362
- $options['' . $list->id] = '(' . $list->id . ') ' . esc_html($list->name);
1363
- }
1364
-
1365
- $this->select($name, $options, null, ['onchange' => 'tnp_lists_toggle(this); return true;']);
1366
- echo '<div id="options-', esc_attr($name), '-notes" class="tnpc_lists_notes">';
1367
- foreach ($lists as $list) {
1368
- $id = $list->id;
1369
- $notes = apply_filters('newsletter_lists_notes', [], $id);
1370
-
1371
- echo '<div class="list_', $id, '" style="display: ', ($value == $id ? 'block' : 'none'), '">';
1372
- if ($list->forced) {
1373
- echo 'Enforced on subscription<br>';
1374
- }
1375
- echo implode('<br>', $notes);
1376
- echo '</div>';
1377
- }
1378
- echo '</div>';
1379
- }
1380
-
1381
- function public_lists_select($name = 'list', $empty_label = null) {
1382
- $lists = $this->get_public_list_options($empty_label);
1383
- $this->select($name, $lists);
1384
- }
1385
-
1386
- /**
1387
- * Generates an associative array with the active lists to be used in a select.
1388
- * @param string $empty_label
1389
- * @return array
1390
- */
1391
- function get_list_options($empty_label = null) {
1392
- $objs = Newsletter::instance()->get_lists();
1393
- $lists = array();
1394
- if ($empty_label) {
1395
- $lists[''] = $empty_label;
1396
- }
1397
- foreach ($objs as $list) {
1398
- $lists['' . $list->id] = '(' . $list->id . ') ' . esc_html($list->name);
1399
- }
1400
- return $lists;
1401
- }
1402
-
1403
- function get_public_list_options($empty_label = null) {
1404
- $objs = Newsletter::instance()->get_lists_public();
1405
- $lists = array();
1406
- if ($empty_label) {
1407
- $lists[''] = $empty_label;
1408
- }
1409
- foreach ($objs as $list) {
1410
- $lists['' . $list->id] = '(' . $list->id . ') ' . esc_html($list->name);
1411
- }
1412
- return $lists;
1413
- }
1414
-
1415
- function date($name) {
1416
- $this->hidden($name);
1417
- $year = date('Y', $this->data[$name]);
1418
- $day = date('j', $this->data[$name]);
1419
- $month = date('m', $this->data[$name]);
1420
- $onchange = "this.form.elements['options[" . esc_attr($name) . "]'].value = new Date(document.getElementById('" . esc_attr($name) . "_year').value, document.getElementById('" . esc_attr($name) . "_month').value, document.getElementById('" . esc_attr($name) . "_day').value, 12, 0, 0).getTime()/1000";
1421
- echo '<select id="' . $name . '_month" onchange="' . esc_attr($onchange) . '">';
1422
- for ($i = 0; $i < 12; $i++) {
1423
- echo '<option value="' . $i . '"';
1424
- if ($month - 1 == $i) {
1425
- echo ' selected';
1426
- }
1427
- echo '>' . date('F', mktime(0, 0, 0, $i + 1, 1, 2000)) . '</option>';
1428
- }
1429
- echo '</select>';
1430
-
1431
- echo '<select id="' . esc_attr($name) . '_day" onchange="' . esc_attr($onchange) . '">';
1432
- for ($i = 1; $i <= 31; $i++) {
1433
- echo '<option value="' . $i . '"';
1434
- if ($day == $i) {
1435
- echo ' selected';
1436
- }
1437
- echo '>' . $i . '</option>';
1438
- }
1439
- echo '</select>';
1440
-
1441
- echo '<select id="' . esc_attr($name) . '_year" onchange="' . esc_attr($onchange) . '">';
1442
- for ($i = 2011; $i <= 2021; $i++) {
1443
- echo '<option value="' . $i . '"';
1444
- if ($year == $i) {
1445
- echo ' selected';
1446
- }
1447
- echo '>' . $i . '</option>';
1448
- }
1449
- echo '</select>';
1450
- }
1451
-
1452
- /**
1453
- * Creates a set of fields to collect a date and sends back the triplet year, month and day.
1454
- *
1455
- * @param string $name
1456
- */
1457
- function date2($name) {
1458
- $year = $this->get_value($name . '_year');
1459
- $day = $this->get_value($name . '_day');
1460
- $month = $this->get_value($name . '_month');
1461
-
1462
- echo '<select name="options[' . $name . '_month]">';
1463
- echo '<option value="">-</option>';
1464
- for ($i = 1; $i <= 12; $i++) {
1465
- echo '<option value="' . $i . '"';
1466
- if ($month == $i) {
1467
- echo ' selected';
1468
- }
1469
- echo '>' . date_i18n('F', mktime(0, 0, 0, $i, 1, 2000)) . '</option>';
1470
- }
1471
- echo '</select>';
1472
-
1473
- echo '<select name="options[' . esc_attr($name) . '_day]">';
1474
- echo '<option value="">-</option>';
1475
- for ($i = 1; $i <= 31; $i++) {
1476
- echo '<option value="' . $i . '"';
1477
- if ($day == $i) {
1478
- echo ' selected';
1479
- }
1480
- echo '>' . $i . '</option>';
1481
- }
1482
- echo '</select>';
1483
-
1484
- echo '<select name="options[' . esc_attr($name) . '_year]">';
1485
- echo '<option value="">-</option>';
1486
- for ($i = 2011; $i <= 2021; $i++) {
1487
- echo '<option value="' . $i . '"';
1488
- if ($year == $i) {
1489
- echo ' selected';
1490
- }
1491
- echo '>' . $i . '</option>';
1492
- }
1493
- echo '</select>';
1494
- }
1495
-
1496
- /**
1497
- * Date and time (hour) selector. Timestamp stored.
1498
- */
1499
- function datetime($name) {
1500
- echo '<input type="hidden" name="tnp_fields[' . esc_attr($name) . ']" value="datetime">';
1501
- $value = (int) $this->get_value($name);
1502
- if (empty($value)) {
1503
- $value = time();
1504
- }
1505
-
1506
- $time = $value + get_option('gmt_offset') * 3600;
1507
- $year = gmdate('Y', $time);
1508
- $day = gmdate('j', $time);
1509
- $month = gmdate('m', $time);
1510
- $hour = gmdate('H', $time);
1511
-
1512
- echo '<select name="' . esc_attr($name) . '_month">';
1513
- for ($i = 1; $i <= 12; $i++) {
1514
- echo '<option value="' . $i . '"';
1515
- if ($month == $i) {
1516
- echo ' selected';
1517
- }
1518
- echo '>' . date('F', mktime(0, 0, 0, $i, 1, 2000)) . '</option>';
1519
- }
1520
- echo '</select>';
1521
-
1522
- echo '<select name="' . esc_attr($name) . '_day">';
1523
- for ($i = 1; $i <= 31; $i++) {
1524
- echo '<option value="' . $i . '"';
1525
- if ($day == $i) {
1526
- echo ' selected';
1527
- }
1528
- echo '>' . $i . '</option>';
1529
- }
1530
- echo '</select>';
1531
-
1532
- $last_year = date('Y') + 2;
1533
- echo '<select name="' . esc_attr($name) . '_year">';
1534
- for ($i = 2011; $i <= $last_year; $i++) {
1535
- echo '<option value="' . $i . '"';
1536
- if ($year == $i) {
1537
- echo ' selected';
1538
- }
1539
- echo '>' . $i . '</option>';
1540
- }
1541
- echo '</select>';
1542
-
1543
- echo '<select name="' . esc_attr($name) . '_hour">';
1544
- for ($i = 0; $i <= 23; $i++) {
1545
- echo '<option value="' . $i . '"';
1546
- if ($hour == $i) {
1547
- echo ' selected';
1548
- }
1549
- echo '>' . $i . ':00</option>';
1550
- }
1551
- echo '</select>';
1552
- }
1553
-
1554
- function hours($name) {
1555
- $hours = array();
1556
- for ($i = 0; $i < 24; $i++) {
1557
- $hours['' . $i] = sprintf('%02d', $i) . ':00';
1558
- }
1559
- $this->select($name, $hours);
1560
- }
1561
-
1562
- function days($name) {
1563
- $days = array(0 => 'Every day', 1 => 'Monday', 2 => 'Tuesday', 3 => 'Wednesday', 4 => 'Thursday', 5 => 'Friday', 6 => 'Saturday', 7 => 'Sunday');
1564
- $this->select($name, $days);
1565
- }
1566
-
1567
- function init($options = array()) {
1568
- $cookie_name = 'newsletter_tab';
1569
- if (isset($options['cookie_name'])) {
1570
- $cookie_name = $options['cookie_name'];
1571
- }
1572
- echo '<script type="text/javascript">
1573
- jQuery(document).ready(function(){
1574
-
1575
- tnp_controls_init();
1576
-
1577
- jQuery("textarea.dynamic").focus(function() {
1578
- jQuery("textarea.dynamic").css("height", "50px");
1579
- jQuery(this).css("height", "400px");
1580
- });
1581
- tabs = jQuery("#tabs").tabs({
1582
- active : jQuery.cookie("' . $cookie_name . '"),
1583
- activate : function( event, ui ){
1584
- jQuery.cookie("' . $cookie_name . '", ui.newTab.index(),{expires: 1});
1585
- }
1586
- });
1587
- jQuery(".tnp-tabs").tabs({});
1588
-
1589
- });
1590
- function newsletter_media(name) {
1591
- var tnp_uploader = wp.media({
1592
- title: "Select an image",
1593
- button: {
1594
- text: "Select"
1595
- },
1596
- multiple: false
1597
- }).on("select", function() {
1598
- var media = tnp_uploader.state().get("selection").first();
1599
- document.getElementById(name + "_id").value = media.id;
1600
- jQuery("#" + name + "_id").trigger("change");
1601
- //alert(media.attributes.url);
1602
- if (media.attributes.url.substring(0, 0) == "/") {
1603
- media.attributes.url = "' . site_url('/') . '" + media.attributes.url;
1604
- }
1605
- document.getElementById(name + "_url").value = media.attributes.url;
1606
-
1607
- var img_url = media.attributes.url;
1608
- if (typeof media.attributes.sizes.medium !== "undefined") img_url = media.attributes.sizes.medium.url;
1609
- if (img_url.substring(0, 0) == "/") {
1610
- img_url = "' . site_url('/') . '" + img_url;
1611
- }
1612
- document.getElementById(name + "_img").src = img_url;
1613
- }).open();
1614
- }
1615
- function newsletter_media_remove(name) {
1616
- if (confirm("Are you sure?")) {
1617
- document.getElementById(name + "_id").value = "";
1618
- document.getElementById(name + "_url").value = "";
1619
- document.getElementById(name + "_img").src = "' . plugins_url('newsletter') . '/images/nomedia.png";
1620
- }
1621
- }
1622
- function newsletter_textarea_preview(id, header, footer) {
1623
- var d = document.getElementById(id + "-iframe").contentWindow.document;
1624
- d.open();
1625
- if (templateEditor) {
1626
- d.write(templateEditor.getValue());
1627
- } else {
1628
- d.write(header + document.getElementById(id).value + footer);
1629
- }
1630
- d.close();
1631
-
1632
- var d = document.getElementById(id + "-iframe-phone").contentWindow.document;
1633
- d.open();
1634
- if (templateEditor) {
1635
- d.write(templateEditor.getValue());
1636
- } else {
1637
- d.write(header + document.getElementById(id).value + footer);
1638
- }
1639
- d.close();
1640
- //jQuery("#" + id + "-iframe-phone").toggle();
1641
- jQuery("#" + id + "-preview").toggle();
1642
- }
1643
- function tnp_select_images(state) {
1644
- if (!state.id) { return state.text; }
1645
- var $state = jQuery("<span class=\"tnp-select2-option\"><img style=\"height: 20px!important; position: relative; top: 5px\" src=\"" + state.element.getAttribute("image") + "\"> " + state.text + "</span>");
1646
- return $state;
1647
- }
1648
- function tnp_select_images_selection(state) {
1649
- if (!state.id) { return state.text; }
1650
- var $state = jQuery("<span class=\"tnp-select2-option\"><img style=\"height: 20px!important; position: relative; top: 5px\" src=\"" + state.element.getAttribute("image") + "\"> " + state.text + "</span>");
1651
- return $state;
1652
- }
1653
-
1654
-
1655
- </script>
1656
- ';
1657
- echo '<input name="act" type="hidden" value=""/>';
1658
- echo '<input name="btn" type="hidden" value=""/>';
1659
- wp_nonce_field('save');
1660
- }
1661
-
1662
- function log_level($name = 'log_level') {
1663
- $this->select($name, array(0 => 'None', 2 => 'Error', 3 => 'Normal', 4 => 'Debug'));
1664
- }
1665
-
1666
- function update_option($name, $data = null) {
1667
- if ($data == null) {
1668
- $data = $this->data;
1669
- }
1670
- update_option($name, $data);
1671
- if (isset($data['log_level'])) {
1672
- update_option($name . '_log_level', $data['log_level']);
1673
- }
1674
- }
1675
-
1676
- function js_redirect($url) {
1677
- echo '<script>';
1678
- echo 'location.href="' . $url . '"';
1679
- echo '</script>';
1680
- die();
1681
- }
1682
-
1683
- /**
1684
- * @deprecated
1685
- */
1686
- function get_test_subscribers() {
1687
- return NewsletterUsers::instance()->get_test_users();
1688
- }
1689
-
1690
- /**
1691
- * Attributes:
1692
- * weight: [true|false]
1693
- * color: [true|false]
1694
- *
1695
- * @param string $name
1696
- * @param array $attrs
1697
- */
1698
- function css_font($name = 'font', $attrs = array()) {
1699
- $default = [
1700
- 'color' => true,
1701
- 'weight' => true,
1702
- 'hide_size' => false,
1703
- 'hide_weight' => false,
1704
- 'hide_color' => false,
1705
- ];
1706
- $attrs = array_merge($default, $attrs);
1707
- $this->css_font_family($name . '_family', !empty($attrs['family_default']));
1708
- if (!$attrs['hide_size']) {
1709
- $this->css_font_size($name . '_size', !empty($attrs['size_default']));
1710
- }
1711
- if ($attrs['weight'] && !$attrs['hide_weight']) {
1712
- $this->css_font_weight($name . '_weight', !empty($attrs['weight_default']));
1713
- }
1714
- if ($attrs['color'] && !$attrs['hide_color']) {
1715
- $this->color($name . '_color');
1716
- }
1717
- }
1718
-
1719
- function css_font_size($name = 'font_size', $show_empty_option = false) {
1720
- $value = $this->get_value($name);
1721
-
1722
- echo '<select class="tnpf-font-size" id="options-', esc_attr($name), '" name="options[', esc_attr($name), ']">';
1723
- if ($show_empty_option) {
1724
- echo "<option value=''>-</option>";
1725
- }
1726
- for ($i = 8; $i <= 50; $i++) {
1727
- echo '<option value="' . $i . '"';
1728
- if ($value == $i) {
1729
- echo ' selected';
1730
- }
1731
- echo '>' . $i . '</option>';
1732
- }
1733
- echo '</select>';
1734
- }
1735
-
1736
- function css_font_weight($name = 'font_weight', $show_empty_option = false) {
1737
- $value = $this->get_value($name);
1738
-
1739
- $fonts = array('normal' => 'Normal', 'bold' => 'Bold');
1740
-
1741
- echo '<select class="tnpf-font-weight" id="options-' . esc_attr($name) . '" name="options[' . esc_attr($name) . ']">';
1742
- if ($show_empty_option) {
1743
- echo "<option value=''>-</option>";
1744
- }
1745
- foreach ($fonts as $key => $font) {
1746
- echo '<option value="', esc_attr($key), '"';
1747
- if ($value == $key) {
1748
- echo ' selected';
1749
- }
1750
- echo '>', esc_html($font), '</option>';
1751
- }
1752
- echo '</select>';
1753
- }
1754
-
1755
- function css_font_family($name = 'font_family', $show_empty_option = false) {
1756
- $value = $this->get_value($name);
1757
-
1758
- $fonts = [];
1759
- if ($show_empty_option) {
1760
- $fonts[''] = 'Default';
1761
- }
1762
-
1763
- $fonts = array_merge($fonts, ['Helvetica, Arial, sans-serif' => 'Helvetica, Arial',
1764
- 'Arial Black, Gadget, sans-serif' => 'Arial Black, Gadget',
1765
- 'Garamond, serif' => 'Garamond',
1766
- 'Courier, monospace' => 'Courier',
1767
- 'Comic Sans MS, cursive' => 'Comic Sans MS',
1768
- 'Impact, Charcoal, sans-serif' => 'Impact, Charcoal',
1769
- 'Tahoma, Geneva, sans-serif' => 'Tahoma, Geneva',
1770
- 'Times New Roman, Times, serif' => 'Times New Roman',
1771
- 'Verdana, Geneva, sans-serif' => 'Verdana, Geneva']);
1772
-
1773
- echo '<select class="tnpf-font-family" id="options-', esc_attr($name), '" name="options[', esc_attr($name), ']">';
1774
- foreach ($fonts as $font => $label) {
1775
- echo '<option value="', esc_attr($font), '"';
1776
- if ($value == $font) {
1777
- echo ' selected';
1778
- }
1779
- echo '>', esc_html($label), '</option>';
1780
- }
1781
- echo '</select>';
1782
- }
1783
-
1784
- function css_text_align($name) {
1785
- $options = array('left' => __('Left', 'newsletter'), 'right' => __('Right', 'newsletter'),
1786
- 'center' => __('Center', 'newsletter'));
1787
- $this->select($name, $options);
1788
- }
1789
-
1790
- function css_border($name) {
1791
- $value = $this->get_value($name . '_width');
1792
-
1793
- echo 'width&nbsp;<select id="options-' . esc_attr($name) . '-width" name="options[' . esc_attr($name) . '_width]">';
1794
- for ($i = 0; $i < 10; $i++) {
1795
- echo '<option value="' . $i . '"';
1796
- if ($value == $i) {
1797
- echo ' selected';
1798
- }
1799
- echo '>' . $i . '</option>';
1800
- }
1801
- echo '</select>&nbsp;px&nbsp;&nbsp;';
1802
-
1803
- $this->select($name . '_type', array('solid' => 'Solid', 'dashed' => 'Dashed'));
1804
-
1805
- $this->color($name . '_color');
1806
-
1807
- $value = $this->get_value($name . '_radius');
1808
-
1809
- echo '&nbsp;&nbsp;radius&nbsp;<select id="options-' . esc_attr($name) . '-radius" name="options[' . esc_attr($name) . '_radius]">';
1810
- for ($i = 0; $i < 10; $i++) {
1811
- echo '<option value="' . $i . '"';
1812
- if ($value == $i) {
1813
- echo ' selected';
1814
- }
1815
- echo '>' . $i . '</option>';
1816
- }
1817
- echo '</select>&nbsp;px';
1818
- }
1819
-
1820
- /**
1821
- * Media selector using the media library of WP. Produces a field which values is an array containing 'id' and 'url'.
1822
- *
1823
- * @param string $name
1824
- */
1825
- function media($name) {
1826
- if (isset($this->data[$name]['id'])) {
1827
- $media_id = (int) $this->data[$name]['id'];
1828
- $media = wp_get_attachment_image_src($media_id, 'medium');
1829
- $media_full = wp_get_attachment_image_src($media_id, 'full');
1830
- } else {
1831
- $media = false;
1832
- }
1833
- echo '<div style="position: relative">';
1834
- echo '<a style="position: absolute; top: 5px; right: 5px; background-color: none; color: #000; padding: 0px 5px 6px 5px; font-size: 24px; display: block; text-decoration: none" href="#" onclick="newsletter_media_remove(\'' . esc_attr($name) . '\'); return false">&times;</a>';
1835
- if ($media === false) {
1836
- $media = array('', '', '');
1837
- $media_full = array('', '', '');
1838
- $media_id = 0;
1839
- echo '<img style="max-width: 200px; max-height: 150px; width: 100px;" id="' . esc_attr($name) . '_img" src="' . plugins_url('newsletter') . '/images/nomedia.png" onclick="newsletter_media(\'' . esc_attr($name) . '\')">';
1840
- } else {
1841
- echo '<img style="max-width: 200px; max-height: 150px;" id="' . esc_attr($name) . '_img" src="' . esc_attr($media[0]) . '" onclick="newsletter_media(\'' . esc_attr($name) . '\')">';
1842
- }
1843
-
1844
- echo '</div>';
1845
- echo '<input type="hidden" id="' . esc_attr($name) . '_id" name="options[' . esc_attr($name) . '][id]" value="' . esc_attr($media_id) . '" size="5">';
1846
- echo '<input type="hidden" id="' . esc_attr($name) . '_url" name="options[' . esc_attr($name) . '][url]" value="' . esc_attr($media_full[0]) . '" size="50">';
1847
- }
1848
-
1849
- function media_input($option, $name, $label) {
1850
-
1851
- if (!empty($label)) {
1852
- $output = '<label class="select" for="tnp_' . esc_attr($name) . '">' . esc_html($label) . ':</label>';
1853
- }
1854
- $output .= '<input id="tnp_' . esc_attr($name) . '" type="text" size="36" name="' . esc_attr($option) . '[' . esc_attr($name) . ']" value="' . esc_attr($val) . '" />';
1855
- $output .= '<input id="tnp_' . esc_attr($name) . '_button" class="button-primary" type="button" value="Select Image" />';
1856
- $output .= '<br class="clear"/>';
1857
-
1858
- echo $output;
1859
- }
1860
-
1861
- function language($name = 'language', $empty_label = 'All') {
1862
- if (!class_exists('SitePress') && !function_exists('pll_default_language') && !class_exists('TRP_Translate_Press')) {
1863
- echo __('Install a multilanguage plugin.', 'newsletter');
1864
- echo ' <a href="https://www.thenewsletterplugin.com/documentation/multilanguage" target="_blank">', __('Read more', 'newsletter'), '</a>';
1865
- return;
1866
- }
1867
-
1868
- $languages = Newsletter::instance()->get_languages();
1869
- if (!empty($empty_label)) {
1870
- $languages = array_merge(array('' => $empty_label), $languages);
1871
- }
1872
- $this->select($name, $languages);
1873
- }
1874
-
1875
- function is_multilanguage() {
1876
- return Newsletter::instance()->is_multilanguage();
1877
- }
1878
-
1879
- /**
1880
- * Creates a checkbox group with all active languages. Each checkbox is named
1881
- * $name[] and values with the relative language code.
1882
- *
1883
- * @param string $name
1884
- */
1885
- function languages($name = 'languages') {
1886
- if (!$this->is_multilanguage()) {
1887
- echo __('Install WPML or Polylang for multilanguage support', 'newsletter');
1888
- return;
1889
- }
1890
-
1891
- $language_options = Newsletter::instance()->get_languages();
1892
-
1893
- if (empty($language_options)) {
1894
- echo __('Your multilanguage plugin is not supported or there are no languages defined', 'newsletter');
1895
- return;
1896
- }
1897
-
1898
- $this->checkboxes_group($name, $language_options);
1899
- }
1900
-
1901
- /**
1902
- * Prints a formatted date using the formats and timezone of WP, including the current date and time and the
1903
- * time left to the passed time.
1904
- *
1905
- * @param int $time
1906
- * @param int $now
1907
- * @param bool $left
1908
- * @return string
1909
- */
1910
- static function print_date($time = null, $now = false, $left = false) {
1911
- if (is_null($time)) {
1912
- $time = time();
1913
- }
1914
- if ($time == false) {
1915
- $buffer = 'none';
1916
- } else {
1917
- $buffer = date_i18n(get_option('date_format') . ' ' . get_option('time_format'), $time + get_option('gmt_offset') * 3600);
1918
-
1919
- if ($now) {
1920
- $buffer .= ' (now: ' . gmdate(get_option('date_format') . ' ' .
1921
- get_option('time_format'), time() + get_option('gmt_offset') * 3600);
1922
- $buffer .= ')';
1923
- }
1924
- if ($left) {
1925
- if ($time - time() < 0) {
1926
- $buffer .= ', ' . (time() - $time) . ' seconds late';
1927
- } else {
1928
- $buffer .= ', ' . gmdate('H:i:s', $time - time()) . ' left';
1929
- }
1930
- }
1931
- }
1932
- return $buffer;
1933
- }
1934
-
1935
- static function delta_time($delta = 0) {
1936
- $seconds = $delta % 60;
1937
- $minutes = floor(($delta / 60) % 60);
1938
- $hours = floor(($delta / (60 * 60)) % 24);
1939
- $days = floor($delta / (24 * 60 * 60));
1940
-
1941
- return $days . ' day(s), ' . $hours . ' hour(s), ' . $minutes . ' minute(s)';
1942
- }
1943
-
1944
- /**
1945
- * Prints the help button near a form field. The label is used as icon title.
1946
- *
1947
- * @param string $url
1948
- * @param string $label
1949
- */
1950
- static function help($url, $label = '') {
1951
- echo '<a href="', $url, '" target="_blank" title="', esc_attr($label), '"><i class="fas fa-question-circle"></i></a>';
1952
- }
1953
-
1954
- static function idea($url, $label = '') {
1955
- echo '<a href="', $url, '" target="_blank" title="', esc_attr($label), '"><i class="fas fa-lightbulb-o"></i></a>';
1956
- }
1957
-
1958
- static function field_help($url, $text = '') {
1959
- if (strpos($url, 'http') !== 0) {
1960
- $url = 'https://www.thenewsletterplugin.com' . $url;
1961
- }
1962
- echo '<a href="', $url, '" target="_blank" style="text-decoration: none" title="' . esc_attr(__('Read more', 'newsletter')) . '"><i class="fas fa-question-circle"></i>';
1963
- if ($text)
1964
- echo '&nbsp;', $text;
1965
- echo '</a>';
1966
- }
1967
-
1968
- static function field_label($label, $help_url = false) {
1969
- echo $label;
1970
- if ($help_url) {
1971
- echo '&nbsp';
1972
- self::field_help($help_url);
1973
- }
1974
- }
1975
-
1976
- /**
1977
- * Prints a panel link to the documentation.
1978
- *
1979
- * @param type $url
1980
- * @param type $text
1981
- */
1982
- static function panel_help($url, $text = '') {
1983
- if (empty($text))
1984
- $text = __('Need help?', 'newsletter');
1985
- echo '<span class="tnp-panel-help"><a href="', $url, '" target="_blank">', $text, '</a></span>';
1986
- }
1987
-
1988
- /**
1989
- * Prints an administration page link to the documentation (just under the administration page title.
1990
- * @param type $url
1991
- * @param type $text
1992
- */
1993
- static function page_help($url, $text = '') {
1994
- if (empty($text))
1995
- $text = __('Need help?', 'newsletter');
1996
- echo '<div class="tnp-page-help"><a href="', $url, '" target="_blank">', $text, '</a></div>';
1997
- }
1998
-
1999
- static function print_truncated($text, $size = 50) {
2000
- if (mb_strlen($text) < $size)
2001
- return esc_html($text);
2002
- $sub = mb_substr($text, 0, $size);
2003
- echo '<span title="', esc_attr($text), '">', esc_html($sub), '...</span>';
2004
- }
2005
-
2006
- function block_background($name = 'block_background') {
2007
- $this->color($name);
2008
- }
2009
-
2010
- function block_padding($name = 'block_padding', $options = array()) {
2011
- echo '<div style="text-align: center; width: 250px;">';
2012
- $this->text($name . '_top', 5);
2013
- echo '<br>';
2014
- $this->text($name . '_left', 5);
2015
- echo "&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;";
2016
- $this->text($name . '_right', 5);
2017
- echo '<br>';
2018
- $this->text($name . '_bottom', 5);
2019
- echo '</div>';
2020
- }
2021
-
2022
- /**
2023
- * Adds the fields used by the composer (version 1) in the page form.
2024
- *
2025
- * @param type $name
2026
- */
2027
- function composer_fields($name = 'body') {
2028
-
2029
- // body
2030
- $value = $this->get_value($name);
2031
-
2032
- // Extracts only the body part
2033
- $x = strpos($value, '<body');
2034
- if ($x) {
2035
- $x = strpos($value, '>', $x);
2036
- $y = strpos($value, '</body>');
2037
- $value = substr($value, $x + 1, $y - $x - 1);
2038
- }
2039
-
2040
- /* Cleans up uncorrectly stored newsletter bodies */
2041
- $value = preg_replace('/<style\s+.*?>.*?<\\/style>/is', '', $value);
2042
- $value = preg_replace('/<meta.*?>/', '', $value);
2043
- $value = preg_replace('/<title\s+.*?>.*?<\\/title>/i', '', $value);
2044
- $value = trim($value);
2045
-
2046
- // Required since esc_html DOES NOT escape the HTML entities (apparently)
2047
- $value = str_replace('&', '&amp;', $value);
2048
- $value = str_replace('"', '&quot;', $value);
2049
- $value = str_replace('<', '&lt;', $value);
2050
- $value = str_replace('>', '&gt;', $value);
2051
- echo '<input type="hidden" name="options[', esc_attr($name), ']" id="options-', esc_attr($name), '" value="', esc_attr($value), '">';
2052
-
2053
- // Used by composer to rebuild the full HTML
2054
- $css = NewsletterEmails::instance()->get_composer_css();
2055
- echo '<input type="hidden" name="options[css]" id="options-css" value="', esc_attr($css), '">';
2056
-
2057
- // subject
2058
- $value = $this->get_value('subject');
2059
- echo '<input type="hidden" name="options[subject]" id="options-subject" value="', esc_attr($value), '">';
2060
- }
2061
-
2062
- function composer_load($name = 'body', $show_subject = false, $show_test = true, $context_type = '') {
2063
-
2064
- global $controls;
2065
- global $tnpc_show_subject;
2066
- $tnpc_show_subject = $show_subject;
2067
-
2068
- wp_enqueue_style('tnpc-style', plugins_url('newsletter') . '/emails/tnp-composer/_css/newsletter-builder.css', array(), time());
2069
-
2070
- include NEWSLETTER_DIR . '/emails/tnp-composer/index.php';
2071
- }
2072
-
2073
- /**
2074
- * Adds the fields used by the composer (version 2) in the page form.
2075
- */
2076
- function composer_fields_v2($name = 'message') {
2077
-
2078
- // The composer, on saving, fills in those fields
2079
- $this->hidden('subject');
2080
- $this->hidden('message');
2081
- $this->hidden('options_preheader');
2082
- $this->hidden('updated');
2083
-
2084
- //$preheader_value = $this->get_value('options_preheader');
2085
- // echo '<input name="options[preheader]" id="options-preheader" type="hidden" value="', esc_attr($preheader_value), '">';
2086
- }
2087
-
2088
- function composer_load_v2($show_subject = false, $show_test = true, $context_type = '') {
2089
-
2090
- global $tnpc_show_subject;
2091
- $tnpc_show_subject = $show_subject;
2092
-
2093
- echo "<link href='", plugins_url('newsletter'), "/emails/tnp-composer/_css/newsletter-builder-v2.css?ver=" . NEWSLETTER_VERSION . "' rel='stylesheet' type='text/css'>";
2094
-
2095
- $controls = $this;
2096
- include NEWSLETTER_DIR . '/emails/tnp-composer/index-v2.php';
2097
- }
2098
-
2099
- function subject($name) {
2100
- $value = $this->get_value($name);
2101
- // Leave the ID with this prefix!
2102
- echo '<div style="position: relative"><input size="80" id="options-subject-', esc_attr($name), '" name="options[' . esc_attr($name) . ']" type="text" placeholder="" value="';
2103
- echo esc_attr($value);
2104
- echo '">';
2105
- echo '&nbsp;<i class="far fa-lightbulb tnp-suggest-subject" data-tnp-modal-target="#subject-ideas-modal"></i>';
2106
-
2107
- echo '<img src="', plugins_url('newsletter'), '/admin/images/subject/android.png" style="position: absolute; width: 16px; left: 330px; top: 25px; display: block; opacity: 0">';
2108
- echo '<img src="', plugins_url('newsletter'), '/admin/images/subject/iphone.png" style="position: absolute; width: 16px; left: 380px; top: 25px; display: block; opacity: 0">';
2109
- echo '</div>';
2110
- }
2111
-
2112
- }
1
+ <?php
2
+
3
+ defined('ABSPATH') || exit;
4
+
5
+ include_once __DIR__ . '/fields.php';
6
+
7
+ class NewsletterControls {
8
+
9
+ var $data = [];
10
+ var $action = false;
11
+ var $button_data = '';
12
+ var $errors = '';
13
+
14
+ /**
15
+ * @var string
16
+ */
17
+ var $messages = '';
18
+
19
+ /**
20
+ * @var array
21
+ */
22
+ var $warnings = array();
23
+ var $countries = array(
24
+ 'AF' => 'Afghanistan',
25
+ 'AX' => 'Aland Islands',
26
+ 'AL' => 'Albania',
27
+ 'DZ' => 'Algeria',
28
+ 'AS' => 'American Samoa',
29
+ 'AD' => 'Andorra',
30
+ 'AO' => 'Angola',
31
+ 'AI' => 'Anguilla',
32
+ 'AQ' => 'Antarctica',
33
+ 'AG' => 'Antigua And Barbuda',
34
+ 'AR' => 'Argentina',
35
+ 'AM' => 'Armenia',
36
+ 'AW' => 'Aruba',
37
+ 'AU' => 'Australia',
38
+ 'AT' => 'Austria',
39
+ 'AZ' => 'Azerbaijan',
40
+ 'BS' => 'Bahamas',
41
+ 'BH' => 'Bahrain',
42
+ 'BD' => 'Bangladesh',
43
+ 'BB' => 'Barbados',
44
+ 'BY' => 'Belarus',
45
+ 'BE' => 'Belgium',
46
+ 'BZ' => 'Belize',
47
+ 'BJ' => 'Benin',
48
+ 'BM' => 'Bermuda',
49
+ 'BT' => 'Bhutan',
50
+ 'BO' => 'Bolivia',
51
+ 'BA' => 'Bosnia And Herzegovina',
52
+ 'BW' => 'Botswana',
53
+ 'BV' => 'Bouvet Island',
54
+ 'BR' => 'Brazil',
55
+ 'IO' => 'British Indian Ocean Territory',
56
+ 'BN' => 'Brunei Darussalam',
57
+ 'BG' => 'Bulgaria',
58
+ 'BF' => 'Burkina Faso',
59
+ 'BI' => 'Burundi',
60
+ 'KH' => 'Cambodia',
61
+ 'CM' => 'Cameroon',
62
+ 'CA' => 'Canada',
63
+ 'CV' => 'Cape Verde',
64
+ 'KY' => 'Cayman Islands',
65
+ 'CF' => 'Central African Republic',
66
+ 'TD' => 'Chad',
67
+ 'CL' => 'Chile',
68
+ 'CN' => 'China',
69
+ 'CX' => 'Christmas Island',
70
+ 'CC' => 'Cocos (Keeling) Islands',
71
+ 'CO' => 'Colombia',
72
+ 'KM' => 'Comoros',
73
+ 'CG' => 'Congo',
74
+ 'CD' => 'Congo, Democratic Republic',
75
+ 'CK' => 'Cook Islands',
76
+ 'CR' => 'Costa Rica',
77
+ 'CI' => 'Cote D\'Ivoire',
78
+ 'HR' => 'Croatia',
79
+ 'CU' => 'Cuba',
80
+ 'CY' => 'Cyprus',
81
+ 'CZ' => 'Czech Republic',
82
+ 'DK' => 'Denmark',
83
+ 'DJ' => 'Djibouti',
84
+ 'DM' => 'Dominica',
85
+ 'DO' => 'Dominican Republic',
86
+ 'EC' => 'Ecuador',
87
+ 'EG' => 'Egypt',
88
+ 'SV' => 'El Salvador',
89
+ 'GQ' => 'Equatorial Guinea',
90
+ 'ER' => 'Eritrea',
91
+ 'EE' => 'Estonia',
92
+ 'ET' => 'Ethiopia',
93
+ 'FK' => 'Falkland Islands (Malvinas)',
94
+ 'FO' => 'Faroe Islands',
95
+ 'FJ' => 'Fiji',
96
+ 'FI' => 'Finland',
97
+ 'FR' => 'France',
98
+ 'GF' => 'French Guiana',
99
+ 'PF' => 'French Polynesia',
100
+ 'TF' => 'French Southern Territories',
101
+ 'GA' => 'Gabon',
102
+ 'GM' => 'Gambia',
103
+ 'GE' => 'Georgia',
104
+ 'DE' => 'Germany',
105
+ 'GH' => 'Ghana',
106
+ 'GI' => 'Gibraltar',
107
+ 'GR' => 'Greece',
108
+ 'GL' => 'Greenland',
109
+ 'GD' => 'Grenada',
110
+ 'GP' => 'Guadeloupe',
111
+ 'GU' => 'Guam',
112
+ 'GT' => 'Guatemala',
113
+ 'GG' => 'Guernsey',
114
+ 'GN' => 'Guinea',
115
+ 'GW' => 'Guinea-Bissau',
116
+ 'GY' => 'Guyana',
117
+ 'HT' => 'Haiti',
118
+ 'HM' => 'Heard Island & Mcdonald Islands',
119
+ 'VA' => 'Holy See (Vatican City State)',
120
+ 'HN' => 'Honduras',
121
+ 'HK' => 'Hong Kong',
122
+ 'HU' => 'Hungary',
123
+ 'IS' => 'Iceland',
124
+ 'IN' => 'India',
125
+ 'ID' => 'Indonesia',
126
+ 'IR' => 'Iran, Islamic Republic Of',
127
+ 'IQ' => 'Iraq',
128
+ 'IE' => 'Ireland',
129
+ 'IM' => 'Isle Of Man',
130
+ 'IL' => 'Israel',
131
+ 'IT' => 'Italy',
132
+ 'JM' => 'Jamaica',
133
+ 'JP' => 'Japan',
134
+ 'JE' => 'Jersey',
135
+ 'JO' => 'Jordan',
136
+ 'KZ' => 'Kazakhstan',
137
+ 'KE' => 'Kenya',
138
+ 'KI' => 'Kiribati',
139
+ 'KR' => 'Korea',
140
+ 'KW' => 'Kuwait',
141
+ 'KG' => 'Kyrgyzstan',
142
+ 'LA' => 'Lao People\'s Democratic Republic',
143
+ 'LV' => 'Latvia',
144
+ 'LB' => 'Lebanon',
145
+ 'LS' => 'Lesotho',
146
+ 'LR' => 'Liberia',
147
+ 'LY' => 'Libyan Arab Jamahiriya',
148
+ 'LI' => 'Liechtenstein',
149
+ 'LT' => 'Lithuania',
150
+ 'LU' => 'Luxembourg',
151
+ 'MO' => 'Macao',
152
+ 'MK' => 'Macedonia',
153
+ 'MG' => 'Madagascar',
154
+ 'MW' => 'Malawi',
155
+ 'MY' => 'Malaysia',
156
+ 'MV' => 'Maldives',
157
+ 'ML' => 'Mali',
158
+ 'MT' => 'Malta',
159
+ 'MH' => 'Marshall Islands',
160
+ 'MQ' => 'Martinique',
161
+ 'MR' => 'Mauritania',
162
+ 'MU' => 'Mauritius',
163
+ 'YT' => 'Mayotte',
164
+ 'MX' => 'Mexico',
165
+ 'FM' => 'Micronesia, Federated States Of',
166
+ 'MD' => 'Moldova',
167
+ 'MC' => 'Monaco',
168
+ 'MN' => 'Mongolia',
169
+ 'ME' => 'Montenegro',
170
+ 'MS' => 'Montserrat',
171
+ 'MA' => 'Morocco',
172
+ 'MZ' => 'Mozambique',
173
+ 'MM' => 'Myanmar',
174
+ 'NA' => 'Namibia',
175
+ 'NR' => 'Nauru',
176
+ 'NP' => 'Nepal',
177
+ 'NL' => 'Netherlands',
178
+ 'AN' => 'Netherlands Antilles',
179
+ 'NC' => 'New Caledonia',
180
+ 'NZ' => 'New Zealand',
181
+ 'NI' => 'Nicaragua',
182
+ 'NE' => 'Niger',
183
+ 'NG' => 'Nigeria',
184
+ 'NU' => 'Niue',
185
+ 'NF' => 'Norfolk Island',
186
+ 'MP' => 'Northern Mariana Islands',
187
+ 'NO' => 'Norway',
188
+ 'OM' => 'Oman',
189
+ 'PK' => 'Pakistan',
190
+ 'PW' => 'Palau',
191
+ 'PS' => 'Palestinian Territory, Occupied',
192
+ 'PA' => 'Panama',
193
+ 'PG' => 'Papua New Guinea',
194
+ 'PY' => 'Paraguay',
195
+ 'PE' => 'Peru',
196
+ 'PH' => 'Philippines',
197
+ 'PN' => 'Pitcairn',
198
+ 'PL' => 'Poland',
199
+ 'PT' => 'Portugal',
200
+ 'PR' => 'Puerto Rico',
201
+ 'QA' => 'Qatar',
202
+ 'RE' => 'Reunion',
203
+ 'RO' => 'Romania',
204
+ 'RU' => 'Russian Federation',
205
+ 'RW' => 'Rwanda',
206
+ 'BL' => 'Saint Barthelemy',
207
+ 'SH' => 'Saint Helena',
208
+ 'KN' => 'Saint Kitts And Nevis',
209
+ 'LC' => 'Saint Lucia',
210
+ 'MF' => 'Saint Martin',
211
+ 'PM' => 'Saint Pierre And Miquelon',
212
+ 'VC' => 'Saint Vincent And Grenadines',
213
+ 'WS' => 'Samoa',
214
+ 'SM' => 'San Marino',
215
+ 'ST' => 'Sao Tome And Principe',
216
+ 'SA' => 'Saudi Arabia',
217
+ 'SN' => 'Senegal',
218
+ 'RS' => 'Serbia',
219
+ 'SC' => 'Seychelles',
220
+ 'SL' => 'Sierra Leone',
221
+ 'SG' => 'Singapore',
222
+ 'SK' => 'Slovakia',
223
+ 'SI' => 'Slovenia',
224
+ 'SB' => 'Solomon Islands',
225
+ 'SO' => 'Somalia',
226
+ 'ZA' => 'South Africa',
227
+ 'GS' => 'South Georgia And Sandwich Isl.',
228
+ 'ES' => 'Spain',
229
+ 'LK' => 'Sri Lanka',
230
+ 'SD' => 'Sudan',
231
+ 'SR' => 'Suriname',
232
+ 'SJ' => 'Svalbard And Jan Mayen',
233
+ 'SZ' => 'Swaziland',
234
+ 'SE' => 'Sweden',
235
+ 'CH' => 'Switzerland',
236
+ 'SY' => 'Syrian Arab Republic',
237
+ 'TW' => 'Taiwan',
238
+ 'TJ' => 'Tajikistan',
239
+ 'TZ' => 'Tanzania',
240
+ 'TH' => 'Thailand',
241
+ 'TL' => 'Timor-Leste',
242
+ 'TG' => 'Togo',
243
+ 'TK' => 'Tokelau',
244
+ 'TO' => 'Tonga',
245
+ 'TT' => 'Trinidad And Tobago',
246
+ 'TN' => 'Tunisia',
247
+ 'TR' => 'Turkey',
248
+ 'TM' => 'Turkmenistan',
249
+ 'TC' => 'Turks And Caicos Islands',
250
+ 'TV' => 'Tuvalu',
251
+ 'UG' => 'Uganda',
252
+ 'UA' => 'Ukraine',
253
+ 'AE' => 'United Arab Emirates',
254
+ 'GB' => 'United Kingdom',
255
+ 'US' => 'United States',
256
+ 'UM' => 'United States Outlying Islands',
257
+ 'UY' => 'Uruguay',
258
+ 'UZ' => 'Uzbekistan',
259
+ 'VU' => 'Vanuatu',
260
+ 'VE' => 'Venezuela',
261
+ 'VN' => 'Viet Nam',
262
+ 'VG' => 'Virgin Islands, British',
263
+ 'VI' => 'Virgin Islands, U.S.',
264
+ 'WF' => 'Wallis And Futuna',
265
+ 'EH' => 'Western Sahara',
266
+ 'YE' => 'Yemen',
267
+ 'ZM' => 'Zambia',
268
+ 'ZW' => 'Zimbabwe',
269
+ 'XX' => 'Undefined',
270
+ 'CW' => 'Curaçao',
271
+ 'SS' => 'South Sudan',
272
+ 'EU' => 'Europe (generic)',
273
+ 'A1' => 'Anonymous IP',
274
+ 'A2' => 'Satellite IP'
275
+ );
276
+
277
+ /**
278
+ *
279
+ * @param array $options
280
+ */
281
+ function __construct($options = null) {
282
+ if ($options === null) {
283
+ if (isset($_POST['options'])) {
284
+ $this->data = stripslashes_deep($_POST['options']);
285
+ }
286
+ } else {
287
+ $this->data = (array) $options;
288
+ }
289
+
290
+ if (isset($_REQUEST['act'])) {
291
+ $this->action = $_REQUEST['act'];
292
+ }
293
+
294
+ if (isset($_REQUEST['btn'])) {
295
+ $this->button_data = $_REQUEST['btn'];
296
+ }
297
+ // Fields analysis
298
+ if (isset($_REQUEST['tnp_fields'])) {
299
+ $fields = $_REQUEST['tnp_fields'];
300
+ if (is_array($fields)) {
301
+ foreach ($fields as $name => $type) {
302
+ if ($type == 'datetime') {
303
+ // Ex. The user insert 01/07/2012 14:30 and it set the time zone to +2. We cannot use the
304
+ // mktime, since it uses the time zone of the machine. We create the time as if we are on
305
+ // GMT 0 and then we subtract the GMT offset (the example date and time on GMT+2 happens
306
+ // "before").
307
+
308
+ $time = gmmktime((int) $_REQUEST[$name . '_hour'], 0, 0, (int) $_REQUEST[$name . '_month'], (int) $_REQUEST[$name . '_day'], (int) $_REQUEST[$name . '_year']);
309
+ $time -= get_option('gmt_offset') * 3600;
310
+ $this->data[$name] = $time;
311
+ continue;
312
+ }
313
+ if ($type === 'array') {
314
+ if (!isset($this->data[$name]))
315
+ $this->data[$name] = [];
316
+ }
317
+ if ($type === 'checkbox') {
318
+ if (!isset($this->data[$name])) {
319
+ $this->data[$name] = 0;
320
+ }
321
+ }
322
+ }
323
+ }
324
+ }
325
+ }
326
+
327
+ function set_data($data) {
328
+ if (is_array($data)) {
329
+ $this->data = $data;
330
+ } else if (is_object($data)) {
331
+ $this->data = (array) $data;
332
+ } else {
333
+ $this->data = [];
334
+ }
335
+ }
336
+
337
+ function merge($options) {
338
+ if (!is_array($options))
339
+ return;
340
+ if ($this->data == null)
341
+ $this->data = array();
342
+ $this->data = array_merge($this->data, $options);
343
+ }
344
+
345
+ function merge_defaults($defaults) {
346
+ if ($this->data == null)
347
+ $this->data = $defaults;
348
+ else
349
+ $this->data = array_merge($defaults, $this->data);
350
+ }
351
+
352
+ /**
353
+ * Return true is there in an asked action is no action name is specified or
354
+ * true is the requested action matches the passed action.
355
+ * Dies if it is not a safe call.
356
+ */
357
+ function is_action($action = null) {
358
+ if ($action == null)
359
+ return $this->action != null;
360
+ if ($this->action == null)
361
+ return false;
362
+ if ($this->action != $action)
363
+ return false;
364
+ if (check_admin_referer('save'))
365
+ return true;
366
+ die('Invalid call');
367
+ }
368
+
369
+ function get_value($name, $def = null) {
370
+ if (!isset($this->data[$name])) {
371
+ return $def;
372
+ }
373
+ return $this->data[$name];
374
+ }
375
+
376
+ function get_value_array($name) {
377
+ if (!isset($this->data[$name]) || !is_array($this->data[$name]))
378
+ return array();
379
+ return $this->data[$name];
380
+ }
381
+
382
+ function show_error($text) {
383
+ echo '<div class="tnp-error">', $text, '</div>';
384
+ }
385
+
386
+ function show_warning($text) {
387
+ echo '<div class="tnp-warning">', $text, '</div>';
388
+ }
389
+
390
+ function show_message($text) {
391
+ echo '<div class="tnpc-message">', $text, '</div>';
392
+ }
393
+
394
+ /**
395
+ * Show the errors and messages.
396
+ */
397
+ function show() {
398
+ static $shown = false;
399
+
400
+ if ($shown) {
401
+ return;
402
+ }
403
+ $shown = true;
404
+
405
+ if (!empty($this->errors)) {
406
+ echo '<div class="tnpc-error">';
407
+ echo $this->errors;
408
+ echo '</div>';
409
+ }
410
+ if (!empty($this->warnings)) {
411
+ foreach ((array) $this->warnings as $warning) {
412
+ echo '<div class="tnpc-warning">';
413
+ echo $warning;
414
+ echo '</div>';
415
+ }
416
+ }
417
+ if (!empty($this->messages)) {
418
+ echo '<div class="tnpc-message">';
419
+ echo $this->messages;
420
+ echo '</div>';
421
+ }
422
+ }
423
+
424
+ function add_message($text) {
425
+ if (!empty($this->messages)) {
426
+ $this->messages .= '<br><br>';
427
+ }
428
+ $this->messages .= $text;
429
+ }
430
+
431
+ function add_message_saved() {
432
+ if (!empty($this->messages)) {
433
+ $this->messages .= '<br><br>';
434
+ }
435
+ $this->messages .= __('Saved.', 'newsletter');
436
+ }
437
+
438
+ function add_message_deleted() {
439
+ if (!empty($this->messages)) {
440
+ $this->messages .= '<br><br>';
441
+ }
442
+ $this->messages .= __('Deleted.', 'newsletter');
443
+ }
444
+
445
+ function add_message_reset() {
446
+ if (!empty($this->messages)) {
447
+ $this->messages .= '<br><br>';
448
+ }
449
+ $this->messages .= __('Options reset.', 'newsletter');
450
+ }
451
+
452
+ function add_message_done() {
453
+ if (!empty($this->messages)) {
454
+ $this->messages .= '<br><br>';
455
+ }
456
+ $this->messages .= __('Done.', 'newsletter');
457
+ }
458
+
459
+ function add_language_warning() {
460
+ $newsletter = Newsletter::instance();
461
+ $current_language = $newsletter->get_current_language();
462
+
463
+ if (!$current_language) {
464
+ return;
465
+ }
466
+ $this->warnings[] = 'You are configuring the language <strong>' . $newsletter->get_language_label($current_language) . '</strong>. Switch to "all languages" to see all options.';
467
+ }
468
+
469
+ function switch_to_all_languages_notice() {
470
+ echo '<div class="tnpc-languages-notice">';
471
+ _e('Switch the administration side to "all languages" to set these options', 'newsletter');
472
+ echo '</div>';
473
+ }
474
+
475
+ function hint($text, $url = '') {
476
+ echo '<div class="tnpc-hint">';
477
+ // Do not escape that, it can be formatted
478
+ echo $text;
479
+ if (!empty($url)) {
480
+ echo ' <a href="' . esc_attr($url) . '" target="_blank">Read more</a>.';
481
+ }
482
+ echo '</div>';
483
+ }
484
+
485
+ function yesno($name) {
486
+ $value = isset($this->data[$name]) ? (int) $this->data[$name] : 0;
487
+
488
+ echo '<select style="width: 60px" name="options[', esc_attr($name), ']">';
489
+ echo '<option value="0"';
490
+ if ($value == 0) {
491
+ echo ' selected';
492
+ }
493
+ echo '>', __('No', 'newsletter'), '</option>';
494
+ echo '<option value="1"';
495
+ if ($value == 1) {
496
+ echo ' selected';
497
+ }
498
+ echo '>', __('Yes', 'newsletter'), '</option>';
499
+ echo '</select>&nbsp;&nbsp;&nbsp;';
500
+ }
501
+
502
+ function enabled($name = 'enabled', $attrs = []) {
503
+ $value = isset($this->data[$name]) ? (int) $this->data[$name] : 0;
504
+ $name = esc_attr($name);
505
+
506
+ echo '<select style="width: 100px" name="options[', $name, ']" id="options-', $name, '"';
507
+ if (isset($attrs['bind_to'])) {
508
+ echo ' onchange="tnp_select_toggle(this, \'', $attrs['bind_to'], '\')"';
509
+ }
510
+ echo '>';
511
+ echo '<option value="0"';
512
+ if ($value == 0) {
513
+ echo ' selected';
514
+ }
515
+ echo '>', __('Disabled', 'newsletter'), '</option>';
516
+ echo '<option value="1"';
517
+ if ($value == 1) {
518
+ echo ' selected';
519
+ }
520
+ echo '>', __('Enabled', 'newsletter'), '</option>';
521
+ echo '</select>';
522
+ if (isset($attrs['bind_to'])) {
523
+ if ($value) {
524
+ echo '<script>jQuery(function ($) {$("#options-', $attrs['bind_to'], '").show()})</script>';
525
+ } else {
526
+ echo '<script>jQuery(function ($) {$("#options-', $attrs['bind_to'], '").hide()})</script>';
527
+ }
528
+ }
529
+ }
530
+
531
+ function disabled($name) {
532
+ $value = isset($this->data[$name]) ? (int) $this->data[$name] : 0;
533
+
534
+ echo '<select style="width: 100px" name="options[' . esc_attr($name) . ']">';
535
+ echo '<option value="0"';
536
+ if ($value == 0) {
537
+ echo ' selected';
538
+ }
539
+ echo '>Enabled</option>';
540
+ echo '<option value="1"';
541
+ if ($value == 1) {
542
+ echo ' selected';
543
+ }
544
+ echo '>Disabled</option>';
545
+ echo '</select>';
546
+ }
547
+
548
+ /**
549
+ * Creates a set of checkbox all named as $name with values and labels extracted from
550
+ * $values_labels. A checkbox will be checked if internal data under key $name is an array
551
+ * and contains the value of the current (echoing) checkbox.
552
+ *
553
+ * On submit it produces an array under the name $name IF at least one checkbox has
554
+ * been checked. Otherwise the key won't be present.
555
+ *
556
+ * @param array $values
557
+ * @param string $name
558
+ * @param array $values_labels
559
+ */
560
+ function checkboxes_group($name, $values_labels) {
561
+ $value_array = $this->get_value_array($name);
562
+
563
+ echo '<div class="tnpc-checkboxes">';
564
+ foreach ($values_labels as $value => $label) {
565
+ echo '<label><input type="checkbox" id="' . esc_attr($name) . '" name="options[' . esc_attr($name) . '][]" value="' . esc_attr($value) . '"';
566
+ if (array_search($value, $value_array) !== false) {
567
+ echo ' checked';
568
+ }
569
+ echo '>';
570
+ if ($label != '') {
571
+ echo '&nbsp;' . esc_html($label);
572
+ }
573
+ echo "</label>";
574
+ }
575
+ echo "<div style='clear: both'></div>";
576
+ }
577
+
578
+ /** Creates a checkbox group with all public post types.
579
+ */
580
+ function post_types($name = 'post_types') {
581
+ $list = array();
582
+ $post_types = get_post_types(array('public' => true), 'objects', 'and');
583
+ foreach ($post_types as $post_type) {
584
+ $list[$post_type->name] = $post_type->labels->name;
585
+ }
586
+
587
+ $this->checkboxes_group($name, $list);
588
+ }
589
+
590
+ function posts_select($name, $max = 20, $args = array()) {
591
+ $args = array_merge(array(
592
+ 'posts_per_page' => 5,
593
+ 'offset' => 0,
594
+ 'category' => '',
595
+ 'category_name' => '',
596
+ 'orderby' => 'date',
597
+ 'order' => 'DESC',
598
+ 'include' => '',
599
+ 'exclude' => '',
600
+ 'meta_key' => '',
601
+ 'meta_value' => '',
602
+ 'post_type' => 'post',
603
+ 'post_mime_type' => '',
604
+ 'post_parent' => '',
605
+ 'author' => '',
606
+ 'author_name' => '',
607
+ 'post_status' => 'publish',
608
+ 'suppress_filters' => true
609
+ ), $args);
610
+ $args['posts_per_page'] = $max;
611
+
612
+ $posts = get_posts($args);
613
+ $options = array();
614
+ foreach ($posts as $post) {
615
+ $options['' . $post->ID] = $post->post_title;
616
+ }
617
+
618
+ $this->select($name, $options);
619
+ }
620
+
621
+ function select_number($name, $min, $max) {
622
+ $options = array();
623
+ for ($i = $min; $i <= $max; $i++) {
624
+ $options['' . $i] = $i;
625
+ }
626
+ $this->select($name, $options);
627
+ }
628
+
629
+ function page($name = 'page', $first = null, $language = '', $show_id = false) {
630
+ $args = array(
631
+ 'post_type' => 'page',
632
+ 'posts_per_page' => 1000,
633
+ 'offset' => 0,
634
+ 'orderby' => 'post_title',
635
+ 'post_status' => 'any',
636
+ 'suppress_filters' => true
637
+ );
638
+
639
+ $pages = get_posts($args);
640
+ //$pages = get_pages();
641
+ $options = array();
642
+ foreach ($pages as $page) {
643
+ /* @var $page WP_Post */
644
+ $label = $page->post_title;
645
+ if ($page->post_status != 'publish') {
646
+ $label .= ' (' . $page->post_status . ')';
647
+ }
648
+ if ($show_id) {
649
+ $label .= ' [' . $page->ID . ']';
650
+ }
651
+ $options[$page->ID] = $label;
652
+ }
653
+ $this->select($name, $options, $first);
654
+ }
655
+
656
+ /** Used to create a select which is part of a group of controls identified by $name that will
657
+ * produce an array of values as $_REQUEST['name'].
658
+ * @param string $name
659
+ * @param array $options Associative array
660
+ */
661
+ function select_group($name, $options) {
662
+ $value_array = $this->get_value_array($name);
663
+
664
+ echo '<select name="options[' . esc_attr($name) . '][]">';
665
+
666
+ foreach ($options as $key => $label) {
667
+ echo '<option value="' . esc_attr($key) . '"';
668
+ if (array_search($key, $value_array) !== false) {
669
+ echo ' selected';
670
+ }
671
+ echo '>' . esc_html($label) . '</option>';
672
+ }
673
+
674
+ echo '</select>';
675
+ }
676
+
677
+ function select($name, $options, $first = null, $attrs = []) {
678
+ echo '<select id="options-' . esc_attr($name) . '" name="options[' . esc_attr($name) . ']"';
679
+ if ($attrs) {
680
+ foreach ($attrs as $key => $value) {
681
+ echo ' ', $key, '="' . esc_attr($value), '"';
682
+ }
683
+ }
684
+ echo '>';
685
+ if (!empty($first)) {
686
+ echo '<option value="">' . esc_html($first) . '</option>';
687
+ }
688
+ $value = $this->get_value($name);
689
+ foreach ($options as $key => $label) {
690
+ echo '<option value="' . esc_attr($key) . '"';
691
+ if ($value == $key) {
692
+ echo ' selected';
693
+ }
694
+ echo '>' . esc_html($label) . '</option>';
695
+ }
696
+ echo '</select>';
697
+ }
698
+
699
+ function select_images($name, $options, $first = null) {
700
+ $value = $this->get_value($name);
701
+
702
+ echo '<select id="options-' . esc_attr($name) . '" name="options[' . esc_attr($name) . ']" style="min-width: 200px">';
703
+ if (!empty($first)) {
704
+ echo '<option value="">' . esc_html($first) . '</option>';
705
+ } else {
706
+ // if (empty($value)) {
707
+ // $keys = array_keys($options);
708
+ // $value = $keys[0];
709
+ // }
710
+ }
711
+ foreach ($options as $key => $data) {
712
+ echo '<option value="' . esc_attr($key) . '" image="' . esc_attr($data['image']) . '"';
713
+ if ($value == $key)
714
+ echo ' selected';
715
+ echo '>' . esc_html($data['label']) . '</option>';
716
+ }
717
+ echo '</select>';
718
+ echo '<script>jQuery("#options-' . esc_attr($name) . '").select2({templateResult: tnp_select_images, templateSelection: tnp_select_images_selection});</script>';
719
+ }
720
+
721
+ function select2($name, $options, $first = null, $multiple = false, $style = null, $placeholder = '') {
722
+
723
+ if ($multiple) {
724
+ $option_name = "options[" . esc_attr($name) . "][]";
725
+ } else {
726
+ $option_name = "options[" . esc_attr($name) . "]";
727
+ }
728
+
729
+ if (is_null($style)) {
730
+ $style = 'width: 100%';
731
+ }
732
+
733
+ $value = $this->get_value($name);
734
+
735
+ echo '<select id="options-', esc_attr($name), '" name="', $option_name, '" style="', $style, '"',
736
+ ($multiple ? ' multiple' : ''), '>';
737
+ if (!empty($first)) {
738
+ echo '<option value="">' . esc_html($first) . '</option>';
739
+ }
740
+
741
+ foreach ($options as $key => $data) {
742
+ echo '<option value="' . esc_attr($key) . '"';
743
+ if (is_array($value) && in_array($key, $value) || (!is_null($value) && $value == $key )) {
744
+ echo ' selected';
745
+ }
746
+ echo '>' . esc_html($data) . '</option>';
747
+ }
748
+
749
+ echo '</select>';
750
+ echo '<script>jQuery("#options-' . esc_attr($name) . '").select2({placeholder: "', esc_js($placeholder), '"});</script>';
751
+ }
752
+
753
+ function select_grouped($name, $groups) {
754
+ $value = $this->get_value($name);
755
+ $name = esc_attr($name);
756
+ echo '<select name="options[', $name, ']">';
757
+
758
+ foreach ($groups as $group) {
759
+ echo '<optgroup label="' . esc_attr($group['']) . '">';
760
+ if (!empty($group)) {
761
+ foreach ($group as $key => $label) {
762
+ if ($key == '') {
763
+ continue;
764
+ }
765
+ echo '<option value="' . esc_attr($key) . '"';
766
+ if ($value == $key) {
767
+ echo ' selected';
768
+ }
769
+ echo '>' . esc_html($label) . '</option>';
770
+ }
771
+ }
772
+ echo '</optgroup>';
773
+ }
774
+ echo '</select>';
775
+ }
776
+
777
+ /**
778
+ * Generated a select control with all available templates. From version 3 there are
779
+ * only on kind of templates, they are no more separated by type.
780
+ */
781
+ function themes($name, $themes, $submit_on_click = true) {
782
+ foreach ($themes as $key => $data) {
783
+ echo '<label style="display: block; float: left; text-align: center; margin-right: 10px;">';
784
+ echo esc_html($key) . '<br>';
785
+ echo '<img src="' . esc_attr($data['screenshot']) . '" width="100" height="100" style="border: 1px solid #666; padding: 5px"><br>';
786
+ echo '<input style="position: relative; top: -40px" type="radio" onchange="this.form.act.value=\'theme\';this.form.submit()" name="options[' . esc_attr($name) . ']" value="' . esc_attr($key) . '"';
787
+ if ($this->data[$name] == $key) {
788
+ echo ' checked';
789
+ }
790
+ echo '>';
791
+ echo '</label>';
792
+ }
793
+ echo '<div style="clear: both"></div>';
794
+ }
795
+
796
+ function value($name) {
797
+ echo esc_html($this->data[$name]);
798
+ }
799
+
800
+ function value_date($name, $show_remaining = true) {
801
+ $time = $this->get_value($name);
802
+
803
+ echo gmdate(get_option('date_format') . ' ' . get_option('time_format'), $time + get_option('gmt_offset') * 3600);
804
+ $delta = $time - time();
805
+ if ($show_remaining && $delta > 0) {
806
+ echo 'Remaining: ';
807
+ $delta = $time - time();
808
+ $days = floor($delta / (24 * 3600));
809
+ $delta = $delta - $days * 24 * 3600;
810
+ $hours = floor($delta / 3600);
811
+ $delta = $delta - $hours * 3600;
812
+ $minutes = floor($delta / 60);
813
+
814
+ if ($days > 0) {
815
+ echo $days . ' days ';
816
+ }
817
+ echo $hours . ' hours ';
818
+ echo $minutes . ' minutes ';
819
+ }
820
+ }
821
+
822
+ function password($name, $size = 20, $placeholder = '') {
823
+ $value = $this->get_value($name);
824
+ $name = esc_attr($name);
825
+ echo '<input id="options-', $name, '" placeholder="' . esc_attr($placeholder) . '" name="options[', $name, ']" type="password" autocomplete="off" ';
826
+ if (!empty($size)) {
827
+ echo 'size="', $size, '" ';
828
+ }
829
+ echo 'value="', esc_attr($value), '">';
830
+ }
831
+
832
+ function text($name, $size = 20, $placeholder = '') {
833
+ $value = $this->get_value($name);
834
+ $name = esc_attr($name);
835
+ echo '<input id="options-', $name, '" placeholder="' . esc_attr($placeholder) . '" title="' . esc_attr($placeholder) . '" name="options[', $name, ']" type="text" ';
836
+ if (!empty($size)) {
837
+ echo 'size="', esc_attr($size), '" ';
838
+ }
839
+ echo 'value="', esc_attr($value), '">';
840
+ }
841
+
842
+ function text_email($name, $attrs = []) {
843
+ if (is_numeric($attrs)) {
844
+ $attrs = ['size' => $attrs];
845
+ }
846
+ $attrs = array_merge(['placeholder' => __('Valid email address', 'newsletter'), 'size' => 40, 'required' => false], $attrs);
847
+
848
+ $value = $this->get_value($name);
849
+ echo '<input name="options[' . esc_attr($name) . ']" type="email" placeholder="';
850
+ echo esc_attr($attrs['placeholder']);
851
+ echo '" size="', esc_attr($attrs['size']), '" value="', esc_attr($value) , '"';
852
+ if ($attrs['required']) {
853
+ echo ' required';
854
+ }
855
+ echo '>';
856
+ }
857
+
858
+ function text_url($name, $size = 40) {
859
+ $value = $this->get_value($name);
860
+ echo '<input name="options[' . esc_attr($name) . ']" type="url" placeholder="http://..." size="' . esc_attr($size) . '" value="';
861
+ echo esc_attr($value);
862
+ echo '"/>';
863
+ }
864
+
865
+ function hidden($name) {
866
+ $value = $this->get_value($name);
867
+ echo '<input name="options[', esc_attr($name), ']" id="options-', esc_attr($name), '" type="hidden" value="', esc_attr($value), '">';
868
+ }
869
+
870
+ /**
871
+ * General button. Attributes:
872
+ * - id: the element HTML id
873
+ * - confirm: if string the text is shown in a confirmation message, if true shows a standard confirm message
874
+ * - icon: the font awesome icon name (fa-xxx)
875
+ * - style: the CSS style
876
+ * - data: free data associated to the button click ($controls->button_data) for example to pass the element ID from a list of elements
877
+ *
878
+ * @param string $action
879
+ * @param string $label
880
+ * @param array $attrs
881
+ */
882
+ function btn($action, $label, $attrs = []) {
883
+ echo '<button class="button-primary tnpc-button"';
884
+ if (isset($attrs['id'])) {
885
+ echo ' id="', esc_attrs($attrs['id']), '"';
886
+ }
887
+ $onclick = "this.form.act.value='" . esc_attr(esc_js(trim($action))) . "';";
888
+ if (!empty($attrs['data'])) {
889
+ $onclick .= "this.form.btn.value='" . esc_attr(esc_js($attrs['data'])) . "';";
890
+ }
891
+ if (isset($attrs['confirm'])) {
892
+ if (is_string($attrs['confirm'])) {
893
+ $onclick .= "if (!confirm('" . esc_attr(esc_js($attrs['confirm'])) . "')) return false;";
894
+ } else if ($attrs['confirm'] === true) {
895
+ $onclick .= "if (!confirm('" . esc_attr(esc_js(__('Proceed?', 'newsletter'))) . "')) return false;";
896
+ }
897
+ }
898
+ echo 'onclick="', $onclick, '"';
899
+ if (!empty($attrs['title'])) {
900
+ echo ' title="', esc_attr($attrs['title']), '"';
901
+ }
902
+ if (!empty($attrs['style'])) {
903
+ echo ' style="', esc_attr($attrs['style']), '"';
904
+ }
905
+ echo '>';
906
+ if (!empty($attrs['icon'])) {
907
+ echo '<i class="fas ', esc_attr($attrs['icon']), '"></i>';
908
+ if (!empty($label)) {
909
+ echo '&nbsp;', esc_html($label);
910
+ }
911
+ } else {
912
+ echo esc_html($label);
913
+ }
914
+ echo '</button>';
915
+ }
916
+
917
+ /**
918
+ * Creates a link looking lie a standard button. Attributes:
919
+ * - title: the link "title" HTML attribute
920
+ * - target: the link "target" HTML attribute
921
+ * - icon: the font awesome icon name (fa-xxx)
922
+ * - style: the CSS style
923
+ *
924
+ * @param string $url
925
+ * @param string $label
926
+ * @param array $attrs
927
+ */
928
+ function btn_link($url, $label, $attrs = []) {
929
+ echo '<a href="', esc_attr($url), '" class="button-primary tnpc-button"';
930
+ if (!empty($attrs['style'])) {
931
+ echo ' style="', esc_attr($attrs['style']), '"';
932
+ }
933
+ if (!empty($attrs['title'])) {
934
+ echo ' title="', esc_attr($attrs['title']), '"';
935
+ }
936
+ if (!empty($attrs['target'])) {
937
+ echo ' target="', esc_attr($attrs['target']), '"';
938
+ }
939
+ echo '>';
940
+ if (!empty($attrs['icon'])) {
941
+ echo '<i class="fas ', esc_attr($attrs['icon']), '"></i>';
942
+ if (!empty($label)) {
943
+ echo '&nbsp;', esc_html($label);
944
+ }
945
+ } else {
946
+ echo esc_html($label);
947
+ }
948
+ echo '</a>';
949
+ }
950
+
951
+ function button($action, $label, $function = '', $id = '') {
952
+ $id = !empty($id) ? " id=\"$id\" " : '';
953
+ if ($function != null) {
954
+ echo '<input ' . $id . ' class="button-primary tnpc-button" type="button" value="' . esc_attr($label) . '" onclick="this.form.act.value=\'' . esc_attr($action) . '\';' . esc_html($function) . '"/>';
955
+ } else {
956
+ echo '<input ' . $id . ' class="button-primary tnpc-button" type="submit" value="' . esc_attr($label) . '" onclick="this.form.act.value=\'' . esc_attr($action) . '\';return true;"/>';
957
+ }
958
+ }
959
+
960
+ function action_link($action, $label, $function = null) {
961
+ if ($function != null) {
962
+ echo '<input class="button-link tnpc-button" type="button" value="' . esc_attr($label) . '" onclick="this.form.act.value=\'' . esc_attr($action) . '\';' . esc_html($function) . '"/>';
963
+ } else {
964
+ echo '<input class="button-link tnpc-button" type="submit" value="' . esc_attr($label) . '" onclick="this.form.act.value=\'' . esc_attr($action) . '\';return true;"/>';
965
+ }
966
+ }
967
+
968
+ function button_save() {
969
+ $this->btn('save', __('Save', 'newsletter'), ['icon' => 'fa-save']);
970
+ }
971
+
972
+ function button_reset($action = 'reset') {
973
+ $this->btn($action, __('Reset', 'newsletter'), ['icon' => 'fa-reply', 'confirm' => true]);
974
+ }
975
+
976
+ function button_copy($data = '') {
977
+ $this->btn('copy', __('Duplicate', 'newsletter'), ['data' => $data, 'icon' => 'fa-copy', 'confirm' => true]);
978
+ }
979
+
980
+ function button_icon_copy($data = '') {
981
+ $this->btn('copy', '', ['data' => $data, 'icon' => 'fa-copy', 'confirm' => true, 'title' => __('Duplicate', 'newsletter')]);
982
+ }
983
+
984
+ /**
985
+ * Creates a button with "delete" action.
986
+ * @param type $data
987
+ */
988
+ function button_delete($data = '') {
989
+ $this->btn('delete', __('Delete', 'newsletter'), ['data' => $data, 'icon' => 'fa-times', 'confirm' => true, 'style' => 'background-color: darkred; color: #ffffff']);
990
+ }
991
+
992
+ function button_icon_delete($data = '') {
993
+ $this->btn('delete', '', ['data' => $data, 'icon' => 'fa-times', 'confirm' => true, 'title' => __('Delete', 'newsletter'), 'style' => 'background-color: darkred; color: #ffffff']);
994
+ }
995
+
996
+ function button_icon_configure($url) {
997
+ $this->btn_link($url, '', ['icon' => 'fa-cog', 'title' => __('Configure', 'newsletter')]);
998
+ }
999
+
1000
+ function button_icon_subscribers($url) {
1001
+ $this->btn_link($url, '', ['icon' => 'fa-users', 'title' => __('Subscribers', 'newsletter')]);
1002
+ }
1003
+
1004
+ function button_statistics($url) {
1005
+ $this->btn_link($url, __('Statistics', 'newsletter'), ['icon' => 'fa-chart-bar']);
1006
+ }
1007
+
1008
+ function button_icon_statistics($url) {
1009
+ $this->btn_link($url, '', ['icon' => 'fa-chart-bar', 'title' => __('Statistics', 'newsletter')]);
1010
+ }
1011
+
1012
+ function button_icon_view($url) {
1013
+ $this->btn_link($url, '', ['icon' => 'fa-eye', 'title' => __('View', 'newsletter'), 'target' => '_blank']);
1014
+ }
1015
+
1016
+ function button_icon_newsletters($url) {
1017
+ $this->btn_link($url, '', ['icon' => 'fa-file-alt', 'title' => __('Newsletters', 'newsletter')]);
1018
+ }
1019
+
1020
+ function button_icon_design($url) {
1021
+ $this->btn_link($url, '', ['icon' => 'fa-paint-brush', 'title' => __('Design', 'newsletter')]);
1022
+ }
1023
+
1024
+ function button_icon_edit($url) {
1025
+ $this->btn_link($url, '', ['icon' => 'fa-edit', 'title' => __('Edit', 'newsletter')]);
1026
+ }
1027
+
1028
+ function button_icon_back($url) {
1029
+ $this->btn_link($url, '', ['icon' => 'fa-chevron-left', 'title' => __('Back', 'newsletter')]);
1030
+ }
1031
+
1032
+ function button_icon($action, $icon, $title = '', $data = '', $confirm = false) {
1033
+ $this->btn($action, '', ['data' => $data, 'icon' => $icon, 'title' => $title, 'confirm' => $confirm]);
1034
+ }
1035
+
1036
+ function button_back($url) {
1037
+ $this->btn_link($url, __('Back', 'newsletter'), ['icon' => 'fa-chevron-left']);
1038
+ }
1039
+
1040
+ function button_test($action = 'test') {
1041
+ $this->btn($action, __('Test', 'newsletter'), ['icon' => 'fa-vial']);
1042
+ }
1043
+
1044
+ /**
1045
+ * @deprecated
1046
+ */
1047
+ function button_primary($action, $label, $function = null) {
1048
+ if ($function != null) {
1049
+ echo '<button class="button-primary" onclick="this.form.act.value=\'' . esc_attr($action) . '\';' . esc_attr($function) . '">', $label, '</button>';
1050
+ } else {
1051
+ echo '<button class="button-primary" onclick="this.form.act.value=\'' . esc_attr($action) . '\'; return true;"/>', $label, '</button>';
1052
+ }
1053
+ }
1054
+
1055
+ function button_confirm($action, $label, $message = true, $data = '') {
1056
+ $this->btn($action, $label, ['data' => $data, 'confirm' => $message]);
1057
+ }
1058
+
1059
+ /**
1060
+ * @deprecated
1061
+ * @param string $url
1062
+ * @param string $label Not escaped.
1063
+ */
1064
+ function button_link($url, $label = '') {
1065
+ echo '<a href="', esc_attr($url), '" class="button-primary">', $label, '</a>';
1066
+ }
1067
+
1068
+ function editor($name, $rows = 5, $cols = 75) {
1069
+ echo '<textarea class="visual" name="options[' . esc_attr($name) . ']" style="width: 100%" wrap="off" rows="' . esc_attr($rows) . '">';
1070
+ echo esc_html($this->get_value($name));
1071
+ echo '</textarea>';
1072
+ }
1073
+
1074
+ function wp_editor($name, $settings = []) {
1075
+
1076
+ add_filter('mce_buttons', function ($mce_buttons) {
1077
+ $mce_buttons[] = 'wp_add_media';
1078
+ //$mce_buttons[] = 'wp_code';
1079
+ return $mce_buttons;
1080
+ });
1081
+
1082
+ $settings = array_merge(['media_buttons' => false], $settings);
1083
+
1084
+ $value = $this->get_value($name);
1085
+ wp_editor($value, $name, array_merge(array(
1086
+ 'tinymce' => array('content_css' => plugins_url('newsletter') . '/admin/wp-editor.css?ver=' . NEWSLETTER_VERSION),
1087
+ 'textarea_name' => 'options[' . esc_attr($name) . ']',
1088
+ 'wpautop' => false
1089
+ ), $settings));
1090
+ }
1091
+
1092
+ function textarea($name, $width = '100%', $height = '50') {
1093
+ $value = $this->get_value($name);
1094
+ if (is_array($value)) {
1095
+ $value = implode("\n", $value);
1096
+ }
1097
+ echo '<textarea id="options-' . esc_attr($name) . '" class="dynamic" name="options[' . esc_attr($name) . ']" wrap="off" style="width:' . esc_attr($width) . ';height:' . esc_attr($height) . '">';
1098
+ echo esc_html($value);
1099
+ echo '</textarea>';
1100
+ }
1101
+
1102
+ function textarea_fixed($name, $width = '100%', $height = '200') {
1103
+ $value = $this->get_value($name);
1104
+ $name = esc_attr($name);
1105
+ echo '<textarea id="options-', $name, '" name="options[', $name, ']" wrap="off" style="width:', esc_attr($width), ';height:', esc_attr($height), 'px">';
1106
+ echo esc_html($value);
1107
+ echo '</textarea>';
1108
+ }
1109
+
1110
+ function textarea_preview($name, $width = '100%', $height = '200', $header = '', $footer = '', $switch_button = true) {
1111
+ $value = $this->get_value($name);
1112
+ $name = esc_attr($name);
1113
+ if ($switch_button) {
1114
+ echo '<input class="button-primary" type="button" onclick="newsletter_textarea_preview(\'options-', $name, '\', \'\', \'\')" value="Switch editor/preview">';
1115
+ echo '<br><br>';
1116
+ }
1117
+ echo '<div style="box-sizing: border-box; position: relative; margin: 0; padding: 0; width:' . esc_attr($width) . '; height:' . esc_attr($height) . '">';
1118
+ echo '<textarea id="options-', $name, '" name="options[', $name, ']" wrap="off" style="width:' . esc_attr($width) . ';height:' . esc_attr($height) . 'px">';
1119
+ echo esc_html($value);
1120
+ echo '</textarea>';
1121
+ echo '<div id="options-', $name, '-preview" style="box-sizing: border-box; background-color: #eee; border: 1px solid #bbb; padding: 15px; width: auto; position: absolute; top: 20px; left: 20px; box-shadow: 0 0 20px #777; z-index: 10000; display: none">';
1122
+ echo '<iframe id="options-', $name, '-iframe" class="tnp-editor-preview-desktop"></iframe>';
1123
+ echo '<iframe id="options-', $name, '-iframe-phone" class="tnp-editor-preview-mobile"></iframe>';
1124
+ echo '</div>';
1125
+ echo '</div>';
1126
+ }
1127
+
1128
+ function email($prefix, $editor = null, $disable_option = false, $settings = array()) {
1129
+ if ($disable_option) {
1130
+ $this->disabled($prefix . '_disabled');
1131
+ echo '<br>';
1132
+ }
1133
+
1134
+ $this->text($prefix . '_subject', 90, 'Subject');
1135
+ echo '<br><br>';
1136
+
1137
+ if ($editor == 'wordpress') {
1138
+ $this->wp_editor($prefix . '_message', $settings);
1139
+ } else if ($editor == 'textarea') {
1140
+ $this->textarea($prefix . '_message');
1141
+ } else {
1142
+ $this->editor($prefix . '_message');
1143
+ }
1144
+ }
1145
+
1146
+ /**
1147
+ * Standard checkbox, when not checked no value is transmitted (checkbox2).
1148
+ *
1149
+ * @param string $name
1150
+ * @param string $label
1151
+ */
1152
+ function checkbox($name, $label = '') {
1153
+ if ($label != '') {
1154
+ echo '<label>';
1155
+ }
1156
+ echo '<input type="checkbox" id="options-' . esc_attr($name) . '" name="options[' . esc_attr($name) . ']" value="1"';
1157
+ if (!empty($this->data[$name])) {
1158
+ echo ' checked';
1159
+ }
1160
+ echo '>';
1161
+ if ($label != '') {
1162
+ echo '&nbsp;' . esc_html($label) . '</label>';
1163
+ }
1164
+ }
1165
+
1166
+ /**
1167
+ * Checkbox with a hidden field to transmit 1 or 0 even when the checkbox is not checked.
1168
+ *
1169
+ * @param string $name
1170
+ * @param string $label
1171
+ */
1172
+ function checkbox2($name, $label = '') {
1173
+ if ($label != '') {
1174
+ echo '<label>';
1175
+ }
1176
+ echo '<input type="checkbox" id="' . esc_attr($name) . '" onchange="document.getElementById(\'' . esc_attr($name) . '_hidden\').value=this.checked?\'1\':\'0\'"';
1177
+ if (!empty($this->data[$name])) {
1178
+ echo ' checked';
1179
+ }
1180
+ echo '>';
1181
+ if ($label != '') {
1182
+ echo '&nbsp;' . esc_html($label) . '</label>';
1183
+ }
1184
+ echo '<input type="hidden" id="' . esc_attr($name) . '_hidden" name="options[' . esc_attr($name) . ']" value="';
1185
+
1186
+ echo empty($this->data[$name]) ? '0' : '1';
1187
+ echo '">';
1188
+ }
1189
+
1190
+ function radio($name, $value, $label = '') {
1191
+ if ($label != '') {
1192
+ echo '<label>';
1193
+ }
1194
+ echo '<input type="radio" id="' . esc_attr($name) . '" name="options[' . esc_attr($name) . ']" value="' . esc_attr($value) . '"';
1195
+ $v = $this->get_value($name);
1196
+ if ($v == $value) {
1197
+ echo ' checked';
1198
+ }
1199
+ echo '>';
1200
+ if ($label != '') {
1201
+ echo '&nbsp;' . esc_html($label) . '</label>';
1202
+ }
1203
+ }
1204
+
1205
+ /**
1206
+ * Creates a checkbox named $name and checked if the internal data contains under
1207
+ * the key $name an array containig the passed value.
1208
+ */
1209
+ function checkbox_group($name, $value, $label = '', $attrs = []) {
1210
+ $attrs = wp_parse_args($attrs, ['label_escape' => true]);
1211
+ echo '<label><input type="checkbox" id="' . esc_attr($name) . '" name="options[' . esc_attr($name) . '][]" value="' . esc_attr($value) . '"';
1212
+ if (isset($this->data[$name]) && is_array($this->data[$name]) && array_search($value, $this->data[$name]) !== false) {
1213
+ echo ' checked';
1214
+ }
1215
+ echo '>';
1216
+ if ($label != '') {
1217
+ if ($attrs['label_escape']) {
1218
+ echo esc_html($label);
1219
+ } else {
1220
+ echo $label;
1221
+ }
1222
+ }
1223
+ echo '</label>';
1224
+ }
1225
+
1226
+ function checkboxes($name, $options) {
1227
+ echo '<div class="tnpc-checkboxes">';
1228
+ foreach ($options as $value => $label) {
1229
+ $this->checkbox_group($name, $value, $label);
1230
+ }
1231
+ echo '<div style="clear: both"></div>';
1232
+ echo '</div>';
1233
+ }
1234
+
1235
+ function color($name, $default = '') {
1236
+ $value = esc_attr($this->get_value($name, $default));
1237
+ $name = esc_attr($name);
1238
+ echo '<input class="tnpc-color" id="options-', $name, '" name="options[', $name, ']" type="text" value="', $value, '">';
1239
+ }
1240
+
1241
+ /** Creates a set of checkbox named $name_[category id] (so they are posted with distinct names).
1242
+ */
1243
+ function categories($name = 'category') {
1244
+ $categories = get_categories();
1245
+ echo '<div class="tnpc-checkboxes">';
1246
+ foreach ($categories as $c) {
1247
+ $this->checkbox($name . '_' . $c->cat_ID, esc_html($c->cat_name));
1248
+ }
1249
+ echo '<div style="clear: both"></div>';
1250
+ }
1251
+
1252
+ /**
1253
+ * Creates a set of checkbox to activate the profile preferences. Every checkbox has a DIV around to
1254
+ * be formatted.
1255
+ */
1256
+ function categories_group($name, $show_mode = false) {
1257
+ $categories = get_categories();
1258
+ if ($show_mode) {
1259
+ $this->select($name . '_mode', array('include' => 'To be included', 'exclude' => 'To be excluded'));
1260
+ }
1261
+ echo '<div class="tnpc-checkboxes">';
1262
+ foreach ($categories as &$c) {
1263
+ $this->checkbox_group($name, $c->cat_ID, esc_html($c->cat_name));
1264
+ }
1265
+ echo '<div style="clear: both"></div>';
1266
+ }
1267
+
1268
+ /**
1269
+ * Creates a set of checkboxes named $name_[preference number] (so they are
1270
+ * distinct fields).
1271
+ * Empty preferences are skipped.
1272
+ */
1273
+ function preferences($name = 'preferences') {
1274
+ $lists = Newsletter::instance()->get_lists();
1275
+
1276
+ echo '<div class="tnpc-checkboxes">';
1277
+ foreach ($lists as $list) {
1278
+ $this->checkbox2($name . '_' . $list->id, esc_html($list->name));
1279
+ }
1280
+ echo '<div style="clear: both"></div>';
1281
+ }
1282
+
1283
+ /** A list of all lists defined each one with a checkbox to select it. An array
1284
+ * of ID of all checked lists is submitted.
1285
+ *
1286
+ * @param string $name
1287
+ */
1288
+ function lists($name = 'lists') {
1289
+ echo '<input type="hidden" name="tnp_fields[' . esc_attr($name) . ']" value="array">';
1290
+ $this->preferences_group($name);
1291
+ }
1292
+
1293
+ function lists_checkboxes($name = 'lists') {
1294
+ $this->preferences_group($name);
1295
+ }
1296
+
1297
+ /**
1298
+ * Creates a set of checkboxes all names $name[] and the preference number as value
1299
+ * so the selected checkboxes are retrieved as an array of values ($REQUEST[$name]
1300
+ * will be an array if at east one preference is checked).
1301
+ */
1302
+ function preferences_group($name = 'preferences') {
1303
+
1304
+ $lists = Newsletter::instance()->get_lists();
1305
+
1306
+ echo '<div class="tnpc-lists">';
1307
+ foreach ($lists as $list) {
1308
+ $this->checkbox_group($name, $list->id, '<span>' . $list->id . '</span> ' . esc_html($list->name), ['label_escape' => false]);
1309
+ }
1310
+ echo '<a href="https://www.thenewsletterplugin.com/documentation/newsletter-lists" target="_blank">'
1311
+ . 'Click here to read more about lists.'
1312
+ . '</a>';
1313
+ echo '</div>';
1314
+ }
1315
+
1316
+ /** Creates as many selects as the active preferences with the three values
1317
+ * 'any', 'yes', 'no' corresponding to the values 0, 1, 2.
1318
+ */
1319
+ function preferences_selects($name = 'preferences', $skip_empty = false) {
1320
+ $lists = Newsletter::instance()->get_lists();
1321
+
1322
+ echo '<div class="newsletter-preferences-group">';
1323
+ foreach ($lists as $list) {
1324
+
1325
+ echo '<div class="newsletter-preferences-item">';
1326
+
1327
+ $this->select($name . '_' . $list->id, array(0 => 'Any', 1 => 'Yes', 2 => 'No'));
1328
+ echo '(' . $list->id . ') ' . esc_html($list->name);
1329
+
1330
+ echo '</div>';
1331
+ }
1332
+ echo '<div style="clear: both"></div>';
1333
+ echo '<a href="https://www.thenewsletterplugin.com/plugins/newsletter/newsletter-preferences" target="_blank">Click here know more about preferences.</a> They can be configured on Subscription/Form field panel.';
1334
+ echo '</div>';
1335
+ }
1336
+
1337
+ /**
1338
+ * Creates a single select with the active preferences.
1339
+ */
1340
+ function preferences_select($name = 'preference', $empty_label = null) {
1341
+ $lists = $this->get_list_options($empty_label);
1342
+ $this->select($name, $lists);
1343
+ echo ' <a href="admin.php?page=newsletter_subscription_lists" target="_blank"><i class="fas fa-edit"></i></a>';
1344
+ }
1345
+
1346
+ function lists_select($name = 'list', $empty_label = null) {
1347
+ $lists = $this->get_list_options($empty_label);
1348
+ $this->select($name, $lists);
1349
+ }
1350
+
1351
+ function lists_select_with_notes($name = 'list', $empty_label = null) {
1352
+
1353
+ $value = $this->get_value($name);
1354
+
1355
+ $lists = Newsletter::instance()->get_lists();
1356
+ $options = [];
1357
+ if ($empty_label) {
1358
+ $options[''] = $empty_label;
1359
+ }
1360
+
1361
+ foreach ($lists as $list) {
1362
+ $options['' . $list->id] = '(' . $list->id . ') ' . esc_html($list->name);
1363
+ }
1364
+
1365
+ $this->select($name, $options, null, ['onchange' => 'tnp_lists_toggle(this); return true;']);
1366
+ echo '<div id="options-', esc_attr($name), '-notes" class="tnpc_lists_notes">';
1367
+ foreach ($lists as $list) {
1368
+ $id = $list->id;
1369
+ $notes = apply_filters('newsletter_lists_notes', [], $id);
1370
+
1371
+ echo '<div class="list_', $id, '" style="display: ', ($value == $id ? 'block' : 'none'), '">';
1372
+ if ($list->forced) {
1373
+ echo 'Enforced on subscription<br>';
1374
+ }
1375
+ echo implode('<br>', $notes);
1376
+ echo '</div>';
1377
+ }
1378
+ echo '</div>';
1379
+ }
1380
+
1381
+ function public_lists_select($name = 'list', $empty_label = null) {
1382
+ $lists = $this->get_public_list_options($empty_label);
1383
+ $this->select($name, $lists);
1384
+ }
1385
+
1386
+ /**
1387
+ * Generates an associative array with the active lists to be used in a select.
1388
+ * @param string $empty_label
1389
+ * @return array
1390
+ */
1391
+ function get_list_options($empty_label = null) {
1392
+ $objs = Newsletter::instance()->get_lists();
1393
+ $lists = array();
1394
+ if ($empty_label) {
1395
+ $lists[''] = $empty_label;
1396
+ }
1397
+ foreach ($objs as $list) {
1398
+ $lists['' . $list->id] = '(' . $list->id . ') ' . esc_html($list->name);
1399
+ }
1400
+ return $lists;
1401
+ }
1402
+
1403
+ function get_public_list_options($empty_label = null) {
1404
+ $objs = Newsletter::instance()->get_lists_public();
1405
+ $lists = array();
1406
+ if ($empty_label) {
1407
+ $lists[''] = $empty_label;
1408
+ }
1409
+ foreach ($objs as $list) {
1410
+ $lists['' . $list->id] = '(' . $list->id . ') ' . esc_html($list->name);
1411
+ }
1412
+ return $lists;
1413
+ }
1414
+
1415
+ function date($name) {
1416
+ $this->hidden($name);
1417
+ $year = date('Y', $this->data[$name]);
1418
+ $day = date('j', $this->data[$name]);
1419
+ $month = date('m', $this->data[$name]);
1420
+ $onchange = "this.form.elements['options[" . esc_attr($name) . "]'].value = new Date(document.getElementById('" . esc_attr($name) . "_year').value, document.getElementById('" . esc_attr($name) . "_month').value, document.getElementById('" . esc_attr($name) . "_day').value, 12, 0, 0).getTime()/1000";
1421
+ echo '<select id="' . $name . '_month" onchange="' . esc_attr($onchange) . '">';
1422
+ for ($i = 0; $i < 12; $i++) {
1423
+ echo '<option value="' . $i . '"';
1424
+ if ($month - 1 == $i) {
1425
+ echo ' selected';
1426
+ }
1427
+ echo '>' . date('F', mktime(0, 0, 0, $i + 1, 1, 2000)) . '</option>';
1428
+ }
1429
+ echo '</select>';
1430
+
1431
+ echo '<select id="' . esc_attr($name) . '_day" onchange="' . esc_attr($onchange) . '">';
1432
+ for ($i = 1; $i <= 31; $i++) {
1433
+ echo '<option value="' . $i . '"';
1434
+ if ($day == $i) {
1435
+ echo ' selected';
1436
+ }
1437
+ echo '>' . $i . '</option>';
1438
+ }
1439
+ echo '</select>';
1440
+
1441
+ echo '<select id="' . esc_attr($name) . '_year" onchange="' . esc_attr($onchange) . '">';
1442
+ for ($i = 2011; $i <= date('Y')+3; $i++) {
1443
+ echo '<option value="' . $i . '"';
1444
+ if ($year == $i) {
1445
+ echo ' selected';
1446
+ }
1447
+ echo '>' . $i . '</option>';
1448
+ }
1449
+ echo '</select>';
1450
+ }
1451
+
1452
+ /**
1453
+ * Creates a set of fields to collect a date and sends back the triplet year, month and day.
1454
+ *
1455
+ * @param string $name
1456
+ */
1457
+ function date2($name) {
1458
+ $year = $this->get_value($name . '_year');
1459
+ $day = $this->get_value($name . '_day');
1460
+ $month = $this->get_value($name . '_month');
1461
+
1462
+ echo '<select name="options[' . $name . '_month]">';
1463
+ echo '<option value="">-</option>';
1464
+ for ($i = 1; $i <= 12; $i++) {
1465
+ echo '<option value="' . $i . '"';
1466
+ if ($month == $i) {
1467
+ echo ' selected';
1468
+ }
1469
+ echo '>' . date_i18n('F', mktime(0, 0, 0, $i, 1, 2000)) . '</option>';
1470
+ }
1471
+ echo '</select>';
1472
+
1473
+ echo '<select name="options[' . esc_attr($name) . '_day]">';
1474
+ echo '<option value="">-</option>';
1475
+ for ($i = 1; $i <= 31; $i++) {
1476
+ echo '<option value="' . $i . '"';
1477
+ if ($day == $i) {
1478
+ echo ' selected';
1479
+ }
1480
+ echo '>' . $i . '</option>';
1481
+ }
1482
+ echo '</select>';
1483
+
1484
+ echo '<select name="options[' . esc_attr($name) . '_year]">';
1485
+ echo '<option value="">-</option>';
1486
+ for ($i = 2011; $i <= date('Y')+3; $i++) {
1487
+ echo '<option value="' . $i . '"';
1488
+ if ($year == $i) {
1489
+ echo ' selected';
1490
+ }
1491
+ echo '>' . $i . '</option>';
1492
+ }
1493
+ echo '</select>';
1494
+ }
1495
+
1496
+ /**
1497
+ * Date and time (hour) selector. Timestamp stored.
1498
+ */
1499
+ function datetime($name) {
1500
+ echo '<input type="hidden" name="tnp_fields[' . esc_attr($name) . ']" value="datetime">';
1501
+ $value = (int) $this->get_value($name);
1502
+ if (empty($value)) {
1503
+ $value = time();
1504
+ }
1505
+
1506
+ $time = $value + get_option('gmt_offset') * 3600;
1507
+ $year = gmdate('Y', $time);
1508
+ $day = gmdate('j', $time);
1509
+ $month = gmdate('m', $time);
1510
+ $hour = gmdate('H', $time);
1511
+
1512
+ echo '<select name="' . esc_attr($name) . '_month">';
1513
+ for ($i = 1; $i <= 12; $i++) {
1514
+ echo '<option value="' . $i . '"';
1515
+ if ($month == $i) {
1516
+ echo ' selected';
1517
+ }
1518
+ echo '>' . date('F', mktime(0, 0, 0, $i, 1, 2000)) . '</option>';
1519
+ }
1520
+ echo '</select>';
1521
+
1522
+ echo '<select name="' . esc_attr($name) . '_day">';
1523
+ for ($i = 1; $i <= 31; $i++) {
1524
+ echo '<option value="' . $i . '"';
1525
+ if ($day == $i) {
1526
+ echo ' selected';
1527
+ }
1528
+ echo '>' . $i . '</option>';
1529
+ }
1530
+ echo '</select>';
1531
+
1532
+ $last_year = date('Y') + 2;
1533
+ echo '<select name="' . esc_attr($name) . '_year">';
1534
+ for ($i = 2011; $i <= $last_year; $i++) {
1535
+ echo '<option value="' . $i . '"';
1536
+ if ($year == $i) {
1537
+ echo ' selected';
1538
+ }
1539
+ echo '>' . $i . '</option>';
1540
+ }
1541
+ echo '</select>';
1542
+
1543
+ echo '<select name="' . esc_attr($name) . '_hour">';
1544
+ for ($i = 0; $i <= 23; $i++) {
1545
+ echo '<option value="' . $i . '"';
1546
+ if ($hour == $i) {
1547
+ echo ' selected';
1548
+ }
1549
+ echo '>' . $i . ':00</option>';
1550
+ }
1551
+ echo '</select>';
1552
+ }
1553
+
1554
+ function hours($name) {
1555
+ $hours = array();
1556
+ for ($i = 0; $i < 24; $i++) {
1557
+ $hours['' . $i] = sprintf('%02d', $i) . ':00';
1558
+ }
1559
+ $this->select($name, $hours);
1560
+ }
1561
+
1562
+ function days($name) {
1563
+ $days = array(0 => 'Every day', 1 => 'Monday', 2 => 'Tuesday', 3 => 'Wednesday', 4 => 'Thursday', 5 => 'Friday', 6 => 'Saturday', 7 => 'Sunday');
1564
+ $this->select($name, $days);
1565
+ }
1566
+
1567
+ function init($options = array()) {
1568
+ $cookie_name = 'newsletter_tab';
1569
+ if (isset($options['cookie_name'])) {
1570
+ $cookie_name = $options['cookie_name'];
1571
+ }
1572
+ echo '<script type="text/javascript">
1573
+ jQuery(document).ready(function(){
1574
+
1575
+ tnp_controls_init();
1576
+
1577
+ jQuery("textarea.dynamic").focus(function() {
1578
+ jQuery("textarea.dynamic").css("height", "50px");
1579
+ jQuery(this).css("height", "400px");
1580
+ });
1581
+ tabs = jQuery("#tabs").tabs({
1582
+ active : jQuery.cookie("' . $cookie_name . '"),
1583
+ activate : function( event, ui ){
1584
+ jQuery.cookie("' . $cookie_name . '", ui.newTab.index(),{expires: 1});
1585
+ }
1586
+ });
1587
+ jQuery(".tnp-tabs").tabs({});
1588
+
1589
+ });
1590
+ function newsletter_media(name) {
1591
+ var tnp_uploader = wp.media({
1592
+ title: "Select an image",
1593
+ button: {
1594
+ text: "Select"
1595
+ },
1596
+ multiple: false
1597
+ }).on("select", function() {
1598
+ var media = tnp_uploader.state().get("selection").first();
1599
+ document.getElementById(name + "_id").value = media.id;
1600
+ jQuery("#" + name + "_id").trigger("change");
1601
+ //alert(media.attributes.url);
1602
+ if (media.attributes.url.substring(0, 0) == "/") {
1603
+ media.attributes.url = "' . site_url('/') . '" + media.attributes.url;
1604
+ }
1605
+ document.getElementById(name + "_url").value = media.attributes.url;
1606
+
1607
+ var img_url = media.attributes.url;
1608
+ if (typeof media.attributes.sizes.medium !== "undefined") img_url = media.attributes.sizes.medium.url;
1609
+ if (img_url.substring(0, 0) == "/") {
1610
+ img_url = "' . site_url('/') . '" + img_url;
1611
+ }
1612
+ document.getElementById(name + "_img").src = img_url;
1613
+ }).open();
1614
+ }
1615
+ function newsletter_media_remove(name) {
1616
+ if (confirm("Are you sure?")) {
1617
+ document.getElementById(name + "_id").value = "";
1618
+ document.getElementById(name + "_url").value = "";
1619
+ document.getElementById(name + "_img").src = "' . plugins_url('newsletter') . '/images/nomedia.png";
1620
+ }
1621
+ }
1622
+ function newsletter_textarea_preview(id, header, footer) {
1623
+ var d = document.getElementById(id + "-iframe").contentWindow.document;
1624
+ d.open();
1625
+ if (templateEditor) {
1626
+ d.write(templateEditor.getValue());
1627
+ } else {
1628
+ d.write(header + document.getElementById(id).value + footer);
1629
+ }
1630
+ d.close();
1631
+
1632
+ var d = document.getElementById(id + "-iframe-phone").contentWindow.document;
1633
+ d.open();
1634
+ if (templateEditor) {
1635
+ d.write(templateEditor.getValue());
1636
+ } else {
1637
+ d.write(header + document.getElementById(id).value + footer);
1638
+ }
1639
+ d.close();
1640
+ //jQuery("#" + id + "-iframe-phone").toggle();
1641
+ jQuery("#" + id + "-preview").toggle();
1642
+ }
1643
+ function tnp_select_images(state) {
1644
+ if (!state.id) { return state.text; }
1645
+ var $state = jQuery("<span class=\"tnp-select2-option\"><img style=\"height: 20px!important; position: relative; top: 5px\" src=\"" + state.element.getAttribute("image") + "\"> " + state.text + "</span>");
1646
+ return $state;
1647
+ }
1648
+ function tnp_select_images_selection(state) {
1649
+ if (!state.id) { return state.text; }
1650
+ var $state = jQuery("<span class=\"tnp-select2-option\"><img style=\"height: 20px!important; position: relative; top: 5px\" src=\"" + state.element.getAttribute("image") + "\"> " + state.text + "</span>");
1651
+ return $state;
1652
+ }
1653
+
1654
+
1655
+ </script>
1656
+ ';
1657
+ echo '<input name="act" type="hidden" value=""/>';
1658
+ echo '<input name="btn" type="hidden" value=""/>';
1659
+ wp_nonce_field('save');
1660
+ }
1661
+
1662
+ function log_level($name = 'log_level') {
1663
+ $this->select($name, array(0 => 'None', 2 => 'Error', 3 => 'Normal', 4 => 'Debug'));
1664
+ }
1665
+
1666
+ function update_option($name, $data = null) {
1667
+ if ($data == null) {
1668
+ $data = $this->data;
1669
+ }
1670
+ update_option($name, $data);
1671
+ if (isset($data['log_level'])) {
1672
+ update_option($name . '_log_level', $data['log_level']);
1673
+ }
1674
+ }
1675
+
1676
+ function js_redirect($url) {
1677
+ echo '<script>';
1678
+ echo 'location.href="' . $url . '"';
1679
+ echo '</script>';
1680
+ die();
1681
+ }
1682
+
1683
+ /**
1684
+ * @deprecated
1685
+ */
1686
+ function get_test_subscribers() {
1687
+ return NewsletterUsers::instance()->get_test_users();
1688
+ }
1689
+
1690
+ /**
1691
+ * Attributes:
1692
+ * weight: [true|false]
1693
+ * color: [true|false]
1694
+ *
1695
+ * @param string $name
1696
+ * @param array $attrs
1697
+ */
1698
+ function css_font($name = 'font', $attrs = array()) {
1699
+ $default = [
1700
+ 'color' => true,
1701
+ 'weight' => true,
1702
+ 'hide_size' => false,
1703
+ 'hide_weight' => false,
1704
+ 'hide_color' => false,
1705
+ ];
1706
+ $attrs = array_merge($default, $attrs);
1707
+ $this->css_font_family($name . '_family', !empty($attrs['family_default']));
1708
+ if (!$attrs['hide_size']) {
1709
+ $this->css_font_size($name . '_size', !empty($attrs['size_default']));
1710
+ }
1711
+ if ($attrs['weight'] && !$attrs['hide_weight']) {
1712
+ $this->css_font_weight($name . '_weight', !empty($attrs['weight_default']));
1713
+ }
1714
+ if ($attrs['color'] && !$attrs['hide_color']) {
1715
+ $this->color($name . '_color');
1716
+ }
1717
+ }
1718
+
1719
+ function css_font_size($name = 'font_size', $show_empty_option = false) {
1720
+ $value = $this->get_value($name);
1721
+
1722
+ echo '<select class="tnpf-font-size" id="options-', esc_attr($name), '" name="options[', esc_attr($name), ']">';
1723
+ if ($show_empty_option) {
1724
+ echo "<option value=''>-</option>";
1725
+ }
1726
+ for ($i = 8; $i <= 50; $i++) {
1727
+ echo '<option value="' . $i . '"';
1728
+ if ($value == $i) {
1729
+ echo ' selected';
1730
+ }
1731
+ echo '>' . $i . '</option>';
1732
+ }
1733
+ echo '</select>';
1734
+ }
1735
+
1736
+ function css_font_weight($name = 'font_weight', $show_empty_option = false) {
1737
+ $value = $this->get_value($name);
1738
+
1739
+ $fonts = array('normal' => 'Normal', 'bold' => 'Bold');
1740
+
1741
+ echo '<select class="tnpf-font-weight" id="options-' . esc_attr($name) . '" name="options[' . esc_attr($name) . ']">';
1742
+ if ($show_empty_option) {
1743
+ echo "<option value=''>-</option>";
1744
+ }
1745
+ foreach ($fonts as $key => $font) {
1746
+ echo '<option value="', esc_attr($key), '"';
1747
+ if ($value == $key) {
1748
+ echo ' selected';
1749
+ }
1750
+ echo '>', esc_html($font), '</option>';
1751
+ }
1752
+ echo '</select>';
1753
+ }
1754
+
1755
+ function css_font_family($name = 'font_family', $show_empty_option = false) {
1756
+ $value = $this->get_value($name);
1757
+
1758
+ $fonts = [];
1759
+ if ($show_empty_option) {
1760
+ $fonts[''] = 'Default';
1761
+ }
1762
+
1763
+ $fonts = array_merge($fonts, ['Helvetica, Arial, sans-serif' => 'Helvetica, Arial',
1764
+ 'Arial Black, Gadget, sans-serif' => 'Arial Black, Gadget',
1765
+ 'Garamond, serif' => 'Garamond',
1766
+ 'Courier, monospace' => 'Courier',
1767
+ 'Comic Sans MS, cursive' => 'Comic Sans MS',
1768
+ 'Impact, Charcoal, sans-serif' => 'Impact, Charcoal',
1769
+ 'Tahoma, Geneva, sans-serif' => 'Tahoma, Geneva',
1770
+ 'Times New Roman, Times, serif' => 'Times New Roman',
1771
+ 'Verdana, Geneva, sans-serif' => 'Verdana, Geneva']);
1772
+
1773
+ echo '<select class="tnpf-font-family" id="options-', esc_attr($name), '" name="options[', esc_attr($name), ']">';
1774
+ foreach ($fonts as $font => $label) {
1775
+ echo '<option value="', esc_attr($font), '"';
1776
+ if ($value == $font) {
1777
+ echo ' selected';
1778
+ }
1779
+ echo '>', esc_html($label), '</option>';
1780
+ }
1781
+ echo '</select>';
1782
+ }
1783
+
1784
+ function css_text_align($name) {
1785
+ $options = array('left' => __('Left', 'newsletter'), 'right' => __('Right', 'newsletter'),
1786
+ 'center' => __('Center', 'newsletter'));
1787
+ $this->select($name, $options);
1788
+ }
1789
+
1790
+ function css_border($name) {
1791
+ $value = $this->get_value($name . '_width');
1792
+
1793
+ echo 'width&nbsp;<select id="options-' . esc_attr($name) . '-width" name="options[' . esc_attr($name) . '_width]">';
1794
+ for ($i = 0; $i < 10; $i++) {
1795
+ echo '<option value="' . $i . '"';
1796
+ if ($value == $i) {
1797
+ echo ' selected';
1798
+ }
1799
+ echo '>' . $i . '</option>';
1800
+ }
1801
+ echo '</select>&nbsp;px&nbsp;&nbsp;';
1802
+
1803
+ $this->select($name . '_type', array('solid' => 'Solid', 'dashed' => 'Dashed'));
1804
+
1805
+ $this->color($name . '_color');
1806
+
1807
+ $value = $this->get_value($name . '_radius');
1808
+
1809
+ echo '&nbsp;&nbsp;radius&nbsp;<select id="options-' . esc_attr($name) . '-radius" name="options[' . esc_attr($name) . '_radius]">';
1810
+ for ($i = 0; $i < 10; $i++) {
1811
+ echo '<option value="' . $i . '"';
1812
+ if ($value == $i) {
1813
+ echo ' selected';
1814
+ }
1815
+ echo '>' . $i . '</option>';
1816
+ }
1817
+ echo '</select>&nbsp;px';
1818
+ }
1819
+
1820
+ /**
1821
+ * Media selector using the media library of WP. Produces a field which values is an array containing 'id' and 'url'.
1822
+ *
1823
+ * @param string $name
1824
+ */
1825
+ function media($name) {
1826
+ if (isset($this->data[$name]['id'])) {
1827
+ $media_id = (int) $this->data[$name]['id'];
1828
+ $media = wp_get_attachment_image_src($media_id, 'medium');
1829
+ $media_full = wp_get_attachment_image_src($media_id, 'full');
1830
+ } else {
1831
+ $media = false;
1832
+ }
1833
+ echo '<div style="position: relative">';
1834
+ echo '<a style="position: absolute; top: 5px; right: 5px; background-color: none; color: #000; padding: 0px 5px 6px 5px; font-size: 24px; display: block; text-decoration: none" href="#" onclick="newsletter_media_remove(\'' . esc_attr($name) . '\'); return false">&times;</a>';
1835
+ if ($media === false) {
1836
+ $media = array('', '', '');
1837
+ $media_full = array('', '', '');
1838
+ $media_id = 0;
1839
+ echo '<img style="max-width: 200px; max-height: 150px; width: 100px;" id="' . esc_attr($name) . '_img" src="' . plugins_url('newsletter') . '/images/nomedia.png" onclick="newsletter_media(\'' . esc_attr($name) . '\')">';
1840
+ } else {
1841
+ echo '<img style="max-width: 200px; max-height: 150px;" id="' . esc_attr($name) . '_img" src="' . esc_attr($media[0]) . '" onclick="newsletter_media(\'' . esc_attr($name) . '\')">';
1842
+ }
1843
+
1844
+ echo '</div>';
1845
+ echo '<input type="hidden" id="' . esc_attr($name) . '_id" name="options[' . esc_attr($name) . '][id]" value="' . esc_attr($media_id) . '" size="5">';
1846
+ echo '<input type="hidden" id="' . esc_attr($name) . '_url" name="options[' . esc_attr($name) . '][url]" value="' . esc_attr($media_full[0]) . '" size="50">';
1847
+ }
1848
+
1849
+ function media_input($option, $name, $label) {
1850
+
1851
+ if (!empty($label)) {
1852
+ $output = '<label class="select" for="tnp_' . esc_attr($name) . '">' . esc_html($label) . ':</label>';
1853
+ }
1854
+ $output .= '<input id="tnp_' . esc_attr($name) . '" type="text" size="36" name="' . esc_attr($option) . '[' . esc_attr($name) . ']" value="' . esc_attr($val) . '" />';
1855
+ $output .= '<input id="tnp_' . esc_attr($name) . '_button" class="button-primary" type="button" value="Select Image" />';
1856
+ $output .= '<br class="clear"/>';
1857
+
1858
+ echo $output;
1859
+ }
1860
+
1861
+ function language($name = 'language', $empty_label = 'All') {
1862
+ if (!class_exists('SitePress') && !function_exists('pll_default_language') && !class_exists('TRP_Translate_Press')) {
1863
+ echo __('Install a multilanguage plugin.', 'newsletter');
1864
+ echo ' <a href="https://www.thenewsletterplugin.com/documentation/multilanguage" target="_blank">', __('Read more', 'newsletter'), '</a>';
1865
+ return;
1866
+ }
1867
+
1868
+ $languages = Newsletter::instance()->get_languages();
1869
+ if (!empty($empty_label)) {
1870
+ $languages = array_merge(array('' => $empty_label), $languages);
1871
+ }
1872
+ $this->select($name, $languages);
1873
+ }
1874
+
1875
+ function is_multilanguage() {
1876
+ return Newsletter::instance()->is_multilanguage();
1877
+ }
1878
+
1879
+ /**
1880
+ * Creates a checkbox group with all active languages. Each checkbox is named
1881
+ * $name[] and values with the relative language code.
1882
+ *
1883
+ * @param string $name
1884
+ */
1885
+ function languages($name = 'languages') {
1886
+ if (!$this->is_multilanguage()) {
1887
+ echo __('Install WPML or Polylang for multilanguage support', 'newsletter');
1888
+ return;
1889
+ }
1890
+
1891
+ $language_options = Newsletter::instance()->get_languages();
1892
+
1893
+ if (empty($language_options)) {
1894
+ echo __('Your multilanguage plugin is not supported or there are no languages defined', 'newsletter');
1895
+ return;
1896
+ }
1897
+
1898
+ $this->checkboxes_group($name, $language_options);
1899
+ }
1900
+
1901
+ /**
1902
+ * Prints a formatted date using the formats and timezone of WP, including the current date and time and the
1903
+ * time left to the passed time.
1904
+ *
1905
+ * @param int $time
1906
+ * @param int $now
1907
+ * @param bool $left
1908
+ * @return string
1909
+ */
1910
+ static function print_date($time = null, $now = false, $left = false) {
1911
+ if (is_null($time)) {
1912
+ $time = time();
1913
+ }
1914
+ if ($time == false) {
1915
+ $buffer = 'none';
1916
+ } else {
1917
+ $buffer = date_i18n(get_option('date_format') . ' ' . get_option('time_format'), $time + get_option('gmt_offset') * 3600);
1918
+
1919
+ if ($now) {
1920
+ $buffer .= ' (now: ' . gmdate(get_option('date_format') . ' ' .
1921
+ get_option('time_format'), time() + get_option('gmt_offset') * 3600);
1922
+ $buffer .= ')';
1923
+ }
1924
+ if ($left) {
1925
+ if ($time - time() < 0) {
1926
+ $buffer .= ', ' . (time() - $time) . ' seconds late';
1927
+ } else {
1928
+ $buffer .= ', ' . gmdate('H:i:s', $time - time()) . ' left';
1929
+ }
1930
+ }
1931
+ }
1932
+ return $buffer;
1933
+ }
1934
+
1935
+ static function delta_time($delta = 0) {
1936
+ $seconds = $delta % 60;
1937
+ $minutes = floor(($delta / 60) % 60);
1938
+ $hours = floor(($delta / (60 * 60)) % 24);
1939
+ $days = floor($delta / (24 * 60 * 60));
1940
+
1941
+ return $days . ' day(s), ' . $hours . ' hour(s), ' . $minutes . ' minute(s)';
1942
+ }
1943
+
1944
+ /**
1945
+ * Prints the help button near a form field. The label is used as icon title.
1946
+ *
1947
+ * @param string $url
1948
+ * @param string $label
1949
+ */
1950
+ static function help($url, $label = '') {
1951
+ echo '<a href="', $url, '" target="_blank" title="', esc_attr($label), '"><i class="fas fa-question-circle"></i></a>';
1952
+ }
1953
+
1954
+ static function idea($url, $label = '') {
1955
+ echo '<a href="', $url, '" target="_blank" title="', esc_attr($label), '"><i class="fas fa-lightbulb-o"></i></a>';
1956
+ }
1957
+
1958
+ static function field_help($url, $text = '') {
1959
+ if (strpos($url, 'http') !== 0) {
1960
+ $url = 'https://www.thenewsletterplugin.com' . $url;
1961
+ }
1962
+ echo '<a href="', $url, '" target="_blank" style="text-decoration: none" title="' . esc_attr(__('Read more', 'newsletter')) . '"><i class="fas fa-question-circle"></i>';
1963
+ if ($text)
1964
+ echo '&nbsp;', $text;
1965
+ echo '</a>';
1966
+ }
1967
+
1968
+ static function field_label($label, $help_url = false) {
1969
+ echo $label;
1970
+ if ($help_url) {
1971
+ echo '&nbsp';
1972
+ self::field_help($help_url);
1973
+ }
1974
+ }
1975
+
1976
+ /**
1977
+ * Prints a panel link to the documentation.
1978
+ *
1979
+ * @param type $url
1980
+ * @param type $text
1981
+ */
1982
+ static function panel_help($url, $text = '') {
1983
+ if (empty($text))
1984
+ $text = __('Need help?', 'newsletter');
1985
+ echo '<span class="tnp-panel-help"><a href="', $url, '" target="_blank">', $text, '</a></span>';
1986
+ }
1987
+
1988
+ /**
1989
+ * Prints an administration page link to the documentation (just under the administration page title.
1990
+ * @param type $url
1991
+ * @param type $text
1992
+ */
1993
+ static function page_help($url, $text = '') {
1994
+ if (empty($text))
1995
+ $text = __('Need help?', 'newsletter');
1996
+ echo '<div class="tnp-page-help"><a href="', $url, '" target="_blank">', $text, '</a></div>';
1997
+ }
1998
+
1999
+ static function print_truncated($text, $size = 50) {
2000
+ if (mb_strlen($text) < $size)
2001
+ return esc_html($text);
2002
+ $sub = mb_substr($text, 0, $size);
2003
+ echo '<span title="', esc_attr($text), '">', esc_html($sub), '...</span>';
2004
+ }
2005
+
2006
+ function block_background($name = 'block_background') {
2007
+ $this->color($name);
2008
+ }
2009
+
2010
+ function block_padding($name = 'block_padding', $options = array()) {
2011
+ echo '<div style="text-align: center; width: 250px;">';
2012
+ $this->text($name . '_top', 5);
2013
+ echo '<br>';
2014
+ $this->text($name . '_left', 5);
2015
+ echo "&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;";
2016
+ $this->text($name . '_right', 5);
2017
+ echo '<br>';
2018
+ $this->text($name . '_bottom', 5);
2019
+ echo '</div>';
2020
+ }
2021
+
2022
+ /**
2023
+ * Adds the fields used by the composer (version 1) in the page form.
2024
+ *
2025
+ * @param type $name
2026
+ */
2027
+ function composer_fields($name = 'body') {
2028
+
2029
+ // body
2030
+ $value = $this->get_value($name);
2031
+
2032
+ // Extracts only the body part
2033
+ $x = strpos($value, '<body');
2034
+ if ($x) {
2035
+ $x = strpos($value, '>', $x);
2036
+ $y = strpos($value, '</body>');
2037
+ $value = substr($value, $x + 1, $y - $x - 1);
2038
+ }
2039
+
2040
+ /* Cleans up uncorrectly stored newsletter bodies */
2041
+ $value = preg_replace('/<style\s+.*?>.*?<\\/style>/is', '', $value);
2042
+ $value = preg_replace('/<meta.*?>/', '', $value);
2043
+ $value = preg_replace('/<title\s+.*?>.*?<\\/title>/i', '', $value);
2044
+ $value = trim($value);
2045
+
2046
+ // Required since esc_html DOES NOT escape the HTML entities (apparently)
2047
+ $value = str_replace('&', '&amp;', $value);
2048
+ $value = str_replace('"', '&quot;', $value);
2049
+ $value = str_replace('<', '&lt;', $value);
2050
+ $value = str_replace('>', '&gt;', $value);
2051
+ echo '<input type="hidden" name="options[', esc_attr($name), ']" id="options-', esc_attr($name), '" value="', esc_attr($value), '">';
2052
+
2053
+ // Used by composer to rebuild the full HTML
2054
+ $css = NewsletterEmails::instance()->get_composer_css();
2055
+ echo '<input type="hidden" name="options[css]" id="options-css" value="', esc_attr($css), '">';
2056
+
2057
+ // subject
2058
+ $value = $this->get_value('subject');
2059
+ echo '<input type="hidden" name="options[subject]" id="options-subject" value="', esc_attr($value), '">';
2060
+ }
2061
+
2062
+ function composer_load($name = 'body', $show_subject = false, $show_test = true, $context_type = '') {
2063
+
2064
+ global $controls;
2065
+ global $tnpc_show_subject;
2066
+ $tnpc_show_subject = $show_subject;
2067
+
2068
+ wp_enqueue_style('tnpc-style', plugins_url('newsletter') . '/emails/tnp-composer/_css/newsletter-builder.css', array(), time());
2069
+
2070
+ include NEWSLETTER_DIR . '/emails/tnp-composer/index.php';
2071
+ }
2072
+
2073
+ /**
2074
+ * Adds the fields used by the composer (version 2) in the page form.
2075
+ */
2076
+ function composer_fields_v2($name = 'message') {
2077
+
2078
+ // The composer, on saving, fills in those fields
2079
+ $this->hidden('subject');
2080
+ $this->hidden('message');
2081
+ $this->hidden('options_preheader');
2082
+ $this->hidden('updated');
2083
+
2084
+ //$preheader_value = $this->get_value('options_preheader');
2085
+ // echo '<input name="options[preheader]" id="options-preheader" type="hidden" value="', esc_attr($preheader_value), '">';
2086
+ }
2087
+
2088
+ function composer_load_v2($show_subject = false, $show_test = true, $context_type = '') {
2089
+
2090
+ global $tnpc_show_subject;
2091
+ $tnpc_show_subject = $show_subject;
2092
+
2093
+ echo "<link href='", plugins_url('newsletter'), "/emails/tnp-composer/_css/newsletter-builder-v2.css?ver=" . NEWSLETTER_VERSION . "' rel='stylesheet' type='text/css'>";
2094
+
2095
+ $controls = $this;
2096
+ include NEWSLETTER_DIR . '/emails/tnp-composer/index-v2.php';
2097
+ }
2098
+
2099
+ function subject($name) {
2100
+ $value = $this->get_value($name);
2101
+ // Leave the ID with this prefix!
2102
+ echo '<div style="position: relative"><input size="80" id="options-subject-', esc_attr($name), '" name="options[' . esc_attr($name) . ']" type="text" placeholder="" value="';
2103
+ echo esc_attr($value);
2104
+ echo '">';
2105
+ echo '&nbsp;<i class="far fa-lightbulb tnp-suggest-subject" data-tnp-modal-target="#subject-ideas-modal"></i>';
2106
+
2107
+ echo '<img src="', plugins_url('newsletter'), '/admin/images/subject/android.png" style="position: absolute; width: 16px; left: 330px; top: 25px; display: block; opacity: 0">';
2108
+ echo '<img src="', plugins_url('newsletter'), '/admin/images/subject/iphone.png" style="position: absolute; width: 16px; left: 380px; top: 25px; display: block; opacity: 0">';
2109
+ echo '</div>';
2110
+ }
2111
+
2112
+ }
includes/helper.php CHANGED
@@ -1,412 +1,417 @@
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, $characters = false) {
52
- if (!$length) return '';
53
-
54
- $excerpt = get_the_excerpt($post->ID);
55
- $excerpt = tnp_delete_all_shordcodes_tags($excerpt);
56
- $excerpt = trim($excerpt);
57
- $excerpt = str_replace('&nbsp;', '', $excerpt);
58
-
59
- if ($characters) {
60
- if (strlen($excerpt) > $length) {
61
- $excerpt = substr($excerpt, 0, $length);
62
- $i = strrpos($excerpt, ' ');
63
- if ($i) {
64
- $excerpt = substr($excerpt, 0, $i);
65
- $excerpt .= '&hellip;';
66
- }
67
- }
68
- } else {
69
- $excerpt = wp_trim_words($excerpt, $length);
70
- }
71
-
72
- return $excerpt;
73
- }
74
-
75
- function tnp_delete_all_shordcodes_tags($post_content = '') {
76
- //Delete open tags
77
- $post_content = preg_replace("/\[[a-zA-Z0-9_-]*?(\s.*?)?\]/", '', $post_content);
78
- //Delete close tags
79
- $post_content = preg_replace("/\[\/[a-zA-Z0-9_-]*?\]/", '', $post_content);
80
-
81
- return $post_content;
82
- }
83
-
84
- function tnp_post_permalink($post) {
85
- return get_permalink($post->ID);
86
- }
87
-
88
- function tnp_post_content($post) {
89
- return $post->post_content;
90
- }
91
-
92
- function tnp_post_title($post) {
93
- return $post->post_title;
94
- }
95
-
96
- function tnp_post_date($post, $format = null) {
97
- if (empty($format)) {
98
- $format = get_option('date_format');
99
- }
100
- return mysql2date($format, $post->post_date);
101
- }
102
-
103
- /**
104
- * Tries to create a resized version of a media uploaded to the media library.
105
- * Returns an empty string if the media does not exists or generally if the attached file
106
- * cannot be found. If the resize fails for whatever reason, fall backs to the
107
- * standard image source returned by WP which is usually not exactly the
108
- * requested size.
109
- *
110
- * @param int $media_id
111
- * @param array $size
112
- * @return string
113
- */
114
- function tnp_media_resize($media_id, $size) {
115
- if (empty($media_id)) {
116
- return '';
117
- }
118
-
119
- $relative_file = get_post_meta($media_id, '_wp_attached_file', true);
120
- if (empty($relative_file)) {
121
- return '';
122
- }
123
-
124
- $width = $size[0];
125
- $height = $size[1];
126
- $crop = false;
127
- if (isset($size[2])) {
128
- $crop = (boolean) $size[2];
129
- }
130
-
131
- $uploads = wp_upload_dir();
132
-
133
- // Based on _wp_relative_upload_path() function for blog which store the
134
- // full patch of media files
135
- if (0 === strpos($relative_file, $uploads['basedir'])) {
136
- $relative_file = str_replace($uploads['basedir'], '', $relative_file);
137
- $relative_file = ltrim($relative_file, '/');
138
- }
139
-
140
- $absolute_file = $uploads['basedir'] . '/' . $relative_file;
141
- // Relative and absolute name of the thumbnail.
142
- $pathinfo = pathinfo($relative_file);
143
-
144
- // We don't know why, but on some systems files with non-ascii characters loose the file name (grrr...)
145
- if (empty($pathinfo['filename'])) {
146
- $src = wp_get_attachment_image_src($media_id, 'full');
147
- return $src[0];
148
- }
149
-
150
- $relative_thumb = $pathinfo['dirname'] . '/' . $pathinfo['filename'] . '-' . $width . 'x' .
151
- $height . ($crop ? '-c' : '') . '.' . $pathinfo['extension'];
152
- $absolute_thumb = $uploads['basedir'] . '/newsletter/thumbnails/' . $relative_thumb;
153
-
154
- // Thumbnail generation if needed.
155
- if (!file_exists($absolute_thumb) || filemtime($absolute_thumb) < filemtime($absolute_file)) {
156
- $r = wp_mkdir_p($uploads['basedir'] . '/newsletter/thumbnails/' . $pathinfo['dirname']);
157
-
158
- if (!$r) {
159
- $src = wp_get_attachment_image_src($media_id, 'full');
160
- return $src[0];
161
- }
162
-
163
- $editor = wp_get_image_editor($absolute_file);
164
- if (is_wp_error($editor)) {
165
- $src = wp_get_attachment_image_src($media_id, 'full');
166
- return $src[0];
167
- //return $editor;
168
- //return $uploads['baseurl'] . '/' . $relative_file;
169
- }
170
-
171
- $original_size = $editor->get_size();
172
- if ($width > $original_size['width'] || $height > $original_size['height']) {
173
- $src = wp_get_attachment_image_src($media_id, 'full');
174
- return $src[0];
175
- }
176
-
177
- $editor->set_quality(80);
178
- $resized = $editor->resize($width, $height, $crop);
179
-
180
- if (is_wp_error($resized)) {
181
- $src = wp_get_attachment_image_src($media_id, 'full');
182
- return $src[0];
183
- }
184
-
185
- $saved = $editor->save($absolute_thumb);
186
- if (is_wp_error($saved)) {
187
- $src = wp_get_attachment_image_src($media_id, 'full');
188
- return $src[0];
189
- //return $saved;
190
- //return $uploads['baseurl'] . '/' . $relative_file;
191
- }
192
- }
193
-
194
- return $uploads['baseurl'] . '/newsletter/thumbnails/' . $relative_thumb;
195
- }
196
-
197
- function _tnp_get_default_media($media_id, $size) {
198
-
199
- $src = wp_get_attachment_image_src($media_id, $size);
200
- if (!$src) {
201
- return null;
202
- }
203
- $media = new TNP_Media();
204
- $media->id = $media_id;
205
- $media->url = $src[0];
206
- $media->width = $src[1];
207
- $media->height = $src[2];
208
- return $media;
209
- }
210
-
211
- function tnp_get_media($media_id, $size) {
212
- $src = wp_get_attachment_image_src($media_id, $size);
213
- if (!$src) {
214
- return null;
215
- }
216
- $media = new TNP_Media();
217
- $media->id = $media_id;
218
- $media->url = $src[0];
219
- $media->width = $src[1];
220
- $media->height = $src[2];
221
- return $media;
222
- }
223
-
224
- /**
225
- * Create a resized version of the media stored in the WP media library.
226
- *
227
- * @param int $media_id
228
- * @param array $size
229
- * @return TNP_Media
230
- */
231
- function tnp_resize($media_id, $size) {
232
- if (empty($media_id)) {
233
- return null;
234
- }
235
-
236
- $relative_file = get_post_meta($media_id, '_wp_attached_file', true);
237
-
238
- if (empty($relative_file)) {
239
- return null;
240
- }
241
-
242
- $uploads = wp_upload_dir();
243
-
244
- // Based on _wp_relative_upload_path() function for blog which store the
245
- // full patch of media files
246
- if (0 === strpos($relative_file, $uploads['basedir'])) {
247
- $relative_file = str_replace($uploads['basedir'], '', $relative_file);
248
- $relative_file = ltrim($relative_file, '/');
249
- }
250
-
251
- $width = $size[0];
252
- $height = $size[1];
253
- $crop = false;
254
- if (isset($size[2])) {
255
- $crop = (boolean) $size[2];
256
- }
257
-
258
- $absolute_file = $uploads['basedir'] . '/' . $relative_file;
259
-
260
- if (substr($relative_file, -4) === '.gif') {
261
- $editor = wp_get_image_editor($absolute_file);
262
- if (is_wp_error($editor)) {
263
- return _tnp_get_default_media($media_id, $size);
264
- }
265
- $new_size = $editor->get_size();
266
- $media = new TNP_Media();
267
- $media->id = $media_id;
268
- $media->width = $new_size['width'];
269
- $media->height = $new_size['height'];
270
- if ($media->width > $width) {
271
- $media->set_width($width);
272
- }
273
- $media->url = $uploads['baseurl'] . '/' . $relative_file;
274
- return $media;
275
- }
276
-
277
- // Relative and absolute name of the thumbnail.
278
- $pathinfo = pathinfo($relative_file);
279
-
280
- // We don't know why, but on some systems files with non-ascii characters loose the file name (grrr...)
281
- if (empty($pathinfo['filename'])) {
282
- return _tnp_get_default_media($media_id, $size);
283
- }
284
-
285
- $relative_thumb = $pathinfo['dirname'] . '/' . $pathinfo['filename'] . '-' . $width . 'x' . $height . ($crop ? '-c' : '') . '.' . $pathinfo['extension'];
286
- $absolute_thumb = $uploads['basedir'] . '/newsletter/thumbnails/' . $relative_thumb;
287
-
288
- // Thumbnail generation if needed.
289
- if (!file_exists($absolute_thumb) || filemtime($absolute_thumb) < filemtime($absolute_file)) {
290
- $r = wp_mkdir_p($uploads['basedir'] . '/newsletter/thumbnails/' . $pathinfo['dirname']);
291
-
292
- if (!$r) {
293
- Newsletter::instance()->logger->error('Unable to create dir ' . $uploads['basedir'] . '/newsletter/thumbnails/' . $pathinfo['dirname']);
294
- return _tnp_get_default_media($media_id, $size);
295
- }
296
-
297
- $editor = wp_get_image_editor($absolute_file);
298
- if (is_wp_error($editor)) {
299
- Newsletter::instance()->logger->error($editor);
300
- Newsletter::instance()->logger->error('File: ' . $absolute_file);
301
- return _tnp_get_default_media($media_id, $size);
302
- }
303
-
304
- $original_size = $editor->get_size();
305
- if ($width > $original_size['width'] && $height > $original_size['height']) {
306
- Newsletter::instance()->logger->error('Requested size larger than the original one');
307
- return _tnp_get_default_media($media_id, $size);
308
- }
309
-
310
- $editor->set_quality(85);
311
- $resized = $editor->resize($width, $height, $crop);
312
-
313
- if (is_wp_error($resized)) {
314
- Newsletter::instance()->logger->error($resized);
315
- Newsletter::instance()->logger->error('File: ' . $absolute_file);
316
- return _tnp_get_default_media($media_id, $size);
317
- }
318
-
319
- $saved = $editor->save($absolute_thumb);
320
- if (is_wp_error($saved)) {
321
- Newsletter::instance()->logger->error($saved);
322
- return _tnp_get_default_media($media_id, $size);
323
- }
324
- $new_size = $editor->get_size();
325
-
326
- $media = new TNP_Media();
327
- $media->width = $new_size['width'];
328
- $media->height = $new_size['height'];
329
- $media->url = $uploads['baseurl'] . '/newsletter/thumbnails/' . $relative_thumb;
330
- } else {
331
- $media = new TNP_Media();
332
- $new_size = getimagesize($absolute_thumb);
333
- $media->width = $new_size[0];
334
- $media->height = $new_size[1];
335
- $media->url = $uploads['baseurl'] . '/newsletter/thumbnails/' . $relative_thumb;
336
- }
337
-
338
- return $media;
339
- }
340
-
341
- function tnp_resize_2x($media_id, $size) {
342
- $size[0] = $size[0] * 2;
343
- $size[1] = $size[1] * 2;
344
- $media = tnp_resize($media_id, $size);
345
- if (!$media)
346
- return $media;
347
- $media->set_width($size[0] / 2);
348
- return $media;
349
- }
350
-
351
- /**
352
- * @param TNP_Media[] $images
353
- *
354
- * @return int
355
- */
356
- function tnp_get_max_height_of($images) {
357
- $max_height = 0;
358
- foreach ($images as $image) {
359
- $max_height = $image->height > $max_height ? $image->height : $max_height;
360
- }
361
-
362
- return $max_height;
363
- }
364
-
365
- /**
366
- * @param WP_Post[] $product_list
367
- * @param array $size
368
- *
369
- * @return TNP_Media[]
370
- */
371
- function tnp_resize_product_list_featured_image($product_list, $size) {
372
- $images = [];
373
- foreach ($product_list as $p) {
374
- $images[$p->ID] = tnp_resize_2x(TNP_Composer::get_post_thumbnail_id($p->ID), $size);
375
- }
376
-
377
- return $images;
378
- }
379
-
380
- /**
381
- * Get media for "posts" composer block
382
- *
383
- * @param WP_Post post
384
- * @param array $size
385
- * @param string $default_image_url
386
- *
387
- * @return TNP_Media
388
- */
389
- function tnp_composer_block_posts_get_media($post, $size, $default_image_url = null) {
390
- $post_thumbnail_id = TNP_Composer::get_post_thumbnail_id($post);
391
-
392
- $media = null;
393
-
394
- if (!empty($post_thumbnail_id)) {
395
- $media = tnp_resize($post_thumbnail_id, array_values($size));
396
- } else if ($default_image_url) {
397
- Newsletter::instance()->logger->error('Thumbnail id not found');
398
- $media = new TNP_Media();
399
- $media->url = $default_image_url;
400
- $media->width = $size['width'];
401
- $media->height = $size['height'];
402
- }
403
- return $media;
404
- }
405
-
406
- function tnp_outlook_wrapper_open($width = 600) {
407
- return NewsletterEmails::get_outlook_wrapper_open($width);
408
- }
409
-
410
- function tnp_outlook_wrapper_close() {
411
- return NewsletterEmails::get_outlook_wrapper_close();
412
- }
 
 
 
 
 
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, $characters = false) {
52
+ if (!$length) return '';
53
+
54
+ $excerpt = get_the_excerpt($post->ID);
55
+ $excerpt = tnp_delete_all_shordcodes_tags($excerpt);
56
+ $excerpt = trim($excerpt);
57
+ $excerpt = str_replace('&nbsp;', '', $excerpt);
58
+
59
+ if ($characters) {
60
+ if (strlen($excerpt) > $length) {
61
+ $excerpt = substr($excerpt, 0, $length);
62
+ $i = strrpos($excerpt, ' ');
63
+ if ($i) {
64
+ $excerpt = substr($excerpt, 0, $i);
65
+ $excerpt .= '&hellip;';
66
+ }
67
+ }
68
+ } else {
69
+ $excerpt = wp_trim_words($excerpt, $length);
70
+ }
71
+
72
+ return $excerpt;
73
+ }
74
+
75
+ function tnp_delete_all_shordcodes_tags($post_content = '') {
76
+ //Delete open tags
77
+ $post_content = preg_replace("/\[[a-zA-Z0-9_-]*?(\s.*?)?\]/", '', $post_content);
78
+ //Delete close tags
79
+ $post_content = preg_replace("/\[\/[a-zA-Z0-9_-]*?\]/", '', $post_content);
80
+
81
+ return $post_content;
82
+ }
83
+
84
+ function tnp_post_permalink($post) {
85
+ return get_permalink($post->ID);
86
+ }
87
+
88
+ function tnp_post_content($post) {
89
+ return $post->post_content;
90
+ }
91
+
92
+ function tnp_post_title($post) {
93
+ return $post->post_title;
94
+ }
95
+
96
+ function tnp_post_date($post, $format = null) {
97
+ if (empty($format)) {
98
+ $format = get_option('date_format');
99
+ }
100
+ return mysql2date($format, $post->post_date);
101
+ }
102
+
103
+ /**
104
+ * Tries to create a resized version of a media uploaded to the media library.
105
+ * Returns an empty string if the media does not exists or generally if the attached file
106
+ * cannot be found. If the resize fails for whatever reason, fall backs to the
107
+ * standard image source returned by WP which is usually not exactly the
108
+ * requested size.
109
+ *
110
+ * @param int $media_id
111
+ * @param array $size
112
+ * @return string
113
+ */
114
+ function tnp_media_resize($media_id, $size) {
115
+ if (empty($media_id)) {
116
+ return '';
117
+ }
118
+
119
+ $relative_file = get_post_meta($media_id, '_wp_attached_file', true);
120
+ if (empty($relative_file)) {
121
+ return '';
122
+ }
123
+
124
+ $width = $size[0];
125
+ $height = $size[1];
126
+ $crop = false;
127
+ if (isset($size[2])) {
128
+ $crop = (boolean) $size[2];
129
+ }
130
+
131
+ $uploads = wp_upload_dir();
132
+
133
+ // Based on _wp_relative_upload_path() function for blog which store the
134
+ // full patch of media files
135
+ if (0 === strpos($relative_file, $uploads['basedir'])) {
136
+ $relative_file = str_replace($uploads['basedir'], '', $relative_file);
137
+ $relative_file = ltrim($relative_file, '/');
138
+ }
139
+
140
+ $absolute_file = $uploads['basedir'] . '/' . $relative_file;
141
+ // Relative and absolute name of the thumbnail.
142
+ $pathinfo = pathinfo($relative_file);
143
+
144
+ // We don't know why, but on some systems files with non-ascii characters loose the file name (grrr...)
145
+ if (empty($pathinfo['filename'])) {
146
+ $src = wp_get_attachment_image_src($media_id, 'full');
147
+ return $src[0];
148
+ }
149
+
150
+ $relative_thumb = $pathinfo['dirname'] . '/' . $pathinfo['filename'] . '-' . $width . 'x' .
151
+ $height . ($crop ? '-c' : '') . '.' . $pathinfo['extension'];
152
+ $absolute_thumb = $uploads['basedir'] . '/newsletter/thumbnails/' . $relative_thumb;
153
+
154
+ // Thumbnail generation if needed.
155
+ if (!file_exists($absolute_thumb) || filemtime($absolute_thumb) < filemtime($absolute_file)) {
156
+ $r = wp_mkdir_p($uploads['basedir'] . '/newsletter/thumbnails/' . $pathinfo['dirname']);
157
+
158
+ if (!$r) {
159
+ $src = wp_get_attachment_image_src($media_id, 'full');
160
+ return $src[0];
161
+ }
162
+
163
+ $editor = wp_get_image_editor($absolute_file);
164
+ if (is_wp_error($editor)) {
165
+ $src = wp_get_attachment_image_src($media_id, 'full');
166
+ return $src[0];
167
+ //return $editor;
168
+ //return $uploads['baseurl'] . '/' . $relative_file;
169
+ }
170
+
171
+ $original_size = $editor->get_size();
172
+ if ($width > $original_size['width'] || $height > $original_size['height']) {
173
+ $src = wp_get_attachment_image_src($media_id, 'full');
174
+ return $src[0];
175
+ }
176
+
177
+ $editor->set_quality(80);
178
+ $resized = $editor->resize($width, $height, $crop);
179
+
180
+ if (is_wp_error($resized)) {
181
+ $src = wp_get_attachment_image_src($media_id, 'full');
182
+ return $src[0];
183
+ }
184
+
185
+ $saved = $editor->save($absolute_thumb);
186
+ if (is_wp_error($saved)) {
187
+ $src = wp_get_attachment_image_src($media_id, 'full');
188
+ return $src[0];
189
+ //return $saved;
190
+ //return $uploads['baseurl'] . '/' . $relative_file;
191
+ }
192
+ }
193
+
194
+ return $uploads['baseurl'] . '/newsletter/thumbnails/' . $relative_thumb;
195
+ }
196
+
197
+ function _tnp_get_default_media($media_id, $size) {
198
+
199
+ $src = wp_get_attachment_image_src($media_id, $size);
200
+ if (!$src) {
201
+ return null;
202
+ }
203
+ $media = new TNP_Media();
204
+ $media->id = $media_id;
205
+ $media->url = $src[0];
206
+ $media->width = $src[1];
207
+ $media->height = $src[2];
208
+ return $media;
209
+ }
210
+
211
+ function tnp_get_media($media_id, $size) {
212
+ $src = wp_get_attachment_image_src($media_id, $size);
213
+ if (!$src) {
214
+ return null;
215
+ }
216
+ $media = new TNP_Media();
217
+ $media->id = $media_id;
218
+ $media->url = $src[0];
219
+ $media->width = $src[1];
220
+ $media->height = $src[2];
221
+ return $media;
222
+ }
223
+
224
+ /**
225
+ * Create a resized version of the media stored in the WP media library.
226
+ *
227
+ * @param int $media_id
228
+ * @param array $size
229
+ * @return TNP_Media
230
+ */
231
+ function tnp_resize($media_id, $size) {
232
+ if (empty($media_id)) {
233
+ return null;
234
+ }
235
+
236
+ $relative_file = get_post_meta($media_id, '_wp_attached_file', true);
237
+
238
+ if (empty($relative_file)) {
239
+ return null;
240
+ }
241
+
242
+ $uploads = wp_upload_dir();
243
+
244
+ // Based on _wp_relative_upload_path() function for blog which store the
245
+ // full path of media files
246
+ if (0 === strpos($relative_file, $uploads['basedir'])) {
247
+ $relative_file = str_replace($uploads['basedir'], '', $relative_file);
248
+ $relative_file = ltrim($relative_file, '/');
249
+ }
250
+
251
+ $width = $size[0];
252
+ $height = $size[1];
253
+ $crop = false;
254
+ if (isset($size[2])) {
255
+ $crop = (boolean) $size[2];
256
+ }
257
+
258
+ $absolute_file = $uploads['basedir'] . '/' . $relative_file;
259
+
260
+ if (substr($relative_file, -4) === '.gif') {
261
+ $editor = wp_get_image_editor($absolute_file);
262
+ if (is_wp_error($editor)) {
263
+ return _tnp_get_default_media($media_id, $size);
264
+ }
265
+ $new_size = $editor->get_size();
266
+ $media = new TNP_Media();
267
+ $media->id = $media_id;
268
+ $media->width = $new_size['width'];
269
+ $media->height = $new_size['height'];
270
+ if ($media->width > $width) {
271
+ $media->set_width($width);
272
+ }
273
+ $media->url = $uploads['baseurl'] . '/' . $relative_file;
274
+ return $media;
275
+ }
276
+
277
+ // Relative and absolute name of the thumbnail.
278
+ $pathinfo = pathinfo($relative_file);
279
+
280
+ // We don't know why, but on some systems files with non-ascii characters loose the file name (grrr...)
281
+ if (empty($pathinfo['filename'])) {
282
+ return _tnp_get_default_media($media_id, $size);
283
+ }
284
+
285
+ $relative_thumb = $pathinfo['dirname'] . '/' . $pathinfo['filename'] . '-' . $width . 'x' . $height . ($crop ? '-c' : '') . '.' . $pathinfo['extension'];
286
+ $absolute_thumb = $uploads['basedir'] . '/newsletter/thumbnails/' . $relative_thumb;
287
+
288
+ // Thumbnail generation if needed.
289
+ if (!file_exists($absolute_thumb) || filemtime($absolute_thumb) < filemtime($absolute_file)) {
290
+ $r = wp_mkdir_p($uploads['basedir'] . '/newsletter/thumbnails/' . $pathinfo['dirname']);
291
+
292
+ if (!$r) {
293
+ Newsletter::instance()->logger->error('Unable to create dir ' . $uploads['basedir'] . '/newsletter/thumbnails/' . $pathinfo['dirname']);
294
+ return _tnp_get_default_media($media_id, $size);
295
+ }
296
+
297
+ $editor = wp_get_image_editor($absolute_file);
298
+ if (is_wp_error($editor)) {
299
+ Newsletter::instance()->logger->error($editor);
300
+ Newsletter::instance()->logger->error('File: ' . $absolute_file);
301
+ return _tnp_get_default_media($media_id, $size);
302
+ }
303
+
304
+ $original_size = $editor->get_size();
305
+ if ($width > $original_size['width'] && ($height > $original_size['height'] || $height == 0)) {
306
+ Newsletter::instance()->logger->error('Requested size larger than the original one');
307
+ return _tnp_get_default_media($media_id, $size);
308
+ }
309
+
310
+ if ($height > $original_size['height'] && ($width > $original_size['width'] || $width == 0)) {
311
+ Newsletter::instance()->logger->error('Requested size larger than the original one');
312
+ return _tnp_get_default_media($media_id, $size);
313
+ }
314
+
315
+ $editor->set_quality(85);
316
+ $resized = $editor->resize($width, $height, $crop);
317
+
318
+ if (is_wp_error($resized)) {
319
+ Newsletter::instance()->logger->error($resized);
320
+ Newsletter::instance()->logger->error('File: ' . $absolute_file);
321
+ return _tnp_get_default_media($media_id, $size);
322
+ }
323
+
324
+ $saved = $editor->save($absolute_thumb);
325
+ if (is_wp_error($saved)) {
326
+ Newsletter::instance()->logger->error($saved);
327
+ return _tnp_get_default_media($media_id, $size);
328
+ }
329
+ $new_size = $editor->get_size();
330
+
331
+ $media = new TNP_Media();
332
+ $media->width = $new_size['width'];
333
+ $media->height = $new_size['height'];
334
+ $media->url = $uploads['baseurl'] . '/newsletter/thumbnails/' . $relative_thumb;
335
+ } else {
336
+ $media = new TNP_Media();
337
+ $new_size = getimagesize($absolute_thumb);
338
+ $media->width = $new_size[0];
339
+ $media->height = $new_size[1];
340
+ $media->url = $uploads['baseurl'] . '/newsletter/thumbnails/' . $relative_thumb;
341
+ }
342
+
343
+ return $media;
344
+ }
345
+
346
+ function tnp_resize_2x($media_id, $size) {
347
+ $size[0] = $size[0] * 2;
348
+ $size[1] = $size[1] * 2;
349
+ $media = tnp_resize($media_id, $size);
350
+ if (!$media)
351
+ return $media;
352
+ $media->set_width($size[0] / 2);
353
+ return $media;
354
+ }
355
+
356
+ /**
357
+ * @param TNP_Media[] $images
358
+ *
359
+ * @return int
360
+ */
361
+ function tnp_get_max_height_of($images) {
362
+ $max_height = 0;
363
+ foreach ($images as $image) {
364
+ $max_height = $image->height > $max_height ? $image->height : $max_height;
365
+ }
366
+
367
+ return $max_height;
368
+ }
369
+
370
+ /**
371
+ * @param WP_Post[] $product_list
372
+ * @param array $size
373
+ *
374
+ * @return TNP_Media[]
375
+ */
376
+ function tnp_resize_product_list_featured_image($product_list, $size) {
377
+ $images = [];
378
+ foreach ($product_list as $p) {
379
+ $images[$p->ID] = tnp_resize_2x(TNP_Composer::get_post_thumbnail_id($p->ID), $size);
380
+ }
381
+
382
+ return $images;
383
+ }
384
+
385
+ /**
386
+ * Get media for "posts" composer block
387
+ *
388
+ * @param WP_Post post
389
+ * @param array $size
390
+ * @param string $default_image_url
391
+ *
392
+ * @return TNP_Media
393
+ */
394
+ function tnp_composer_block_posts_get_media($post, $size, $default_image_url = null) {
395
+ $post_thumbnail_id = TNP_Composer::get_post_thumbnail_id($post);
396
+
397
+ $media = null;
398
+
399
+ if (!empty($post_thumbnail_id)) {
400
+ $media = tnp_resize($post_thumbnail_id, array_values($size));
401
+ } else if ($default_image_url) {
402
+ Newsletter::instance()->logger->error('Thumbnail id not found');
403
+ $media = new TNP_Media();
404
+ $media->url = $default_image_url;
405
+ $media->width = $size['width'];
406
+ $media->height = $size['height'];
407
+ }
408
+ return $media;
409
+ }
410
+
411
+ function tnp_outlook_wrapper_open($width = 600) {
412
+ return NewsletterEmails::get_outlook_wrapper_open($width);
413
+ }
414
+
415
+ function tnp_outlook_wrapper_close() {
416
+ return NewsletterEmails::get_outlook_wrapper_close();
417
+ }
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.3.4
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.
@@ -13,7 +13,7 @@
13
  Requires at least: 4.6
14
  Requires PHP: 5.6
15
 
16
- Copyright 2009-2021 The Newsletter Team (email: info@thenewsletterplugin.com, web: https://www.thenewsletterplugin.com)
17
 
18
  Newsletter is free software: you can redistribute it and/or modify
19
  it under the terms of the GNU General Public License as published by
@@ -37,7 +37,7 @@ if (version_compare(phpversion(), '5.6', '<')) {
37
  return;
38
  }
39
 
40
- define('NEWSLETTER_VERSION', '7.3.4');
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.3.5
8
  Author: Stefano Lissa & The Newsletter Team
9
  Author URI: https://www.thenewsletterplugin.com
10
  Disclaimer: Use at your own risk. No warranty expressed or implied is provided.
13
  Requires at least: 4.6
14
  Requires PHP: 5.6
15
 
16
+ Copyright 2009-2022 The Newsletter Team (email: info@thenewsletterplugin.com, web: https://www.thenewsletterplugin.com)
17
 
18
  Newsletter is free software: you can redistribute it and/or modify
19
  it under the terms of the GNU General Public License as published by
37
  return;
38
  }
39
 
40
+ define('NEWSLETTER_VERSION', '7.3.5');
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.2
4
- Stable tag: 7.3.4
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,12 @@ Thank you, The Newsletter Team
118
 
119
  == Changelog ==
120
 
 
 
 
 
 
 
121
  = 7.3.4 =
122
 
123
  * Fixed delivery fatal error management
1
  === Newsletter ===
2
  Tags: newsletter, email marketing, welcome email, signup forms, contact, lead generation, marketing automation
3
+ Tested up to: 5.8.3
4
+ Stable tag: 7.3.5
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.3.5 =
122
+
123
+ * WP 5.8.3 compatibility check
124
+ * Fixed 2021 max year in date picker
125
+ * Typos
126
+
127
  = 7.3.4 =
128
 
129
  * Fixed delivery fatal error management
system/scheduler.php CHANGED
@@ -63,7 +63,7 @@ if ($controls->is_action('test')) {
63
  </p>
64
  <ul>
65
  <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>
66
- <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>
67
  <li>Configure an <a href="https://www.thenewsletterplugin.com/documentation/delivery-and-spam/newsletter-delivery-engine/" target="_blank">external cron service</a>
68
  (if you have a license you can use our <a href="https://www.thenewsletterplugin.com/account/cron/" target="_blank">cron service</a>)</li>
69
  </ul>
63
  </p>
64
  <ul>
65
  <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>
66
+ <li>Install the <a href="https://wordpress.org/plugins/wp-crontrol/" target="_blank">WP Crontrol</a> plugin which shows all the scheduled jobs and delays</li>
67
  <li>Configure an <a href="https://www.thenewsletterplugin.com/documentation/delivery-and-spam/newsletter-delivery-engine/" target="_blank">external cron service</a>
68
  (if you have a license you can use our <a href="https://www.thenewsletterplugin.com/account/cron/" target="_blank">cron service</a>)</li>
69
  </ul>
tnp-header.php CHANGED
@@ -291,7 +291,7 @@ $warning |= empty($status_options['mail']);
291
  <input type="hidden" value="plugin-header" name="nr">
292
  <input type="hidden" value="3" name="nl[]">
293
  <input type="hidden" value="single" name="optin">
294
- <input type="email" name="ne" value="<?php echo esc_attr(get_option('admin_email')) ?>">
295
  <input type="submit" value="<?php esc_attr_e('Subscribe', 'newsletter') ?>">
296
  </form>
297
  </div>
291
  <input type="hidden" value="plugin-header" name="nr">
292
  <input type="hidden" value="3" name="nl[]">
293
  <input type="hidden" value="single" name="optin">
294
+ <input type="email" name="ne" value="<?php echo esc_attr($current_user->user_email) ?>">
295
  <input type="submit" value="<?php esc_attr_e('Subscribe', 'newsletter') ?>">
296
  </form>
297
  </div>