Newsletter - Version 6.4.9

Version Description

  • Added background selection to the composer
  • Reactivated the Pint theme
  • Improved blocks layout
  • Inline editing for title and excerpt on Posts block
  • Changed the image cropping method on newsletter included images
  • Posts block can now specify an offset to skip the first n posts
  • Fixed the display of multiline title on some blocks (was overlapping)
  • Added the excerpt length on Posts block
Download this release

Release Info

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

Code changes from version 6.4.8 to 6.4.9

admin.css CHANGED
@@ -728,6 +728,18 @@ p.description {
728
 
729
  .tnp-theme-preview img {
730
  border-radius: 10px;
 
 
 
 
 
 
 
 
 
 
 
 
731
  }
732
 
733
 
728
 
729
  .tnp-theme-preview img {
730
  border-radius: 10px;
731
+ height: 190px;
732
+ width: auto;
733
+ }
734
+
735
+ .tnp-theme-preview .tnp-theme-composer {
736
+ height: 250px;
737
+ width: auto;
738
+ }
739
+
740
+ .tnp-theme-preview .tnp-theme-html {
741
+ height: 250px;
742
+ width: auto;
743
  }
744
 
745
 
emails/blocks/canspam/block.php CHANGED
@@ -14,7 +14,11 @@ $default_options = array(
14
  'block_padding_top' => 15,
15
  'block_padding_bottom' => 15,
16
  'block_padding_left' => 15,
17
- 'block_padding_right' => 15
 
 
 
 
18
  );
19
  $options = array_merge($default_options, $options);
20
  ?>
@@ -29,16 +33,11 @@ $options = array_merge($default_options, $options);
29
  color: <?php echo $options['font_color'] ?>;
30
  }
31
  </style>
32
- <table width="100%" style="width: 100%!important" border="0" cellspacing="0" cellpadding="0" align="center" class="responsive-table">
33
- <tr>
34
- <td align="center" class="canspam-text">
35
- <?php echo!empty($block_options['footer_title']) ? $block_options['footer_title'] : 'Your Company' ?>
36
- <br>
37
- <?php echo!empty($block_options['footer_contact']) ? $block_options['footer_contact'] : 'Company Address, Phone Number' ?>
38
- <br>
39
- <em><?php echo!empty($block_options['footer_legal']) ? $block_options['footer_legal'] : 'Copyright or Legal text' ?></em>
40
- </div>
41
- </td>
42
- </tr>
43
- </table>
44
 
 
 
 
 
 
 
 
14
  'block_padding_top' => 15,
15
  'block_padding_bottom' => 15,
16
  'block_padding_left' => 15,
17
+ 'block_padding_right' => 15,
18
+ 'title'=>$info['footer_title'],
19
+ 'address'=>$info['footer_contact'],
20
+ 'copyright'=>$info['footer_legal'],
21
+
22
  );
23
  $options = array_merge($default_options, $options);
24
  ?>
33
  color: <?php echo $options['font_color'] ?>;
34
  }
35
  </style>
 
 
 
 
 
 
 
 
 
 
 
 
36
 
37
+ <div inline-class="canspam-text">
38
+ <strong><?php echo $options['title'] ?></strong>
39
+ <br>
40
+ <?php echo $options['address'] ?>
41
+ <br>
42
+ <em><?php echo $options['copyright'] ?></em>
43
+ </div>
emails/blocks/cta/block.php CHANGED
@@ -43,7 +43,8 @@ $options = array_merge($default_options, $options);
43
  display: inline-block;
44
  }
45
  </style>
46
- <a href="<?php echo $options['url'] ?>" target="_blank" rel="noopener" class="cta-button"><?php echo $options['text'] ?></a>
 
47
 
48
  <div itemscope="" itemtype="http://schema.org/EmailMessage">
49
  <div itemprop="potentialAction" itemscope="" itemtype="http://schema.org/ViewAction">
43
  display: inline-block;
44
  }
45
  </style>
46
+
47
+ <a href="<?php echo $options['url'] ?>" target="_blank" rel="noopener" inline-class="cta-button"><?php echo $options['text'] ?></a>
48
 
49
  <div itemscope="" itemtype="http://schema.org/EmailMessage">
50
  <div itemprop="potentialAction" itemscope="" itemtype="http://schema.org/ViewAction">
emails/blocks/footer/block.php CHANGED
@@ -29,17 +29,10 @@ $options = array_merge($default_options, $options);
29
  text-decoration: none;
30
  }
31
  </style>
32
- <table width="100%" border="0" cellspacing="0" cellpadding="0">
33
- <tr>
34
- <td align="center">
35
 
36
- <a class="footer-text" href="{profile_url}"><?php echo $options['profile'] ?></a>
37
 
38
- <span class="footer-text">&nbsp;&nbsp;&nbsp;|&nbsp;&nbsp;&nbsp;</span>
39
 
40
- <a class="footer-text" href="{email_url}"><?php echo $options['view'] ?></a>
41
-
42
- </td>
43
- </tr>
44
- </table>
45
 
29
  text-decoration: none;
30
  }
31
  </style>
 
 
 
32
 
33
+ <a inline-class="footer-text" href="{profile_url}"><?php echo $options['profile'] ?></a>
34
 
35
+ <span inline-class="footer-text">&nbsp;&nbsp;&nbsp;|&nbsp;&nbsp;&nbsp;</span>
36
 
37
+ <a inline-class="footer-text" href="{email_url}"><?php echo $options['view'] ?></a>
 
 
 
 
38
 
emails/blocks/header/block.php CHANGED
@@ -19,12 +19,10 @@ $default_options = array(
19
  $options = array_merge($default_options, $options);
20
 
21
  if (empty($info['header_logo']['id'])) {
22
- $image = false;
23
  } else {
24
- $image = tnp_media_resize($info['header_logo']['id'], array(200, 80));
25
- if (is_wp_error($image)) {
26
- $image = false;
27
- }
28
  }
29
 
30
  $empty = empty($info['header_logo']['id']) && empty($info['header_sub']) && empty($info['header_title']);
@@ -58,28 +56,24 @@ $empty = empty($info['header_logo']['id']) && empty($info['header_sub']) && empt
58
  color: <?php echo $options['font_color'] ?>;
59
  }
60
  .header-logo-img {
61
- display: block;
62
- max-width: 100%
63
  }
64
  </style>
65
 
66
- <table border="0" cellpadding="0" cellspacing="0" width="100%">
67
  <tr>
68
- <?php if ($image) { ?>
69
- <td align="left" width="50%" inline-class="header-logo">
70
  <a href="<?php echo home_url() ?>" target="_blank">
71
- <img alt="<?php echo esc_attr($info['header_title']) ?>" src="<?php echo $image ?>" class="header-logo-img" border="0">
72
  </a>
73
- </td>
74
- <?php } else { ?>
75
- <td align="left" width="50%" inline-class="header-logo">
76
- <a href="<?php echo home_url() ?>" target="_blank" class="header-title">
77
  <?php echo esc_attr($info['header_title']) ?>
78
  </a>
79
- </td>
80
- <?php } ?>
81
-
82
-
83
  <td width="50%" align="right" class="mobile-hide" inline-class="header-text">
84
  <?php echo $info['header_sub'] ?>
85
  </td>
19
  $options = array_merge($default_options, $options);
20
 
21
  if (empty($info['header_logo']['id'])) {
22
+ $media = false;
23
  } else {
24
+ $media = tnp_resize($info['header_logo']['id'], array(200, 80));
25
+ $media->alt = $info['header_title'];
 
 
26
  }
27
 
28
  $empty = empty($info['header_logo']['id']) && empty($info['header_sub']) && empty($info['header_title']);
56
  color: <?php echo $options['font_color'] ?>;
57
  }
58
  .header-logo-img {
59
+ display: inline-block;
60
+ max-width: 100%!important;
61
  }
62
  </style>
63
 
64
+ <table border="0" cellpadding="0" cellspacing="0" width="100%" class="header-table">
65
  <tr>
66
+ <td align="left" width="50%" inline-class="header-logo" class="header-logo-global">
67
+ <?php if ($media) { ?>
68
  <a href="<?php echo home_url() ?>" target="_blank">
69
+ <img alt="<?php echo esc_attr($media->alt) ?>" src="<?php echo $media->url ?>" width="<?php echo $media->width ?>" height="<?php echo $media->height ?>" inline-class="header-logo-img" border="0">
70
  </a>
71
+ <?php } else { ?>
72
+ <a href="<?php echo home_url() ?>" target="_blank" inline-class="header-title">
 
 
73
  <?php echo esc_attr($info['header_title']) ?>
74
  </a>
75
+ <?php } ?>
76
+ </td>
 
 
77
  <td width="50%" align="right" class="mobile-hide" inline-class="header-text">
78
  <?php echo $info['header_sub'] ?>
79
  </td>
emails/blocks/header/style.css CHANGED
@@ -1,11 +1,8 @@
1
- .header-logo {
2
- text-align: center!important;
3
- }
4
  @media all and (max-width: 640) {
5
  .header-table td {
6
  width: 100%!important;
7
  }
8
- .header-logo {
9
  text-align: center!important;
10
  }
11
  }
 
 
 
1
  @media all and (max-width: 640) {
2
  .header-table td {
3
  width: 100%!important;
4
  }
5
+ .header-logo-global {
6
  text-align: center!important;
7
  }
8
  }
emails/blocks/heading/block.php CHANGED
@@ -5,7 +5,6 @@
5
  * Description: Section title
6
  */
7
 
8
-
9
  $default_options = array(
10
  'text' => 'An Awesome Title',
11
  'align' => 'center',
@@ -23,21 +22,18 @@ $options = array_merge($default_options, $options);
23
  ?>
24
 
25
  <style>
26
- .heading-text {
27
  padding: 10px;
28
  text-align: <?php echo $options['align'] ?>;
29
  font-size: <?php echo $options['font_size'] ?>px;
30
  font-family: <?php echo $options['font_family'] ?>;
31
  font-weight: <?php echo $options['font_weight'] ?>;
32
  color: <?php echo $options['font_color'] ?>;
 
 
33
  }
34
  </style>
35
- <table border="0" cellpadding="0" cellspacing="0" width="100%" >
36
- <tr>
37
- <td align="center" class="heading-text">
38
-
39
- <?php echo $options['text'] ?>
40
 
41
- </td>
42
- </tr>
43
- </table>
5
  * Description: Section title
6
  */
7
 
 
8
  $default_options = array(
9
  'text' => 'An Awesome Title',
10
  'align' => 'center',
22
  ?>
23
 
24
  <style>
25
+ .heading-text-inline {
26
  padding: 10px;
27
  text-align: <?php echo $options['align'] ?>;
28
  font-size: <?php echo $options['font_size'] ?>px;
29
  font-family: <?php echo $options['font_family'] ?>;
30
  font-weight: <?php echo $options['font_weight'] ?>;
31
  color: <?php echo $options['font_color'] ?>;
32
+ line-height: normal!important;
33
+ letter-spacing: normal;
34
  }
35
  </style>
 
 
 
 
 
36
 
37
+ <div inline-class="heading-text-inline">
38
+ <?php echo $options['text'] ?>
39
+ </div>
emails/blocks/hero/block.php CHANGED
@@ -26,7 +26,6 @@ $defaults = array(
26
  'button_color' => '#ffffff',
27
  'button_font_size' => 20,
28
  'button_background' => '#256F9C',
29
- 'layout' => 'full',
30
  'block_padding_top'=>20,
31
  'block_padding_bottom'=>20
32
  );
@@ -58,12 +57,13 @@ $layout = $options['layout'];
58
 
59
  if (!empty($options['image']['id'])) {
60
  if ($layout == 'full') {
61
- $image = tnp_media_resize($options['image']['id'], array(600, 0));
62
  } else {
63
- $image = tnp_media_resize($options['image']['id'], array(300, 200, true));
64
  }
 
65
  } else {
66
- $image = false;
67
  }
68
  ?>
69
 
@@ -98,7 +98,7 @@ if (!empty($options['image']['id'])) {
98
  <tr>
99
  <td class="padding-copy tnpc-row-edit">
100
  <a href="<?php echo $url ?>" target="_blank" rel="noopener nofollow">
101
- <img src="<?php echo $image ?>" border="0" alt="Image" inline-class="hero-image">
102
  </a>
103
  </td>
104
  </tr>
@@ -153,7 +153,7 @@ if (!empty($options['image']['id'])) {
153
  <table width="290" align="left" class="hero-table">
154
  <tr>
155
  <td align="center" valign="top">
156
- <img src="<?php echo $image ?>" border="0" alt="" style="max-width: 100%!important; height: auto!important; display: block;" class="img-max">
157
  </td>
158
  </tr>
159
  </table>
26
  'button_color' => '#ffffff',
27
  'button_font_size' => 20,
28
  'button_background' => '#256F9C',
 
29
  'block_padding_top'=>20,
30
  'block_padding_bottom'=>20
31
  );
57
 
58
  if (!empty($options['image']['id'])) {
59
  if ($layout == 'full') {
60
+ $media = tnp_resize($options['image']['id'], array(600, 0));
61
  } else {
62
+ $media = tnp_resize($options['image']['id'], array(300, 200, true));
63
  }
64
+ $media->alt = $options['title'];
65
  } else {
66
+ $media = false;
67
  }
68
  ?>
69
 
98
  <tr>
99
  <td class="padding-copy tnpc-row-edit">
100
  <a href="<?php echo $url ?>" target="_blank" rel="noopener nofollow">
101
+ <img src="<?php echo $media->url ?>" border="0" alt="<?php echo esc_attr($media->alt) ?>" width="<?php echo $media->width ?>" height="<?php echo $media->height ?>" inline-class="hero-image">
102
  </a>
103
  </td>
104
  </tr>
153
  <table width="290" align="left" class="hero-table">
154
  <tr>
155
  <td align="center" valign="top">
156
+ <img src="<?php echo $media->url ?>" border="0" alt="<?php echo esc_attr($media->alt) ?>" width="<?php echo $media->width ?>" height="<?php echo $media->height ?>" style="max-width: 100%!important; height: auto!important; display: block;" class="img-max">
157
  </td>
158
  </tr>
159
  </table>
emails/blocks/html/block.php CHANGED
@@ -30,7 +30,7 @@ $options = array_merge($default_options, $options);
30
  </style>
31
  <table width="100%" border="0" cellpadding="0" align="center" cellspacing="0">
32
  <tr>
33
- <td width="100%" valign="top" align="center" class="html-td">
34
  <?php echo $options['html'] ?>
35
  </td>
36
  </tr>
30
  </style>
31
  <table width="100%" border="0" cellpadding="0" align="center" cellspacing="0">
32
  <tr>
33
+ <td width="100%" valign="top" align="center" inline-class="html-td" class="html-td-global">
34
  <?php echo $options['html'] ?>
35
  </td>
36
  </tr>
emails/blocks/html/style.css CHANGED
@@ -1,4 +1,4 @@
1
- .html-td p {
2
  font-family: Helvetica, Arial, sans-serif;
3
  font-size: 16px;
4
  }
1
+ .html-td-global p {
2
  font-family: Helvetica, Arial, sans-serif;
3
  font-size: 16px;
4
  }
emails/blocks/image/block.php CHANGED
@@ -22,22 +22,27 @@ $options = array_merge($defaults, $options);
22
 
23
  $alt = '';
24
  if (empty($options['image']['id'])) {
 
25
  // A placeholder can be set by a preset and it is kept indefinitely
26
  if (!empty($options['placeholder'])) {
27
- $image = $options['placeholder'];
 
 
28
  } else {
29
- $image = 'https://source.unsplash.com/600x250/daily';
 
 
30
  }
31
  } else {
32
- $image = tnp_media_resize($options['image']['id'], array(600, 0));
33
- $alt = $options['image_alt'];
34
  }
35
 
36
  $url = $options['url'];
37
  ?>
38
 
39
  <?php if (!empty($url)) { ?>
40
- <a href="<?php echo $url ?>" target="_blank"><img src="<?php echo $image ?>" border="0" alt="" style="max-width: 100%!important; height: auto!important; display: inline-block;"></a>
41
  <?php } else { ?>
42
- <img src="<?php echo $image ?>" border="0" alt="<?php echo esc_attr($alt) ?>" style="max-width: 100%!important; height: auto!important; display: inline-block;">
43
  <?php } ?>
22
 
23
  $alt = '';
24
  if (empty($options['image']['id'])) {
25
+ $media = new TNP_Media();
26
  // A placeholder can be set by a preset and it is kept indefinitely
27
  if (!empty($options['placeholder'])) {
28
+ $media->url = $options['placeholder'];
29
+ $media->width = 600;
30
+ $media->height = 250;
31
  } else {
32
+ $media->url = 'https://source.unsplash.com/600x250/daily';
33
+ $media->width = 600;
34
+ $media->height = 250;
35
  }
36
  } else {
37
+ $media = tnp_resize($options['image']['id'], array(600, 0));
38
+ $media->alt = $options['image_alt'];
39
  }
40
 
41
  $url = $options['url'];
42
  ?>
43
 
44
  <?php if (!empty($url)) { ?>
45
+ <a href="<?php echo $media->url ?>" target="_blank"><img src="<?php echo $image ?>" width="<?php echo $media->width ?>" height="<?php echo $media->height ?>" border="0" alt="<?php echo esc_attr($media->alt) ?>" style="max-width: 100%!important; height: auto!important; display: inline-block;"></a>
46
  <?php } else { ?>
47
+ <img src="<?php echo $media->url ?>" border="0" alt="<?php echo esc_attr($media->alt) ?>" width="<?php echo $media->width ?>" height="<?php echo $media->height ?>" style="max-width: 100%!important; height: auto!important; display: inline-block;">
48
  <?php } ?>
emails/blocks/posts/block.php CHANGED
@@ -17,7 +17,7 @@ $defaults = array(
17
  'font_color' => '#333333',
18
  'title_font_family' => 'Helvetica, Arial, sans-serif',
19
  'title_font_size' => '25',
20
- 'title_font_color' => ' #333333',
21
  'max' => 4,
22
  'button_label' => __('Read more...', 'newsletter'),
23
  'categories' => '',
@@ -32,21 +32,27 @@ $defaults = array(
32
  'block_padding_left' => 15,
33
  'block_padding_right' => 15,
34
  'block_padding_top' => 15,
35
- 'block_padding_bottom' => 15
 
 
 
 
36
  );
37
 
38
  $options = array_merge($defaults, $options);
39
 
40
  $font_family = $options['font_family'];
41
  $font_size = $options['font_size'];
 
42
 
43
  $title_font_family = $options['title_font_family'];
44
  $title_font_size = $options['title_font_size'];
45
 
46
  $show_image = !empty($options['show_image']);
47
 
48
- $filters = array();
49
  $filters['posts_per_page'] = (int) $options['max'];
 
50
 
51
  if (!empty($options['categories'])) {
52
  $filters['category__in'] = $options['categories'];
@@ -66,7 +72,7 @@ if (!empty($context['last_run'])) {
66
 
67
  $posts = Newsletter::instance()->get_posts($filters, $options['language']);
68
 
69
- if ($context['type'] == 'automated') {
70
  // No new posts
71
  if (empty($posts)) {
72
  if (isset($options['automated_required'])) {
@@ -75,6 +81,7 @@ if ($context['type'] == 'automated') {
75
  return;
76
  }
77
 
 
78
  if ($options['automated_include'] == 'max') {
79
  unset($filters['date_query']);
80
  $posts = Newsletter::instance()->get_posts($filters, $options['language']);
@@ -89,8 +96,8 @@ $button_font_family = $options['button_font_family'];
89
  $button_font_size = $options['button_font_size'];
90
  $button_color = $options['button_font_color'];
91
 
92
- $alternative = plugins_url('newsletter') . '/emails/blocks/posts/images/blank.png';
93
- $alternative_2 = plugins_url('newsletter') . '/emails/blocks/posts/images/blank-240x160.png';
94
 
95
  remove_all_filters('excerpt_more');
96
  ?>
@@ -160,13 +167,23 @@ remove_all_filters('excerpt_more');
160
  ?>
161
 
162
  <tr>
163
- <?php if ($show_image) { ?>
164
- <td valign="top" style="padding: 30px 0 0 0; width: 105px!important" class="mobile-hide">
165
- <a href="<?php echo tnp_post_permalink($post) ?>" target="_blank">
166
- <img src="<?php echo tnp_post_thumbnail_src($post, array(105, 105, true), $alternative) ?>" width="105" height="105" alt="Image" border="0" style="display: block; font-family: Arial; color: #666666; font-size: 14px; min-width: 105px!important; width: 105px!important;">
 
 
 
 
 
 
 
 
 
 
167
  </a>
168
  </td>
169
- <?php } ?>
170
  <td style="padding: 30px 0 0 0;" class="no-padding">
171
  <!-- ARTICLE -->
172
  <table border="0" cellspacing="0" cellpadding="0" width="100%">
@@ -178,13 +195,23 @@ remove_all_filters('excerpt_more');
178
  </tr>
179
  <?php } ?>
180
  <tr>
181
- <td align="left" inline-class="posts-post-title" class="padding-copy tnpc-row-edit" data-type="title">
182
- <?php echo tnp_post_title($post) ?>
 
 
 
 
 
183
  </td>
184
  </tr>
185
  <tr>
186
- <td align="left" inline-class="posts-post-excerpt" class="padding-copy tnpc-row-edit" data-type="text">
187
- <?php echo tnp_post_excerpt($post) ?>
 
 
 
 
 
188
  </td>
189
  </tr>
190
  <tr>
@@ -265,24 +292,40 @@ remove_all_filters('excerpt_more');
265
  <table cellspacing="0" cellpadding="0" border="0" width="100%">
266
  <?php foreach (array_chunk($posts, 2) AS $row) { ?>
267
  <tr>
268
- <td valign="top" style="padding: 10px;" class="mobile-wrapper">
269
 
270
  <!-- LEFT COLUMN -->
271
  <table cellpadding="0" cellspacing="0" border="0" width="47%" align="left" class="responsive-table">
272
  <tr>
273
  <td style="padding: 20px 0 40px 0;">
274
  <table cellpadding="0" cellspacing="0" border="0" width="100%">
275
- <?php if ($show_image) { ?>
 
 
 
 
276
  <tr>
277
  <td align="center" valign="middle" class="tnpc-row-edit" data-type="image">
278
- <a href="<?php echo tnp_post_permalink($row[0]) ?>" target="_blank">
279
- <img src="<?php echo tnp_post_thumbnail_src($row[0], array(240, 160, true), $alternative_2) ?>" alt="Image" width="240" height="160" border="0" class="img-max">
 
 
 
 
 
280
  </a>
281
  </td>
282
  </tr>
283
- <?php } ?>
284
  <tr>
285
- <td align="center" inline-class="posts-post-title" class="tnpc-row-edit" data-type="title"><?php echo tnp_post_title($row[0]) ?></td>
 
 
 
 
 
 
 
286
  </tr>
287
  <?php if (!empty($options['show_date'])) { ?>
288
  <tr>
@@ -292,7 +335,14 @@ remove_all_filters('excerpt_more');
292
  </tr>
293
  <?php } ?>
294
  <tr>
295
- <td align="center" inline-class="posts-post-excerpt" class="tnpc-row-edit" data-type="text"><?php echo tnp_post_excerpt($row[0]) ?></td>
 
 
 
 
 
 
 
296
  </tr>
297
  <tr>
298
  <td align="center">
@@ -318,16 +368,30 @@ remove_all_filters('excerpt_more');
318
  <td style="padding: 20px 0 40px 0;">
319
  <table cellpadding="0" cellspacing="0" border="0" width="100%">
320
  <?php if ($show_image) { ?>
 
 
 
 
321
  <tr>
322
  <td align="center" valign="middle" class="tnpc-row-edit" data-type="image">
323
  <a href="<?php echo tnp_post_permalink($row[1]) ?>" target="_blank">
324
- <img src="<?php echo tnp_post_thumbnail_src($row[1], array(240, 160, true), $alternative_2) ?>" alt="Image" width="240" height="160" border="0" class="img-max">
 
 
 
325
  </a>
326
  </td>
327
  </tr>
328
  <?php } ?>
329
  <tr>
330
- <td align="center" inline-class="posts-post-title" class="tnpc-row-edit" data-type="title"><?php echo tnp_post_title($row[1]) ?></td>
 
 
 
 
 
 
 
331
  </tr>
332
  <?php if (!empty($options['show_date'])) { ?>
333
  <tr>
@@ -337,7 +401,14 @@ remove_all_filters('excerpt_more');
337
  </tr>
338
  <?php } ?>
339
  <tr>
340
- <td align="center" inline-class="posts-post-excerpt" class="tnpc-row-edit" data-type="text"><?php echo tnp_post_excerpt($row[1]) ?></td>
 
 
 
 
 
 
 
341
  </tr>
342
  <tr>
343
  <td align="center">
17
  'font_color' => '#333333',
18
  'title_font_family' => 'Helvetica, Arial, sans-serif',
19
  'title_font_size' => '25',
20
+ 'title_font_color' => '#333333',
21
  'max' => 4,
22
  'button_label' => __('Read more...', 'newsletter'),
23
  'categories' => '',
32
  'block_padding_left' => 15,
33
  'block_padding_right' => 15,
34
  'block_padding_top' => 15,
35
+ 'block_padding_bottom' => 15,
36
+ 'excerpt_length' => 30,
37
+ 'post_offset' => 0,
38
+ 'automated_include' => 'new',
39
+ 'inline_edits' => []
40
  );
41
 
42
  $options = array_merge($defaults, $options);
43
 
44
  $font_family = $options['font_family'];
45
  $font_size = $options['font_size'];
46
+ $excerpt_length = $options['excerpt_length'];
47
 
48
  $title_font_family = $options['title_font_family'];
49
  $title_font_size = $options['title_font_size'];
50
 
51
  $show_image = !empty($options['show_image']);
52
 
53
+ $filters = array();
54
  $filters['posts_per_page'] = (int) $options['max'];
55
+ $filters['offset'] = max( (int) $options['post_offset'], 0 );
56
 
57
  if (!empty($options['categories'])) {
58
  $filters['category__in'] = $options['categories'];
72
 
73
  $posts = Newsletter::instance()->get_posts($filters, $options['language']);
74
 
75
+ if ( isset( $context['type'] ) && $context['type'] == 'automated' ) {
76
  // No new posts
77
  if (empty($posts)) {
78
  if (isset($options['automated_required'])) {
81
  return;
82
  }
83
 
84
+ // We have something new but we need to reload the posts without filtering by date
85
  if ($options['automated_include'] == 'max') {
86
  unset($filters['date_query']);
87
  $posts = Newsletter::instance()->get_posts($filters, $options['language']);
96
  $button_font_size = $options['button_font_size'];
97
  $button_color = $options['button_font_color'];
98
 
99
+ $alternative = plugins_url( 'newsletter' ) . '/emails/blocks/posts/images/blank.png';
100
+ $alternative_2 = plugins_url( 'newsletter' ) . '/emails/blocks/posts/images/blank-240x160.png';
101
 
102
  remove_all_filters('excerpt_more');
103
  ?>
167
  ?>
168
 
169
  <tr>
170
+ <?php if ( $show_image ) { ?>
171
+ <?php
172
+ $size = array( 'width' => 105, 'height' => 105 );
173
+ $media = tnp_composer_block_posts_get_media( $post, $size, $alternative );
174
+ ?>
175
+ <td valign="top" style="padding: 30px 0 0 0; width: <?php echo $size['width'] ?>px!important"
176
+ class="mobile-hide">
177
+ <a href="<?php echo tnp_post_permalink( $post ) ?>" target="_blank">
178
+ <img src="<?php echo $media->url ?>"
179
+ width="<?php echo $media->width ?>"
180
+ height="<?php echo $media->height ?>"
181
+ alt="Image"
182
+ border="0"
183
+ style="display: block; font-family: Arial;color: #666666; font-size: 14px;min-width: <?php echo $size['width'] ?>px!important;width: <?php echo $size['width'] ?>px!important;">
184
  </a>
185
  </td>
186
+ <?php } ?>
187
  <td style="padding: 30px 0 0 0;" class="no-padding">
188
  <!-- ARTICLE -->
189
  <table border="0" cellspacing="0" cellpadding="0" width="100%">
195
  </tr>
196
  <?php } ?>
197
  <tr>
198
+ <td align="left"
199
+ inline-class="posts-post-title"
200
+ class="padding-copy tnpc-row-edit tnpc-inline-editable"
201
+ data-type="title" data-id="<?php echo $post->ID ?>">
202
+ <?php echo TNP_Composer::is_post_field_edited_inline( $options['inline_edits'], 'title', $post->ID ) ?
203
+ TNP_Composer::get_edited_inline_post_field( $options['inline_edits'], 'title', $post->ID ) :
204
+ tnp_post_title($post) ?>
205
  </td>
206
  </tr>
207
  <tr>
208
+ <td align="left"
209
+ inline-class="posts-post-excerpt"
210
+ class="padding-copy tnpc-row-edit tnpc-inline-editable"
211
+ data-type="text" data-id="<?php echo $post->ID ?>">
212
+ <?php echo TNP_Composer::is_post_field_edited_inline( $options['inline_edits'], 'text', $post->ID ) ?
213
+ TNP_Composer::get_edited_inline_post_field( $options['inline_edits'], 'text', $post->ID ) :
214
+ tnp_post_excerpt( $post, $excerpt_length ) ?>
215
  </td>
216
  </tr>
217
  <tr>
292
  <table cellspacing="0" cellpadding="0" border="0" width="100%">
293
  <?php foreach (array_chunk($posts, 2) AS $row) { ?>
294
  <tr>
295
+ <td valign="top" style="padding: 10px;" class="mobile-wrapper two-columns">
296
 
297
  <!-- LEFT COLUMN -->
298
  <table cellpadding="0" cellspacing="0" border="0" width="47%" align="left" class="responsive-table">
299
  <tr>
300
  <td style="padding: 20px 0 40px 0;">
301
  <table cellpadding="0" cellspacing="0" border="0" width="100%">
302
+ <?php if ( $show_image ) { ?>
303
+ <?php
304
+ $size = array( 'width' => 240, 'height' => 160, "crop" => true );
305
+ $media = tnp_composer_block_posts_get_media( $row[0], $size, $alternative_2 );
306
+ ?>
307
  <tr>
308
  <td align="center" valign="middle" class="tnpc-row-edit" data-type="image">
309
+ <a href="<?php echo tnp_post_permalink( $row[0] ) ?>" target="_blank">
310
+ <img src="<?php echo $media->url ?>"
311
+ width="<?php echo $media->width ?>"
312
+ height="<?php echo $media->height ?>"
313
+ alt="Image"
314
+ border="0"
315
+ class="img-max">
316
  </a>
317
  </td>
318
  </tr>
319
+ <?php } ?>
320
  <tr>
321
+ <td align="center"
322
+ inline-class="posts-post-title"
323
+ class="tnpc-row-edit tnpc-inline-editable"
324
+ data-type="title" data-id="<?php echo $row[0]->ID ?>">
325
+ <?php echo TNP_Composer::is_post_field_edited_inline( $options['inline_edits'], 'title', $row[0]->ID ) ?
326
+ TNP_Composer::get_edited_inline_post_field( $options['inline_edits'], 'title', $row[0]->ID ) :
327
+ tnp_post_title( $row[0] ) ?>
328
+ </td>
329
  </tr>
330
  <?php if (!empty($options['show_date'])) { ?>
331
  <tr>
335
  </tr>
336
  <?php } ?>
337
  <tr>
338
+ <td align="center"
339
+ inline-class="posts-post-excerpt"
340
+ class="tnpc-row-edit tnpc-inline-editable"
341
+ data-type="text" data-id="<?php echo $row[0]->ID ?>">
342
+ <?php echo TNP_Composer::is_post_field_edited_inline( $options['inline_edits'], 'text', $row[0]->ID ) ?
343
+ TNP_Composer::get_edited_inline_post_field( $options['inline_edits'], 'text', $row[0]->ID ) :
344
+ tnp_post_excerpt( $row[0], $excerpt_length ) ?>
345
+ </td>
346
  </tr>
347
  <tr>
348
  <td align="center">
368
  <td style="padding: 20px 0 40px 0;">
369
  <table cellpadding="0" cellspacing="0" border="0" width="100%">
370
  <?php if ($show_image) { ?>
371
+ <?php
372
+ $size = array( 'width' => 240, 'height' => 160, "crop" => true );
373
+ $media = tnp_composer_block_posts_get_media( $row[1], $size, $alternative_2 );
374
+ ?>
375
  <tr>
376
  <td align="center" valign="middle" class="tnpc-row-edit" data-type="image">
377
  <a href="<?php echo tnp_post_permalink($row[1]) ?>" target="_blank">
378
+ <img src="<?php echo $media->url ?>"
379
+ width="<?php echo $media->width ?>"
380
+ height="<?php echo $media->height ?>"
381
+ alt="Image" border="0" class="img-max">
382
  </a>
383
  </td>
384
  </tr>
385
  <?php } ?>
386
  <tr>
387
+ <td align="center"
388
+ inline-class="posts-post-title"
389
+ class="tnpc-row-edit tnpc-inline-editable"
390
+ data-type="title" data-id="<?php echo $row[1]->ID ?>">
391
+ <?php echo TNP_Composer::is_post_field_edited_inline( $options['inline_edits'], 'title', $row[1]->ID ) ?
392
+ TNP_Composer::get_edited_inline_post_field( $options['inline_edits'], 'title', $row[1]->ID ) :
393
+ tnp_post_title( $row[1] ) ?>
394
+ </td>
395
  </tr>
396
  <?php if (!empty($options['show_date'])) { ?>
397
  <tr>
401
  </tr>
402
  <?php } ?>
403
  <tr>
404
+ <td align="center"
405
+ inline-class="posts-post-excerpt"
406
+ class="tnpc-row-edit tnpc-inline-editable"
407
+ data-type="text" data-id="<?php echo $row[1]->ID ?>">
408
+ <?php echo TNP_Composer::is_post_field_edited_inline( $options['inline_edits'], 'text', $row[1]->ID ) ?
409
+ TNP_Composer::get_edited_inline_post_field( $options['inline_edits'], 'text', $row[1]->ID ) :
410
+ tnp_post_excerpt( $row[1], $excerpt_length ) ?>
411
+ </td>
412
  </tr>
413
  <tr>
414
  <td align="center">
emails/blocks/posts/options.php CHANGED
@@ -18,13 +18,31 @@
18
 
19
  <?php $fields->font('title_font', __('Title font', 'newsletter')) ?>
20
 
21
- <?php $fields->font('font', __('Excerpt font', 'newsletter')) ?>
22
-
23
- <?php $fields->checkbox('show_image', __('Show image', 'newsletter')) ?>
24
 
25
- <?php $fields->checkbox('show_date', __('Show date', 'newsletter')) ?>
26
 
27
- <?php $fields->select_number('max', __('Max posts', 'newsletter'), 1, 40); ?>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
28
 
29
  <?php $fields->language(); ?>
30
 
@@ -32,7 +50,7 @@
32
 
33
  <?php $fields->section(__('Filters', 'newsletter')) ?>
34
  <?php $fields->categories(); ?>
35
- <?php $fields->text('tags', __('Tags', 'newsletter')); ?>
36
 
37
  <?php $fields->block_commons() ?>
38
 
18
 
19
  <?php $fields->font('title_font', __('Title font', 'newsletter')) ?>
20
 
21
+ <?php $fields->number( 'excerpt_length', __( 'Excerpt words', 'newsletter' ), array( 'min' => 0 ) ); ?>
 
 
22
 
23
+ <?php $fields->font('font', __('Excerpt font', 'newsletter')) ?>
24
 
25
+ <div class="tnp-field">
26
+ <label class="tnp-label"><?php _e('Dates and images', 'newsletter')?></div>
27
+ <div class="tnp-field-row">
28
+ <div class="tnp-field-col-2">
29
+ <?php $fields->checkbox('show_image', __('Show image', 'newsletter')) ?>
30
+ </div>
31
+ <div class="tnp-field-col-2">
32
+ <?php $fields->checkbox('show_date', __('Show date', 'newsletter')) ?>
33
+ </div>
34
+ <div style="clear: both"></div>
35
+ </div>
36
+ </div>
37
+
38
+ <div class="tnp-field-row">
39
+ <div class="tnp-field-col-2">
40
+ <?php $fields->select_number('max', __('Max posts', 'newsletter'), 1, 40); ?>
41
+ </div>
42
+ <div class="tnp-field-col-2">
43
+ <?php $fields->select_number( 'post_offset', __( 'Posts offset', 'newsletter' ), 0, 20); ?>
44
+ </div>
45
+ </div>
46
 
47
  <?php $fields->language(); ?>
48
 
50
 
51
  <?php $fields->section(__('Filters', 'newsletter')) ?>
52
  <?php $fields->categories(); ?>
53
+ <?php $fields->text('tags', __('Tags', 'newsletter'), ['description'=>__('Comma separated')]); ?>
54
 
55
  <?php $fields->block_commons() ?>
56
 
emails/composer.php CHANGED
@@ -2,10 +2,10 @@
2
  defined('ABSPATH') || exit;
3
 
4
  require_once NEWSLETTER_INCLUDES_DIR . '/controls.php';
 
5
  $controls = new NewsletterControls();
6
  $module = NewsletterEmails::instance();
7
 
8
- wp_enqueue_style('tnpc-style', plugins_url('/tnp-composer/_css/newsletter-builder.css', __FILE__), array(), time());
9
  wp_enqueue_style('tnpc-newsletter-style', home_url('/') . '?na=emails-composer-css');
10
 
11
  include NEWSLETTER_INCLUDES_DIR . '/codemirror.php';
@@ -14,44 +14,34 @@ if ($controls->is_action()) {
14
 
15
  if (empty($_GET['id'])) {
16
 
17
- $email = array();
18
- $email['status'] = 'new';
19
- $email['track'] = Newsletter::instance()->options['track'];
20
- $email['token'] = $module->get_token();
21
-
22
- $email['message'] = $controls->data['body'];
23
- $email['subject'] = $controls->data['subject'];
24
-
25
- $email['message_text'] = 'This email requires a modern e-mail reader but you can view the email online here:
26
- {email_url}.
27
-
28
- Thank you, ' . wp_specialchars_decode(get_option('blogname'), ENT_QUOTES) . '
29
-
30
- To change your subscription follow: {profile_url}.';
31
-
32
-
33
- $email['editor'] = NewsletterEmails::EDITOR_COMPOSER;
34
- $email['type'] = 'message';
35
- $email['send_on'] = time();
36
- $email['query'] = "select * from " . NEWSLETTER_USERS_TABLE . " where status='C'";
37
-
38
- $email = Newsletter::instance()->save_email($email, ARRAY_A);
39
  } else {
40
 
41
- $email['id'] = $_GET['id'];
42
- $email['editor'] = NewsletterEmails::EDITOR_COMPOSER;
43
- $email['message'] = $controls->data['body'];
44
- $email['subject'] = $controls->data['subject'];
45
- $email = Newsletter::instance()->save_email($email, ARRAY_A);
46
  }
47
 
48
  $controls->add_message_saved();
49
 
50
 
51
- /* * * Post save tasks ** */
52
-
53
  if ($controls->is_action('test')) {
54
- $module->send_test_email($module->get_email($email['id']), $controls);
55
  }
56
 
57
  if ($controls->is_action('preview')) {
@@ -60,20 +50,19 @@ To change your subscription follow: {profile_url}.';
60
  $redirect = $module->get_admin_page_url('composer');
61
  }
62
 
63
- $controls->js_redirect($redirect . '&id=' . $email['id']);
64
 
65
  return;
66
  } else {
67
 
68
  if (!empty($_GET['id'])) {
69
- $email = Newsletter::instance()->get_email((int) $_GET['id'], ARRAY_A);
70
- $controls->data = $email;
71
  }
72
  }
73
 
74
  if (isset($email)) {
75
- $controls->data['body'] = $email['message'];
76
- $controls->data['subject'] = $email['subject'];
77
  }
78
  ?>
79
 
@@ -87,7 +76,7 @@ if (isset($email)) {
87
 
88
  <div class="wrap tnp-emails-composer" id="tnp-wrap">
89
 
90
- <?php $controls->composer_load('body', true); ?>
91
 
92
  <div id="tnp-heading" class="tnp-composer-heading">
93
  <div class="tnpc-logo">
@@ -97,7 +86,7 @@ if (isset($email)) {
97
  <form method="post" action="" id="tnpc-form">
98
  <?php $controls->init(); ?>
99
 
100
- <?php $controls->composer_fields(); ?>
101
 
102
  <?php $controls->button_confirm('reset', __('Back to last save', 'newsletter'), 'Are you sure?'); ?>
103
  <?php $controls->button('save', __('Save', 'newsletter'), 'tnpc_save(this.form); this.form.submit();'); ?>
@@ -105,4 +94,4 @@ if (isset($email)) {
105
  </form>
106
  </div>
107
  </div>
108
- </div>
2
  defined('ABSPATH') || exit;
3
 
4
  require_once NEWSLETTER_INCLUDES_DIR . '/controls.php';
5
+
6
  $controls = new NewsletterControls();
7
  $module = NewsletterEmails::instance();
8
 
 
9
  wp_enqueue_style('tnpc-newsletter-style', home_url('/') . '?na=emails-composer-css');
10
 
11
  include NEWSLETTER_INCLUDES_DIR . '/codemirror.php';
14
 
15
  if (empty($_GET['id'])) {
16
 
17
+ // Create a new email
18
+ $email = new stdClass();
19
+ $email->status = 'new';
20
+ $email->track = Newsletter::instance()->options['track'];
21
+ $email->token = $module->get_token();
22
+ $email->message_text = "This email requires a modern e-mail reader but you can view the email online here:\n{email_url}.\nThank you, " . wp_specialchars_decode(get_option('blogname'), ENT_QUOTES) .
23
+ "\nTo change your subscription follow: {profile_url}.";
24
+ $email->editor = NewsletterEmails::EDITOR_COMPOSER;
25
+ $email->type = 'message';
26
+ $email->send_on = time();
27
+ $email->query = "select * from " . NEWSLETTER_USERS_TABLE . " where status='C'";
28
+
29
+ TNP_Composer::update_email($email, $controls);
30
+
31
+ $email = Newsletter::instance()->save_email($email);
 
 
 
 
 
 
 
32
  } else {
33
 
34
+ $email = Newsletter::instance()->get_email($_GET['id']);
35
+ TNP_Composer::update_email($email, $controls);
36
+ $email = Newsletter::instance()->save_email($email);
37
+
 
38
  }
39
 
40
  $controls->add_message_saved();
41
 
42
 
 
 
43
  if ($controls->is_action('test')) {
44
+ $module->send_test_email($module->get_email($email->id), $controls);
45
  }
46
 
47
  if ($controls->is_action('preview')) {
50
  $redirect = $module->get_admin_page_url('composer');
51
  }
52
 
53
+ $controls->js_redirect($redirect . '&id=' . $email->id);
54
 
55
  return;
56
  } else {
57
 
58
  if (!empty($_GET['id'])) {
59
+ $email = Newsletter::instance()->get_email((int) $_GET['id']);
60
+
61
  }
62
  }
63
 
64
  if (isset($email)) {
65
+ TNP_Composer::prepare_controls($controls, $email);
 
66
  }
67
  ?>
68
 
76
 
77
  <div class="wrap tnp-emails-composer" id="tnp-wrap">
78
 
79
+ <?php $controls->composer_load_v2(true); ?>
80
 
81
  <div id="tnp-heading" class="tnp-composer-heading">
82
  <div class="tnpc-logo">
86
  <form method="post" action="" id="tnpc-form">
87
  <?php $controls->init(); ?>
88
 
89
+ <?php $controls->composer_fields_v2(); ?>
90
 
91
  <?php $controls->button_confirm('reset', __('Back to last save', 'newsletter'), 'Are you sure?'); ?>
92
  <?php $controls->button('save', __('Save', 'newsletter'), 'tnpc_save(this.form); this.form.submit();'); ?>
94
  </form>
95
  </div>
96
  </div>
97
+ </div>
emails/edit.php CHANGED
@@ -124,10 +124,17 @@ if ($controls->is_action('test') || $controls->is_action('save') || $controls->i
124
  } else {
125
  $email['send_on'] = $controls->data['send_on'];
126
  }
127
-
128
  // Reset and refill the options
129
- $email['options'] = array();
130
-
 
 
 
 
 
 
 
131
  foreach ($controls->data as $name => $value) {
132
  if (strpos($name, 'options_') === 0) {
133
  $email['options'][substr($name, 8)] = $value;
124
  } else {
125
  $email['send_on'] = $controls->data['send_on'];
126
  }
127
+
128
  // Reset and refill the options
129
+ // Try without the reset and let's see where the problems are
130
+ //$email['options'] = array();
131
+
132
+ // Reset only specific keys
133
+ unset($email['options']['lists']);
134
+ unset($email['options']['lists_operator']);
135
+ unset($email['options']['lists_exclude']);
136
+ unset($email['options']['sex']);
137
+
138
  foreach ($controls->data as $name => $value) {
139
  if (strpos($name, 'options_') === 0) {
140
  $email['options'][substr($name, 8)] = $value;
emails/emails.php CHANGED
@@ -110,6 +110,7 @@ class NewsletterEmails extends NewsletterModule {
110
  $controls->init();
111
  echo '<input type="hidden" name="action" value="tnpc_render">';
112
  echo '<input type="hidden" name="b" value="' . esc_attr($_REQUEST['id']) . '">';
 
113
 
114
  ob_start();
115
  include $block['dir'] . '/options.php';
@@ -181,13 +182,23 @@ class NewsletterEmails extends NewsletterModule {
181
  * The last run parameter can instruct the block to generate content conditioned to
182
  * the passed timestamp (for example limiting the content to new posts from the last
183
  * run timestamp).
 
 
184
  *
185
- * @param string $theme (Rinominare)
186
  * @return string
187
  */
188
- function regenerate($theme, $context = array()) {
189
- $this->logger->debug('Starting email regeneration');
190
- $this->logger->debug($context);
 
 
 
 
 
 
 
 
191
 
192
  if (empty($theme)) {
193
  $this->logger->debug('The email was empty');
@@ -234,6 +245,12 @@ class NewsletterEmails extends NewsletterModule {
234
  if (!empty($context['last_run']) && $has_dynamic_blocks && $all_empty) {
235
  return '';
236
  }
 
 
 
 
 
 
237
 
238
  $x = strpos($theme, '<body');
239
  if ($x !== false) {
@@ -242,6 +259,13 @@ class NewsletterEmails extends NewsletterModule {
242
  } else {
243
 
244
  }
 
 
 
 
 
 
 
245
  return array('body' => $result, 'subject' => $subject);
246
  }
247
 
@@ -386,17 +410,14 @@ class NewsletterEmails extends NewsletterModule {
386
  * @param type $block_id
387
  * @param type $wrapper
388
  */
389
- function tnpc_render_callback() {
390
- $block_id = $_POST['b'];
391
- $wrapper = isset($_POST['full']);
392
- if (isset($_POST['options']) && is_array($_POST['options'])) {
393
- $options = stripslashes_deep($_POST['options']);
394
- } else {
395
- $options = array();
396
- }
397
- $this->render_block($block_id, $wrapper, $options);
398
- wp_die();
399
- }
400
 
401
  function tnpc_preview_callback() {
402
  $email = Newsletter::instance()->get_email($_REQUEST['id'], ARRAY_A);
@@ -942,6 +963,51 @@ class NewsletterEmails extends NewsletterModule {
942
  }
943
  }
944
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
945
  }
946
 
947
  NewsletterEmails::instance();
110
  $controls->init();
111
  echo '<input type="hidden" name="action" value="tnpc_render">';
112
  echo '<input type="hidden" name="b" value="' . esc_attr($_REQUEST['id']) . '">';
113
+ echo '<input type="hidden" name="options[inline_edits]" value="' . esc_attr( serialize( $controls->data['inline_edits'] ) ) . '">';
114
 
115
  ob_start();
116
  include $block['dir'] . '/options.php';
182
  * The last run parameter can instruct the block to generate content conditioned to
183
  * the passed timestamp (for example limiting the content to new posts from the last
184
  * run timestamp).
185
+ *
186
+ * $email can actually be even a string containing the full newsletter HTML code.
187
  *
188
+ * @param TNP_Email $email (Rinominare)
189
  * @return string
190
  */
191
+ function regenerate($email, $context = array()) {
192
+
193
+ // Cannot be removed due to compatibility issues with old Automated versions
194
+ if (is_object($email)) {
195
+ $theme = $email->message;
196
+ } else {
197
+ $theme = $email;
198
+ }
199
+
200
+ //$this->logger->debug('Starting email regeneration');
201
+ //$this->logger->debug($context);
202
 
203
  if (empty($theme)) {
204
  $this->logger->debug('The email was empty');
245
  if (!empty($context['last_run']) && $has_dynamic_blocks && $all_empty) {
246
  return '';
247
  }
248
+
249
+ // We need to keep the CSS/HEAD part, the regenearion is only about blocks
250
+
251
+ if (is_object($email)) {
252
+ $result = TNP_Composer::get_main_wrapper_open($email) . $result . TNP_Composer::get_main_wrapper_close($email);
253
+ }
254
 
255
  $x = strpos($theme, '<body');
256
  if ($x !== false) {
259
  } else {
260
 
261
  }
262
+
263
+ if (is_object($email)) {
264
+ $email->message = $result;
265
+ $email->subject = $subject;
266
+ }
267
+
268
+ // Kept for compatibility
269
  return array('body' => $result, 'subject' => $subject);
270
  }
271
 
410
  * @param type $block_id
411
  * @param type $wrapper
412
  */
413
+ function tnpc_render_callback() {
414
+ $block_id = $_POST['b'];
415
+ $wrapper = isset( $_POST['full'] );
416
+ $options = $this->restore_options_from_request();
417
+
418
+ $this->render_block( $block_id, $wrapper, $options );
419
+ wp_die();
420
+ }
 
 
 
421
 
422
  function tnpc_preview_callback() {
423
  $email = Newsletter::instance()->get_email($_REQUEST['id'], ARRAY_A);
963
  }
964
  }
965
 
966
+ function restore_options_from_request() {
967
+
968
+ if ( isset( $_POST['options'] ) && is_array( $_POST['options'] ) ) {
969
+ // Get all block options
970
+ $options = stripslashes_deep( $_POST['options'] );
971
+
972
+ // Deserialize inline edits when
973
+ // render is preformed on saving block options
974
+ if ( isset( $options['inline_edits'] ) && is_serialized( $options['inline_edits'] ) ) {
975
+ $options['inline_edits'] = unserialize( $options['inline_edits'] );
976
+ }
977
+
978
+ // Restore inline edits from data-json
979
+ // coming from inline editing
980
+ // and merge with current inline edit
981
+ if ( isset( $_POST['encoded_options'] ) ) {
982
+ $decoded_options = $this->options_decode( $_POST['encoded_options'] );
983
+
984
+ $to_merge_inline_edits = [];
985
+
986
+ if ( isset( $decoded_options['inline_edits'] ) ) {
987
+ foreach ( $decoded_options['inline_edits'] as $decoded_inline_edit ) {
988
+ $to_merge_inline_edits[ $decoded_inline_edit['post_id'] . $decoded_inline_edit['type'] ] = $decoded_inline_edit;
989
+ }
990
+ }
991
+
992
+ //Overwrite with new edited content
993
+ if ( isset( $options['inline_edits'] ) ) {
994
+ foreach ( $options['inline_edits'] as $inline_edit ) {
995
+ $to_merge_inline_edits[ $inline_edit['post_id'] . $inline_edit['type'] ] = $inline_edit;
996
+ }
997
+ }
998
+
999
+ $options['inline_edits'] = array_values( $to_merge_inline_edits );
1000
+ $options = array_merge( $decoded_options, $options );
1001
+ }
1002
+
1003
+ return $options;
1004
+
1005
+ }
1006
+
1007
+ return array();
1008
+
1009
+ }
1010
+
1011
  }
1012
 
1013
  NewsletterEmails::instance();
emails/images/html.png CHANGED
Binary file
emails/theme.php CHANGED
@@ -76,24 +76,25 @@ $themes = $module->themes->get_all_with_data();
76
  <div class="tnp-theme-preview">
77
  <p><?php echo _e('Responsive Drag & Drop Composer', 'newsletter') ?></p>
78
  <a href="<?php echo $module->get_admin_page_url('composer'); ?>" style="margin-right: 20px; margin-bottom: 20px">
79
- <img src="<?php echo plugins_url('newsletter') . '/emails/images/composer.gif' ?>" width="420" height="200">
80
  </a>
81
  </div>
82
 
83
  <div class="tnp-theme-preview">
84
  <p>&lt;&gt; Raw HTML</p>
85
  <a href="<?php echo wp_nonce_url('admin.php?page=newsletter_emails_new&id=rawhtml', 'newsletter-new') ?>" style="margin-right: 20px; margin-bottom: 20px">
86
- <img src="<?php echo plugins_url('newsletter') . '/emails/images/html.png' ?>" width="200" height="200">
87
  </a>
88
  </div>
89
 
90
  </div>
 
91
 
92
  <?php foreach ($themes as $id => $data) { ?>
93
  <div class="tnp-theme-preview">
94
  <p><?php echo esc_html($data['name']) ?></p>
95
  <a href="<?php echo wp_nonce_url('admin.php?page=newsletter_emails_new&id=' . urlencode($id), 'newsletter-new') ?>" style="margin-right: 20px; margin-bottom: 20px">
96
- <img src="<?php echo esc_attr($data['screenshot']) ?>" width="300" height="450">
97
  </a>
98
  </div>
99
  <?php } ?>
76
  <div class="tnp-theme-preview">
77
  <p><?php echo _e('Responsive Drag & Drop Composer', 'newsletter') ?></p>
78
  <a href="<?php echo $module->get_admin_page_url('composer'); ?>" style="margin-right: 20px; margin-bottom: 20px">
79
+ <img class="tnp-theme-composer" src="<?php echo plugins_url('newsletter') . '/emails/images/composer.gif' ?>">
80
  </a>
81
  </div>
82
 
83
  <div class="tnp-theme-preview">
84
  <p>&lt;&gt; Raw HTML</p>
85
  <a href="<?php echo wp_nonce_url('admin.php?page=newsletter_emails_new&id=rawhtml', 'newsletter-new') ?>" style="margin-right: 20px; margin-bottom: 20px">
86
+ <img class="tnp-theme-html" src="<?php echo plugins_url('newsletter') . '/emails/images/html.png' ?>">
87
  </a>
88
  </div>
89
 
90
  </div>
91
+ <h2>Classic Themes</h2>
92
 
93
  <?php foreach ($themes as $id => $data) { ?>
94
  <div class="tnp-theme-preview">
95
  <p><?php echo esc_html($data['name']) ?></p>
96
  <a href="<?php echo wp_nonce_url('admin.php?page=newsletter_emails_new&id=' . urlencode($id), 'newsletter-new') ?>" style="margin-right: 20px; margin-bottom: 20px">
97
+ <img src="<?php echo esc_attr($data['screenshot']) ?>">
98
  </a>
99
  </div>
100
  <?php } ?>
emails/tnp-composer/_css/newsletter-builder-v2.css ADDED
@@ -0,0 +1,892 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ .tnp-composer-heading {
2
+ background-color: #0073aa;
3
+ border-radius: 0px !important;
4
+ border-top: 5px solid #ffffff;
5
+ }
6
+
7
+ .tnp-composer-heading h2 {
8
+ display: inline-block;
9
+ margin-left: 30px !important;
10
+ text-transform: none !important;
11
+ font-weight: 400 !important;
12
+ }
13
+
14
+ .tnp-composer-heading a {
15
+ display: inline-block;
16
+ margin-left: 30px;
17
+ }
18
+
19
+ .tnp-composer-heading form {
20
+ display: inline-block;
21
+ margin-left: 30px;
22
+ }
23
+
24
+ .tnp-composer-heading img {
25
+ width: 50px;
26
+ vertical-align: middle;
27
+ }
28
+
29
+ #newsletter-builder {
30
+ position: relative;
31
+ overflow: hidden;
32
+ width: 100%;
33
+ background-color: #FFFFFF;
34
+ }
35
+
36
+ .tnp-builder-column {
37
+ overflow: auto;
38
+ height: 85vh;
39
+ float: left;
40
+ }
41
+
42
+ #newsletter-builder-sidebar {
43
+ z-index: 1;
44
+ width: 33.33%;
45
+ background-color: #ECF0F1;
46
+ position: relative;
47
+ }
48
+
49
+ #newsletter-builder-sidebar h4 {
50
+ /* margin: 5px; */
51
+ /* text-align: center; */
52
+ color: #868686;
53
+ /* margin-bottom: 20px; */
54
+ font-family: Montserrat, sans-serif;
55
+ font-weight: 300;
56
+ border-bottom: 1px solid #fff;
57
+ padding-bottom: 10px;
58
+ }
59
+
60
+ /*#newsletter-builder-sidebar h4 span {
61
+ background-color: #27AE60;
62
+ padding: 2px 5px;
63
+ border-radius: 3px;
64
+ }*/
65
+
66
+
67
+ #newsletter-builder-sidebar .newsletter-sidebar-add-buttons img {
68
+ width: 150px;
69
+ height: auto;
70
+ }
71
+
72
+ .newsletter-sidebar-add-buttons {
73
+ border-radius: 4px;
74
+ padding: 5px;
75
+ margin: 5px;
76
+ }
77
+
78
+ .tnp-body-lite {
79
+ background-color: #FFFFFF !important;
80
+ }
81
+
82
+ .newsletter-sidebar-buttons-content-tab {
83
+ margin: 1px;
84
+ position: relative;
85
+ display: inline-block;
86
+ }
87
+ .newsletter-sidebar-buttons-content-tab:hover {
88
+ cursor: move;
89
+ }
90
+ .newsletter-sidebar-buttons-content-tab:hover img{
91
+ opacity: 0.8;
92
+ }
93
+ .newsletter-sidebar-buttons-content-tab:hover .newsletter-sidebar-buttons-content-tab-add{
94
+ opacity: 0.5;
95
+ }
96
+ .newsletter-sidebar-buttons-content-tab-add {
97
+ height: 100%;
98
+ width: 100%;
99
+ background-color: rgba(70,70,70,1);
100
+ position: absolute;
101
+ left: 0;
102
+ top: 0;
103
+ /*float: left;*/
104
+ /*margin-top: -15px;*/
105
+ /*margin-left: -50px;*/
106
+ -webkit-transition: all 0.5s;
107
+ -moz-transition: all 0.5s;
108
+ -o-transition: all 0.5s;
109
+ transition: all 0.5s;
110
+ z-index: 2;
111
+ opacity: 0;
112
+ text-align: center;
113
+ line-height: inherit;
114
+ color: white;
115
+ }
116
+ .newsletter-sidebar-buttons-content-tab-add:hover {
117
+ background-color: rgba(0,0,0,1);
118
+ /* cursor: pointer;*/
119
+ }
120
+
121
+ #newsletter-builder-area {
122
+ background-color: #fff;
123
+ width: 66.66%;
124
+ box-sizing: border-box;
125
+ padding-left: 50px;
126
+ padding-right: 50px;
127
+ padding-top: 10px;
128
+ }
129
+
130
+
131
+
132
+ #newsletter-builder-area-center-frame-content {
133
+ /*float: left;*/
134
+ /*width: 730px;*/
135
+ /*background-color: rgba(153,153,153,1);*/
136
+ min-height: 50px;
137
+ padding-bottom: 75px;
138
+ background-color: #ECF0F1;
139
+ padding-top: 30px;
140
+ /*border: 1px dashed #eee;*/
141
+ }
142
+
143
+ #newsletter-mobile-preview-area {
144
+ margin-left: 30px;
145
+ box-sizing: border-box;
146
+ margin-top: 30px;
147
+ text-align: center;
148
+ border: 1px solid #ddd;
149
+ border-radius: 10px;
150
+ padding-left: 10px;
151
+ padding-right: 10px;
152
+ padding-top: 10px;
153
+ }
154
+ #newsletter-mobile-preview-area input {
155
+ width: 100px;
156
+ }
157
+
158
+ iframe#tnpc-mobile-preview {
159
+ height: 500px;
160
+ box-sizing: border-box;
161
+ width: 320px;
162
+ border-radius: 30px;
163
+ margin-top: 20px;
164
+ margin-left: 20px;
165
+ background-color: #F6F8FD;
166
+ }
167
+
168
+ .tnpc-row {
169
+ -webkit-transition: box-shadow 0.5s;
170
+ -moz-transition: box-shadow 0.5s;
171
+ -o-transition: box-shadow 0.5s;
172
+ transition: box-shadow 0.5s;
173
+ position: relative;
174
+ }
175
+ .tnpc-row:hover {
176
+ cursor: move;
177
+ /*border: 2px dashed #999;*/
178
+ -webkit-box-shadow: 0px 0px 20px 0px rgba(0,0,0,0.2);
179
+ -moz-box-shadow: 0px 0px 20px 0px rgba(0,0,0,0.2);
180
+ box-shadow: 0px 0px 20px 0px rgba(0,0,0,0.2);
181
+ }
182
+ .tnpc-row.ui-sortable-helper {
183
+ max-width: 700px!important;
184
+ }
185
+ .tnpc-row-delete, .tnpc-row-edit-block, .tnpc-row-clone {
186
+ height: 30px;
187
+ width: 30px;
188
+ top: 0px;
189
+ background-color: rgba(255,255,255,0.5);
190
+ z-index: 5;
191
+ position: absolute;
192
+ color: rgba(102,102,102,1);
193
+ -webkit-transition: all 0.5s;
194
+ -moz-transition: all 0.5s;
195
+ -o-transition: all 0.5s;
196
+ transition: all 0.5s;
197
+ opacity: 0;
198
+ text-align: center;
199
+ font-size: 18px;
200
+ }
201
+ .tnpc-row-delete i, .tnpc-row-edit-block i, .tnpc-row-clone i {
202
+ line-height: 30px;
203
+ }
204
+ .tnpc-row-delete:hover {
205
+ background-color: #E74C3C;
206
+ cursor: pointer;
207
+ color: rgba(255,255,255,1);
208
+ }
209
+ .tnpc-row:hover .tnpc-row-delete, .tnpc-row:hover .tnpc-row-edit-block, .tnpc-row:hover .tnpc-row-clone {
210
+ opacity: 1;
211
+ }
212
+ .tnpc-row-delete {
213
+ right: 0px;
214
+ z-index: 5;
215
+ }
216
+ .tnpc-row-edit-block {
217
+ right: 60px;
218
+ }
219
+ .tnpc-row-edit-block:hover {
220
+ background-color: #e0e0e0;
221
+ cursor: pointer;
222
+ color: rgba(0, 0, 0, 1);
223
+ }
224
+
225
+ .tnpc-row-clone {
226
+ right: 30px;
227
+ }
228
+ .tnpc-row-clone:hover {
229
+ background-color: #e0e0e0;;
230
+ cursor: pointer;
231
+ color: rgba(0,0,0,1);
232
+ }
233
+
234
+ .tnpc-row-edit {
235
+ position: relative;
236
+ }
237
+ .tnpc-row-edit-hover {
238
+ height: 100%;
239
+ width: 100%;
240
+ background-color: rgba(63,141,191,0.8);
241
+ position: absolute;
242
+ left: 0px;
243
+ top: 0px;
244
+ cursor: default;
245
+ -webkit-transition: all 0.5s;
246
+ -moz-transition: all 0.5s;
247
+ -o-transition: all 0.5s;
248
+ transition: all 0.5s;
249
+ }
250
+ .tnpc-row-edit-hover i {
251
+ position: absolute;
252
+ height: 30px;
253
+ width: 30px;
254
+ line-height: 30px;
255
+ left: 50%;
256
+ top: 50%;
257
+ text-align: center;
258
+ margin-top: -15px;
259
+ margin-left: -15px;
260
+ color: rgba(255,255,255,1);
261
+ -webkit-transition: all 0.5s;
262
+ -moz-transition: all 0.5s;
263
+ -o-transition: all 0.5s;
264
+ transition: all 0.5s;
265
+ -webkit-border-radius: 50%;
266
+ -moz-border-radius: 50%;
267
+ border-radius: 50%;
268
+ font-size: 16px;
269
+ }
270
+ .tnpc-row-edit-hover i:hover {
271
+ background-color: rgba(0,0,0,0.5);
272
+ cursor: pointer;
273
+ }
274
+
275
+ .tnpc-drop-here {
276
+ padding:10px;
277
+ text-align: center;
278
+ }
279
+
280
+ .tnpc-edit {
281
+ height: 100vh;
282
+ width: 100vw;
283
+ z-index: 10;
284
+ display: none;
285
+ position: absolute;
286
+ top: 0px;
287
+ left: 0px;
288
+ }
289
+
290
+ .tnpc-edit-box-title {
291
+ /*float: left;*/
292
+ width: 100%;
293
+ font-size: 29px;
294
+ color: #666666;
295
+ font-weight: 300;
296
+ margin-bottom: 40px;
297
+ }
298
+
299
+ .tnpc-edit-box-content {
300
+ /*float: left;*/
301
+ width: 100%;
302
+ margin-top: 10px;
303
+ }
304
+ .tnpc-edit-box-content-text {
305
+ /*float: left;*/
306
+ width: 100%;
307
+ font-size: 15px;
308
+ color: #666666;
309
+ font-weight: 600;
310
+ margin: 15px 0px 10px;
311
+ text-transform: uppercase;
312
+ }
313
+
314
+ .tnpc-edit-box-content-text span {
315
+ font-size: 11px;
316
+ color: #95A5A6;
317
+ background-color: #D3EADC;
318
+ padding: 2px 5px;
319
+ text-transform: none;
320
+ border-radius: 5px;
321
+ }
322
+
323
+ .tnpc-edit-box-content-field {
324
+ /*float: left;*/
325
+ width: 100%;
326
+ }
327
+
328
+ .tnpc-edit-box-content-field-input {
329
+ height: 33px;
330
+ width: 380px;
331
+ border: none !important;
332
+ outline: none;
333
+ font-family: inherit;
334
+ padding-right: 10px;
335
+ font-size: 15px;
336
+ -webkit-transition: all 0.5s;
337
+ -moz-transition: all 0.5s;
338
+ -o-transition: all 0.5s;
339
+ transition: all 0.5s;
340
+ color: rgba(102,102,102,1);
341
+ margin-bottom: 10px;
342
+ }
343
+ .tnpc-edit-box-content-field-input:focus {
344
+ -webkit-box-shadow: inset 0px 0px 10px 0px rgba(0,0,0,0.2);
345
+ -moz-box-shadow: inset 0px 0px 10px 0px rgba(0,0,0,0.2);
346
+ box-shadow: inset 0px 0px 10px 0px rgba(0,0,0,0.2);
347
+ }
348
+ .tnpc-edit-box-content-field-textarea {
349
+ /*float: left;*/
350
+ height: 180px;
351
+ width: 380px;
352
+ border: 1px solid rgba(204,204,204,1);
353
+ outline: none;
354
+ font-family: inherit;
355
+ font-size: 15px;
356
+ -webkit-transition: all 0.5s;
357
+ -moz-transition: all 0.5s;
358
+ -o-transition: all 0.5s;
359
+ transition: all 0.5s;
360
+ color: rgba(102,102,102,1);
361
+ resize: none;
362
+ padding: 10px;
363
+ }
364
+ .tnpc-edit-box-content-field-textarea:focus {
365
+ -webkit-box-shadow: inset 0px 0px 10px 0px rgba(0,0,0,0.2);
366
+ -moz-box-shadow: inset 0px 0px 10px 0px rgba(0,0,0,0.2);
367
+ box-shadow: inset 0px 0px 10px 0px rgba(0,0,0,0.2);
368
+ }
369
+ .tnpc-edit-box-content-icons {
370
+ /*float: left;*/
371
+ height: 388px;
372
+ width: 388px;
373
+ border: 1px solid rgba(204,204,204,1);
374
+ margin-top: 15px;
375
+ overflow-y: scroll;
376
+ }
377
+ .tnpc-edit-box-content-icons i {
378
+ line-height: 50px;
379
+ background-color: rgba(225,225,225,1);
380
+ /*float: left;*/
381
+ height: 50px;
382
+ width: 50px;
383
+ margin-top: 10px;
384
+ margin-left: 10px;
385
+ text-align: center;
386
+ -webkit-transition: all 0.5s;
387
+ -moz-transition: all 0.5s;
388
+ -o-transition: all 0.5s;
389
+ transition: all 0.5s;
390
+ font-size: 28px;
391
+ color: rgba(51,51,51,1);
392
+ }
393
+ .tnpc-edit-box-content-icons i:hover {
394
+ cursor: pointer;
395
+ background-color: rgba(153,153,153,1);
396
+ -webkit-border-radius: 50%;
397
+ -moz-border-radius: 50%;
398
+ border-radius: 50%;
399
+ color: rgba(0,0,0,1);
400
+ }
401
+
402
+ /* Save and cancel buttons container on block options popup */
403
+ .tnpc-edit-box-buttons{
404
+ margin-top: 10px;
405
+ text-align: right;
406
+ margin-right: 10px;
407
+ }
408
+
409
+ .tnpc-edit-box-buttons-save{
410
+ height: 35px;
411
+ text-align: right;
412
+ line-height: 35px;
413
+ color: #27AE60;
414
+ font-weight: 600;
415
+ font-size: 15px;
416
+ -webkit-border-radius: 3px;
417
+ -moz-border-radius: 3px;
418
+ border-radius: 3px;
419
+ -webkit-transition: background 0.5s;
420
+ -moz-transition: background 0.5s;
421
+ -o-transition: background 0.5s;
422
+ transition: background 0.5s;
423
+ cursor: pointer;
424
+ /*float: left;*/
425
+ /*padding-right: 25px;
426
+ padding-left: 25px;
427
+ width: 33%;*/
428
+ display: inline-block;
429
+ }
430
+ .tnpc-edit-box-buttons-save:hover {
431
+ color: #2ECC71;
432
+ }
433
+ .tnpc-edit-box-buttons-cancel{
434
+ height: 35px;
435
+ text-align: right;
436
+ line-height: 35px;
437
+ color: #666;
438
+ font-weight: normal;
439
+ font-size: 15px;
440
+ -webkit-border-radius: 3px;
441
+ -moz-border-radius: 3px;
442
+ border-radius: 3px;
443
+ -webkit-transition: background 0.5s;
444
+ -moz-transition: background 0.5s;
445
+ -o-transition: background 0.5s;
446
+ transition: background 0.5s;
447
+ cursor: pointer;
448
+ /*float: left;*/
449
+ /*padding-right: 25px;
450
+ padding-left: 25px;
451
+ width: 33%;*/
452
+ display: inline-block;
453
+ margin-right: 25px;
454
+ }
455
+ .tnpc-edit-box-buttons-cancel:hover {
456
+ color: #E74C3C;
457
+ }
458
+
459
+ .tnpc-edit-box-content-field .iris-square {
460
+ margin-right: 10px;
461
+ }
462
+
463
+ .tnpc-edit-box-content-field .iris-picker .iris-slider {
464
+ height: 100% !important;
465
+ }
466
+
467
+
468
+
469
+ /* Tnp Composer Preview */
470
+
471
+
472
+ .tnpc-subject a {
473
+ font-family: Source Sans Pro;
474
+ font-weight: 700;
475
+ text-transform: uppercase;
476
+ text-decoration: none;
477
+ background-color: #3498DB;
478
+ color: white;
479
+ padding: 2px 10px;
480
+ border-radius: 10px;
481
+ font-size: 13px;
482
+ letter-spacing: 0.1em;
483
+ }
484
+
485
+
486
+ .tnpc-preview {
487
+ margin-top: 10px;
488
+ }
489
+
490
+ .tnpc-preview .fake-browser-ui iframe {
491
+ width: 700px;
492
+ }
493
+
494
+ .tnpc-preview .fake-mobile-browser-ui iframe {
495
+ width: 320px;
496
+ }
497
+
498
+ .fake-browser-ui {
499
+ padding: 30px 0 0;
500
+ border-radius: 3px;
501
+ border-bottom: 10px solid #ccc;
502
+ background: #ddd;
503
+ display: inline-block;
504
+ position: relative;
505
+ line-height: 0;
506
+ vertical-align: top;
507
+ margin-left: 20px;
508
+ }
509
+
510
+ .fake-mobile-browser-ui {
511
+ padding: 30px 10px 37px;
512
+ border-radius: 10px;
513
+ border-bottom: 10px solid #ccc;
514
+ background: #ddd;
515
+ display: inline-block;
516
+ position: relative;
517
+ line-height: 0;
518
+ margin-left: 30px;
519
+ }
520
+
521
+ .fake-browser-ui .frame {
522
+ display: block;
523
+ height: 25px;
524
+ position: absolute;
525
+ top: 12px;
526
+ left: 8px;
527
+ }
528
+
529
+ .fake-mobile-browser-ui .frame {
530
+ display: block;
531
+ height: 25px;
532
+ margin-top: 10px;
533
+ }
534
+
535
+ .fake-browser-ui span {
536
+ height: 12px;
537
+ width: 12px;
538
+ border-radius: 8px;
539
+ background-color: #eee;
540
+ border: 1px solid #dadada;
541
+ float: left;
542
+ margin: 0 0 0 4px;
543
+ }
544
+
545
+ .fake-mobile-browser-ui span {
546
+ height: 50px;
547
+ width: 50px;
548
+ border-radius: 60px;
549
+ background-color: #eee;
550
+ border: 2px solid #ccc;
551
+ display: block;
552
+ margin: auto;
553
+ }
554
+
555
+ .fake-browser-ui .bt-1 {
556
+ background-color: #ED594A;
557
+ }
558
+
559
+ .fake-browser-ui .bt-2 {
560
+ background-color: #FDD800;
561
+ }
562
+
563
+ .fake-browser-ui .bt-3 {
564
+ background-color: #5AC05A;
565
+ }
566
+
567
+
568
+ /* Tnp Html Editor */
569
+
570
+ #tnpc-html-editor {
571
+ height: 600px;
572
+ border-top: 20px solid #323232;
573
+ border-radius: 8px;
574
+ }
575
+
576
+ /* List Block Styles */ *
577
+
578
+ .tnp-select2-option {
579
+ /* background-color: red; */
580
+ }
581
+
582
+ .tnp-select2-option img {
583
+ height: 15px;
584
+ margin-right: 5px;
585
+ vertical-align: middle;
586
+ background-color: rgba(234, 234, 234, 0.25);
587
+ padding: 10px;
588
+ border-radius: 5px;
589
+ }
590
+
591
+ /* ************************************************************************** */
592
+ /* Block options layer over the sidebar */
593
+
594
+ /* Main container */
595
+ #tnpc-block-options {
596
+ height: 100vh;
597
+ z-index: 10;
598
+ display: none;
599
+ position: absolute;
600
+ top: 0px;
601
+ left: 0px;
602
+ bottom: 0;
603
+ right: 0;
604
+ background-color: #ECF0F1;
605
+ padding: 0;
606
+ }
607
+
608
+ /* Form */
609
+ form#tnpc-block-options-form {
610
+ background-color: #fff;
611
+ padding: 15px;
612
+ margin-top: 50px;
613
+ }
614
+
615
+ #tnpc-block-options-form, #tnpc-block-options-form p {
616
+ color: #444;
617
+ background-color: #ECF0F1 !important;
618
+ }
619
+
620
+
621
+ #tnpc-block-options-form h3 {
622
+ color: #000;
623
+ }
624
+
625
+ #tnpc-block-options-form table.form-table th {
626
+ /*background-color: #f4f4f4;*/
627
+ width: 100%;
628
+ vertical-align: top;
629
+ float: left;
630
+ font-weight: normal;
631
+ text-transform: uppercase;
632
+ font-size: 13px;
633
+ padding-top: 10px;
634
+ padding-bottom: 5px;
635
+ padding-left: 0;
636
+ padding-right: 0;
637
+
638
+ }
639
+
640
+ #tnpc-block-options-form table.form-table td {
641
+ float: left;
642
+ padding: 0;
643
+ margin: 0;
644
+ border: 0;
645
+ width: 100%;
646
+ }
647
+
648
+ #tnpc-block-options-form table.form-table {
649
+ margin: 0px;
650
+ border-collapse: separate!important;
651
+ border-spacing: 1px!important;
652
+ }
653
+
654
+ #tnpc-block-options-form table.form-table table.tnp-button-colors {
655
+ border: 0;
656
+ border-collapse: collapse;
657
+ }
658
+ #tnpc-block-options-form table.form-table table.tnp-button-colors td {
659
+ border: 0;
660
+ padding-top: 0;
661
+ }
662
+
663
+ /* Save and cancel button container */
664
+ #tnpc-block-options-buttons {
665
+ padding: 20px;
666
+ text-align: right;
667
+ background-color: #ecf0f1;
668
+ width: 31%;
669
+ position: fixed;
670
+ height: 70px;
671
+ border-bottom: 1px solid #ffffff;
672
+ z-index: 9999999;
673
+ }
674
+
675
+ #tnpc-block-options-save{
676
+ }
677
+
678
+ #tnpc-block-options-save:hover {
679
+ }
680
+
681
+ #tnpc-block-options-cancel{
682
+ }
683
+
684
+ #tnpc-block-options-cancel:hover {
685
+ }
686
+
687
+
688
+ /* Style the tab */
689
+ .tnpc-tabs {
690
+ overflow: hidden;
691
+ background-color: #fff;
692
+ font-family: Montserrat, sans-serif;
693
+ }
694
+
695
+ /* Style the buttons that are used to open the tab content */
696
+ .tnpc-tabs button {
697
+ background-color: inherit;
698
+ float: left;
699
+ border: none;
700
+ outline: none;
701
+ cursor: pointer;
702
+ padding: 14px 16px;
703
+ transition: 0.3s;
704
+ color: #6a8ba0;
705
+ }
706
+
707
+ /* Change background color of buttons on hover */
708
+ .tnpc-tabs button:hover {
709
+ background-color: #ddd;
710
+ }
711
+
712
+ /* Create an active/current tablink class */
713
+ .tnpc-tabs button.active {
714
+ background-color: #ECF0F1;
715
+ color: #3498DB;
716
+ }
717
+
718
+ /* Style the tab content */
719
+ .tabcontent {
720
+ display: none;
721
+ padding: 6px 12px;
722
+ border-top: none;
723
+ }
724
+
725
+ /* Style Reset, Save, Save & Preview footer */
726
+
727
+ .tnpc-controls {
728
+ text-align: right;
729
+ }
730
+
731
+ .tnpc-logo {
732
+ float: left;
733
+ }
734
+
735
+ .tnpc-logo p {
736
+ font-family: Montserrat, Sans-serif;
737
+ color: #fff !important;
738
+ font-size: 16px;
739
+ margin-left: 20px !important;
740
+ margin-top: 5px !important;
741
+ }
742
+
743
+ /* Style Subject Area */
744
+ /* No influenza anche il contenuto della mail */
745
+ #newsletter-builder-area p {
746
+ /*background-color: #ECF0F1;
747
+ padding: 15px;*/
748
+ }
749
+
750
+ /* Global Options elements style */
751
+
752
+ #tnpc-general-options select {
753
+ box-shadow: none;
754
+ border-radius: 0px;
755
+ border: none;
756
+ margin-right: 5px;
757
+ }
758
+
759
+ /* Blocks options global styles */
760
+
761
+ .tnpc-block-options-warning {
762
+ background-color: #def9e9;
763
+ padding: 10px 15px;
764
+ }
765
+
766
+ /* Presets */
767
+
768
+ .tnpc-presets-title {
769
+ padding: 0px 20px 25px;
770
+ font-size: 21px;
771
+ margin-bottom: 30px;
772
+ color: #484848;
773
+ border-bottom: 3px solid white;
774
+ }
775
+
776
+ .tnpc-preset {
777
+ float: left;
778
+ margin: 15px;
779
+ cursor: pointer;
780
+ width: 150px;
781
+ height: 263px;
782
+ background: white;
783
+ border-radius: 8px;
784
+ box-shadow: 0 0 2px 0px #dee3e4;
785
+ position: relative;
786
+ }
787
+
788
+ .tnpc-preset:hover {
789
+ box-shadow: 0 0 8px 8px #dee3e4;
790
+ }
791
+
792
+ .tnpc-preset-label {
793
+ position: absolute;
794
+ top: 200px;
795
+ left: 50%;
796
+ text-align: center;
797
+ transform: translate(-50%, -50%);
798
+ font-size: 14px;
799
+ width: 80%;
800
+ }
801
+
802
+ .tnpc-inline-editable {
803
+ cursor: text;
804
+ }
805
+
806
+ .tnpc-inline-editable {
807
+ cursor: text;
808
+ position: relative;
809
+ }
810
+
811
+ .tnpc-inline-editable:hover {
812
+ color: #EEE !important;
813
+ }
814
+
815
+ .tnpc-inline-editable:hover:after {
816
+ content: '';
817
+ cursor: pointer;
818
+ position: absolute;
819
+ top: 0;
820
+ left: 0;
821
+ width: 100%;
822
+ height: 100%;
823
+ background-color: rgba(0, 0, 0, 0.2);
824
+ opacity: 1;
825
+ border-radius: 2px;
826
+ }
827
+
828
+ .tnpc-inline-editable:hover:before {
829
+ content: '\f464';
830
+ font-family: dashicons;
831
+ position: absolute;
832
+ top: 0;
833
+ bottom: 0;
834
+ left: 0;
835
+ right: 0;
836
+ margin: auto;
837
+ width: 32px;
838
+ height: 32px;
839
+ font-size: 32px;
840
+ line-height: 32px;
841
+ color: #333;
842
+ }
843
+
844
+ .tnpc-inline-editable-form {
845
+ position: relative;
846
+ margin-top: 25px;
847
+ }
848
+
849
+ .tnpc-inline-editable-form textarea,
850
+ .tnpc-inline-editable-form input {
851
+ width: 95%;
852
+ margin-left: 20px;
853
+ }
854
+
855
+ .two-columns .tnpc-inline-editable-form-actions {
856
+ right: 0;
857
+ }
858
+
859
+ .tnpc-inline-editable-form input {
860
+ padding: 5px;
861
+ font-size: 25px;
862
+ font-family: Helvetica, Arial, sans-serif;
863
+ font-weight: normal;
864
+ color: rgb(51, 51, 51);
865
+ line-height: normal;
866
+ }
867
+
868
+ .tnpc-inline-editable-form-actions {
869
+ position: absolute;
870
+ top: -25px;
871
+ right: 5px;
872
+ display: flex;
873
+ align-items: center;
874
+ flex-wrap: wrap;
875
+ }
876
+
877
+ .tnpc-inline-editable-form-actions button {
878
+ background: none;
879
+ padding: 0;
880
+ border: none;
881
+ }
882
+
883
+ .tnpc-inline-editable-form-actions span {
884
+ display: block;
885
+ font-size: 25px;
886
+ color: #333;
887
+ cursor: pointer;
888
+ }
889
+
890
+ .tnpc-inline-editable-form-actions span:first-child {
891
+ margin-right: 5px;
892
+ }
emails/tnp-composer/_scripts/newsletter-builder-v2.js ADDED
@@ -0,0 +1,546 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // add delete buttons
2
+ jQuery.fn.add_delete = function () {
3
+ this.append('<div class="tnpc-row-delete" title="Delete"><img src="' + TNP_PLUGIN_URL + '/emails/tnp-composer/_assets/delete.png" width="32"></div>');
4
+ this.find('.tnpc-row-delete').perform_delete();
5
+ };
6
+
7
+ // delete row
8
+ jQuery.fn.perform_delete = function () {
9
+ this.click(function () {
10
+ // hide block edit form
11
+ jQuery("#tnpc-block-options").hide();
12
+ // remove block
13
+ jQuery(this).parent().remove();
14
+ tnpc_mobile_preview();
15
+ });
16
+ }
17
+
18
+ // add edit button
19
+ jQuery.fn.add_block_edit = function () {
20
+ this.append('<div class="tnpc-row-edit-block" title="Edit"><img src="' + TNP_PLUGIN_URL + '/emails/tnp-composer/_assets/edit.png" width="32"></div>');
21
+ this.find('.tnpc-row-edit-block').perform_block_edit();
22
+ }
23
+
24
+ // add clone button
25
+ jQuery.fn.add_block_clone = function () {
26
+ this.append('<div class="tnpc-row-clone" title="Clone"><img src="' + TNP_PLUGIN_URL + '/emails/tnp-composer/_assets/copy.png" width="32"></div>');
27
+ this.find('.tnpc-row-clone').perform_clone();
28
+ }
29
+
30
+ let start_options = null;
31
+ let container = null;
32
+
33
+ jQuery.fn.perform_block_edit = function () {
34
+
35
+ jQuery(".tnpc-row-edit-block").click(function (e) {
36
+ e.preventDefault()
37
+ });
38
+
39
+ this.click(function (e) {
40
+
41
+ e.preventDefault();
42
+
43
+ target = jQuery(this).parent().find('.edit-block');
44
+
45
+ jQuery("#tnpc-edit-block .bgcolor").val(target.css("background-color"));
46
+ jQuery("#tnpc-edit-block .font").val(target.css("font-family"));
47
+
48
+ jQuery('.bgcolor').wpColorPicker().iris('color', target.css("background-color"));
49
+
50
+ // The row container which is a global variable and used later after the options save
51
+ container = jQuery(this).closest("table");
52
+
53
+ if (container.hasClass('tnpc-row-block')) {
54
+
55
+ jQuery("#tnpc-block-options").fadeIn(500);
56
+ var options = container.find(".tnpc-block-content").attr("data-json");
57
+ // Compatibility
58
+ if (!options) {
59
+ options = target.attr("data-options");
60
+ }
61
+ //debugger;
62
+ jQuery("#tnpc-block-options-form").load(ajaxurl, {
63
+ action: "tnpc_options",
64
+ id: container.data("id"),
65
+ context_type: tnp_context_type,
66
+ options: options
67
+ }, function () {
68
+ start_options = jQuery("#tnpc-block-options-form").serialize();
69
+ });
70
+
71
+ } else {
72
+ alert("This is deprecated block version and cannot be edited. Please replace it with a new one.");
73
+ }
74
+
75
+ });
76
+
77
+ };
78
+
79
+ jQuery.fn.perform_clone = function () {
80
+
81
+ jQuery(".tnpc-row-clone").click(function (e) {
82
+ e.preventDefault()
83
+ });
84
+
85
+ this.click(function (e) {
86
+
87
+ e.preventDefault();
88
+
89
+ // hide block edit form
90
+ jQuery("#tnpc-block-options").hide();
91
+
92
+ // find the row
93
+ let row = jQuery(this).closest('.tnpc-row');
94
+
95
+ // clone the block
96
+ let new_row = row.clone();
97
+ new_row.find(".tnpc-row-delete").remove();
98
+ new_row.find(".tnpc-row-edit-block").remove();
99
+ new_row.find(".tnpc-row-clone").remove();
100
+
101
+ new_row.add_delete();
102
+ new_row.add_block_edit();
103
+ new_row.add_block_clone();
104
+ // if (new_row.hasClass('tnpc-row-block')) {
105
+ // new_row.find(".tnpc-row-edit-block i").click();
106
+ // }
107
+ new_row.insertAfter(row);
108
+ tnpc_mobile_preview();
109
+ });
110
+ };
111
+
112
+
113
+ jQuery(function () {
114
+
115
+ // collapse wp menu
116
+ jQuery('body').addClass('folded');
117
+
118
+ // open blocks tab
119
+ document.getElementById("defaultOpen").click();
120
+
121
+ // preload content from a body named input
122
+ var preloadedContent = jQuery('input[name="message"]').val();
123
+ if (!preloadedContent) {
124
+ preloadedContent = jQuery('input[name="options[message]"]').val();
125
+ }
126
+ // console.log(preloadedContent);
127
+ if (!preloadedContent) {
128
+ tnpc_show_presets();
129
+ } else {
130
+ jQuery('#newsletter-builder-area-center-frame-content').html(preloadedContent);
131
+ start_composer();
132
+ }
133
+
134
+ // subject management
135
+ jQuery('#options-title').val(jQuery('#tnpc-form input[name="options[subject]"]').val());
136
+
137
+ // Add event to update composer wrapper background color
138
+ jQuery('#options-options_composer_background').on('change', function (e) {
139
+ jQuery('#newsletter-builder-area-center-frame-content').css('background-color', e.target.value);
140
+ });
141
+
142
+ jQuery('#newsletter-builder-area-center-frame-content').css('background-color', jQuery('#options-options_composer_background').val());
143
+
144
+ // Init global styles values
145
+ /*
146
+ let globalStyles = JSON.parse(jQuery('#tnpc-form input[name="options[global-styles]"]').val());
147
+ if ('global-styles-bgcolor' in globalStyles) {
148
+ jQuery('#options-global-styles-bgcolor').val(globalStyles['global-styles-bgcolor']);
149
+ jQuery('#newsletter-builder-area-center-frame-content').css('background-color', globalStyles['global-styles-bgcolor']);
150
+ }
151
+ */
152
+
153
+ });
154
+
155
+ function start_composer() {
156
+
157
+ //Drag & Drop
158
+ jQuery("#newsletter-builder-area-center-frame-content").sortable({
159
+ revert: false,
160
+ placeholder: "placeholder",
161
+ forcePlaceholderSize: true,
162
+ opacity: 0.6,
163
+ tolerance: "pointer",
164
+ helper: function (e) {
165
+ var helper = jQuery(document.getElementById("sortable-helper")).clone();
166
+ return helper;
167
+ },
168
+ update: function (event, ui) {
169
+ //console.log(event);
170
+ //console.log(ui.item.data("id"));
171
+ // debugger;
172
+ if (ui.item.attr("id") == "draggable-helper") {
173
+ loading_row = jQuery('<div style="text-align: center; padding: 20px; background-color: #d4d5d6; color: #52BE7F;"><i class="fa fa-cog fa-2x fa-spin" /></div>');
174
+ ui.item.before(loading_row);
175
+ ui.item.remove();
176
+ var data = {
177
+ 'action': 'tnpc_render',
178
+ 'b': ui.item.data("id"),
179
+ 'full': 1
180
+ };
181
+ jQuery.post(ajaxurl, data, function (response) {
182
+ new_row = jQuery(response);
183
+ // ui.item.before(new_row);
184
+ // ui.item.remove();
185
+ loading_row.before(new_row);
186
+ loading_row.remove();
187
+ new_row.add_delete();
188
+ new_row.add_block_edit();
189
+ new_row.add_block_clone();
190
+ // new_row.find(".tnpc-row-edit").hover_edit();
191
+ if (new_row.hasClass('tnpc-row-block')) {
192
+ new_row.find(".tnpc-row-edit-block").click();
193
+ }
194
+ tnpc_mobile_preview();
195
+ }).fail(function () {
196
+ alert("Block rendering failed.");
197
+ loading_row.remove();
198
+ });
199
+ } else {
200
+ tnpc_mobile_preview();
201
+ }
202
+ }
203
+ });
204
+
205
+ jQuery(".newsletter-sidebar-buttons-content-tab").draggable({
206
+ connectToSortable: "#newsletter-builder-area-center-frame-content",
207
+
208
+ // Build the helper for dragging
209
+ helper: function (e) {
210
+ var helper = jQuery(document.getElementById("draggable-helper")).clone();
211
+ // Do not uset .data() with jQuery
212
+ helper.attr("data-id", e.currentTarget.dataset.id);
213
+ helper.html(e.currentTarget.dataset.name);
214
+ return helper;
215
+ },
216
+ revert: false,
217
+ start: function () {
218
+ if (jQuery('.tnpc-row').length) {
219
+ } else {
220
+ jQuery('#newsletter-builder-area-center-frame-content').append('<div class="tnpc-drop-here">Drag&Drop blocks here!</div>');
221
+ }
222
+ },
223
+ stop: function (event, ui) {
224
+ jQuery('.tnpc-drop-here').remove();
225
+ }
226
+ });
227
+
228
+ // Closes the block options layer (without saving)
229
+ jQuery("#tnpc-block-options-cancel").click(function () {
230
+ jQuery(this).parent().parent().fadeOut(500);
231
+ jQuery.post(ajaxurl, start_options, function (response) {
232
+ target.html(response);
233
+ jQuery("#tnpc-block-options-form").html("");
234
+ });
235
+ });
236
+
237
+ // Fires the save event for block options
238
+ jQuery("#tnpc-block-options-save").click(function (e) {
239
+ e.preventDefault();
240
+ // fix for Codemirror
241
+ if (typeof templateEditor !== 'undefined') {
242
+ templateEditor.save();
243
+ }
244
+
245
+ if (window.tinymce)
246
+ window.tinymce.triggerSave();
247
+
248
+ jQuery("#tnpc-block-options").fadeOut(500);
249
+
250
+ var data = jQuery("#tnpc-block-options-form").serialize();
251
+
252
+ jQuery.post(ajaxurl, data, function (response) {
253
+ target.html(response);
254
+ tnpc_mobile_preview();
255
+ //target.attr("data-options", options);
256
+ //target.find(".tnpc-row-edit").hover_edit();
257
+ jQuery("#tnpc-block-options-form").html("");
258
+ });
259
+ });
260
+
261
+ // live preview from block options *** EXPERIMENTAL ***
262
+ jQuery('#tnpc-block-options-form').change(function () {
263
+ var data = jQuery("#tnpc-block-options-form").serialize();
264
+ jQuery.post(ajaxurl, data, function (response) {
265
+ target.html(response);
266
+ }).fail(function () {
267
+ alert("Block rendering failed");
268
+ });
269
+
270
+ });
271
+
272
+ jQuery(".tnpc-row").add_delete();
273
+ jQuery(".tnpc-row").add_block_edit();
274
+ jQuery(".tnpc-row").add_block_clone();
275
+
276
+ tnpc_mobile_preview();
277
+
278
+ }
279
+
280
+ function tnpc_mobile_preview() {
281
+
282
+ var d = document.getElementById("tnpc-mobile-preview").contentWindow.document;
283
+ d.open();
284
+
285
+ d.write("<!DOCTYPE html>\n<html>\n<head>\n");
286
+ d.write("<link rel='stylesheet' href='" + TNP_HOME_URL + "?na=emails-composer-css&ver=" + Math.random() + "' type='text/css'>");
287
+ d.write("<style type='text/css'>.tnpc-row-delete, .tnpc-row-edit-block, .tnpc-row-clone { display: none; }</style>");
288
+ d.write("</head>\n<body style='margin: 0; padding: 0;'><div style='width: 320px!important'>");
289
+ d.write(jQuery("#newsletter-builder-area-center-frame-content").html());
290
+ d.write("</div>\n</body>\n</html>");
291
+ d.close();
292
+ }
293
+
294
+ function tnpc_save(form) {
295
+
296
+ jQuery("#newsletter-preloaded-export").html(jQuery("#newsletter-builder-area-center-frame-content").html());
297
+
298
+ jQuery("#newsletter-preloaded-export .tnpc-row-delete").remove();
299
+ jQuery("#newsletter-preloaded-export .tnpc-row-edit-block").remove();
300
+ jQuery("#newsletter-preloaded-export .tnpc-row-clone").remove();
301
+ jQuery("#newsletter-preloaded-export .tnpc-row").removeClass("ui-draggable");
302
+
303
+ form.elements["options[message]"].value = jQuery("#newsletter-preloaded-export").html();
304
+ if (document.getElementById("options-title")) {
305
+ form.elements["options[subject]"].value = jQuery('#options-title').val();
306
+ } else {
307
+ form.elements["options[subject]"].value = "";
308
+ }
309
+ form.elements["options[global-styles]"].value = JSON.stringify(jQuery('#tnpc-global-styles-form').serializeArray());
310
+
311
+ var global_form = document.getElementById("tnpc-global-styles-form");
312
+ tnpc_copy_form(global_form, form);
313
+
314
+ jQuery("#newsletter-preloaded-export").html(' ');
315
+ }
316
+
317
+ function tnpc_copy_form(source, dest) {
318
+ for (var i = 0; i < source.elements.length; i++) {
319
+ var e = source.elements[i];
320
+ if (dest.elements[e.name]) {
321
+ dest.elements[e.name].value = e.value;
322
+ }
323
+ }
324
+ }
325
+
326
+ function tnpc_test() {
327
+ let form = document.getElementById("tnpc-form");
328
+ tnpc_save(form);
329
+ form.act.value = "test";
330
+ form.submit();
331
+ }
332
+
333
+ function openTab(evt, tabName) {
334
+ evt.preventDefault();
335
+ // Declare all variables
336
+ var i, tabcontent, tablinks;
337
+
338
+ // Get all elements with class="tabcontent" and hide them
339
+ tabcontent = document.getElementsByClassName("tabcontent");
340
+ for (i = 0; i < tabcontent.length; i++) {
341
+ tabcontent[i].style.display = "none";
342
+ }
343
+
344
+ // Get all elements with class="tablinks" and remove the class "active"
345
+ tablinks = document.getElementsByClassName("tablinks");
346
+ for (i = 0; i < tablinks.length; i++) {
347
+ tablinks[i].className = tablinks[i].className.replace(" active", "");
348
+ }
349
+
350
+ // Show the current tab, and add an "active" class to the button that opened the tab
351
+ document.getElementById(tabName).style.display = "block";
352
+ evt.currentTarget.className += " active";
353
+ }
354
+
355
+
356
+ function tnpc_show_presets() {
357
+
358
+ jQuery('.tnpc-controls input').attr('disabled', true);
359
+ jQuery('#newsletter-builder-area-center-frame-content').load(ajaxurl, {
360
+ action: "tnpc_presets",
361
+ });
362
+
363
+ }
364
+
365
+ function tnpc_load_preset(id) {
366
+
367
+ jQuery('#newsletter-builder-area-center-frame-content').load(ajaxurl, {
368
+ action: "tnpc_presets",
369
+ id: id
370
+ }, function () {
371
+ start_composer();
372
+ jQuery('.tnpc-controls input').attr('disabled', false);
373
+ });
374
+
375
+ }
376
+
377
+ function tnpc_scratch() {
378
+
379
+ jQuery('#newsletter-builder-area-center-frame-content').html(" ");
380
+ start_composer();
381
+
382
+ }
383
+
384
+ function tnpc_reload_options(e) {
385
+ e.preventDefault();
386
+ let options = jQuery("#tnpc-block-options-form").serializeArray();
387
+ for (let i = 0; i < options.length; i++) {
388
+ if (options[i].name == 'action') {
389
+ options[i].value = 'tnpc_options';
390
+ }
391
+ }
392
+ options["action"] = "tnpc_options";
393
+ options["id"] = container.data("id");
394
+ jQuery("#tnpc-block-options-form").load(ajaxurl, options);
395
+ }
396
+
397
+ jQuery(document).ready(function () {
398
+
399
+ var TNPInlineEditor = (function () {
400
+
401
+ var className = 'tnpc-inline-editable';
402
+ var newInputName = 'new_name';
403
+ var activeInlineElements = [];
404
+
405
+ function init() {
406
+ // find all inline editable elements
407
+ jQuery('#newsletter-builder-area-center-frame-content').on('click', '.' + className, function (e) {
408
+ removeAllActiveElements();
409
+
410
+ var originalEl = jQuery(this).hide();
411
+ var newEl = jQuery(getEditableComponent(this.innerText.trim(), this.dataset.id, this.dataset.type)).insertAfter(this);
412
+
413
+ activeInlineElements.push({'originalEl': originalEl, 'newEl': newEl});
414
+
415
+ //Add submit event listener for newly created block
416
+ jQuery('.tnpc-inline-editable-form-' + this.dataset.type + this.dataset.id).on('submit', function (e) {
417
+ submit(e, newEl, jQuery(originalEl));
418
+ });
419
+
420
+ //Add close event listener for newly created block
421
+ jQuery('.tnpc-inline-editable-form-actions .tnpc-dismiss-' + this.dataset.type + this.dataset.id).on('click', function (e) {
422
+ removeAllActiveElements();
423
+ });
424
+
425
+ });
426
+
427
+ // Close all created elements if clicked outside
428
+ jQuery('#newsletter-builder-area-center-frame-content').on('click', function (e) {
429
+ if (activeInlineElements.length > 0
430
+ && !jQuery(e.target).hasClass(className)
431
+ && jQuery(e.target).closest('.tnpc-inline-editable-container').length === 0) {
432
+ removeAllActiveElements();
433
+ }
434
+ });
435
+
436
+ }
437
+
438
+ function removeAllActiveElements() {
439
+ activeInlineElements.forEach(function (obj) {
440
+ obj.originalEl.show();
441
+
442
+ obj.newEl.off();
443
+ obj.newEl.remove();
444
+ });
445
+
446
+ activeInlineElements = []
447
+ }
448
+
449
+ function getEditableComponent(value, id, type) {
450
+
451
+ var element = '';
452
+
453
+ switch (type) {
454
+ case 'text': {
455
+ element = "<textarea name='" + newInputName + "' class='" + className + "-textarea' rows='5'>" + value + "</textarea>";
456
+ break;
457
+ }
458
+ case 'title': {
459
+ element = "<input name='" + newInputName + "' class='" + className + "-textinput' value='" + value + "' type='text'>";
460
+ break;
461
+ }
462
+ }
463
+
464
+ var component = "<td>";
465
+ component += "<form class='tnpc-inline-editable-form tnpc-inline-editable-form-" + type + id + "'>";
466
+ component += "<input type='hidden' name='id' value='" + id + "'>";
467
+ component += "<input type='hidden' name='type' value='" + type + "'>";
468
+ component += "<input type='hidden' name='old_value' value='" + value + "'>";
469
+ component += "<div class='tnpc-inline-editable-container'>";
470
+ component += element;
471
+ component += "<div class='tnpc-inline-editable-form-actions'>";
472
+ component += "<button type='submit'><span class='dashicons dashicons-yes-alt' title='save'></span></button>";
473
+ component += "<span class='dashicons dashicons-dismiss tnpc-dismiss-" + type + id + "' title='close'></span>";
474
+ component += "</div>";
475
+ component += "</div>";
476
+ component += "</form>";
477
+ component += "</td>";
478
+ return component;
479
+ }
480
+
481
+ function submit(e, elementToDeleteAfterSubmit, elementToShow) {
482
+ e.preventDefault();
483
+
484
+ var id = elementToDeleteAfterSubmit.find('form input[name=id]').val();
485
+ var type = elementToDeleteAfterSubmit.find('form input[name=type]').val();
486
+ var newValue = elementToDeleteAfterSubmit.find('form [name="' + newInputName + '"]').val();
487
+
488
+ ajax_render_block(elementToShow, type, id, newValue);
489
+
490
+ elementToDeleteAfterSubmit.remove();
491
+ elementToShow.show();
492
+
493
+ }
494
+
495
+ function ajax_render_block(inlineElement, type, postId, newContent) {
496
+
497
+ var target = inlineElement.closest('.edit-block');
498
+ var container = target.closest('table');
499
+ var blockContent = target.children('.tnpc-block-content');
500
+
501
+ if (container.hasClass('tnpc-row-block')) {
502
+ var data = {
503
+ 'action': 'tnpc_render',
504
+ 'b': container.data('id'),
505
+ 'full': 1,
506
+ 'options': {
507
+ 'inline_edits': [{
508
+ 'type': type,
509
+ 'post_id': postId,
510
+ 'content': newContent
511
+ }]
512
+ },
513
+ 'encoded_options': blockContent.data('json')
514
+ };
515
+
516
+ jQuery.post(ajaxurl, data, function (response) {
517
+ new_row = jQuery(response);
518
+
519
+ target.before(new_row);
520
+ target.remove();
521
+
522
+ new_row.add_delete();
523
+ new_row.add_block_edit();
524
+ new_row.add_block_clone();
525
+
526
+ if (new_row.hasClass('tnpc-row-block')) {
527
+ new_row.find(".tnpc-row-edit-block").click();
528
+ }
529
+ tnpc_mobile_preview();
530
+
531
+ }).fail(function () {
532
+ alert("Block rendering failed.");
533
+ });
534
+
535
+ }
536
+
537
+ }
538
+
539
+ return {init: init};
540
+ }
541
+
542
+ )();
543
+
544
+ TNPInlineEditor.init();
545
+
546
+ });
emails/tnp-composer/css/newsletter.css CHANGED
@@ -1,4 +1,3 @@
1
- /* CLIENT-SPECIFIC STYLES */
2
  #outlook a{padding:0;} /* Force Outlook to provide a "view in browser" message */
3
  .ReadMsgBody{width:100%;} .ExternalClass{width:100%;} /* Force Hotmail to display emails at full width */
4
  .ExternalClass, .ExternalClass p, .ExternalClass span, .ExternalClass font, .ExternalClass td, .ExternalClass div {line-height: 100%;} /* Force Hotmail to display normal line spacing */
@@ -6,13 +5,11 @@ body, table, td, a{-webkit-text-size-adjust:100%; -ms-text-size-adjust:100%;} /*
6
  table, td{mso-table-lspace:0pt; mso-table-rspace:0pt;} /* Remove spacing between tables in Outlook 2007 and up */
7
  img{-ms-interpolation-mode:bicubic;} /* Allow smoother rendering of resized image in Internet Explorer */
8
 
9
- /* RESET STYLES */
10
  body{margin:0; padding:0; height:100% !important; margin:0; padding:0; width:100% !important;}
11
  img{border:0; height:auto; line-height:100%; outline:none; text-decoration:none; max-width: 100%!important}
12
  table{border-collapse:collapse !important;}
 
13
 
14
-
15
- /* MOBILE STYLES */
16
  @media screen and (max-width: 525px) {
17
 
18
  /* ALLOWS FOR FLUID TABLES */
@@ -96,5 +93,4 @@ table{border-collapse:collapse !important;}
96
  border: 0 !important;
97
  font-size: 16px !important;
98
  }
99
-
100
  }
 
1
  #outlook a{padding:0;} /* Force Outlook to provide a "view in browser" message */
2
  .ReadMsgBody{width:100%;} .ExternalClass{width:100%;} /* Force Hotmail to display emails at full width */
3
  .ExternalClass, .ExternalClass p, .ExternalClass span, .ExternalClass font, .ExternalClass td, .ExternalClass div {line-height: 100%;} /* Force Hotmail to display normal line spacing */
5
  table, td{mso-table-lspace:0pt; mso-table-rspace:0pt;} /* Remove spacing between tables in Outlook 2007 and up */
6
  img{-ms-interpolation-mode:bicubic;} /* Allow smoother rendering of resized image in Internet Explorer */
7
 
 
8
  body{margin:0; padding:0; height:100% !important; margin:0; padding:0; width:100% !important;}
9
  img{border:0; height:auto; line-height:100%; outline:none; text-decoration:none; max-width: 100%!important}
10
  table{border-collapse:collapse !important;}
11
+ img.aligncenter{display:block;margin:0 auto;}
12
 
 
 
13
  @media screen and (max-width: 525px) {
14
 
15
  /* ALLOWS FOR FLUID TABLES */
93
  border: 0 !important;
94
  font-size: 16px !important;
95
  }
 
96
  }
emails/tnp-composer/index-v2.php ADDED
@@ -0,0 +1,153 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * This file is included by NewsletterControls to create the composer.
4
+ */
5
+
6
+ /* @var $this NewsletterControls */
7
+
8
+ defined('ABSPATH') || exit;
9
+
10
+ $list = NewsletterEmails::instance()->get_blocks();
11
+
12
+ $blocks = array();
13
+ foreach ($list as $key => $data) {
14
+ if (!isset($blocks[$data['section']]))
15
+ $blocks[$data['section']] = array();
16
+ $blocks[$data['section']][$key]['name'] = $data['name'];
17
+ $blocks[$data['section']][$key]['filename'] = $key;
18
+ $blocks[$data['section']][$key]['icon'] = $data['icon'];
19
+ }
20
+
21
+ // order the sections
22
+ $blocks = array_merge(array_flip(array('header', 'content', 'footer')), $blocks);
23
+
24
+ // prepare the options for the default blocks
25
+ $block_options = get_option('newsletter_main');
26
+
27
+ $fields = new NewsletterFields($controls);
28
+ ?>
29
+ <style>
30
+ .placeholder {
31
+ border: 3px dashed #ddd!important;
32
+ background-color: #eee!important;
33
+ height: 50px;
34
+ margin: 0;
35
+ width: 100%;
36
+ box-sizing: border-box!important;
37
+ }
38
+ #newsletter-builder-area-center-frame-content {
39
+ min-height: 300px!important;
40
+ }
41
+ </style>
42
+
43
+ <style>
44
+ <?php echo NewsletterEmails::instance()->get_composer_css(); ?>
45
+ </style>
46
+
47
+ <div id="newsletter-builder">
48
+
49
+ <div id="newsletter-builder-area" class="tnp-builder-column">
50
+
51
+ <?php if ($tnpc_show_subject) { ?>
52
+ <p>
53
+ <?php $this->text('title', 60, 'Newsletter subject'); ?>
54
+ <a href="#" class="tnp-suggest-button" onclick="tnp_suggest_subject(); return false;"><?php _e('Get ideas', 'newsletter') ?></a>
55
+ </p>
56
+ <?php } ?>
57
+
58
+ <div id="newsletter-builder-area-center-frame-content">
59
+
60
+ <!-- Composer content -->
61
+
62
+ </div>
63
+ </div>
64
+
65
+ <div id="newsletter-builder-sidebar" class="tnp-builder-column">
66
+
67
+ <div class="tnpc-tabs">
68
+ <button class="tablinks" onclick="openTab(event, 'tnpc-blocks')" id="defaultOpen"><?php _e('Blocks', 'newsletter') ?></button>
69
+ <button class="tablinks" onclick="openTab(event, 'tnpc-global-styles')"><?php _e('Global Styles', 'newsletter') ?></button>
70
+ <button class="tablinks" onclick="openTab(event, 'tnpc-mobile-tab')"><i class="fa fa-mobile"></i> <?php _e('Mobile Preview', 'newsletter') ?></button>
71
+ <?php if ($show_test) { ?>
72
+ <button class="tablinks" onclick="openTab(event, 'tnpc-test-tab')"><i class="fa fa-paper-plane"></i> <?php _e('Test', 'newsletter') ?></button>
73
+ <?php } ?>
74
+
75
+ </div>
76
+
77
+ <div id="tnpc-blocks" class="tabcontent">
78
+ <?php foreach ($blocks as $k => $section) { ?>
79
+ <div class="newsletter-sidebar-add-buttons" id="sidebar-add-<?php echo $k ?>">
80
+ <h4><span><?php echo ucfirst($k) ?></span></h4>
81
+ <?php foreach ($section AS $key => $block) { ?>
82
+ <div class="newsletter-sidebar-buttons-content-tab" data-id="<?php echo $key ?>" data-name="<?php echo esc_attr($block['name']) ?>">
83
+ <img src="<?php echo $block['icon'] ?>" title="<?php echo esc_attr($block['name']) ?>">
84
+ </div>
85
+ <?php } ?>
86
+ </div>
87
+ <?php } ?>
88
+ </div>
89
+
90
+ <div id="tnpc-global-styles" class="tabcontent">
91
+
92
+ <form id="tnpc-global-styles-form">
93
+
94
+ <?php $fields->color('options_composer_background', __('Background color', 'newsletter'), ['default'=>'#f4f4f4']) ?>
95
+ </form>
96
+
97
+ </div>
98
+
99
+
100
+ <div id="tnpc-mobile-tab" class="tabcontent">
101
+
102
+ <iframe id="tnpc-mobile-preview"></iframe>
103
+
104
+ </div>
105
+
106
+ <div id="tnpc-test-tab" class="tabcontent">
107
+
108
+ <p><?php _e("Test subscribers:") ?></p>
109
+ <ul>
110
+ <?php foreach (NewsletterUsers::instance()->get_test_users() AS $user) { ?>
111
+ <li><?php echo $user->email ?></li>
112
+ <?php } ?>
113
+ </ul>
114
+ <button class="button-secondary" onclick="tnpc_test()"><?php _e("Send a test", 'newsletter') ?></button>
115
+ <p>
116
+ <a href="https://www.thenewsletterplugin.com/documentation/subscribers#test" target="_blank">
117
+ <?php _e('Read more about test subscribers', 'newsletter') ?></a>
118
+ </p>
119
+ </div>
120
+
121
+ <!-- Block options container (dynamically loaded -->
122
+ <div id="tnpc-block-options">
123
+ <div id="tnpc-block-options-buttons">
124
+ <span id="tnpc-block-options-cancel" class="button-secondary"><?php _e("Cancel", "newsletter") ?></span>
125
+ <span id="tnpc-block-options-save" class="button-primary"><?php _e("Apply", "newsletter") ?></span>
126
+ </div>
127
+ <form id="tnpc-block-options-form" onsubmit="return false;"></form>
128
+
129
+ </div>
130
+
131
+ </div>
132
+
133
+ <div style="clear: both"></div>
134
+
135
+ </div>
136
+
137
+ <div style="display: none">
138
+ <div id="newsletter-preloaded-export"></div>
139
+ <!-- Block placeholder used by jQuery UI -->
140
+ <div id="draggable-helper" style="width: 500px; border: 3px dashed #ddd; opacity: .7; background-color: #fff; text-align: center; text-transform: uppercase; font-size: 14px; color: #aaa; padding: 20px;"></div>
141
+ <div id="sortable-helper" style="width: 700px; height: 75px;border: 3px dashed #ddd; opacity: .7; background-color: #fff; text-align: center; text-transform: uppercase; font-size: 14px; color: #aaa; padding: 20px;"></div>
142
+ </div>
143
+
144
+ <script type="text/javascript">
145
+ TNP_PLUGIN_URL = "<?php echo NEWSLETTER_URL ?>";
146
+ TNP_HOME_URL = "<?php echo home_url('/', is_ssl() ? 'https' : 'http') ?>";
147
+ tnp_context_type = "<?php echo $context_type ?>";
148
+ </script>
149
+ <script type="text/javascript" src="<?php echo plugins_url('newsletter'); ?>/emails/tnp-composer/_scripts/newsletter-builder-v2.js?ver=<?php echo time() ?>"></script>
150
+
151
+ <?php include NEWSLETTER_DIR . '/emails/subjects.php'; ?>
152
+
153
+ <?php if (function_exists('wp_enqueue_editor')) wp_enqueue_editor(); ?>
emails/tnp-composer/index.php CHANGED
@@ -1,4 +1,10 @@
1
  <?php
 
 
 
 
 
 
2
  defined('ABSPATH') || exit;
3
 
4
  $list = NewsletterEmails::instance()->get_blocks();
@@ -59,13 +65,12 @@ $block_options = get_option('newsletter_main');
59
  <div id="newsletter-builder-sidebar" class="tnp-builder-column">
60
 
61
  <div class="tnpc-tabs">
62
- <button class="tablinks" onclick="openTab(event, 'tnpc-blocks')" id="defaultOpen"><?php _e('Blocks', 'newsletter') ?></button>
63
- <?php /* <button class="tablinks" onclick="openTab(event, 'tnpc-general-options')"><?php _e('General Options', 'newsletter') ?></button> */ ?>
64
- <button class="tablinks" onclick="openTab(event, 'tnpc-mobile-tab')"><i class="fa fa-mobile"></i> <?php _e('Mobile Preview', 'newsletter') ?></button>
65
- <?php if ($show_test) { ?>
66
- <button class="tablinks" onclick="openTab(event, 'tnpc-test-tab')"><i class="fa fa-paper-plane"></i> <?php _e('Test', 'newsletter') ?></button>
67
- <?php } ?>
68
-
69
  </div>
70
 
71
  <div id="tnpc-blocks" class="tabcontent">
1
  <?php
2
+ /**
3
+ * This file is included by NewsletterControls to create the composer.
4
+ */
5
+
6
+ /* @var $this NewsletterControls */
7
+
8
  defined('ABSPATH') || exit;
9
 
10
  $list = NewsletterEmails::instance()->get_blocks();
65
  <div id="newsletter-builder-sidebar" class="tnp-builder-column">
66
 
67
  <div class="tnpc-tabs">
68
+ <button class="tablinks" onclick="openTab(event, 'tnpc-blocks')" id="defaultOpen"><?php _e('Blocks', 'newsletter') ?></button>
69
+ <button class="tablinks" onclick="openTab(event, 'tnpc-mobile-tab')"><i class="fa fa-mobile"></i> <?php _e('Mobile Preview', 'newsletter') ?></button>
70
+ <?php if ($show_test) { ?>
71
+ <button class="tablinks" onclick="openTab(event, 'tnpc-test-tab')"><i class="fa fa-paper-plane"></i> <?php _e('Test', 'newsletter') ?></button>
72
+ <?php } ?>
73
+
 
74
  </div>
75
 
76
  <div id="tnpc-blocks" class="tabcontent">
includes/addon.php ADDED
@@ -0,0 +1,161 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * User by add-ons as base-class.
5
+ */
6
+ class NewsletterAddon {
7
+
8
+ var $logger;
9
+ var $admin_logger;
10
+ var $name;
11
+ var $options;
12
+ var $version;
13
+
14
+ public function __construct($name, $version = '0.0.0') {
15
+ $this->name = $name;
16
+ $this->version = $version;
17
+ if (is_admin()) {
18
+ $old_version = get_option('newsletter_' . $name . '_version');
19
+ if ($version != $old_version) {
20
+ $this->upgrade($old_version === false);
21
+ update_option('newsletter_' . $name . '_version', $version, false);
22
+ }
23
+ }
24
+ add_action('newsletter_init', array($this, 'init'));
25
+ }
26
+
27
+ function upgrade($first_install = false) {
28
+
29
+ }
30
+
31
+ function init() {
32
+
33
+ }
34
+
35
+ /**
36
+ *
37
+ * @return NewsletterLogger
38
+ */
39
+ function get_logger() {
40
+ if (!$this->logger) {
41
+ $this->logger = new NewsletterLogger($this->name);
42
+ }
43
+ return $this->logger;
44
+ }
45
+
46
+ function get_admin_logger() {
47
+ if (!$this->admin_logger) {
48
+ $this->admin_logger = new NewsletterLogger($this->name . '-admin');
49
+ }
50
+ return $this->admin_logger;
51
+ }
52
+
53
+ function setup_options() {
54
+ if ($this->options)
55
+ return;
56
+ $this->options = get_option('newsletter_' . $this->name, array());
57
+ }
58
+
59
+ function save_options($options) {
60
+ update_option('newsletter_' . $this->name, $options);
61
+ $this->setup_options();
62
+ }
63
+
64
+ function merge_defaults($defaults) {
65
+ $options = get_option('newsletter_' . $this->name, array());
66
+ $options = array_merge($defaults, $options);
67
+ $this->save_options($options);
68
+ }
69
+
70
+ /**
71
+ * @global wpdb $wpdb
72
+ * @param string $query
73
+ */
74
+ function query($query) {
75
+ global $wpdb;
76
+
77
+ $r = $wpdb->query($query);
78
+ if ($r === false) {
79
+ $logger = $this->get_logger();
80
+ $logger->fatal($query);
81
+ $logger->fatal($wpdb->last_error);
82
+ }
83
+ return $r;
84
+ }
85
+
86
+ }
87
+
88
+ /**
89
+ * Used by mailers as base-class.
90
+ */
91
+ class NewsletterMailerAddon extends NewsletterAddon {
92
+
93
+ var $enabled = false;
94
+
95
+ function __construct($name, $version = '0.0.0') {
96
+ parent::__construct($name, $version);
97
+ $this->setup_options();
98
+ $this->enabled = !empty($this->options['enabled']);
99
+ }
100
+
101
+ function init() {
102
+ parent::init();
103
+ add_action('newsletter_register_mailer', function () {
104
+ if ($this->enabled) {
105
+ Newsletter::instance()->register_mailer($this->get_mailer());
106
+ }
107
+ });
108
+ }
109
+
110
+ /**
111
+ *
112
+ * @return NewsletterMailer
113
+ */
114
+ function get_mailer() {
115
+ return null;
116
+ }
117
+
118
+ function get_last_run() {
119
+ return get_option('newsletter_' . $this->name . '_last_run', 0);
120
+ }
121
+
122
+ function save_last_run($time) {
123
+ update_option('newsletter_' . $this->name . '_last_run', $time);
124
+ }
125
+
126
+ function save_options($options) {
127
+ parent::save_options($options);
128
+ $this->enabled = !empty($options['enabled']);
129
+ }
130
+
131
+ static function get_test_message($to, $subject = '') {
132
+ $message = new TNP_Mailer_Message();
133
+ $message->to = $to;
134
+ $message->to_name = '';
135
+ $message->body = "<!DOCTYPE html>\n";
136
+ $message->body .= "This is the rich text (HTML) version of a test message.</p>\n";
137
+ $message->body .= "This is a <strong>bold text</strong></p>\n";
138
+ $message->body .= "This is a <a href='http://www.thenewsletterplugin.com'>link to www.thenewsletterplugin.com</a></p>\n";
139
+ $message->body_text = 'This is the TEXT version of a test message. You should see this message only if you email client does not support the rich text (HTML) version.';
140
+ $message->headers['X-Newsletter-Email-Id'] = '0';
141
+ if (empty($subject)) {
142
+ $message->subject = '[' . get_option('blogname') . '] Test message from Newsletter (' . date(DATE_ISO8601) . ')';
143
+ } else {
144
+ $message->subject = $subject;
145
+ }
146
+ $message->from = Newsletter::instance()->options['sender_email'];
147
+ $message->from_name = Newsletter::instance()->options['sender_name'];
148
+ return $message;
149
+ }
150
+
151
+ function get_test_messages($to, $count) {
152
+ $messages = array();
153
+ for ($i = 0; $i < $count; $i++) {
154
+ $messages[] = self::get_test_message($to, '[' . get_option('blogname') . '] Test message ' . ($i + 1) . ' from Newsletter (' . date(DATE_ISO8601) . ')');
155
+ }
156
+ return $messages;
157
+ }
158
+
159
+ }
160
+
161
+
includes/composer.php ADDED
@@ -0,0 +1,318 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /** For old style coders */
4
+ function tnp_register_block($dir) {
5
+ return TNP_Composer::register_block($dir);
6
+ }
7
+
8
+ class TNP_Composer {
9
+
10
+ static $block_dirs = array();
11
+
12
+ static function register_block($dir) {
13
+ // Checks
14
+
15
+ if (!file_exists($dir . '/block.php')) {
16
+ $error = new WP_Error('1', 'block.php missing on folder ' . $dir);
17
+ NewsletterEmails::instance()->logger->error($error);
18
+ return $error;
19
+ }
20
+ self::$block_dirs[] = $dir;
21
+ return true;
22
+ }
23
+
24
+ /**
25
+ * Return normalized array from json encoded global style options
26
+ *
27
+ * @param $raw
28
+ *
29
+ * @return array
30
+ */
31
+ static function normalize_global_style_options($raw) {
32
+ $global_styles = json_decode($raw);
33
+ $regex_rule = "/^options\[([\w-]*)\]$/";
34
+ $global_styles_formatted = array();
35
+ foreach ($global_styles as $input) {
36
+ preg_match($regex_rule, $input->name, $match);
37
+
38
+ $global_styles_formatted["$match[1]"] = $input->value;
39
+ }
40
+
41
+ return $global_styles_formatted;
42
+ }
43
+
44
+ /**
45
+ * @param string $open
46
+ * @param string $inner
47
+ * @param string $close
48
+ * @param string[] $markers
49
+ *
50
+ * @return string
51
+ */
52
+ static function wrap_html_element($open, $inner, $close, $markers = array('<!-- tnp -->', '<!-- /tnp -->')) {
53
+
54
+ return $open . $markers[0] . $inner . $markers[1] . $close;
55
+ }
56
+
57
+ /**
58
+ * @param string $block
59
+ * @param string[] $markers
60
+ *
61
+ * @return string
62
+ */
63
+ static function unwrap_html_element($block, $markers = array('<!-- tnp -->', '<!-- /tnp -->')) {
64
+ if (self::_has_markers($block, $markers)) {
65
+ self::_escape_markers($markers);
66
+ $pattern = sprintf('/%s(.*?)%s/s', $markers[0], $markers[1]);
67
+
68
+ $matches = array();
69
+ preg_match($pattern, $block, $matches);
70
+
71
+ return $matches[1];
72
+ }
73
+
74
+ return $block;
75
+ }
76
+
77
+ /**
78
+ * @param string $block
79
+ * @param string[] $markers
80
+ *
81
+ * @return bool
82
+ */
83
+ private static function _has_markers($block, $markers = array('<!-- tnp -->', '<!-- /tnp -->')) {
84
+
85
+ self::_escape_markers($markers);
86
+
87
+ $pattern = sprintf('/%s(.*?)%s/s', $markers[0], $markers[1]);
88
+
89
+ return preg_match($pattern, $block);
90
+ }
91
+
92
+ static function get_html_open($email) {
93
+ $open = "<!DOCTYPE html>\n";
94
+ $open .= "<html>\n<head>\n<title>" . esc_html($email->subject) . "</title>\n";
95
+ $open .= "<meta charset=\"utf-8\">\n<meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\n";
96
+ $open .= "<meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n";
97
+ $open .= "<style type=\"text/css\">\n";
98
+ $open .= NewsletterEmails::instance()->get_composer_css();
99
+ $open .= "\n</style>\n";
100
+ $open .= "</head>\n<body style=\"margin: 0; padding: 0;\">\n";
101
+ return $open;
102
+ }
103
+
104
+ static function get_html_close($email) {
105
+ return "</body>\n</html>";
106
+ }
107
+
108
+ /**
109
+ *
110
+ * @param TNP_Email $email
111
+ * @return string
112
+ */
113
+ static function get_main_wrapper_open($email) {
114
+ if (!isset($email->options['composer_background']))
115
+ return '';
116
+
117
+ $bgcolor = $email->options['composer_background'];
118
+ return "\n\n<table cellpadding='0' cellspacing='0' border='0' width='100%'>\n" .
119
+ "<tr>\n" .
120
+ "<td bgcolor='$bgcolor' valign='top'>\n" .
121
+ "<!--[if gte mso 9]>\n" .
122
+ "<v:rect xmlns:v='urn:schemas-microsoft-com:vml' fill='true' stroke='false' style='mso-width-percent:1000;'>\n" .
123
+ "<v:fill type='tile' color='$bgcolor' />\n" .
124
+ "<v:textbox style='mso-fit-shape-to-text:true' inset='0,0,0,0'>\n" .
125
+ "<![endif]-->\n\n<!-- tnp -->\n\n";
126
+ }
127
+
128
+ /**
129
+ *
130
+ * @param TNP_Email $email
131
+ * @return string
132
+ */
133
+ static function get_main_wrapper_close($email) {
134
+ if (!isset($email->options['composer_background']))
135
+ return '';
136
+
137
+ return "\n\n<!-- /tnp -->\n\n<!--[if gte mso 9]>\n" .
138
+ "</v:textbox>\n" .
139
+ "</v:rect>\n" .
140
+ "<![endif]-->\n" .
141
+ "</td>\n" .
142
+ "</tr>\n" .
143
+ "</table>\n\n";
144
+ }
145
+
146
+ /**
147
+ * Wrap email coming from composer block with <doctype>, <body> and other stuff
148
+ *
149
+ * @param array $email
150
+ * @param string $body
151
+ *
152
+ * @return string
153
+ */
154
+ static function wrap_email($email, $body) {
155
+
156
+ $open = '<!DOCTYPE html><html><head><title>' . $email['subject'] . '</title><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1"><meta http-equiv="X-UA-Compatible" content="IE=edge">';
157
+ $open .= '<style type="text/css">' . NewsletterEmails::instance()->get_composer_css() . '</style>';
158
+ $open .= '</head><body style="margin: 0; padding: 0;">';
159
+
160
+ $close = '';
161
+
162
+ if (isset($email['options']['global-styles']['global-styles-bgcolor'])) {
163
+ $bgcolor = $email['options']['global-styles']['global-styles-bgcolor'];
164
+ $open .= "<table cellpadding='0' cellspacing='0' border='0' width='100%'>
165
+ <tr>
166
+ <td bgcolor='$bgcolor' valign='top'>
167
+ <!--[if gte mso 9]>
168
+ <v:rect xmlns:v='urn:schemas-microsoft-com:vml' fill='true' stroke='false' style='mso-width-percent:1000;'>
169
+ <v:fill type='tile' color='$bgcolor' />
170
+ <v:textbox style='mso-fit-shape-to-text:true' inset='0,0,0,0'>
171
+ <![endif]-->";
172
+
173
+ $close .= "<!--[if gte mso 9]>
174
+ </v:textbox>
175
+ </v:rect>
176
+ <![endif]-->
177
+ </td>
178
+ </tr>
179
+ </table>";
180
+ }
181
+
182
+ $close .= '</body></html>';
183
+
184
+ return self::wrap_html_element($open, $body, $close);
185
+ }
186
+
187
+ /**
188
+ * Remove <doctype>, <body> and unnecessary envelopes for editing with composer
189
+ *
190
+ * @param string $html_email
191
+ *
192
+ * @return string
193
+ */
194
+ static function unwrap_email($html_email) {
195
+
196
+ if (self::_has_markers($html_email)) {
197
+ $html_email = self::unwrap_html_element($html_email);
198
+ } else {
199
+ //KEEP FOR OLD EMAIL COMPATIBILITY
200
+ // Extracts only the body part
201
+ $x = strpos($html_email, '<body');
202
+ if ($x) {
203
+ $x = strpos($html_email, '>', $x);
204
+ $y = strpos($html_email, '</body>');
205
+ $html_email = substr($html_email, $x + 1, $y - $x - 1);
206
+ }
207
+
208
+ /* Cleans up uncorrectly stored newsletter bodies */
209
+ $html_email = preg_replace('/<style\s+.*?>.*?<\\/style>/is', '', $html_email);
210
+ $html_email = preg_replace('/<meta.*?>/', '', $html_email);
211
+ $html_email = preg_replace('/<title\s+.*?>.*?<\\/title>/i', '', $html_email);
212
+ $html_email = trim($html_email);
213
+ }
214
+
215
+ // Required since esc_html DOES NOT escape the HTML entities (apparently)
216
+ $html_email = str_replace('&', '&amp;', $html_email);
217
+ $html_email = str_replace('"', '&quot;', $html_email);
218
+ $html_email = str_replace('<', '&lt;', $html_email);
219
+ $html_email = str_replace('>', '&gt;', $html_email);
220
+
221
+ return $html_email;
222
+ }
223
+
224
+ private static function _escape_markers(&$markers) {
225
+ $markers[0] = str_replace('/', '\/', $markers[0]);
226
+ $markers[1] = str_replace('/', '\/', $markers[1]);
227
+ }
228
+
229
+ /**
230
+ * Using the data collected inside $controls (and submitted by a form containing the
231
+ * composer fields), updates the email. The message body is completed with doctype,
232
+ * head, style and the main wrapper.
233
+ *
234
+ * @param TNP_Email $email
235
+ * @param NewsletterControls $controls
236
+ */
237
+ static function update_email($email, $controls) {
238
+ if (isset($controls->data['subject'])) {
239
+ $email->subject = $controls->data['subject'];
240
+ }
241
+
242
+ // They should be only composer options
243
+ foreach ($controls->data as $name => $value) {
244
+ if (strpos($name, 'options_') === 0) {
245
+ $email->options[substr($name, 8)] = $value;
246
+ }
247
+ }
248
+
249
+ //var_dump($email->options);
250
+ //die();
251
+
252
+ $email->editor = NewsletterEmails::EDITOR_COMPOSER;
253
+
254
+ $email->options['global-styles'] = TNP_Composer::normalize_global_style_options($controls->data['global-styles']);
255
+
256
+ // TODO: align the field name, please!
257
+ $email->message = self::get_html_open($email) . self::get_main_wrapper_open($email) .
258
+ $controls->data['message'] . self::get_main_wrapper_close($email) . self::get_html_close($email);
259
+ }
260
+
261
+ /**
262
+ * Prepares a controls object injecting the relevant fields from an email
263
+ * which cannot be directly used by controls.
264
+ *
265
+ * @param Newsletter $controls
266
+ * @param TNP_Email $email
267
+ */
268
+ static function prepare_controls($controls, $email) {
269
+ foreach ($email->options as $name => $value) {
270
+ if (strpos($name, 'composer_') === 0) {
271
+ $controls->data['options_' . $name] = $value;
272
+ }
273
+ }
274
+
275
+ $controls->data['message'] = TNP_Composer::unwrap_email($email->message);
276
+ $controls->data['subject'] = $email->subject;
277
+ }
278
+
279
+ /**
280
+ * Extract inline edited post field from inline_edit_list[]
281
+ *
282
+ * @param array $inline_edit_list
283
+ * @param string $field_type
284
+ * @param int $post_id
285
+ *
286
+ * @return string
287
+ */
288
+ static function get_edited_inline_post_field( $inline_edit_list, $field_type, $post_id ) {
289
+
290
+ foreach ( $inline_edit_list as $edit ) {
291
+ if ( $edit['type'] == $field_type && $edit['post_id'] == $post_id ) {
292
+ return $edit['content'];
293
+ }
294
+ }
295
+
296
+ return '';
297
+ }
298
+
299
+ /**
300
+ * Check if inline_edit_list[] have inline edit field for specific post
301
+ *
302
+ * @param array $inline_edit_list
303
+ * @param string $field_type
304
+ * @param int $post_id
305
+ *
306
+ * @return bool
307
+ */
308
+ static function is_post_field_edited_inline( $inline_edit_list, $field_type, $post_id ) {
309
+ foreach ( $inline_edit_list as $edit ) {
310
+ if ( $edit['type'] == $field_type && $edit['post_id'] == $post_id ) {
311
+ return true;
312
+ }
313
+ }
314
+
315
+ return false;
316
+ }
317
+
318
+ }
includes/controls.php CHANGED
@@ -259,7 +259,6 @@ class NewsletterControls {
259
  'ZM' => 'Zambia',
260
  'ZW' => 'Zimbabwe',
261
  'XX' => 'Undefined',
262
-
263
  'CW' => 'Curaçao',
264
  'SS' => 'South Sudan',
265
  'EU' => 'Europe (generic)',
@@ -741,7 +740,7 @@ class NewsletterControls {
741
  echo $minutes . ' minutes ';
742
  }
743
  }
744
-
745
  function password($name, $size = 20, $placeholder = '') {
746
  $value = $this->get_value($name);
747
  echo '<input id="options-', esc_attr($name), '" placeholder="' . esc_attr($placeholder) . '" name="options[' . $name . ']" type="password" autocomplete="off" ';
@@ -749,7 +748,7 @@ class NewsletterControls {
749
  echo 'size="' . $size . '" ';
750
  }
751
  echo 'value="', esc_attr($value), '">';
752
- }
753
 
754
  function text($name, $size = 20, $placeholder = '') {
755
  $value = $this->get_value($name);
@@ -804,14 +803,14 @@ class NewsletterControls {
804
  echo esc_html(__('Reset', 'newsletter'));
805
  echo '</button>';
806
  }
807
-
808
  function button_link($url, $label) {
809
  echo '<a href="', esc_attr($url), '" class="button-primary">', $label, '</a>';
810
  }
811
-
812
  function button_configure($url) {
813
  echo '<a href="', esc_attr($url), '" class="button-primary"><i class="fa fa-cog"></i>', _e('Configure', 'newsletter'), '</a>';
814
- }
815
 
816
  function button_back($url) {
817
  echo '<a href="';
@@ -1004,10 +1003,12 @@ class NewsletterControls {
1004
  echo '<div style="clear: both"></div>';
1005
  echo '</div>';
1006
  }
1007
-
1008
- function color($name) {
1009
 
1010
  $value = $this->get_value($name);
 
 
1011
  //echo '<input id="options-', esc_attr($name), '" class="tnp-controls-color" name="options[' . $name . ']" type="text" value="';
1012
  echo '<input id="options-', esc_attr($name), '" name="options[' . $name . ']" type="color" value="';
1013
  echo esc_attr($value);
@@ -1651,6 +1652,11 @@ class NewsletterControls {
1651
  echo '</div>';
1652
  }
1653
 
 
 
 
 
 
1654
  function composer_fields($name = 'body') {
1655
 
1656
  // body
@@ -1697,4 +1703,38 @@ class NewsletterControls {
1697
  include NEWSLETTER_DIR . '/emails/tnp-composer/index.php';
1698
  }
1699
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1700
  }
259
  'ZM' => 'Zambia',
260
  'ZW' => 'Zimbabwe',
261
  'XX' => 'Undefined',
 
262
  'CW' => 'Curaçao',
263
  'SS' => 'South Sudan',
264
  'EU' => 'Europe (generic)',
740
  echo $minutes . ' minutes ';
741
  }
742
  }
743
+
744
  function password($name, $size = 20, $placeholder = '') {
745
  $value = $this->get_value($name);
746
  echo '<input id="options-', esc_attr($name), '" placeholder="' . esc_attr($placeholder) . '" name="options[' . $name . ']" type="password" autocomplete="off" ';
748
  echo 'size="' . $size . '" ';
749
  }
750
  echo 'value="', esc_attr($value), '">';
751
+ }
752
 
753
  function text($name, $size = 20, $placeholder = '') {
754
  $value = $this->get_value($name);
803
  echo esc_html(__('Reset', 'newsletter'));
804
  echo '</button>';
805
  }
806
+
807
  function button_link($url, $label) {
808
  echo '<a href="', esc_attr($url), '" class="button-primary">', $label, '</a>';
809
  }
810
+
811
  function button_configure($url) {
812
  echo '<a href="', esc_attr($url), '" class="button-primary"><i class="fa fa-cog"></i>', _e('Configure', 'newsletter'), '</a>';
813
+ }
814
 
815
  function button_back($url) {
816
  echo '<a href="';
1003
  echo '<div style="clear: both"></div>';
1004
  echo '</div>';
1005
  }
1006
+
1007
+ function color($name, $default = '') {
1008
 
1009
  $value = $this->get_value($name);
1010
+ if (empty($value) && $default) $value = $default;
1011
+
1012
  //echo '<input id="options-', esc_attr($name), '" class="tnp-controls-color" name="options[' . $name . ']" type="text" value="';
1013
  echo '<input id="options-', esc_attr($name), '" name="options[' . $name . ']" type="color" value="';
1014
  echo esc_attr($value);
1652
  echo '</div>';
1653
  }
1654
 
1655
+ /**
1656
+ * Adds the fields used by the composer (version 1) in the page form.
1657
+ *
1658
+ * @param type $name
1659
+ */
1660
  function composer_fields($name = 'body') {
1661
 
1662
  // body
1703
  include NEWSLETTER_DIR . '/emails/tnp-composer/index.php';
1704
  }
1705
 
1706
+ /**
1707
+ * Adds the fields used by the composer (version 2) in the page form.
1708
+ */
1709
+ function composer_fields_v2($name = 'message') {
1710
+ //TODO [Gioacchino] check su dove è richiamata questa funzione
1711
+
1712
+ /*foreach ($this->data as $key=>$value) {
1713
+ if (strpos($key, 'options_composer_') === 0) {
1714
+ $this->hidden($key);
1715
+ }
1716
+ }*/
1717
+ $this->hidden('options_composer_background');
1718
+ //$this->hidden('options_composer_background_image');
1719
+ $this->hidden('subject');
1720
+ $this->hidden('message');
1721
+
1722
+ // Global style background color
1723
+ $value = $this->get_value('options');
1724
+ //var_dump($value);
1725
+ //die();
1726
+ $value = isset($value['global-styles']) ? $value['global-styles'] : ['global-styles-bgcolor' => '#ECF0F1'];
1727
+ echo '<input type="hidden" name="options[global-styles]" id="options-global-styles" value="', esc_attr(json_encode($value)), '">';
1728
+ }
1729
+
1730
+ function composer_load_v2($show_subject = false, $show_test = true, $context_type = '') {
1731
+
1732
+ global $tnpc_show_subject;
1733
+ $tnpc_show_subject = $show_subject;
1734
+
1735
+ wp_enqueue_style('tnpc-style', plugins_url('newsletter') . '/emails/tnp-composer/_css/newsletter-builder-v2.css', array(), time());
1736
+ $controls = $this;
1737
+ include NEWSLETTER_DIR . '/emails/tnp-composer/index-v2.php';
1738
+ }
1739
+
1740
  }
includes/fields.php CHANGED
@@ -58,17 +58,30 @@ class NewsletterFields {
58
  $this->_close();
59
  }
60
 
61
- public function text($name, $label = '', $attrs = array()) {
 
62
  $attrs = $this->_merge_base_attrs($attrs);
63
- $attrs = array_merge(array('description' => '', 'placeholder' => '', 'size' => 0, 'label_after' => ''), $attrs);
64
  $this->_open();
65
  $this->_label($label);
66
  $value = $this->controls->get_value($name);
67
- echo '<input id="', $this->_id($name), '" placeholder="', esc_attr($attrs['placeholder']), '" name="options[' . $name . ']" type="text"';
 
 
68
  if (!empty($attrs['size'])) {
69
  echo ' style="width: ', $attrs['size'], 'px"';
70
  }
 
 
 
 
 
 
 
 
 
71
  echo ' value="', esc_attr($value), '">';
 
72
  if (!empty($attrs['label_after']))
73
  echo $attrs['label_after'];
74
  //$this->controls->text($name, $attrs['size'], $attrs['placeholder']);
@@ -76,6 +89,16 @@ class NewsletterFields {
76
  $this->_close();
77
  }
78
 
 
 
 
 
 
 
 
 
 
 
79
  public function multitext($name, $label = '', $count = 10, $attrs = array()) {
80
  $attrs = $this->_merge_base_attrs($attrs);
81
  $attrs = array_merge(array('description' => '', 'placeholder' => '', 'size' => 0, 'label_after' => ''), $attrs);
@@ -118,7 +141,7 @@ class NewsletterFields {
118
  }
119
  if (version_compare($wp_version, '4.8', '<')) {
120
  echo '<p><strong>Rich editor available only with WP 4.8+</strong></p>';
121
- }
122
  echo '<textarea id="options-' . esc_attr($name) . '" name="options[' . esc_attr($name) . ']" style="width: 100%;height:250px">';
123
  echo esc_html($value);
124
  echo '</textarea>';
@@ -177,10 +200,10 @@ class NewsletterFields {
177
 
178
  /** Collects a color in RGB format (#RRGGBB) with a picker. */
179
  public function color($name, $label, $attrs = array()) {
180
- $attrs = array_merge(array('description' => '', 'placeholder' => ''), $attrs);
181
  $this->_open('tnp-color');
182
  $this->_label($label);
183
- $this->controls->color($name);
184
  $this->_description($attrs);
185
  $this->_close();
186
  }
@@ -272,8 +295,8 @@ class NewsletterFields {
272
  'author_name' => '',
273
  'post_status' => 'publish',
274
  'suppress_filters' => true),
275
- 'last_post_option'=>false
276
- ), $args);
277
  $args['filters']['posts_per_page'] = $count;
278
 
279
  $posts = get_posts($args['filters']);
@@ -307,7 +330,7 @@ class NewsletterFields {
307
  * @param type $attrs
308
  */
309
  public function media($name, $label = '', $attrs = array()) {
310
- $attrs = $this->_merge_attrs($attrs, array('alt'=>false));
311
  $this->_open();
312
  $this->_label($label);
313
  $this->controls->media($name);
58
  $this->_close();
59
  }
60
 
61
+ /** General Input field with default type = text */
62
+ public function input($name, $label = '', $attrs = array()) {
63
  $attrs = $this->_merge_base_attrs($attrs);
64
+ $attrs = array_merge(array('description' => '', 'placeholder' => '', 'size' => 0, 'label_after' => '', 'type' => 'text'), $attrs);
65
  $this->_open();
66
  $this->_label($label);
67
  $value = $this->controls->get_value($name);
68
+
69
+ echo '<input id="', $this->_id($name), '" placeholder="', esc_attr($attrs['placeholder']), '" name="options[', $name, ']" type="', $attrs['type'], '"';
70
+
71
  if (!empty($attrs['size'])) {
72
  echo ' style="width: ', $attrs['size'], 'px"';
73
  }
74
+
75
+ if (isset($attrs['min'])) {
76
+ echo ' min="' . (int) $attrs['min'] . '"';
77
+ }
78
+
79
+ if (isset($attrs['max'])) {
80
+ echo ' max="' . (int) $attrs['max'] . '"';
81
+ }
82
+
83
  echo ' value="', esc_attr($value), '">';
84
+
85
  if (!empty($attrs['label_after']))
86
  echo $attrs['label_after'];
87
  //$this->controls->text($name, $attrs['size'], $attrs['placeholder']);
89
  $this->_close();
90
  }
91
 
92
+ public function text($name, $label = '', $attrs = array()) {
93
+ $attrs = array_merge(array('type' => 'text'), $attrs);
94
+ $this->input($name, $label, $attrs);
95
+ }
96
+
97
+ public function number($name, $label = '', $attrs = array()) {
98
+ $attrs = array_merge(array('type' => 'number'), $attrs);
99
+ $this->input($name, $label, $attrs);
100
+ }
101
+
102
  public function multitext($name, $label = '', $count = 10, $attrs = array()) {
103
  $attrs = $this->_merge_base_attrs($attrs);
104
  $attrs = array_merge(array('description' => '', 'placeholder' => '', 'size' => 0, 'label_after' => ''), $attrs);
141
  }
142
  if (version_compare($wp_version, '4.8', '<')) {
143
  echo '<p><strong>Rich editor available only with WP 4.8+</strong></p>';
144
+ }
145
  echo '<textarea id="options-' . esc_attr($name) . '" name="options[' . esc_attr($name) . ']" style="width: 100%;height:250px">';
146
  echo esc_html($value);
147
  echo '</textarea>';
200
 
201
  /** Collects a color in RGB format (#RRGGBB) with a picker. */
202
  public function color($name, $label, $attrs = array()) {
203
+ $attrs = array_merge(array('description' => '', 'placeholder' => '', 'default' => '#000000'), $attrs);
204
  $this->_open('tnp-color');
205
  $this->_label($label);
206
+ $this->controls->color($name, $attrs['default']);
207
  $this->_description($attrs);
208
  $this->_close();
209
  }
295
  'author_name' => '',
296
  'post_status' => 'publish',
297
  'suppress_filters' => true),
298
+ 'last_post_option' => false
299
+ ), $args);
300
  $args['filters']['posts_per_page'] = $count;
301
 
302
  $posts = get_posts($args['filters']);
330
  * @param type $attrs
331
  */
332
  public function media($name, $label = '', $attrs = array()) {
333
+ $attrs = $this->_merge_attrs($attrs, array('alt' => false));
334
  $this->_open();
335
  $this->_label($label);
336
  $this->controls->media($name);
includes/helper.php CHANGED
@@ -42,16 +42,24 @@ function tnp_post_thumbnail_src($post, $size = 'thumbnail', $alternative = '') {
42
  return $media[0];
43
  }
44
 
45
- function tnp_post_excerpt($post, $length = 30) {
46
- if (empty($post->post_excerpt)) {
47
- $excerpt = wp_strip_all_tags(strip_shortcodes($post->post_content));
48
- $excerpt = wp_trim_words($excerpt, $length);
49
- } else {
50
- $excerpt = wp_trim_words($post->post_excerpt, $length);
51
- }
52
-
53
- $excerpt = preg_replace("/\[vc_row.*?\]/", "", $excerpt);
54
- return $excerpt;
 
 
 
 
 
 
 
 
55
  }
56
 
57
  function tnp_post_permalink($post) {
@@ -109,7 +117,7 @@ function tnp_media_resize($media_id, $size) {
109
  // Thumbnail generation if needed.
110
  if (!file_exists($absolute_thumb) || filemtime($absolute_thumb) < filemtime($absolute_file)) {
111
  $r = wp_mkdir_p($uploads['basedir'] . '/newsletter/thumbnails/' . $pathinfo['dirname']);
112
-
113
  if (!$r) {
114
  $src = wp_get_attachment_image_src($media_id, 'full');
115
  return $src[0];
@@ -122,7 +130,7 @@ function tnp_media_resize($media_id, $size) {
122
  //return $editor;
123
  //return $uploads['baseurl'] . '/' . $relative_file;
124
  }
125
-
126
  $original_size = $editor->get_size();
127
  if ($width > $original_size['width'] || $height > $original_size['height']) {
128
  $src = wp_get_attachment_image_src($media_id, 'full');
@@ -148,6 +156,126 @@ function tnp_media_resize($media_id, $size) {
148
 
149
  return $uploads['baseurl'] . '/newsletter/thumbnails/' . $relative_thumb;
150
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
151
 
152
  function tnp_outlook_wrapper_open($width = 600) {
153
  return NewsletterEmails::get_outlook_wrapper_open($width);
42
  return $media[0];
43
  }
44
 
45
+ function tnp_post_excerpt( $post, $length = 30 ) {
46
+ if ( empty( $post->post_excerpt ) ) {
47
+ $excerpt = tnp_delete_all_shordcodes_tags( wp_strip_all_tags( $post->post_content ) );
48
+ $excerpt = wp_trim_words( $excerpt, $length );
49
+ } else {
50
+ $excerpt = wp_trim_words( $post->post_excerpt, $length );
51
+ }
52
+
53
+ return $excerpt;
54
+ }
55
+
56
+ function tnp_delete_all_shordcodes_tags( $post_content = '' ) {
57
+ //Delete open tags
58
+ $post_content = preg_replace( "/\[[a-zA-Z0-9_-]*?(\s.*?)?\]/", '', $post_content );
59
+ //Delete close tags
60
+ $post_content = preg_replace( "/\[\/[a-zA-Z0-9_-]*?\]/", '', $post_content );
61
+
62
+ return $post_content;
63
  }
64
 
65
  function tnp_post_permalink($post) {
117
  // Thumbnail generation if needed.
118
  if (!file_exists($absolute_thumb) || filemtime($absolute_thumb) < filemtime($absolute_file)) {
119
  $r = wp_mkdir_p($uploads['basedir'] . '/newsletter/thumbnails/' . $pathinfo['dirname']);
120
+
121
  if (!$r) {
122
  $src = wp_get_attachment_image_src($media_id, 'full');
123
  return $src[0];
130
  //return $editor;
131
  //return $uploads['baseurl'] . '/' . $relative_file;
132
  }
133
+
134
  $original_size = $editor->get_size();
135
  if ($width > $original_size['width'] || $height > $original_size['height']) {
136
  $src = wp_get_attachment_image_src($media_id, 'full');
156
 
157
  return $uploads['baseurl'] . '/newsletter/thumbnails/' . $relative_thumb;
158
  }
159
+
160
+ function _tnp_get_default_media($media_id, $size) {
161
+
162
+ $src = wp_get_attachment_image_src($media_id, $size);
163
+ if (!$src) {
164
+ return null;
165
+ }
166
+ $media = new TNP_Media();
167
+ $media->url = $src[0];
168
+ $media->width = $src[1];
169
+ $media->height = $src[2];
170
+ return $media;
171
+ }
172
+
173
+ /**
174
+ * Create a resized version of the media stored in the WP media library.
175
+ *
176
+ * @param int $media_id
177
+ * @param array $size
178
+ * @return TNP_Media
179
+ */
180
+ function tnp_resize($media_id, $size) {
181
+ if (empty($media_id)) {
182
+ return null;
183
+ }
184
+
185
+ $relative_file = get_post_meta($media_id, '_wp_attached_file', true);
186
+
187
+ if (empty($relative_file)) {
188
+ return null;
189
+ }
190
+
191
+ $width = $size[0];
192
+ $height = $size[1];
193
+ $crop = false;
194
+ if (isset($size[2])) {
195
+ $crop = (boolean) $size[2];
196
+ }
197
+
198
+ $uploads = wp_upload_dir();
199
+ $absolute_file = $uploads['basedir'] . '/' . $relative_file;
200
+ // Relative and absolute name of the thumbnail.
201
+ $pathinfo = pathinfo($relative_file);
202
+ $relative_thumb = $pathinfo['dirname'] . '/' . $pathinfo['filename'] . '-' . $width . 'x' . $height . ($crop ? '-c' : '') . '.' . $pathinfo['extension'];
203
+ $absolute_thumb = $uploads['basedir'] . '/newsletter/thumbnails/' . $relative_thumb;
204
+
205
+ // Thumbnail generation if needed.
206
+ if (!file_exists($absolute_thumb) || filemtime($absolute_thumb) < filemtime($absolute_file)) {
207
+ $r = wp_mkdir_p($uploads['basedir'] . '/newsletter/thumbnails/' . $pathinfo['dirname']);
208
+
209
+ if (!$r) {
210
+ Newsletter::instance()->logger->error('Unable to create dir ' . $uploads['basedir'] . '/newsletter/thumbnails/' . $pathinfo['dirname']);
211
+ return _tnp_get_default_media($media_id);
212
+ }
213
+
214
+ $editor = wp_get_image_editor($absolute_file);
215
+ if (is_wp_error($editor)) {
216
+ Newsletter::instance()->logger->error($editor);
217
+ return _tnp_get_default_media($media_id, $size);
218
+ }
219
+
220
+ $original_size = $editor->get_size();
221
+ if ($width > $original_size['width'] && $height > $original_size['height']) {
222
+ Newsletter::instance()->logger->error('Requested size larger than the original one');
223
+ return _tnp_get_default_media($media_id, $size);
224
+ }
225
+
226
+ $editor->set_quality(85);
227
+ $resized = $editor->resize($width, $height, $crop);
228
+
229
+ if (is_wp_error($resized)) {
230
+ Newsletter::instance()->logger->error($resized);
231
+ return _tnp_get_default_media($media_id, $size);
232
+ }
233
+
234
+ $saved = $editor->save($absolute_thumb);
235
+ if (is_wp_error($saved)) {
236
+ Newsletter::instance()->logger->error($saved);
237
+ return _tnp_get_default_media($media_id, $size);
238
+ }
239
+ $new_size = $editor->get_size();
240
+
241
+ $media = new TNP_Media();
242
+ $media->width = $new_size['width'];
243
+ $media->height = $new_size['height'];
244
+ $media->url = $uploads['baseurl'] . '/newsletter/thumbnails/' . $relative_thumb;
245
+ } else {
246
+ $media = new TNP_Media();
247
+ $new_size = getimagesize($absolute_thumb);
248
+ $media->width = $new_size[0];
249
+ $media->height = $new_size[1];
250
+ $media->url = $uploads['baseurl'] . '/newsletter/thumbnails/' . $relative_thumb;
251
+ }
252
+
253
+ return $media;
254
+ }
255
+
256
+ /**
257
+ * Get media for "posts" composer block
258
+ *
259
+ * @param WP_Post post
260
+ * @param array $size
261
+ * @param string $default_image_url
262
+ *
263
+ * @return TNP_Media
264
+ */
265
+ function tnp_composer_block_posts_get_media( $post, $size, $default_image_url ) {
266
+ $post_thumbnail_id = get_post_thumbnail_id( $post );
267
+
268
+ if ( ! empty( $post_thumbnail_id ) ) {
269
+ $media = tnp_resize( $post_thumbnail_id, array_values( $size ) );
270
+ } else {
271
+ $media = new TNP_Media();
272
+ $media->url = $default_image_url;
273
+ $media->width = $size['width'];
274
+ $media->height = $size['height'];
275
+ }
276
+
277
+ return $media;
278
+ }
279
 
280
  function tnp_outlook_wrapper_open($width = 600) {
281
  return NewsletterEmails::get_outlook_wrapper_open($width);
includes/{mailers.php → mailer.php} RENAMED
@@ -1,5 +1,222 @@
1
  <?php
2
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3
  /**
4
  * Wrapper mailer for old addons registering the "mail" method (ultra deprecated).
5
  */
@@ -319,3 +536,5 @@ class NewsletterDefaultSMTPMailer extends NewsletterMailer {
319
  }
320
 
321
  }
 
 
1
  <?php
2
 
3
+ /**
4
+ *
5
+ */
6
+ class NewsletterMailer {
7
+
8
+ const ERROR_GENERIC = '1';
9
+ const ERROR_FATAL = '2';
10
+
11
+ /* @var NewsletterLogger */
12
+
13
+ var $logger;
14
+ var $name;
15
+ var $options;
16
+ private $delta;
17
+ protected $batch_size = 1;
18
+
19
+ public function __construct($name, $options = array()) {
20
+ $this->name = $name;
21
+ $this->options = $options;
22
+ }
23
+
24
+ public function get_name() {
25
+ return $this->name;
26
+ }
27
+
28
+ public function get_description() {
29
+ return $this->name;
30
+ }
31
+
32
+ public function get_batch_size() {
33
+ return $this->batch_size;
34
+ }
35
+
36
+ function send_with_stats($message) {
37
+ $this->delta = microtime(true);
38
+ $r = $this->send($message);
39
+ $this->delta = microtime(true) - $this->delta;
40
+ return $r;
41
+ }
42
+
43
+ /**
44
+ *
45
+ * @param TNP_Mailer_Message $message
46
+ * @return bool|WP_Error
47
+ */
48
+ public function send($message) {
49
+ $message->error = 'No mailing system available';
50
+ return new WP_Error(self::ERROR_FATAL, 'No mailing system available');
51
+ }
52
+
53
+ public function send_batch_with_stats($messages) {
54
+ $this->delta = microtime(true);
55
+ $r = $this->send_batch($messages);
56
+ $this->delta = microtime(true) - $this->delta;
57
+ return $r;
58
+ }
59
+
60
+ function get_capability() {
61
+ return (int) (3600 * $this->batch_size / $this->delta);
62
+ }
63
+
64
+ /**
65
+ *
66
+ * @param TNP_Mailer_Message[] $messages
67
+ * @return bool|WP_Error
68
+ */
69
+ public function send_batch($messages) {
70
+
71
+ // We should not get there is the batch size is one, the caller should use "send()". We can get
72
+ // there if the array of messages counts to one, since could be the last of a series of chunks.
73
+ if ($this->batch_size == 1 || count($messages) == 1) {
74
+ $last_result = true;
75
+ foreach ($messages as $message) {
76
+ $r = $this->send($message);
77
+ if (is_wp_error($r)) {
78
+ $last_result = $r;
79
+ }
80
+ }
81
+ return $last_result;
82
+ }
83
+
84
+ // We should always get there
85
+ if (count($messages) <= $this->batch_size) {
86
+ return $this->send_chunk($messages);
87
+ }
88
+
89
+ // We should not get here, since it is not optimized
90
+ $chunks = array_chunk($message, $this->batch_size);
91
+ $last_result = true;
92
+ foreach ($chunks as $chunk) {
93
+ $r = $this->send_chunk($chunk);
94
+ if (is_wp_error($r)) {
95
+ $last_result = $r;
96
+ }
97
+ }
98
+ return $last_result;
99
+ }
100
+
101
+ protected function send_chunk($messages) {
102
+ $last_result = true;
103
+ foreach ($messages as $message) {
104
+ $r = $this->send($message);
105
+ if (is_wp_error($r)) {
106
+ $last_result = $r;
107
+ }
108
+ }
109
+ return $last_result;
110
+ }
111
+
112
+ /**
113
+ *
114
+ * @return NewsletterLogger
115
+ */
116
+ function get_logger() {
117
+ if ($this->logger) {
118
+ return $this->logger;
119
+ }
120
+ $this->logger = new NewsletterLogger('mailer-' . $this->name);
121
+ return $this->logger;
122
+ }
123
+
124
+ /**
125
+ *
126
+ * @param TNP_Mailer_Message $message
127
+ * @return bool|WP_Error
128
+ */
129
+ public function enqueue(TNP_Mailer_Message $message) {
130
+ // Optimization when there is no queue
131
+ if ($this->queue_max == 0) {
132
+ $r = $this->send($message);
133
+ return $r;
134
+ }
135
+
136
+ $this->queue[] = $message;
137
+ if (count($this->queue) >= $this->queue_max) {
138
+ return $this->flush();
139
+ }
140
+ return true;
141
+ }
142
+
143
+ public function flush() {
144
+ $undelivered = array();
145
+ foreach ($this->queue as $message) {
146
+ $r = $this->deliver($message);
147
+ if (is_wp_error($r)) {
148
+ $message->error = $r;
149
+ $undelivered[] = $message;
150
+ }
151
+ }
152
+
153
+ $this->queue = array();
154
+
155
+ if ($undelivered) {
156
+ return new WP_Error(self::ERROR_GENERAL, 'Error while flushing messages', $undelivered);
157
+ }
158
+
159
+ return true;
160
+ }
161
+
162
+ /**
163
+ * Original mail function simulation for compatibility.
164
+ * @deprecated
165
+ *
166
+ * @param string $to
167
+ * @param string $subject
168
+ * @param array $message
169
+ * @param array $headers
170
+ * @param bool $enqueue
171
+ * @param type $from Actually ignored
172
+ * @return type
173
+ */
174
+ public function mail($to, $subject, $message, $headers = null, $enqueue = false, $from = false) {
175
+ $mailer_message = new TNP_Mailer_Message();
176
+ $mailer_message->to = $to;
177
+ $mailer_message->subject = $subject;
178
+ $mailer_message->headers = $headers;
179
+ $mailer_message->body = $message['html'];
180
+ $mailer_message->body_text = $message['text'];
181
+
182
+ if ($enqueue) {
183
+ return !is_wp_error($this->enqueue($mailer_message));
184
+ }
185
+ return !is_wp_error($this->send($mailer_message));
186
+ }
187
+
188
+ function save_last_run($time) {
189
+ update_option($this->prefix . '_last_run', $time);
190
+ }
191
+
192
+ function get_last_run() {
193
+ return (int) get_option($this->prefix . '_last_run', 0);
194
+ }
195
+
196
+ }
197
+
198
+ /**
199
+ * @property string $to
200
+ * @property string $subject
201
+ * @property string $body
202
+ * @property array $headers
203
+ * @property string $from
204
+ * @property string $from_name
205
+ */
206
+ class TNP_Mailer_Message {
207
+
208
+ var $to_name = '';
209
+ var $headers = array();
210
+ var $user_id = 0;
211
+ var $email_id = 0;
212
+ var $error = '';
213
+ var $subject = '';
214
+ var $body = '';
215
+ var $body_text = '';
216
+
217
+ }
218
+
219
+
220
  /**
221
  * Wrapper mailer for old addons registering the "mail" method (ultra deprecated).
222
  */
536
  }
537
 
538
  }
539
+
540
+
includes/module.php CHANGED
@@ -2,49 +2,18 @@
2
 
3
  defined('ABSPATH') || exit;
4
 
 
 
 
 
 
 
 
5
  class TNP_Media {
6
  var $url;
7
  var $width;
8
  var $height;
9
- }
10
-
11
- function tnp_register_block($dir) {
12
- TNP_Composer::register_block($dir);
13
- }
14
-
15
- function tnpc_button($options, $prefix = 'button') {
16
- return TNP_Composer::button($options, $prefix);
17
- }
18
-
19
- class TNP_Composer {
20
-
21
- static $block_dirs = array();
22
-
23
- static function register_block($dir) {
24
- // Checks
25
-
26
- if (!file_exists($dir . '/block.php')) {
27
- $error = new WP_Error('1', 'block.php missing on folder ' . $dir);
28
- NewsletterEmails::instance()->logger->error($error);
29
- return $error;
30
- }
31
- self::$block_dirs[] = $dir;
32
- return true;
33
- }
34
-
35
- static function button($options, $prefix = 'button') {
36
- $b = '<table border="0" cellpadding="0" cellspacing="0" role="presentation" style="border-collapse:separate;line-height:100%;">';
37
- $b .= '<tr>';
38
- $b .= '<td align="center" bgcolor="' . $options[$prefix . '_background'] . '" role="presentation" style="border:none;border-radius:3px;cursor:auto;mso-padding-alt:10px 25px;background:' . $options[$prefix . '_background'] . '" valign="middle">';
39
- $b .= '<a href="' . $options[$prefix . '_url'] . '"';
40
- $b .= ' style="display:inline-block;background:' . $options[$prefix . '_background'] . ';color:' . $options[$prefix . '_font_color'] . ';font-family:' . $options[$prefix . '_font_family'] . ';font-size:' . $options[$prefix . '_font_size'] . 'px;font-weight:' . $options[$prefix . '_font_weight'] . ';line-height:120%;margin:0;text-decoration:none;text-transform:none;padding:10px 25px;mso-padding-alt:0px;border-radius:3px;"';
41
- $b .= ' target="_blank">';
42
- $b .= $options[$prefix . '_label'];
43
- $b .= '</a>';
44
- $b .= '</td></tr></table>';
45
- return $b;
46
- }
47
-
48
  }
49
 
50
  /**
@@ -106,392 +75,6 @@ abstract class TNP_Email {
106
 
107
  }
108
 
109
- /**
110
- * @property string $id Theme identifier
111
- * @property string $dir Absolute path to the theme folder
112
- * @property string $name Theme name
113
- */
114
- class TNP_Theme {
115
-
116
- var $dir;
117
- var $name;
118
-
119
- public function get_defaults() {
120
- @include $this->dir . '/theme-defaults.php';
121
- if (!isset($theme_defaults) || !is_array($theme_defaults))
122
- return array();
123
- return $theme_defaults;
124
- }
125
-
126
- }
127
-
128
- class NewsletterAddon {
129
-
130
- var $logger;
131
- var $admin_logger;
132
- var $name;
133
- var $options;
134
- var $version;
135
-
136
- public function __construct($name, $version = '0.0.0') {
137
- $this->name = $name;
138
- $this->version = $version;
139
- if (is_admin()) {
140
- $old_version = get_option('newsletter_' . $name . '_version');
141
- if ($version != $old_version) {
142
- $this->upgrade($old_version === false);
143
- update_option('newsletter_' . $name . '_version', $version, false);
144
- }
145
- }
146
- add_action('newsletter_init', array($this, 'init'));
147
- }
148
-
149
- function upgrade($first_install = false) {
150
-
151
- }
152
-
153
- function init() {
154
-
155
- }
156
-
157
- /**
158
- *
159
- * @return NewsletterLogger
160
- */
161
- function get_logger() {
162
- if (!$this->logger) {
163
- $this->logger = new NewsletterLogger($this->name);
164
- }
165
- return $this->logger;
166
- }
167
-
168
- function get_admin_logger() {
169
- if (!$this->admin_logger) {
170
- $this->admin_logger = new NewsletterLogger($this->name . '-admin');
171
- }
172
- return $this->admin_logger;
173
- }
174
-
175
- function setup_options() {
176
- if ($this->options)
177
- return;
178
- $this->options = get_option('newsletter_' . $this->name, array());
179
- }
180
-
181
- function save_options($options) {
182
- update_option('newsletter_' . $this->name, $options);
183
- $this->setup_options();
184
- }
185
-
186
- function merge_defaults($defaults) {
187
- $options = get_option('newsletter_' . $this->name, array());
188
- $options = array_merge($defaults, $options);
189
- $this->save_options($options);
190
- }
191
-
192
- /**
193
- * @global wpdb $wpdb
194
- * @param string $query
195
- */
196
- function query($query) {
197
- global $wpdb;
198
-
199
- $r = $wpdb->query($query);
200
- if ($r === false) {
201
- $logger = $this->get_logger();
202
- $logger->fatal($query);
203
- $logger->fatal($wpdb->last_error);
204
- }
205
- return $r;
206
- }
207
-
208
- }
209
-
210
- class NewsletterMailerAddon extends NewsletterAddon {
211
-
212
- var $enabled = false;
213
-
214
- function __construct($name, $version = '0.0.0') {
215
- parent::__construct($name, $version);
216
- $this->setup_options();
217
- $this->enabled = !empty($this->options['enabled']);
218
- }
219
-
220
- function init() {
221
- parent::init();
222
- add_action('newsletter_register_mailer', function () {
223
- if ($this->enabled) {
224
- Newsletter::instance()->register_mailer($this->get_mailer());
225
- }
226
- });
227
- }
228
-
229
- /**
230
- *
231
- * @return NewsletterMailer
232
- */
233
- function get_mailer() {
234
- return null;
235
- }
236
-
237
- function get_last_run() {
238
- return get_option('newsletter_' . $this->name . '_last_run', 0);
239
- }
240
-
241
- function save_last_run($time) {
242
- update_option('newsletter_' . $this->name . '_last_run', $time);
243
- }
244
-
245
- function save_options($options) {
246
- parent::save_options($options);
247
- $this->enabled = !empty($options['enabled']);
248
- }
249
-
250
- static function get_test_message($to, $subject = '') {
251
- $message = new TNP_Mailer_Message();
252
- $message->to = $to;
253
- $message->to_name = '';
254
- $message->body = "<!DOCTYPE html>\n";
255
- $message->body .= "This is the rich text (HTML) version of a test message.</p>\n";
256
- $message->body .= "This is a <strong>bold text</strong></p>\n";
257
- $message->body .= "This is a <a href='http://www.thenewsletterplugin.com'>link to www.thenewsletterplugin.com</a></p>\n";
258
- $message->body_text = 'This is the TEXT version of a test message. You should see this message only if you email client does not support the rich text (HTML) version.';
259
- $message->headers['X-Newsletter-Email-Id'] = '0';
260
- if (empty($subject)) {
261
- $message->subject = '[' . get_option('blogname') . '] Test message from Newsletter (' . date(DATE_ISO8601) . ')';
262
- } else {
263
- $message->subject = $subject;
264
- }
265
- $message->from = Newsletter::instance()->options['sender_email'];
266
- $message->from_name = Newsletter::instance()->options['sender_name'];
267
- return $message;
268
- }
269
-
270
- function get_test_messages($to, $count) {
271
- $messages = array();
272
- for ($i = 0; $i < $count; $i++) {
273
- $messages[] = self::get_test_message($to, '[' . get_option('blogname') . '] Test message ' . ($i + 1) . ' from Newsletter (' . date(DATE_ISO8601) . ')');
274
- }
275
- return $messages;
276
- }
277
-
278
- }
279
-
280
- /**
281
- */
282
- class NewsletterMailer {
283
-
284
- const ERROR_GENERIC = '1';
285
- const ERROR_FATAL = '2';
286
-
287
- /* @var NewsletterLogger */
288
-
289
- var $logger;
290
- var $name;
291
- var $options;
292
- private $delta;
293
- protected $batch_size = 1;
294
-
295
- public function __construct($name, $options = array()) {
296
- $this->name = $name;
297
- $this->options = $options;
298
- }
299
-
300
- public function get_name() {
301
- return $this->name;
302
- }
303
-
304
- public function get_description() {
305
- return $this->name;
306
- }
307
-
308
- public function get_batch_size() {
309
- return $this->batch_size;
310
- }
311
-
312
- function send_with_stats($message) {
313
- $this->delta = microtime(true);
314
- $r = $this->send($message);
315
- $this->delta = microtime(true) - $this->delta;
316
- return $r;
317
- }
318
-
319
- /**
320
- *
321
- * @param TNP_Mailer_Message $message
322
- * @return bool|WP_Error
323
- */
324
- public function send($message) {
325
- $message->error = 'No mailing system available';
326
- return new WP_Error(self::ERROR_FATAL, 'No mailing system available');
327
- }
328
-
329
- public function send_batch_with_stats($messages) {
330
- $this->delta = microtime(true);
331
- $r = $this->send_batch($messages);
332
- $this->delta = microtime(true) - $this->delta;
333
- return $r;
334
- }
335
-
336
- function get_capability() {
337
- return (int) (3600 * $this->batch_size / $this->delta);
338
- }
339
-
340
- /**
341
- *
342
- * @param TNP_Mailer_Message[] $messages
343
- * @return bool|WP_Error
344
- */
345
- public function send_batch($messages) {
346
-
347
- // We should not get there is the batch size is one, the caller should use "send()". We can get
348
- // there if the array of messages counts to one, since could be the last of a series of chunks.
349
- if ($this->batch_size == 1 || count($messages) == 1) {
350
- $last_result = true;
351
- foreach ($messages as $message) {
352
- $r = $this->send($message);
353
- if (is_wp_error($r)) {
354
- $last_result = $r;
355
- }
356
- }
357
- return $last_result;
358
- }
359
-
360
- // We should always get there
361
- if (count($messages) <= $this->batch_size) {
362
- return $this->send_chunk($messages);
363
- }
364
-
365
- // We should not get here, since it is not optimized
366
- $chunks = array_chunk($message, $this->batch_size);
367
- $last_result = true;
368
- foreach ($chunks as $chunk) {
369
- $r = $this->send_chunk($chunk);
370
- if (is_wp_error($r)) {
371
- $last_result = $r;
372
- }
373
- }
374
- return $last_result;
375
- }
376
-
377
- protected function send_chunk($messages) {
378
- $last_result = true;
379
- foreach ($messages as $message) {
380
- $r = $this->send($message);
381
- if (is_wp_error($r)) {
382
- $last_result = $r;
383
- }
384
- }
385
- return $last_result;
386
- }
387
-
388
- /**
389
- *
390
- * @return NewsletterLogger
391
- */
392
- function get_logger() {
393
- if ($this->logger) {
394
- return $this->logger;
395
- }
396
- $this->logger = new NewsletterLogger('mailer-' . $this->name);
397
- return $this->logger;
398
- }
399
-
400
- /**
401
- *
402
- * @param TNP_Mailer_Message $message
403
- * @return bool|WP_Error
404
- */
405
- public function enqueue(TNP_Mailer_Message $message) {
406
- // Optimization when there is no queue
407
- if ($this->queue_max == 0) {
408
- $r = $this->send($message);
409
- return $r;
410
- }
411
-
412
- $this->queue[] = $message;
413
- if (count($this->queue) >= $this->queue_max) {
414
- return $this->flush();
415
- }
416
- return true;
417
- }
418
-
419
- public function flush() {
420
- $undelivered = array();
421
- foreach ($this->queue as $message) {
422
- $r = $this->deliver($message);
423
- if (is_wp_error($r)) {
424
- $message->error = $r;
425
- $undelivered[] = $message;
426
- }
427
- }
428
-
429
- $this->queue = array();
430
-
431
- if ($undelivered) {
432
- return new WP_Error(self::ERROR_GENERAL, 'Error while flushing messages', $undelivered);
433
- }
434
-
435
- return true;
436
- }
437
-
438
- /**
439
- * Original mail function simulation for compatibility.
440
- * @deprecated
441
- *
442
- * @param string $to
443
- * @param string $subject
444
- * @param array $message
445
- * @param array $headers
446
- * @param bool $enqueue
447
- * @param type $from Actually ignored
448
- * @return type
449
- */
450
- public function mail($to, $subject, $message, $headers = null, $enqueue = false, $from = false) {
451
- $mailer_message = new TNP_Mailer_Message();
452
- $mailer_message->to = $to;
453
- $mailer_message->subject = $subject;
454
- $mailer_message->headers = $headers;
455
- $mailer_message->body = $message['html'];
456
- $mailer_message->body_text = $message['text'];
457
-
458
- if ($enqueue) {
459
- return !is_wp_error($this->enqueue($mailer_message));
460
- }
461
- return !is_wp_error($this->send($mailer_message));
462
- }
463
-
464
- function save_last_run($time) {
465
- update_option($this->prefix . '_last_run', $time);
466
- }
467
-
468
- function get_last_run() {
469
- return (int) get_option($this->prefix . '_last_run', 0);
470
- }
471
-
472
- }
473
-
474
- /**
475
- * @property string $to
476
- * @property string $subject
477
- * @property string $body
478
- * @property array $headers
479
- * @property string $from
480
- * @property string $from_name
481
- */
482
- class TNP_Mailer_Message {
483
-
484
- var $to_name = '';
485
- var $headers = array();
486
- var $user_id = 0;
487
- var $email_id = 0;
488
- var $error = '';
489
- var $subject = '';
490
- var $body = '';
491
- var $body_text = '';
492
-
493
- }
494
-
495
  class NewsletterModule {
496
 
497
  /**
2
 
3
  defined('ABSPATH') || exit;
4
 
5
+ require_once __DIR__ . '/logger.php';
6
+ require_once __DIR__ . '/store.php';
7
+ require_once __DIR__ . '/composer.php';
8
+ require_once __DIR__ . '/addon.php';
9
+ require_once __DIR__ . '/mailer.php';
10
+ require_once __DIR__ . '/themes.php';
11
+
12
  class TNP_Media {
13
  var $url;
14
  var $width;
15
  var $height;
16
+ var $alt;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
17
  }
18
 
19
  /**
75
 
76
  }
77
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
78
  class NewsletterModule {
79
 
80
  /**
includes/themes.php CHANGED
@@ -2,6 +2,25 @@
2
 
3
  defined('ABSPATH') || exit;
4
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
5
  /**
6
  * Registers a Newsletter theme to be shown as option on standard newsletter creation
7
  * Designers love functions...
@@ -86,6 +105,7 @@ class NewsletterThemes {
86
  $list['blank'] = $this->build_theme(NEWSLETTER_DIR . '/emails/themes/blank');
87
  $list['cta-2015'] = $this->build_theme(NEWSLETTER_DIR . '/emails/themes/cta-2015');
88
  $list['vimeo-like'] = $this->build_theme(NEWSLETTER_DIR . '/emails/themes/vimeo-like');
 
89
 
90
  // Extensions folder scan
91
  $dir = WP_CONTENT_DIR . '/extensions/newsletter/' . $this->module . '/themes';
2
 
3
  defined('ABSPATH') || exit;
4
 
5
+ /**
6
+ * @property string $id Theme identifier
7
+ * @property string $dir Absolute path to the theme folder
8
+ * @property string $name Theme name
9
+ */
10
+ class TNP_Theme {
11
+
12
+ var $dir;
13
+ var $name;
14
+
15
+ public function get_defaults() {
16
+ @include $this->dir . '/theme-defaults.php';
17
+ if (!isset($theme_defaults) || !is_array($theme_defaults)) {
18
+ return array();
19
+ }
20
+ return $theme_defaults;
21
+ }
22
+ }
23
+
24
  /**
25
  * Registers a Newsletter theme to be shown as option on standard newsletter creation
26
  * Designers love functions...
105
  $list['blank'] = $this->build_theme(NEWSLETTER_DIR . '/emails/themes/blank');
106
  $list['cta-2015'] = $this->build_theme(NEWSLETTER_DIR . '/emails/themes/cta-2015');
107
  $list['vimeo-like'] = $this->build_theme(NEWSLETTER_DIR . '/emails/themes/vimeo-like');
108
+ $list['pint'] = $this->build_theme(NEWSLETTER_DIR . '/emails/themes/pint');
109
 
110
  // Extensions folder scan
111
  $dir = WP_CONTENT_DIR . '/extensions/newsletter/' . $this->module . '/themes';
plugin.php CHANGED
@@ -4,7 +4,7 @@
4
  Plugin Name: Newsletter
5
  Plugin URI: https://www.thenewsletterplugin.com/plugins/newsletter
6
  Description: Newsletter is a cool plugin to create your own subscriber list, to send newsletters, to build your business. <strong>Before update give a look to <a href="https://www.thenewsletterplugin.com/category/release">this page</a> to know what's changed.</strong>
7
- Version: 6.4.8
8
  Author: Stefano Lissa & The Newsletter Team
9
  Author URI: https://www.thenewsletterplugin.com
10
  Disclaimer: Use at your own risk. No warranty expressed or implied is provided.
@@ -28,7 +28,7 @@
28
 
29
  */
30
 
31
- define('NEWSLETTER_VERSION', '6.4.8');
32
 
33
  global $newsletter, $wpdb;
34
 
@@ -71,14 +71,7 @@ if (!defined('NEWSLETTER_CRON_INTERVAL'))
71
  if (!defined('NEWSLETTER_HEADER'))
72
  define('NEWSLETTER_HEADER', true);
73
 
74
- // Force the whole system log level to this value
75
- //define('NEWSLETTER_LOG_LEVEL', 4);
76
-
77
- require_once NEWSLETTER_INCLUDES_DIR . '/logger.php';
78
- require_once NEWSLETTER_INCLUDES_DIR . '/store.php';
79
  require_once NEWSLETTER_INCLUDES_DIR . '/module.php';
80
- require_once NEWSLETTER_INCLUDES_DIR . '/mailers.php';
81
- require_once NEWSLETTER_INCLUDES_DIR . '/themes.php';
82
  require_once NEWSLETTER_INCLUDES_DIR . '/TNP.php';
83
 
84
  class Newsletter extends NewsletterModule {
4
  Plugin Name: Newsletter
5
  Plugin URI: https://www.thenewsletterplugin.com/plugins/newsletter
6
  Description: Newsletter is a cool plugin to create your own subscriber list, to send newsletters, to build your business. <strong>Before update give a look to <a href="https://www.thenewsletterplugin.com/category/release">this page</a> to know what's changed.</strong>
7
+ Version: 6.4.9
8
  Author: Stefano Lissa & The Newsletter Team
9
  Author URI: https://www.thenewsletterplugin.com
10
  Disclaimer: Use at your own risk. No warranty expressed or implied is provided.
28
 
29
  */
30
 
31
+ define('NEWSLETTER_VERSION', '6.4.9');
32
 
33
  global $newsletter, $wpdb;
34
 
71
  if (!defined('NEWSLETTER_HEADER'))
72
  define('NEWSLETTER_HEADER', true);
73
 
 
 
 
 
 
74
  require_once NEWSLETTER_INCLUDES_DIR . '/module.php';
 
 
75
  require_once NEWSLETTER_INCLUDES_DIR . '/TNP.php';
76
 
77
  class Newsletter extends NewsletterModule {
readme.txt CHANGED
@@ -2,7 +2,7 @@
2
  Tags: email, email marketing, newsletter, newsletter subscribers, welcome email, signup forms, contact, lead generation, popup, marketing automation
3
  Requires at least: 3.4.0
4
  Tested up to: 5.3.2
5
- Stable tag: 6.4.8
6
  Requires PHP: 5.6
7
  Contributors: satollo,webagile,michael-travan
8
 
@@ -109,6 +109,17 @@ Thank you, The Newsletter Team
109
 
110
  == Changelog ==
111
 
 
 
 
 
 
 
 
 
 
 
 
112
  = 6.4.8 =
113
 
114
  * Antispam on PHP API
@@ -119,6 +130,14 @@ Thank you, The Newsletter Team
119
  * Profile saving antispam check
120
  * Fixed hero block (button)
121
  * Added logging on spam checking (enable info lov level to see the spam check results in the logs)
 
 
 
 
 
 
 
 
122
 
123
  = 6.4.6 =
124
 
2
  Tags: email, email marketing, newsletter, newsletter subscribers, welcome email, signup forms, contact, lead generation, popup, marketing automation
3
  Requires at least: 3.4.0
4
  Tested up to: 5.3.2
5
+ Stable tag: 6.4.9
6
  Requires PHP: 5.6
7
  Contributors: satollo,webagile,michael-travan
8
 
109
 
110
  == Changelog ==
111
 
112
+ = 6.4.9 =
113
+
114
+ * Added background selection to the composer
115
+ * Reactivated the Pint theme
116
+ * Improved blocks layout
117
+ * Inline editing for title and excerpt on Posts block
118
+ * Changed the image cropping method on newsletter included images
119
+ * Posts block can now specify an offset to skip the first *n* posts
120
+ * Fixed the display of multiline title on some blocks (was overlapping)
121
+ * Added the excerpt length on Posts block
122
+
123
  = 6.4.8 =
124
 
125
  * Antispam on PHP API
130
  * Profile saving antispam check
131
  * Fixed hero block (button)
132
  * Added logging on spam checking (enable info lov level to see the spam check results in the logs)
133
+ = Next =
134
+
135
+ * Removed the shortcodes from generated excerpt for blog post composer block
136
+ * New media resize to better fit the email layout standards
137
+ * Updated image block
138
+ * Added "Excerpt words" field on "Blog Posts" composer block
139
+ * Added "Posts offset" field on "Blog Posts" composer block
140
+ * Added background color on email
141
 
142
  = 6.4.6 =
143
 
subscription/antibot.php CHANGED
@@ -27,7 +27,7 @@ if ($controls->is_action()) {
27
  <div id="tnp-heading">
28
 
29
  <h2><?php _e('Security', 'newsletter') ?></h2>
30
- <?php $controls->page_help('https://www.thenewsletterplugin.com/documentation/antiflood') ?>
31
 
32
  </div>
33
 
@@ -55,7 +55,7 @@ if ($controls->is_action()) {
55
  <th><?php _e('Disable antibot', 'newsletter') ?></th>
56
  <td>
57
  <?php $controls->yesno('disabled'); ?>
58
- <?php $controls->help('https://www.thenewsletterplugin.com/documentation/antiflood') ?>
59
  <p class="description">
60
  <?php _e('Disable for ajax form submission', 'newsletter'); ?>
61
  </p>
@@ -71,7 +71,7 @@ if ($controls->is_action()) {
71
  1 => __('Enabled', 'newsletter')
72
  ));
73
  ?>
74
- <?php $controls->help('https://www.thenewsletterplugin.com/documentation/antiflood') ?>
75
  </td>
76
  </tr>
77
 
@@ -94,13 +94,13 @@ if ($controls->is_action()) {
94
  360 => '60 ' . __('minutes', 'newsletter')
95
  ));
96
  ?>
97
- <?php $controls->help('https://www.thenewsletterplugin.com/documentation/antiflood') ?>
98
  </td>
99
  </tr>
100
  <tr>
101
  <th><?php _e('Captcha', 'newsletter') ?> </th>
102
  <td>
103
- <?php $controls->enabled('captcha'); ?> <?php $controls->field_help('https://www.thenewsletterplugin.com/documentation/antiflood#captcha') ?>
104
  </td>
105
  </tr>
106
  <?php /*
@@ -124,7 +124,7 @@ if ($controls->is_action()) {
124
  <tr>
125
  <th>
126
  <?php _e('IP black list', 'newsletter') ?>
127
- <?php $controls->field_help('https://www.thenewsletterplugin.com/documentation/antiflood#ip') ?>
128
  </th>
129
  <td>
130
  <?php $controls->textarea('ip_blacklist'); ?>
@@ -134,7 +134,7 @@ if ($controls->is_action()) {
134
  <tr>
135
  <th>
136
  <?php _e('Address black list', 'newsletter') ?>
137
- <?php $controls->field_help('https://www.thenewsletterplugin.com/documentation/antiflood#domains') ?>
138
  </th>
139
  <td>
140
  <?php $controls->textarea('address_blacklist'); ?>
27
  <div id="tnp-heading">
28
 
29
  <h2><?php _e('Security', 'newsletter') ?></h2>
30
+ <?php $controls->page_help('https://www.thenewsletterplugin.com/documentation/subscription/antiflood') ?>
31
 
32
  </div>
33
 
55
  <th><?php _e('Disable antibot', 'newsletter') ?></th>
56
  <td>
57
  <?php $controls->yesno('disabled'); ?>
58
+ <?php $controls->help('https://www.thenewsletterplugin.com/documentation/subscription/antiflood') ?>
59
  <p class="description">
60
  <?php _e('Disable for ajax form submission', 'newsletter'); ?>
61
  </p>
71
  1 => __('Enabled', 'newsletter')
72
  ));
73
  ?>
74
+ <?php $controls->help('https://www.thenewsletterplugin.com/documentation/subscription/antiflood') ?>
75
  </td>
76
  </tr>
77
 
94
  360 => '60 ' . __('minutes', 'newsletter')
95
  ));
96
  ?>
97
+ <?php $controls->help('https://www.thenewsletterplugin.com/documentation/subscription/antiflood') ?>
98
  </td>
99
  </tr>
100
  <tr>
101
  <th><?php _e('Captcha', 'newsletter') ?> </th>
102
  <td>
103
+ <?php $controls->enabled('captcha'); ?> <?php $controls->field_help('https://www.thenewsletterplugin.com/documentation/subscription/antiflood/#captcha') ?>
104
  </td>
105
  </tr>
106
  <?php /*
124
  <tr>
125
  <th>
126
  <?php _e('IP black list', 'newsletter') ?>
127
+ <?php $controls->field_help('https://www.thenewsletterplugin.com/documentation/subscription/antiflood/#ip') ?>
128
  </th>
129
  <td>
130
  <?php $controls->textarea('ip_blacklist'); ?>
134
  <tr>
135
  <th>
136
  <?php _e('Address black list', 'newsletter') ?>
137
+ <?php $controls->field_help('https://www.thenewsletterplugin.com/documentation/subscription/antiflood/#domains') ?>
138
  </th>
139
  <td>
140
  <?php $controls->textarea('address_blacklist'); ?>