Newsletter - Version 3.2.3

Version Description

  • Added schedule list on Diagnostic panel
  • Removed the enable/disable resubscription option
  • Added a check for the delivery engine shutdown on some particular situations
  • Revisited the WordPress registration integration
  • Revisited the WordPress user import and moved on subscriber massive action panel
  • Added links to new documentation chapter
  • Removed a survived reference to an old table
  • Reactivated the replacement of the {blog_url} tag
  • Fixed the tracking code injection
  • Fixed a default query generation for compatibility with 2.5 version
  • Fixed the tag replacements when using the old forms
Download this release

Release Info

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

Code changes from version 3.0.9 to 3.2.3

Files changed (71) hide show
  1. admin.css +176 -79
  2. api/whatis.txt +0 -1
  3. bounce/bounce.php +0 -60
  4. bounce/index.php +0 -19
  5. config-sample.php +1 -0
  6. do/change.php +7 -8
  7. do/confirm.php +5 -1
  8. do/subscribe.php +1 -0
  9. do/unsubscribe.php +6 -1
  10. emails/edit.php +118 -40
  11. emails/emails.php +12 -14
  12. emails/index.php +78 -65
  13. emails/new.php +29 -50
  14. emails/preview.php +0 -1
  15. emails/themes/default/screenshot.png +0 -0
  16. emails/themes/default/theme-options.php +8 -0
  17. emails/themes/default/theme.php +17 -4
  18. emails/themes/pint/images/bg.jpg +0 -0
  19. emails/themes/pint/screenshot.png +0 -0
  20. emails/themes/pint/theme-options.php +1 -0
  21. emails/themes/pint/theme-text.php +9 -0
  22. emails/themes/pint/theme.php +68 -0
  23. emails/themes/theme-1/screenshot.png +0 -0
  24. emails/themes/theme-3/screenshot.png +0 -0
  25. emails/themes/vimeo-like/screenshot.png +0 -0
  26. feed/feed.php +91 -0
  27. feed/index.php +339 -0
  28. feed/languages/en_US.php +5 -0
  29. feed/preview.php +11 -0
  30. feed/themes/default/theme-options.php +67 -0
  31. feed/themes/default/theme.php +104 -0
  32. header.php +23 -8
  33. images/errors.png +0 -0
  34. images/messages.png +0 -0
  35. images/preamble.png +0 -0
  36. images/theme-screenshot.png +0 -0
  37. includes/controls.php +149 -39
  38. includes/logger.php +7 -2
  39. includes/module.php +285 -49
  40. includes/store.php +10 -2
  41. includes/themes.php +76 -12
  42. diagnostic.php → main/diagnostic.php +136 -101
  43. main/index.php +259 -0
  44. main/languages/en_US.php +3 -4
  45. main.php → main/main.php +64 -72
  46. plugin-menu.inc.php +0 -45
  47. plugin.php +288 -263
  48. readme.txt +113 -4
  49. statistics/index.php +37 -25
  50. statistics/statistics.php +18 -19
  51. statistics/view.php +16 -9
  52. subscription/email.php +1 -2
  53. subscription/forms.php +3 -0
  54. subscription/languages/en_US.php +31 -23
  55. subscription/menu.inc.php +4 -5
  56. subscription/options.php +80 -48
  57. subscription/page.php +1 -0
  58. subscription/profile.php +7 -9
  59. subscription/subscription.php +349 -237
  60. users/edit.php +7 -8
  61. users/export.php +22 -14
  62. users/import.php +11 -0
  63. users/index-old.php +274 -0
  64. users/index.php +72 -126
  65. users/massive.php +75 -9
  66. users/menu.inc.php +8 -7
  67. users/new.php +4 -1
  68. users/stats.php +59 -14
  69. users/users.php +22 -36
  70. welcome.php +0 -146
  71. widget.php +18 -11
admin.css CHANGED
@@ -6,7 +6,7 @@
6
  * http://jquery.org/license
7
  *
8
  * http://docs.jquery.com/UI/Theming/API
9
- */
10
 
11
  /* Layout helpers
12
  ----------------------------------*/
@@ -47,7 +47,7 @@
47
  * http://jquery.org/license
48
  *
49
  * http://docs.jquery.com/UI/Accordion#theming
50
- */
51
  /* IE/Win - Fix animation bug - #4615 */
52
  .ui-accordion { width: 100%; }
53
  .ui-accordion .ui-accordion-header { cursor: pointer; position: relative; margin-top: 1px; zoom: 1; }
@@ -66,7 +66,7 @@
66
  * http://jquery.org/license
67
  *
68
  * http://docs.jquery.com/UI/Autocomplete#theming
69
- */
70
  .ui-autocomplete { position: absolute; cursor: default; }
71
 
72
  /* workarounds */
@@ -80,36 +80,36 @@
80
  * http://jquery.org/license
81
  *
82
  * http://docs.jquery.com/UI/Menu#theming
83
- */
84
  .ui-menu {
85
- list-style:none;
86
- padding: 2px;
87
- margin: 0;
88
- display:block;
89
- float: left;
90
  }
91
  .ui-menu .ui-menu {
92
- margin-top: -3px;
93
  }
94
  .ui-menu .ui-menu-item {
95
- margin:0;
96
- padding: 0;
97
- zoom: 1;
98
- float: left;
99
- clear: left;
100
- width: 100%;
101
  }
102
  .ui-menu .ui-menu-item a {
103
- text-decoration:none;
104
- display:block;
105
- padding:.2em .4em;
106
- line-height:1.5;
107
- zoom:1;
108
  }
109
  .ui-menu .ui-menu-item a.ui-state-hover,
110
  .ui-menu .ui-menu-item a.ui-state-active {
111
- font-weight: normal;
112
- margin: -1px;
113
  }
114
  /*
115
  * jQuery UI Button 1.8.16
@@ -119,7 +119,7 @@
119
  * http://jquery.org/license
120
  *
121
  * http://docs.jquery.com/UI/Button#theming
122
- */
123
  .ui-button { display: inline-block; position: relative; padding: 0; margin-right: .1em; text-decoration: none !important; cursor: pointer; text-align: center; zoom: 1; overflow: visible; } /* the overflow property removes extra width in IE */
124
  .ui-button-icon-only { width: 2.2em; } /* to make room for the icon, a width needs to be set here */
125
  button.ui-button-icon-only { width: 2.4em; } /* button elements seem to need a little more width */
@@ -157,7 +157,7 @@ button.ui-button::-moz-focus-inner { border: 0; padding: 0; } /* reset extra pad
157
  * http://jquery.org/license
158
  *
159
  * http://docs.jquery.com/UI/Datepicker#theming
160
- */
161
  .ui-datepicker { width: 17em; padding: .2em .2em 0; display: none; }
162
  .ui-datepicker .ui-datepicker-header { position:relative; padding:.2em 0; }
163
  .ui-datepicker .ui-datepicker-prev, .ui-datepicker .ui-datepicker-next { position:absolute; top: 2px; width: 1.8em; height: 1.8em; }
@@ -224,7 +224,7 @@ button.ui-button::-moz-focus-inner { border: 0; padding: 0; } /* reset extra pad
224
  * http://jquery.org/license
225
  *
226
  * http://docs.jquery.com/UI/Dialog#theming
227
- */
228
  .ui-dialog { position: absolute; padding: .2em; width: 300px; overflow: hidden; }
229
  .ui-dialog .ui-dialog-titlebar { padding: .4em 1em; position: relative; }
230
  .ui-dialog .ui-dialog-title { float: left; margin: .1em 16px .1em 0; }
@@ -245,7 +245,7 @@ button.ui-button::-moz-focus-inner { border: 0; padding: 0; } /* reset extra pad
245
  * http://jquery.org/license
246
  *
247
  * http://docs.jquery.com/UI/Progressbar#theming
248
- */
249
  .ui-progressbar { height:2em; text-align: left; }
250
  .ui-progressbar .ui-progressbar-value {margin: -1px; height:100%; }/*
251
  * jQuery UI Resizable 1.8.16
@@ -255,7 +255,7 @@ button.ui-button::-moz-focus-inner { border: 0; padding: 0; } /* reset extra pad
255
  * http://jquery.org/license
256
  *
257
  * http://docs.jquery.com/UI/Resizable#theming
258
- */
259
  .ui-resizable { position: relative;}
260
  .ui-resizable-handle { position: absolute;font-size: 0.1px;z-index: 99999; display: block; }
261
  .ui-resizable-disabled .ui-resizable-handle, .ui-resizable-autohide .ui-resizable-handle { display: none; }
@@ -274,7 +274,7 @@ button.ui-button::-moz-focus-inner { border: 0; padding: 0; } /* reset extra pad
274
  * http://jquery.org/license
275
  *
276
  * http://docs.jquery.com/UI/Selectable#theming
277
- */
278
  .ui-selectable-helper { position: absolute; z-index: 100; border:1px dotted black; }
279
  /*
280
  * jQuery UI Slider 1.8.16
@@ -284,7 +284,7 @@ button.ui-button::-moz-focus-inner { border: 0; padding: 0; } /* reset extra pad
284
  * http://jquery.org/license
285
  *
286
  * http://docs.jquery.com/UI/Slider#theming
287
- */
288
  .ui-slider { position: relative; text-align: left; }
289
  .ui-slider .ui-slider-handle { position: absolute; z-index: 2; width: 1.2em; height: 1.2em; cursor: default; }
290
  .ui-slider .ui-slider-range { position: absolute; z-index: 1; font-size: .7em; display: block; border: 0; background-position: 0 0; }
@@ -307,7 +307,7 @@ button.ui-button::-moz-focus-inner { border: 0; padding: 0; } /* reset extra pad
307
  * http://jquery.org/license
308
  *
309
  * http://docs.jquery.com/UI/Tabs#theming
310
- */
311
  .ui-tabs { position: relative; padding: .2em; zoom: 1; } /* position: relative prevents IE scroll bug (element with position: relative inside container with overflow: auto appear as "fixed") */
312
  .ui-tabs .ui-tabs-nav { margin: 0; padding: .2em .2em 0; }
313
  .ui-tabs .ui-tabs-nav li { list-style: none; float: left; position: relative; top: 1px; margin: 0 .2em 1px 0; border-bottom: 0 !important; padding: 0; white-space: nowrap; }
@@ -327,7 +327,7 @@ button.ui-button::-moz-focus-inner { border: 0; padding: 0; } /* reset extra pad
327
  * http://docs.jquery.com/UI/Theming/API
328
  *
329
  * To view and modify this theme, visit http://jqueryui.com/themeroller/
330
- */
331
 
332
 
333
  /* Component containers
@@ -566,14 +566,34 @@ button.ui-button::-moz-focus-inner { border: 0; padding: 0; } /* reset extra pad
566
  .ui-widget-shadow { margin: -8px/*{offsetTopShadow}*/ 0 0 -8px/*{offsetLeftShadow}*/; padding: 8px/*{thicknessShadow}*/; background: #aaaaaa/*{bgColorShadow}*/ url(images/ui-bg_flat_0_aaaaaa_40x100.png)/*{bgImgUrlShadow}*/ 50%/*{bgShadowXPos}*/ 50%/*{bgShadowYPos}*/ repeat-x/*{bgShadowRepeat}*/; opacity: .3;filter:Alpha(Opacity=30)/*{opacityShadow}*/; -moz-border-radius: 8px/*{cornerRadiusShadow}*/; -khtml-border-radius: 8px/*{cornerRadiusShadow}*/; -webkit-border-radius: 8px/*{cornerRadiusShadow}*/; border-radius: 8px/*{cornerRadiusShadow}*/; }
567
 
568
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
569
  /* Admin header */
570
  #newsletter-header {
571
- text-align: left;
572
- background-color: #f4f4f4;
573
- padding: 5px;
574
- padding-left: 15px;
575
- border-radius: 3px;
576
- text-transform: uppercase;
 
577
  }
578
 
579
  #newsletter-header a {
@@ -588,12 +608,32 @@ button.ui-button::-moz-focus-inner { border: 0; padding: 0; } /* reset extra pad
588
  margin-bottom: 15px;
589
  }
590
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
591
  .wrap h2 {
592
  color: #21759B;
 
 
 
 
593
  }
594
 
595
  .wrap h3 {
596
-
597
  }
598
 
599
  .wrap h4 {
@@ -603,15 +643,20 @@ button.ui-button::-moz-focus-inner { border: 0; padding: 0; } /* reset extra pad
603
  font-style: italic;
604
  }
605
 
606
- .wrap li {
 
 
 
 
 
 
 
607
  margin-left: 20px;
608
  list-style-type: disc;
609
  }
610
 
611
  .form-table {
612
- xborder: 1px solid #ccc;
613
  background-color: #fff;
614
- border: 3px solid #ddd;
615
  }
616
 
617
  .form-table th {
@@ -672,14 +717,12 @@ table.clicks {
672
  }
673
 
674
  .hints {
675
- border: 1px solid #ccc;
676
- background-color: #f7f7f7;
677
  padding: 5px;
678
  margin-top: 10px;
679
  border-radius: 4px 4px;
680
- -moz-border-radius: 4px;
681
- -webkit-border-radius: 4px;
682
- font-size: 11px;
683
  color: #666;
684
  }
685
 
@@ -699,54 +742,61 @@ table.clicks {
699
  }
700
 
701
  .nl-checkbox-group {
702
- float: left;
703
- margin-right: 5px;
704
- border: 1px solid #ccc;
705
- background-color: #f4f4f4;
706
- width: 200px;
707
- margin-bottom: 5px;
708
- padding: 5px;
709
- white-space: nowrap;
710
- overflow: hidden;
711
  }
712
 
713
- .newsletter-preferences-item {
714
- float: left;
715
- margin-right: 5px;
716
- border: 1px solid #ccc;
717
- background-color: #f4f4f4;
718
- width: 200px;
719
- margin-bottom: 5px;
720
- padding: 5px;
721
- white-space: nowrap;
722
- overflow: hidden;
723
  }
724
 
725
- .newsletter-preferences-item label {
726
  display: inline;
727
  }
728
 
729
- .form-table td .nl-checkbox-group label {
730
- display: inline;
 
 
 
 
 
 
 
 
731
  }
732
 
733
- #tabs .form-table {
734
- border: 0;
735
- font-size: 12px;
736
  }
737
 
738
- #tabs .form-table th {
739
- font-size: 12px;
740
  }
741
 
742
  .ui-tabs .ui-tabs-nav li a {
743
- font-size: 12px;
744
  }
745
 
746
 
747
 
748
  .widefat td, .widefat th {
749
- vertical-align: middle;
750
  }
751
 
752
  /*
@@ -779,7 +829,15 @@ table.clicks {
779
  border-width: 1px;
780
  padding: .6em;
781
  margin-bottom: .6em;
 
 
 
 
 
782
 
 
 
 
783
  }
784
 
785
  .newsletter-error {
@@ -789,7 +847,11 @@ table.clicks {
789
  border-style: solid;
790
  border-width: 1px;
791
  padding: .6em;
 
792
  margin-bottom: .6em;
 
 
 
793
  }
794
 
795
  #newsletter-warnings {
@@ -802,17 +864,52 @@ table.clicks {
802
  margin-bottom: .6em;
803
  }
804
 
 
 
 
 
 
 
 
 
 
805
  /* Text under the panel title to explain the panel purpose. */
806
  .preamble {
807
  margin-bottom: 15px;
 
 
 
 
 
 
 
 
 
808
  }
809
 
810
  .preamble p {
811
- font-size: 12px;
 
 
 
 
 
 
 
 
 
 
 
 
812
  }
813
 
814
  .tab-preamble p {
815
- font-size: .9em;
816
- color: #777;
817
  }
818
 
 
 
 
 
 
 
6
  * http://jquery.org/license
7
  *
8
  * http://docs.jquery.com/UI/Theming/API
9
+ */
10
 
11
  /* Layout helpers
12
  ----------------------------------*/
47
  * http://jquery.org/license
48
  *
49
  * http://docs.jquery.com/UI/Accordion#theming
50
+ */
51
  /* IE/Win - Fix animation bug - #4615 */
52
  .ui-accordion { width: 100%; }
53
  .ui-accordion .ui-accordion-header { cursor: pointer; position: relative; margin-top: 1px; zoom: 1; }
66
  * http://jquery.org/license
67
  *
68
  * http://docs.jquery.com/UI/Autocomplete#theming
69
+ */
70
  .ui-autocomplete { position: absolute; cursor: default; }
71
 
72
  /* workarounds */
80
  * http://jquery.org/license
81
  *
82
  * http://docs.jquery.com/UI/Menu#theming
83
+ */
84
  .ui-menu {
85
+ list-style:none;
86
+ padding: 2px;
87
+ margin: 0;
88
+ display:block;
89
+ float: left;
90
  }
91
  .ui-menu .ui-menu {
92
+ margin-top: -3px;
93
  }
94
  .ui-menu .ui-menu-item {
95
+ margin:0;
96
+ padding: 0;
97
+ zoom: 1;
98
+ float: left;
99
+ clear: left;
100
+ width: 100%;
101
  }
102
  .ui-menu .ui-menu-item a {
103
+ text-decoration:none;
104
+ display:block;
105
+ padding:.2em .4em;
106
+ line-height:1.5;
107
+ zoom:1;
108
  }
109
  .ui-menu .ui-menu-item a.ui-state-hover,
110
  .ui-menu .ui-menu-item a.ui-state-active {
111
+ font-weight: normal;
112
+ margin: -1px;
113
  }
114
  /*
115
  * jQuery UI Button 1.8.16
119
  * http://jquery.org/license
120
  *
121
  * http://docs.jquery.com/UI/Button#theming
122
+ */
123
  .ui-button { display: inline-block; position: relative; padding: 0; margin-right: .1em; text-decoration: none !important; cursor: pointer; text-align: center; zoom: 1; overflow: visible; } /* the overflow property removes extra width in IE */
124
  .ui-button-icon-only { width: 2.2em; } /* to make room for the icon, a width needs to be set here */
125
  button.ui-button-icon-only { width: 2.4em; } /* button elements seem to need a little more width */
157
  * http://jquery.org/license
158
  *
159
  * http://docs.jquery.com/UI/Datepicker#theming
160
+ */
161
  .ui-datepicker { width: 17em; padding: .2em .2em 0; display: none; }
162
  .ui-datepicker .ui-datepicker-header { position:relative; padding:.2em 0; }
163
  .ui-datepicker .ui-datepicker-prev, .ui-datepicker .ui-datepicker-next { position:absolute; top: 2px; width: 1.8em; height: 1.8em; }
224
  * http://jquery.org/license
225
  *
226
  * http://docs.jquery.com/UI/Dialog#theming
227
+ */
228
  .ui-dialog { position: absolute; padding: .2em; width: 300px; overflow: hidden; }
229
  .ui-dialog .ui-dialog-titlebar { padding: .4em 1em; position: relative; }
230
  .ui-dialog .ui-dialog-title { float: left; margin: .1em 16px .1em 0; }
245
  * http://jquery.org/license
246
  *
247
  * http://docs.jquery.com/UI/Progressbar#theming
248
+ */
249
  .ui-progressbar { height:2em; text-align: left; }
250
  .ui-progressbar .ui-progressbar-value {margin: -1px; height:100%; }/*
251
  * jQuery UI Resizable 1.8.16
255
  * http://jquery.org/license
256
  *
257
  * http://docs.jquery.com/UI/Resizable#theming
258
+ */
259
  .ui-resizable { position: relative;}
260
  .ui-resizable-handle { position: absolute;font-size: 0.1px;z-index: 99999; display: block; }
261
  .ui-resizable-disabled .ui-resizable-handle, .ui-resizable-autohide .ui-resizable-handle { display: none; }
274
  * http://jquery.org/license
275
  *
276
  * http://docs.jquery.com/UI/Selectable#theming
277
+ */
278
  .ui-selectable-helper { position: absolute; z-index: 100; border:1px dotted black; }
279
  /*
280
  * jQuery UI Slider 1.8.16
284
  * http://jquery.org/license
285
  *
286
  * http://docs.jquery.com/UI/Slider#theming
287
+ */
288
  .ui-slider { position: relative; text-align: left; }
289
  .ui-slider .ui-slider-handle { position: absolute; z-index: 2; width: 1.2em; height: 1.2em; cursor: default; }
290
  .ui-slider .ui-slider-range { position: absolute; z-index: 1; font-size: .7em; display: block; border: 0; background-position: 0 0; }
307
  * http://jquery.org/license
308
  *
309
  * http://docs.jquery.com/UI/Tabs#theming
310
+ */
311
  .ui-tabs { position: relative; padding: .2em; zoom: 1; } /* position: relative prevents IE scroll bug (element with position: relative inside container with overflow: auto appear as "fixed") */
312
  .ui-tabs .ui-tabs-nav { margin: 0; padding: .2em .2em 0; }
313
  .ui-tabs .ui-tabs-nav li { list-style: none; float: left; position: relative; top: 1px; margin: 0 .2em 1px 0; border-bottom: 0 !important; padding: 0; white-space: nowrap; }
327
  * http://docs.jquery.com/UI/Theming/API
328
  *
329
  * To view and modify this theme, visit http://jqueryui.com/themeroller/
330
+ */
331
 
332
 
333
  /* Component containers
566
  .ui-widget-shadow { margin: -8px/*{offsetTopShadow}*/ 0 0 -8px/*{offsetLeftShadow}*/; padding: 8px/*{thicknessShadow}*/; background: #aaaaaa/*{bgColorShadow}*/ url(images/ui-bg_flat_0_aaaaaa_40x100.png)/*{bgImgUrlShadow}*/ 50%/*{bgShadowXPos}*/ 50%/*{bgShadowYPos}*/ repeat-x/*{bgShadowRepeat}*/; opacity: .3;filter:Alpha(Opacity=30)/*{opacityShadow}*/; -moz-border-radius: 8px/*{cornerRadiusShadow}*/; -khtml-border-radius: 8px/*{cornerRadiusShadow}*/; -webkit-border-radius: 8px/*{cornerRadiusShadow}*/; border-radius: 8px/*{cornerRadiusShadow}*/; }
567
 
568
 
569
+
570
+
571
+
572
+
573
+
574
+
575
+ .ui-tabs {
576
+ border-color: #ddd;
577
+ }
578
+
579
+ .ui-tabs-nav {
580
+ background-image: none;
581
+ background-color: #fff;
582
+ border: 0;
583
+ border-bottom: 1px solid #ddd;
584
+ border-radius: 0;
585
+ }
586
+
587
+
588
  /* Admin header */
589
  #newsletter-header {
590
+ text-align: left;
591
+ background-color: #f4f4f4;
592
+ padding: 5px;
593
+ padding-left: 15px;
594
+ border-radius: 3px;
595
+ text-transform: uppercase;
596
+ font-size: 12px;
597
  }
598
 
599
  #newsletter-header a {
608
  margin-bottom: 15px;
609
  }
610
 
611
+ .wrap {
612
+ font-size: 14px;
613
+ line-height: 150%;
614
+ font-family: sans-serif;
615
+
616
+ }
617
+
618
+ .wrap td, .wrap th {
619
+ font-size: 14px;
620
+ font-family: sans-serif;
621
+ }
622
+
623
+ .main-index a {
624
+ font-weight: bold;
625
+ }
626
+
627
  .wrap h2 {
628
  color: #21759B;
629
+ font-size: 20px;
630
+ margin: 10px 0;
631
+ padding: 0;
632
+ font-family: Georgia;
633
  }
634
 
635
  .wrap h3 {
636
+ font-family: Georgia;
637
  }
638
 
639
  .wrap h4 {
643
  font-style: italic;
644
  }
645
 
646
+ .wrap h5 {
647
+ color: #666;
648
+ font-size: 14px;
649
+ padding: 0;
650
+ margin: 10px 0;
651
+ }
652
+
653
+ .wrap ul li {
654
  margin-left: 20px;
655
  list-style-type: disc;
656
  }
657
 
658
  .form-table {
 
659
  background-color: #fff;
 
660
  }
661
 
662
  .form-table th {
717
  }
718
 
719
  .hints {
720
+ border: 1px solid #e4e4ee;
721
+ background-color: #f4f4ff;
722
  padding: 5px;
723
  margin-top: 10px;
724
  border-radius: 4px 4px;
725
+ font-size: 12px;
 
 
726
  color: #666;
727
  }
728
 
742
  }
743
 
744
  .nl-checkbox-group {
745
+ float: left;
746
+ margin-right: 5px;
747
+ border: 1px solid #ccc;
748
+ background-color: #f4f4f4;
749
+ width: 200px;
750
+ margin-bottom: 5px;
751
+ padding: 5px;
752
+ white-space: nowrap;
753
+ overflow: hidden;
754
  }
755
 
756
+ .newsletter-checkboxes-item {
757
+ float: left;
758
+ margin-right: 5px;
759
+ border: 1px solid #ccc;
760
+ background-color: #f4f4f4;
761
+ width: 200px;
762
+ margin-bottom: 5px;
763
+ padding: 5px;
764
+ white-space: nowrap;
765
+ overflow: hidden;
766
  }
767
 
768
+ .newsletter-checkboxes-item label {
769
  display: inline;
770
  }
771
 
772
+ .newsletter-preferences-item {
773
+ float: left;
774
+ margin-right: 5px;
775
+ border: 1px solid #ccc;
776
+ background-color: #f4f4f4;
777
+ width: 200px;
778
+ margin-bottom: 5px;
779
+ padding: 5px;
780
+ white-space: nowrap;
781
+ overflow: hidden;
782
  }
783
 
784
+ .newsletter-preferences-item label {
785
+ display: inline;
 
786
  }
787
 
788
+ .form-table td .nl-checkbox-group label {
789
+ display: inline;
790
  }
791
 
792
  .ui-tabs .ui-tabs-nav li a {
793
+ font-size: 12px;
794
  }
795
 
796
 
797
 
798
  .widefat td, .widefat th {
799
+ vertical-align: middle;
800
  }
801
 
802
  /*
829
  border-width: 1px;
830
  padding: .6em;
831
  margin-bottom: .6em;
832
+ background-image: url("images/messages.png");
833
+ padding-left: 30px;
834
+ background-repeat: no-repeat;
835
+ background-position: left center;
836
+ }
837
 
838
+ .newsletter-error-span {
839
+ color: #f00;
840
+ font-weight: bold;
841
  }
842
 
843
  .newsletter-error {
847
  border-style: solid;
848
  border-width: 1px;
849
  padding: .6em;
850
+ padding-left: 30px;
851
  margin-bottom: .6em;
852
+ background-image: url("images/messages.png");
853
+ background-repeat: no-repeat;
854
+ background-position: left center;
855
  }
856
 
857
  #newsletter-warnings {
864
  margin-bottom: .6em;
865
  }
866
 
867
+ .newsletter-buttons {
868
+ margin-top: 1em;
869
+ padding: 1em;
870
+ }
871
+
872
+ .newsletter-buttons-bottom {
873
+ xborder-top: 1px solid #ddd;
874
+ }
875
+
876
  /* Text under the panel title to explain the panel purpose. */
877
  .preamble {
878
  margin-bottom: 15px;
879
+ border-radius: 3px;
880
+ background-color: #f4f4f4;
881
+ padding: 10px;
882
+ background-image: url("images/preamble.png");
883
+ background-repeat: no-repeat;
884
+ background-position: left;
885
+ padding-left: 65px;
886
+ font-size: 13px;
887
+ font-family: sans-serif;
888
  }
889
 
890
  .preamble p {
891
+ margin: 0;
892
+ }
893
+
894
+ .tab-preamble {
895
+ margin-bottom: 15px;
896
+ border-radius: 3px;
897
+ background-color: #f4f4f4;
898
+ padding: 10px;
899
+ background-repeat: no-repeat;
900
+ background-position: left;
901
+ font-size: 13px;
902
+ line-height: normal;
903
+ font-family: sans-serif;
904
  }
905
 
906
  .tab-preamble p {
907
+ margin: 0;
 
908
  }
909
 
910
+ .newsletter-paginator {
911
+ margin-top: 10px;
912
+ margin-bottom: 5px;
913
+ }
914
+
915
+
api/whatis.txt DELETED
@@ -1 +0,0 @@
1
- This folder will contain the actual api functions as soon as they will be tranformed in a module.
 
bounce/bounce.php DELETED
@@ -1,60 +0,0 @@
1
- <?php
2
-
3
- class NewsletterBounce extends NewsletterModule {
4
-
5
- const VERSION = '1.0.0';
6
-
7
- static $instance;
8
-
9
- /**
10
- * @return NewsletterBounce
11
- */
12
- static function instance() {
13
- if (self::$instance == null) {
14
- self::$instance = new NewsletterBounce();
15
- }
16
- return self::$instance;
17
- }
18
-
19
- function __construct() {
20
- parent::__construct('bounce', self::VERSION);
21
- }
22
-
23
- function upgrade() {
24
- global $wpdb, $charset_collate;
25
- parent::upgrade();
26
- }
27
-
28
- /**
29
- * Run based on scheduled daily hour and generate, if needed, an email that will be then sent by
30
- * Newsletter delivery engine.
31
- *
32
- * @global Newsletter $newsetter
33
- */
34
- function run($force = false) {
35
- global $wpdb, $newsletter, $post;
36
-
37
- if (!$force && !$this->check_transient('run', 3600)) return;
38
-
39
- $this->save_last_run(time());
40
- }
41
-
42
- }
43
-
44
- add_action('newsletter_admin_menu', 'newsletter_bounce_admin_menu');
45
-
46
- /**
47
- * Add menu pages for this module.
48
- * @global Newsletter $newsletter
49
- */
50
- function newsletter_bounce_admin_menu() {
51
- global $newsletter;
52
- $newsletter->add_menu_page('bounce', 'index', 'Bounce');
53
- }
54
-
55
- add_action('newsletter_bounce', 'newsletter_bounce_run');
56
-
57
- function newsletter_bounce_run() {
58
- NewsletterBounce::instance()->run();
59
- }
60
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
bounce/index.php DELETED
@@ -1,19 +0,0 @@
1
- <?php
2
- require_once NEWSLETTER_INCLUDES_DIR . '/controls.php';
3
- $module = NewsletterBounce::instance();
4
- $controls = new NewsletterControls();
5
-
6
- if ($controls->is_action('save')) {
7
- $module->save_options($controls->data);
8
- $controls->messages = 'Saved.';
9
- }
10
- ?>
11
-
12
- <div class="wrap">
13
- <h2>Bounce (not working)</h2>
14
- <p>
15
- In this panel you can configure the bounce detection system. Remember the mailbox you select as trap for bounce messages
16
- must accept all address in the form [prefix]+[something]@domain.tld.
17
- </p>
18
-
19
- </div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
config-sample.php CHANGED
@@ -1,4 +1,5 @@
1
  <?php
 
2
  /*
3
  * Move this file inside the /wp_content/newsletter folder to activate it and rename it
4
  * "config.php".
1
  <?php
2
+
3
  /*
4
  * Move this file inside the /wp_content/newsletter folder to activate it and rename it
5
  * "config.php".
do/change.php CHANGED
@@ -15,26 +15,25 @@ switch ($field) {
15
  break;
16
  // Should be managed by Feed by Mail
17
  case 'feed':
18
- //if (isset($value) && ($value === '0' || $value === '1')) {
19
  NewsletterUsers::instance()->set_user_field($user->id, 'feed', $value);
20
- //} else die('Invalid feed value');
21
  break;
22
  }
23
 
24
  if (strpos($field, 'preference_') === 0) {
25
  $idx = (int) substr($field, 11);
26
- //echo $idx;
27
  $options_profile = get_option('newsletter_profile');
28
 
29
  if ($options_profile['list_' . $idx . '_status'] == 0) {
30
  die('Not allowed field.');
31
  }
32
- //die($value);
33
- //if (isset($value) && ($value === '0' || $value === '1')) {
34
  NewsletterUsers::instance()->set_user_field($user->id, 'list_' . $idx, $value);
35
- //} else {
36
- // die('Invalid preference value');
37
- //}
38
  }
39
 
40
  if (isset($url)) {
15
  break;
16
  // Should be managed by Feed by Mail
17
  case 'feed':
18
+ if (isset($value) && ($value === '0' || $value === '1')) {
19
  NewsletterUsers::instance()->set_user_field($user->id, 'feed', $value);
20
+ } else die('Invalid feed value');
21
  break;
22
  }
23
 
24
  if (strpos($field, 'preference_') === 0) {
25
  $idx = (int) substr($field, 11);
 
26
  $options_profile = get_option('newsletter_profile');
27
 
28
  if ($options_profile['list_' . $idx . '_status'] == 0) {
29
  die('Not allowed field.');
30
  }
31
+
32
+ if (isset($value) && ($value === '0' || $value === '1')) {
33
  NewsletterUsers::instance()->set_user_field($user->id, 'list_' . $idx, $value);
34
+ } else {
35
+ die('Invalid preference value');
36
+ }
37
  }
38
 
39
  if (isset($url)) {
do/confirm.php CHANGED
@@ -9,4 +9,8 @@ unset($_GET['na']);
9
  include '../../../../wp-load.php';
10
 
11
  $user = NewsletterSubscription::instance()->confirm();
12
- NewsletterSubscription::instance()->show_message('confirmed', $user);
 
 
 
 
9
  include '../../../../wp-load.php';
10
 
11
  $user = NewsletterSubscription::instance()->confirm();
12
+ if ($user->status == 'E') {
13
+ NewsletterSubscription::instance()->show_message('error', $user->id);
14
+ } else {
15
+ NewsletterSubscription::instance()->show_message('confirmed', $user);
16
+ }
do/subscribe.php CHANGED
@@ -7,5 +7,6 @@ unset($_GET['na']);
7
  require_once '../../../../wp-load.php';
8
 
9
  $user = NewsletterSubscription::instance()->subscribe();
 
10
  if ($user->status == 'C') NewsletterSubscription::instance()->show_message('confirmed', $user->id);
11
  if ($user->status == 'S') NewsletterSubscription::instance()->show_message('confirmation', $user->id);
7
  require_once '../../../../wp-load.php';
8
 
9
  $user = NewsletterSubscription::instance()->subscribe();
10
+ if ($user->status == 'E') NewsletterSubscription::instance()->show_message('error', $user->id);
11
  if ($user->status == 'C') NewsletterSubscription::instance()->show_message('confirmed', $user->id);
12
  if ($user->status == 'S') NewsletterSubscription::instance()->show_message('confirmation', $user->id);
do/unsubscribe.php CHANGED
@@ -1,4 +1,5 @@
1
  <?php
 
2
  // Patch to avoid "na" parameter to disturb the call
3
  unset($_REQUEST['na']);
4
  unset($_POST['na']);
@@ -7,4 +8,8 @@ unset($_GET['na']);
7
  require_once '../../../../wp-load.php';
8
 
9
  $user = NewsletterSubscription::instance()->unsubscribe();
10
- NewsletterSubscription::instance()->show_message('unsubscribed', $user);
 
 
 
 
1
  <?php
2
+
3
  // Patch to avoid "na" parameter to disturb the call
4
  unset($_REQUEST['na']);
5
  unset($_POST['na']);
8
  require_once '../../../../wp-load.php';
9
 
10
  $user = NewsletterSubscription::instance()->unsubscribe();
11
+ if ($user->status == 'E') {
12
+ NewsletterSubscription::instance()->show_message('error', $user->id);
13
+ } else {
14
+ NewsletterSubscription::instance()->show_message('unsubscribed', $user);
15
+ }
emails/edit.php CHANGED
@@ -14,6 +14,10 @@ if (!$controls->is_action()) {
14
  $controls->data = $email;
15
  if (!empty($email['preferences'])) $controls->data['preferences'] = explode(',', $email['preferences']);
16
  if (!empty($email['sex'])) $controls->data['sex'] = explode(',', $email['sex']);
 
 
 
 
17
  }
18
 
19
  if ($controls->is_action('test') || $controls->is_action('save') || $controls->is_action('send') || $controls->is_action('editor')) {
@@ -34,6 +38,16 @@ if ($controls->is_action('test') || $controls->is_action('save') || $controls->i
34
  $email['subject'] = $controls->data['subject'];
35
  $email['track'] = $controls->data['track'];
36
 
 
 
 
 
 
 
 
 
 
 
37
  if (is_array($controls->data['preferences'])) $email['preferences'] = implode(',', $controls->data['preferences']);
38
  else $email['preferences'] = '';
39
 
@@ -42,16 +56,36 @@ if ($controls->is_action('test') || $controls->is_action('save') || $controls->i
42
 
43
  // Before send, we build the query to extract subscriber, so the delivery engine does not
44
  // have to worry about the email parameters
45
- $query = "select * from " . $wpdb->prefix . "newsletter where status='C'";
 
 
 
 
 
 
 
 
46
 
47
  $preferences = $controls->data['preferences'];
48
  if (is_array($preferences)) {
49
- $query .= " and (";
50
- foreach ($preferences as $x) {
51
- $query .= "list_" . $x . "=1 or ";
 
 
 
 
 
 
 
 
 
 
 
 
 
 
52
  }
53
- $query = substr($query, 0, -4);
54
- $query .= ")";
55
  }
56
 
57
  $sex = $controls->data['sex'];
@@ -73,21 +107,26 @@ if ($controls->is_action('test') || $controls->is_action('save') || $controls->i
73
  $email['sent'] = 0;
74
  $email['last_id'] = 0;
75
  $email['send_on'] = $controls->data['send_on'];
76
-
77
  if ($controls->is_action('editor')) {
78
  $email['editor'] = $email['editor'] == 0?1:0;
79
  }
80
 
81
- Newsletter::instance()->save_email($email);
82
-
 
 
 
83
  $controls->data['message'] = $email['message'];
 
 
84
  }
85
 
86
  if ($controls->is_action('send')) {
87
 
88
  $wpdb->update($wpdb->prefix . 'newsletter_emails', array('status' => 'sending'), array('id' => $email_id));
89
  $email['status'] = 'sending';
90
- $controls->messages = "Email added to the queue.";
91
  }
92
 
93
  if ($controls->is_action('pause')) {
@@ -112,10 +151,10 @@ if ($controls->is_action('abort')) {
112
  if ($controls->is_action('test')) {
113
  $users = NewsletterUsers::instance()->get_test_users();
114
  if (count($users) == 0) {
115
- $controls->errors = 'There is no test subscribers to who send this email. Mark some subscribers as test subscriber from the Subscriber panel.';
116
  } else {
117
  Newsletter::instance()->send(Newsletter::instance()->get_email($email_id), $users);
118
- $controls->messages = 'Test emails sent to ' . count($users) . ' test users.';
119
  }
120
  }
121
 
@@ -130,6 +169,7 @@ if ($email['editor'] == 0) {
130
  $controls->data['message'] = substr($controls->data['message'], $x + 1, $y - $x - 1);
131
  }
132
  }
 
133
  ?>
134
 
135
  <script type="text/javascript" src="<?php echo NEWSLETTER_URL; ?>/tiny_mce/tiny_mce.js"></script>
@@ -171,7 +211,14 @@ if ($email['editor'] == 0) {
171
  <?php $help_url = 'http://www.satollo.net/plugins/newsletter/newsletters-module'; ?>
172
  <?php include NEWSLETTER_DIR . '/header.php'; ?>
173
 
174
- <h2>Newsletters Module</h2>
 
 
 
 
 
 
 
175
 
176
  <?php $controls->show(); ?>
177
 
@@ -195,6 +242,7 @@ if ($email['editor'] == 0) {
195
  <li><a href="#tabs-2">Message (textual)</a></li>
196
  <li><a href="#tabs-3">Who will receive it</a></li>
197
  <li><a href="#tabs-4">Status</a></li>
 
198
  </ul>
199
 
200
 
@@ -246,27 +294,7 @@ if ($email['editor'] == 0) {
246
  <th>Approximative number of receivers</th>
247
  <td>
248
  <?php
249
- // Compute the receivers ids that should receive that email
250
- $query = "select count(*) from " . NEWSLETTER_USERS_TABLE . " where status='C'";
251
-
252
- if (is_array($controls->data['preferences'])) {
253
- $query .= " and (";
254
- foreach ($controls->data['preferences'] as $x) {
255
- $query .= "list_" . $x . "=1 or ";
256
- }
257
- $query = substr($query, 0, -4);
258
- $query .= ")";
259
- }
260
-
261
- if (is_array($controls->data['sex'])) {
262
- $query .= " and sex in (";
263
- foreach ($controls->data['sex'] as $x) {
264
- $query .= "'" . $x . "', ";
265
- }
266
- $query = substr($query, 0, -2);
267
- $query .= ")";
268
- }
269
- echo $wpdb->get_var($query);
270
  ?>
271
  <div class="hints">
272
  If you change selections below, save the email to update this values.
@@ -276,10 +304,7 @@ if ($email['editor'] == 0) {
276
  <tr valign="top">
277
  <th>Sex</th>
278
  <td>
279
- <div class="nl-checkbox-group"><?php $controls->checkbox_group('sex', 'f', 'Women'); ?></div>
280
- <div class="nl-checkbox-group"><?php $controls->checkbox_group('sex', 'm', 'Men'); ?></div>
281
- <div class="nl-checkbox-group"><?php $controls->checkbox_group('sex', 'n', 'Not specified'); ?></div>
282
- <div style="clear: both"></div>
283
  <div class="hints">
284
  Leaving all sex options unselected means to NOT filter by sex.
285
  </div>
@@ -288,10 +313,15 @@ if ($email['editor'] == 0) {
288
  <tr valign="top">
289
  <th>Preferences</th>
290
  <td>
 
 
 
 
291
  <?php $controls->preferences_group('preferences', true); ?>
292
- <div style="clear: both"></div>
293
  <div class="hints">
294
- Leaving all preferences unselected means to NOT filter by preference.
 
 
295
  </div>
296
  </td>
297
  </tr>
@@ -305,6 +335,29 @@ if ($email['editor'] == 0) {
305
  </div>
306
  </td>
307
  </tr>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
308
  </table>
309
  </div>
310
 
@@ -325,9 +378,34 @@ if ($email['editor'] == 0) {
325
  <th>Email sent</th>
326
  <td><?php echo $email['sent']; ?> of <?php echo $email['total']; ?></td>
327
  </tr>
 
 
 
 
328
  </table>
329
  </div>
330
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
331
 
332
  </div>
333
 
14
  $controls->data = $email;
15
  if (!empty($email['preferences'])) $controls->data['preferences'] = explode(',', $email['preferences']);
16
  if (!empty($email['sex'])) $controls->data['sex'] = explode(',', $email['sex']);
17
+ $email_options = unserialize($email['options']);
18
+ if (is_array($email_options)) {
19
+ $controls->data = array_merge($controls->data, $email_options);
20
+ }
21
  }
22
 
23
  if ($controls->is_action('test') || $controls->is_action('save') || $controls->is_action('send') || $controls->is_action('editor')) {
38
  $email['subject'] = $controls->data['subject'];
39
  $email['track'] = $controls->data['track'];
40
 
41
+ // Builds the extended options
42
+ $email['options'] = array();
43
+ $email['options']['preferences_status'] = $controls->data['preferences_status'];
44
+ $email['options']['preferences'] = $controls->data['preferences'];
45
+ $email['options']['sex'] = $controls->data['sex'];
46
+ $email['options']['status'] = $controls->data['status'];
47
+ $email['options']['wp_users'] = $controls->data['wp_users'];
48
+
49
+ $email['options'] = serialize($email['options']);
50
+
51
  if (is_array($controls->data['preferences'])) $email['preferences'] = implode(',', $controls->data['preferences']);
52
  else $email['preferences'] = '';
53
 
56
 
57
  // Before send, we build the query to extract subscriber, so the delivery engine does not
58
  // have to worry about the email parameters
59
+ if ($controls->data['status'] == 'S') {
60
+ $query = "select * from " . $wpdb->prefix . "newsletter where status='S'";
61
+ } else {
62
+ $query = "select * from " . $wpdb->prefix . "newsletter where status='C'";
63
+ }
64
+
65
+ if ($controls->data['wp_users'] == '1') {
66
+ $query .= " and wp_user_id<>0";
67
+ }
68
 
69
  $preferences = $controls->data['preferences'];
70
  if (is_array($preferences)) {
71
+
72
+ // Not set one of the preferences specified
73
+ if ($controls->data['preferences_status'] == 1) {
74
+ $query .= " and (";
75
+ foreach ($preferences as $x) {
76
+ $query .= "list_" . $x . "=0 or ";
77
+ }
78
+ $query = substr($query, 0, -4);
79
+ $query .= ")";
80
+ }
81
+ else {
82
+ $query .= " and (";
83
+ foreach ($preferences as $x) {
84
+ $query .= "list_" . $x . "=1 or ";
85
+ }
86
+ $query = substr($query, 0, -4);
87
+ $query .= ")";
88
  }
 
 
89
  }
90
 
91
  $sex = $controls->data['sex'];
107
  $email['sent'] = 0;
108
  $email['last_id'] = 0;
109
  $email['send_on'] = $controls->data['send_on'];
110
+
111
  if ($controls->is_action('editor')) {
112
  $email['editor'] = $email['editor'] == 0?1:0;
113
  }
114
 
115
+ $res = Newsletter::instance()->save_email($email);
116
+ if ($res === false) {
117
+ $controls->errors = 'Unable to save. Try to deactivate and reactivate the plugin may be the database is out of sync.';
118
+ }
119
+
120
  $controls->data['message'] = $email['message'];
121
+
122
+ $controls->messages .= 'Saved.<br>';
123
  }
124
 
125
  if ($controls->is_action('send')) {
126
 
127
  $wpdb->update($wpdb->prefix . 'newsletter_emails', array('status' => 'sending'), array('id' => $email_id));
128
  $email['status'] = 'sending';
129
+ $controls->messages .= "Email added to the queue.";
130
  }
131
 
132
  if ($controls->is_action('pause')) {
151
  if ($controls->is_action('test')) {
152
  $users = NewsletterUsers::instance()->get_test_users();
153
  if (count($users) == 0) {
154
+ $controls->errors = 'There are no test subscribers. Read more about test subscribers <a href="http://www.satollo.net/plugins/newsletter/subscribers-module#test" target="_blank">here</a>.';
155
  } else {
156
  Newsletter::instance()->send(Newsletter::instance()->get_email($email_id), $users);
157
+ $controls->messages .= 'Test emails sent to ' . count($users) . ' test subscribers. Read more about test subscribers <a href="http://www.satollo.net/plugins/newsletter/subscribers-module#test" target="_blank">here</a>.';
158
  }
159
  }
160
 
169
  $controls->data['message'] = substr($controls->data['message'], $x + 1, $y - $x - 1);
170
  }
171
  }
172
+
173
  ?>
174
 
175
  <script type="text/javascript" src="<?php echo NEWSLETTER_URL; ?>/tiny_mce/tiny_mce.js"></script>
211
  <?php $help_url = 'http://www.satollo.net/plugins/newsletter/newsletters-module'; ?>
212
  <?php include NEWSLETTER_DIR . '/header.php'; ?>
213
 
214
+ <h5>Newsletters Module</h5>
215
+
216
+ <h2>Edit Newsletter</h2>
217
+ <?php
218
+ if ($controls->data['status'] == 'S') {
219
+ echo '<div class="newsletter-message">Warning! This email is configured to be sent to NOT CONFIRMED subscribers.</div>';
220
+ }
221
+ ?>
222
 
223
  <?php $controls->show(); ?>
224
 
242
  <li><a href="#tabs-2">Message (textual)</a></li>
243
  <li><a href="#tabs-3">Who will receive it</a></li>
244
  <li><a href="#tabs-4">Status</a></li>
245
+ <!--<li><a href="#tabs-5">Documentation</a></li>-->
246
  </ul>
247
 
248
 
294
  <th>Approximative number of receivers</th>
295
  <td>
296
  <?php
297
+ echo $wpdb->get_var(str_replace('*', 'count(*)', $email['query']));
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
298
  ?>
299
  <div class="hints">
300
  If you change selections below, save the email to update this values.
304
  <tr valign="top">
305
  <th>Sex</th>
306
  <td>
307
+ <?php $controls->checkboxes_group('sex', array('f'=>'Women', 'm'=>'Men', 'n'=>'Not specified')); ?>
 
 
 
308
  <div class="hints">
309
  Leaving all sex options unselected means to NOT filter by sex.
310
  </div>
313
  <tr valign="top">
314
  <th>Preferences</th>
315
  <td>
316
+ Subscribers with at least one preference
317
+ <?php $controls->select('preferences_status', array(0=>'ACTIVE', 1=>'NOT ACTIVE')); ?>
318
+ between the selected ones below:
319
+
320
  <?php $controls->preferences_group('preferences', true); ?>
 
321
  <div class="hints">
322
+ You can address the newsletter to subscribers who selected at least one of the options or to who
323
+ has not selected at least one of the options.
324
+ <a href="http://www.satollo.net/plugins/newsletter/newsletter-preferences" target="_blank">Read more about the "NOT ACTIVE" usage</a>.
325
  </div>
326
  </td>
327
  </tr>
335
  </div>
336
  </td>
337
  </tr>
338
+ <tr valign="top">
339
+ <th>Status</th>
340
+ <td>
341
+ <?php $controls->select('status', array('C'=>'Confirmed', 'S'=>'Not confirmed')); ?>
342
+
343
+ <div class="hints">
344
+ <strong>Warning! Use this option with care!</strong>
345
+ <br>
346
+ You should NEVER send emails to not confirmed subscribers, but if you need to send them
347
+ an email to ask for confirmation, you can use this option.
348
+ </div>
349
+ </td>
350
+ </tr>
351
+ <tr valign="top">
352
+ <th>Registered users?</th>
353
+ <td>
354
+ <?php $controls->yesno('wp_users'); ?>
355
+
356
+ <div class="hints">
357
+ Limit to the subscribers which are WordPress users as well.
358
+ </div>
359
+ </td>
360
+ </tr>
361
  </table>
362
  </div>
363
 
378
  <th>Email sent</th>
379
  <td><?php echo $email['sent']; ?> of <?php echo $email['total']; ?></td>
380
  </tr>
381
+ <tr valign="top">
382
+ <th>Query</th>
383
+ <td><?php echo $email['query']; ?></td>
384
+ </tr>
385
  </table>
386
  </div>
387
 
388
+ <!--
389
+ <div id="tabs-5">
390
+ <p>Tags documented below can be used on newsletter body. Some of them can be used on subject as well.</p>
391
+
392
+ <p>
393
+ Special tags, like the preference setting tag, can be used to highly interact with your subscribers, see
394
+ the Newsletter Preferences page for examples.
395
+ </p>
396
+ --
397
+
398
+ <dl>
399
+ <dt>{set_preference_N}</dt>
400
+ <dd>
401
+ This tag creates a URL which, once clicked, set the preference numner N on the user profile and redirecting the
402
+ subscriber to his profile panel. Preferences can be configured on Subscription/Form fields panel.
403
+ </dd>
404
+ </dl>
405
+
406
+ </ul>
407
+ </div>
408
+ -->
409
 
410
  </div>
411
 
emails/emails.php CHANGED
@@ -5,17 +5,9 @@ require_once NEWSLETTER_INCLUDES_DIR . '/module.php';
5
 
6
  class NewsletterEmails extends NewsletterModule {
7
 
8
- const VERSION = '1.0.7';
9
-
10
- /**
11
- * @var NewsletterThemes
12
- */
13
- var $themes;
14
-
15
  static $instance;
16
 
17
  /**
18
- *
19
  * @return NewsletterEmails
20
  */
21
  static function instance() {
@@ -26,12 +18,15 @@ class NewsletterEmails extends NewsletterModule {
26
  }
27
 
28
  function __construct() {
29
- parent::__construct('emails', self::VERSION);
30
  $this->themes = new NewsletterThemes('emails');
 
31
  }
32
 
33
  function upgrade() {
34
  global $wpdb, $charset_collate;
 
 
 
35
  $this->upgrade_query("alter table " . NEWSLETTER_EMAILS_TABLE . " change column `type` `type` varchar(50) not null default ''");
36
  $this->upgrade_query("alter table " . NEWSLETTER_EMAILS_TABLE . " add column token varchar(10) not null default ''");
37
  $this->upgrade_query("alter table " . NEWSLETTER_EMAILS_TABLE . " drop column visibility");
@@ -44,11 +39,12 @@ class NewsletterEmails extends NewsletterModule {
44
  return true;
45
  }
46
 
47
- function save_options($options) {
48
- $this->options = $options;
49
- parent::save_options($options);
50
- // This separately save the theme options
51
- $this->themes->save_options($options['theme'], $options);
 
52
  }
53
 
54
  /**
@@ -110,3 +106,5 @@ class NewsletterEmails extends NewsletterModule {
110
  }
111
 
112
  }
 
 
5
 
6
  class NewsletterEmails extends NewsletterModule {
7
 
 
 
 
 
 
 
 
8
  static $instance;
9
 
10
  /**
 
11
  * @return NewsletterEmails
12
  */
13
  static function instance() {
18
  }
19
 
20
  function __construct() {
 
21
  $this->themes = new NewsletterThemes('emails');
22
+ parent::__construct('emails', '1.0.8');
23
  }
24
 
25
  function upgrade() {
26
  global $wpdb, $charset_collate;
27
+
28
+ parent::upgrade();
29
+
30
  $this->upgrade_query("alter table " . NEWSLETTER_EMAILS_TABLE . " change column `type` `type` varchar(50) not null default ''");
31
  $this->upgrade_query("alter table " . NEWSLETTER_EMAILS_TABLE . " add column token varchar(10) not null default ''");
32
  $this->upgrade_query("alter table " . NEWSLETTER_EMAILS_TABLE . " drop column visibility");
39
  return true;
40
  }
41
 
42
+ function admin_menu() {
43
+ $this->add_menu_page('index', 'Newsletters');
44
+ $this->add_admin_page('list', 'Email List');
45
+ $this->add_admin_page('new', 'Email New');
46
+ $this->add_admin_page('edit', 'Email Edit');
47
+ $this->add_admin_page('theme', 'Email List');
48
  }
49
 
50
  /**
106
  }
107
 
108
  }
109
+
110
+ NewsletterEmails::instance();
emails/index.php CHANGED
@@ -1,5 +1,4 @@
1
  <?php
2
-
3
  require_once NEWSLETTER_INCLUDES_DIR . '/controls.php';
4
  $controls = new NewsletterControls();
5
  $module = NewsletterEmails::instance();
@@ -25,6 +24,7 @@ if ($controls->is_action('copy')) {
25
  $email['subject'] = $original->subject;
26
  $email['message'] = $original->message;
27
  $email['message_text'] = $original->message_text;
 
28
  $email['type'] = 'message';
29
  Newsletter::instance()->save_email($email);
30
  $controls->messages .= 'Message duplicated.';
@@ -48,74 +48,87 @@ $emails = Newsletter::instance()->get_emails('message');
48
  <?php $help_url = 'http://www.satollo.net/plugins/newsletter/newsletters-module'; ?>
49
  <?php include NEWSLETTER_DIR . '/header.php'; ?>
50
 
51
- <h2>Newsletters Module</h2>
52
 
53
- <div class="preamble">
54
- <p>Here you can manage your messages: compose, deliver, monitor.</p>
55
- </div>
56
 
57
- <?php $controls->show(); ?>
 
 
58
 
59
- <form method="post" action="admin.php?page=newsletter/emails/index.php">
60
- <?php $controls->init(); ?>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
61
 
62
- <?php if ($module->has_old_emails()) { ?>
63
- <div class="newsletter-message">
64
  <p>
65
- Your Newsletter installation has emails still in old format. To get them listed, you should convert them in
66
- a new format. Would you to convert them now?
 
67
  </p>
68
- <p>
69
- <?php $controls->button('convert', 'Convert now'); ?>
70
- <?php //$controls->button('unconvert', 'Unconvert (DEBUG)'); ?>
71
- </p>
72
- </div>
73
- <?php } ?>
74
-
75
- <p>
76
- <a href="admin.php?page=newsletter/emails/new.php" class="button">New message</a>
77
- <?php $controls->button_confirm('delete_selected', 'Delete selected messages', 'Proceed?'); ?>
78
- <?php $controls->button('send', 'Trigger now'); ?>
79
- </p>
80
- <table class="widefat" style="width: auto">
81
- <thead>
82
- <tr>
83
- <th>&nbsp;</th>
84
- <th>Id</th>
85
- <th>Subject</th>
86
- <th>Date</th>
87
- <th>Status</th>
88
- <th>&nbsp;</th>
89
- <th>&nbsp;</th>
90
- <th>&nbsp;</th>
91
- <th>&nbsp;</th>
92
- </tr>
93
- </thead>
94
-
95
- <tbody>
96
- <?php foreach ($emails as &$email) { ?>
97
- <tr>
98
- <td><input type="checkbox" name="ids[]" value="<?php echo $email->id; ?>"/></td>
99
- <td><?php echo $email->id; ?></td>
100
- <td><?php echo htmlspecialchars($email->subject); ?></td>
101
- <td><?php echo $module->date($email->send_on); ?></td>
102
- <td>
103
- <?php if ($email->status == 'new' && $email->send_on > time()) { ?>
104
- planned
105
- <?php } else { ?>
106
- <?php echo $email->status; ?>
107
- <?php } ?>
108
- (<?php echo $email->sent; ?>/<?php echo $email->total; ?>)
109
- </td>
110
- <td><a class="button" href="admin.php?page=newsletter/emails/edit.php&amp;id=<?php echo $email->id; ?>">Edit</a></td>
111
- <td>
112
- <a class="button" href="<?php echo NewsletterStatistics::instance()->get_statistics_url($email->id); ?>">Statistics</a>
113
- </td>
114
- <td><?php $controls->button_confirm('copy', 'Copy', 'Proceed?', $email->id); ?></td>
115
- <td><?php $controls->button_confirm('delete', 'Delete', 'Proceed?', $email->id); ?></td>
116
- </tr>
117
- <?php } ?>
118
- </tbody>
119
- </table>
120
- </form>
121
  </div>
1
  <?php
 
2
  require_once NEWSLETTER_INCLUDES_DIR . '/controls.php';
3
  $controls = new NewsletterControls();
4
  $module = NewsletterEmails::instance();
24
  $email['subject'] = $original->subject;
25
  $email['message'] = $original->message;
26
  $email['message_text'] = $original->message_text;
27
+ $email['send_on'] = time();
28
  $email['type'] = 'message';
29
  Newsletter::instance()->save_email($email);
30
  $controls->messages .= 'Message duplicated.';
48
  <?php $help_url = 'http://www.satollo.net/plugins/newsletter/newsletters-module'; ?>
49
  <?php include NEWSLETTER_DIR . '/header.php'; ?>
50
 
51
+ <h5>Newsletters Module</h5>
52
 
53
+ <h2>Newsletter List</h2>
 
 
54
 
55
+ <div class="preamble">
56
+ <p>Here you can manage your messages: compose, deliver, monitor.</p>
57
+ </div>
58
 
59
+ <?php $controls->show(); ?>
60
+
61
+ <form method="post" action="">
62
+ <?php $controls->init(); ?>
63
+
64
+ <?php if ($module->has_old_emails()) { ?>
65
+ <div class="newsletter-message">
66
+ <p>
67
+ Your Newsletter installation has emails still in old format. To get them listed, you should convert them in
68
+ a new format. Would you to convert them now?
69
+ </p>
70
+ <p>
71
+ <?php $controls->button('convert', 'Convert now'); ?>
72
+ <?php //$controls->button('unconvert', 'Unconvert (DEBUG)'); ?>
73
+ </p>
74
+ </div>
75
+ <?php } ?>
76
 
 
 
77
  <p>
78
+ <a href="<?php echo $module->get_admin_page_url('new'); ?>" class="button">New message</a>
79
+ <?php $controls->button_confirm('delete_selected', 'Delete selected messages', 'Proceed?'); ?>
80
+ <?php $controls->button('send', 'Trigger the delivery engine'); ?>
81
  </p>
82
+ <table class="widefat" style="width: auto">
83
+ <thead>
84
+ <tr>
85
+ <th>&nbsp;</th>
86
+ <th>Id</th>
87
+ <th>Subject</th>
88
+
89
+ <th>Status</th>
90
+ <th>Progress<sup>*</sup></th>
91
+ <th>Date</th>
92
+ <th>&nbsp;</th>
93
+ <th>&nbsp;</th>
94
+ <th>&nbsp;</th>
95
+ <th>&nbsp;</th>
96
+ </tr>
97
+ </thead>
98
+
99
+ <tbody>
100
+ <?php foreach ($emails as &$email) { ?>
101
+ <tr>
102
+ <td><input type="checkbox" name="ids[]" value="<?php echo $email->id; ?>"/></td>
103
+ <td><?php echo $email->id; ?></td>
104
+ <td><?php echo htmlspecialchars($email->subject); ?></td>
105
+
106
+ <td>
107
+ <?php
108
+ if ($email->status == 'sending') {
109
+ if ($email->send_on > time()) {
110
+ echo 'planned';
111
+ }
112
+ else {
113
+ echo 'sending';
114
+ }
115
+ } else {
116
+ echo $email->status;
117
+ }
118
+ ?>
119
+ </td>
120
+ <td><?php if ($email->status == 'sent' || $email->status == 'sending')echo $email->sent . ' of ' . $email->total; ?></td>
121
+ <td><?php if ($email->status == 'sent' || $email->status == 'sending') echo $module->format_date($email->send_on); ?></td>
122
+ <td><a class="button" href="<?php echo $module->get_admin_page_url('edit'); ?>&amp;id=<?php echo $email->id; ?>">Edit</a></td>
123
+ <td>
124
+ <a class="button" href="<?php echo NewsletterStatistics::instance()->get_statistics_url($email->id); ?>">Statistics</a>
125
+ </td>
126
+ <td><?php $controls->button_confirm('copy', 'Copy', 'Proceed?', $email->id); ?></td>
127
+ <td><?php $controls->button_confirm('delete', 'Delete', 'Proceed?', $email->id); ?></td>
128
+ </tr>
129
+ <?php } ?>
130
+ </tbody>
131
+ </table>
132
+ <p><sup>*</sup> The expected total can change at the delivery end due to subscriptions/unsubscriptions in the meanwhile.</p>
133
+ </form>
 
134
  </div>
emails/new.php CHANGED
@@ -2,34 +2,21 @@
2
  require_once NEWSLETTER_INCLUDES_DIR . '/controls.php';
3
  $controls = new NewsletterControls();
4
  $module = NewsletterEmails::instance();
5
- $store = NewsletterStore::instance();
6
 
7
 
8
- if ($controls->is_action('change')) {
9
- // Recover the selected theme options, if any, and use them.
10
  $controls->merge($module->themes->get_options($controls->data['theme']));
11
  $module->save_options($controls->data);
12
  }
13
 
14
  if ($controls->is_action('save')) {
15
  $module->save_options($controls->data);
 
16
  }
17
 
18
- if ($controls->is_action('create') || $controls->is_action('test')) {
19
  $module->save_options($controls->data);
20
 
21
- if ($controls->is_action('test')) {
22
- $users = $controls->get_test_subscribers();
23
- $email = new stdClass();
24
- $email->id = 0;
25
- $email->message = $controls->data['message'];
26
- $email->message_text = $controls->data['message_text'];
27
- $email->subject = 'Test subject';
28
- $email->track = $controls->data['track'];
29
- $email->type = 'message';
30
- $newsletter->send($email, $users);
31
- }
32
-
33
  if ($controls->is_action('create')) {
34
  $email = array();
35
  $email['status'] = 'new';
@@ -38,11 +25,16 @@ if ($controls->is_action('create') || $controls->is_action('test')) {
38
 
39
  $theme_options = $module->get_current_theme_options();
40
  $theme_url = $module->get_current_theme_url();
 
41
 
42
  ob_start();
43
  include $module->get_current_theme_file_path('theme.php');
44
  $email['message'] = ob_get_clean();
45
 
 
 
 
 
46
  ob_start();
47
  include $module->get_current_theme_file_path('theme-text.php');
48
  $email['message_text'] = ob_get_clean();
@@ -52,10 +44,10 @@ if ($controls->is_action('create') || $controls->is_action('test')) {
52
  $email = Newsletter::instance()->save_email($email);
53
  ?>
54
  <script>
55
- location.href="admin.php?page=newsletter/emails/edit.php&id=<?php echo $email->id; ?>";
56
  </script>
57
  <div class="wrap">
58
- <p>If you are not automatically redirected to the composer, <a href="admin.php?page=newsletter/emails/edit.php&id=<?php echo $email->id; ?>">click here</a>.</p>
59
  </div>
60
  <?php
61
  return;
@@ -63,7 +55,7 @@ if ($controls->is_action('create') || $controls->is_action('test')) {
63
  }
64
 
65
  if ($controls->data == null) {
66
- $controls->data = NewsletterEmails::instance()->get_options();
67
  }
68
 
69
 
@@ -102,49 +94,43 @@ function newsletter_emails_get_theme_options($theme) {
102
  <?php $help_url = 'http://www.satollo.net/plugins/newsletter/newsletters-module'; ?>
103
  <?php include NEWSLETTER_DIR . '/header.php'; ?>
104
 
105
- <h2>Newsletters Module</h2>
106
-
107
 
108
  <?php $controls->show(); ?>
109
 
110
- <!--
111
- <p>
112
- <strong>Select a theme</strong> to compose a precompiled message, tune the theme setting, look at the previews and then preceed to the
113
- composer.
114
- </p>
115
- -->
116
-
117
- <form method="post" action="admin.php?page=newsletter/emails/new.php" id="newsletter-form">
118
  <?php $controls->init(); ?>
119
- <div style="padding: .6em; border: 1px solid #ddd; background-color: #f4f4f4; border-radius: 3px;">
120
- <strong>Choose a theme</strong>
121
- <?php $controls->select('theme', NewsletterEmails::instance()->themes->get_all()); ?>
122
- <?php $controls->button('change', 'Change theme'); ?>
123
- <a href="http://www.satollo.net/plugins/newsletter/newsletter-themes" target="_blank">(more about themes)</a>
124
- </div>
125
 
126
  <p>
127
- <?php $controls->button('save', 'Save options and refresh'); ?>
128
- <?php $controls->button('create', 'Create the email'); ?>
129
  </p>
130
 
131
  <div id="tabs">
132
  <ul>
 
133
  <li><a href="#tabs-2">Preview</a></li>
134
  <li><a href="#tabs-3">Preview (textual)</a></li>
135
- <li><a href="#tabs-1">Theme options</a></li>
136
- <li><a href="#tabs-4">Help</a></li>
137
  </ul>
138
 
 
139
  <div id="tabs-1">
140
- <?php
141
- include NewsletterEmails::instance()->get_current_theme_file_path('theme-options.php');
142
- ?>
 
143
  </div>
144
 
145
 
146
  <div id="tabs-2">
147
- <iframe src="<?php echo wp_nonce_url(NEWSLETTER_URL . '/emails/preview.php?' . time()); ?>" width="100%" height="500"></iframe>
 
 
 
148
  </div>
149
 
150
 
@@ -152,13 +138,6 @@ function newsletter_emails_get_theme_options($theme) {
152
  <iframe src="<?php echo wp_nonce_url(NEWSLETTER_URL . '/emails/preview-text.php?' . time()); ?>" width="100%" height="500"></iframe>
153
  </div>
154
 
155
- <div id="tabs-4">
156
- <p>
157
- Custom themes can be created starting from the supplied themes (on <code>wp_content/plugins/newsletter/emails/themes</code>
158
- each subfolder is a theme)
159
- and copied inside the <code>wp_content/newsletter/emails/themes</code> folder.
160
- </p>
161
- </div>
162
  </div>
163
 
164
  </form>
2
  require_once NEWSLETTER_INCLUDES_DIR . '/controls.php';
3
  $controls = new NewsletterControls();
4
  $module = NewsletterEmails::instance();
 
5
 
6
 
7
+ if ($controls->is_action('theme')) {
 
8
  $controls->merge($module->themes->get_options($controls->data['theme']));
9
  $module->save_options($controls->data);
10
  }
11
 
12
  if ($controls->is_action('save')) {
13
  $module->save_options($controls->data);
14
+ $controls->messages = 'Saved.';
15
  }
16
 
17
+ if ($controls->is_action('create')) {
18
  $module->save_options($controls->data);
19
 
 
 
 
 
 
 
 
 
 
 
 
 
20
  if ($controls->is_action('create')) {
21
  $email = array();
22
  $email['status'] = 'new';
25
 
26
  $theme_options = $module->get_current_theme_options();
27
  $theme_url = $module->get_current_theme_url();
28
+ $theme_subject = '';
29
 
30
  ob_start();
31
  include $module->get_current_theme_file_path('theme.php');
32
  $email['message'] = ob_get_clean();
33
 
34
+ if (!empty($theme_subject)) {
35
+ $email['subject'] = $theme_subject;
36
+ }
37
+
38
  ob_start();
39
  include $module->get_current_theme_file_path('theme-text.php');
40
  $email['message_text'] = ob_get_clean();
44
  $email = Newsletter::instance()->save_email($email);
45
  ?>
46
  <script>
47
+ location.href="<?php echo $module->get_admin_page_url('edit'); ?>&id=<?php echo $email->id; ?>";
48
  </script>
49
  <div class="wrap">
50
+ <p>If you are not automatically redirected to the composer, <a href="<?php echo $module->get_admin_page_url('edit'); ?>&id=<?php echo $email->id; ?>">click here</a>.</p>
51
  </div>
52
  <?php
53
  return;
55
  }
56
 
57
  if ($controls->data == null) {
58
+ $controls->data = $module->get_options();
59
  }
60
 
61
 
94
  <?php $help_url = 'http://www.satollo.net/plugins/newsletter/newsletters-module'; ?>
95
  <?php include NEWSLETTER_DIR . '/header.php'; ?>
96
 
97
+ <h2>New Newsletter</h2>
 
98
 
99
  <?php $controls->show(); ?>
100
 
101
+ <form method="post" action="<?php echo $module->get_admin_page_url('new'); ?>">
 
 
 
 
 
 
 
102
  <?php $controls->init(); ?>
103
+ <h3>Choose a theme</h3>
104
+ <?php //$controls->select('theme', NewsletterEmails::instance()->themes->get_all()); ?>
105
+ <?php //$controls->button('change', 'Change theme'); ?>
106
+
107
+ <?php $controls->themes('theme', $module->themes->get_all_with_data()); ?>
 
108
 
109
  <p>
110
+ <?php $controls->button_primary('create', 'Create the email'); ?>
 
111
  </p>
112
 
113
  <div id="tabs">
114
  <ul>
115
+ <li><a href="#tabs-1">Theme options</a></li>
116
  <li><a href="#tabs-2">Preview</a></li>
117
  <li><a href="#tabs-3">Preview (textual)</a></li>
 
 
118
  </ul>
119
 
120
+
121
  <div id="tabs-1">
122
+ <?php @include $module->get_current_theme_file_path('theme-options.php');?>
123
+ <div class="newsletter-buttons newsletter-buttons-bottom">
124
+ <?php $controls->button('save', 'Save options and refresh'); ?>
125
+ </div>
126
  </div>
127
 
128
 
129
  <div id="tabs-2">
130
+ <div class="tab-preamble">
131
+ <p>After the email is created, you can edit every part of this message.</p>
132
+ </div>
133
+ <iframe src="<?php echo wp_nonce_url(NEWSLETTER_URL . '/emails/preview.php?' . time()); ?>" width="100%" height="700"></iframe>
134
  </div>
135
 
136
 
138
  <iframe src="<?php echo wp_nonce_url(NEWSLETTER_URL . '/emails/preview-text.php?' . time()); ?>" width="100%" height="500"></iframe>
139
  </div>
140
 
 
 
 
 
 
 
 
141
  </div>
142
 
143
  </form>
emails/preview.php CHANGED
@@ -8,7 +8,6 @@ if (!check_admin_referer())
8
  // Used by theme code
9
  $theme_options = NewsletterEmails::instance()->get_current_theme_options();
10
  $theme_url = NewsletterEmails::instance()->get_current_theme_url();
11
-
12
  header('Content-Type: text/html;charset=UTF-8');
13
 
14
  include(NewsletterEmails::instance()->get_current_theme_file_path('theme.php'));
8
  // Used by theme code
9
  $theme_options = NewsletterEmails::instance()->get_current_theme_options();
10
  $theme_url = NewsletterEmails::instance()->get_current_theme_url();
 
11
  header('Content-Type: text/html;charset=UTF-8');
12
 
13
  include(NewsletterEmails::instance()->get_current_theme_file_path('theme.php'));
emails/themes/default/screenshot.png ADDED
Binary file
emails/themes/default/theme-options.php CHANGED
@@ -7,4 +7,12 @@
7
  <th>Add latest posts</th>
8
  <td><?php $controls->checkbox('theme_posts'); ?></td>
9
  </tr>
 
 
 
 
 
 
 
 
10
  </table>
7
  <th>Add latest posts</th>
8
  <td><?php $controls->checkbox('theme_posts'); ?></td>
9
  </tr>
10
+ <tr>
11
+ <th>Add post thumbnails</th>
12
+ <td><?php $controls->checkbox('theme_thumbnails'); ?></td>
13
+ </tr>
14
+ <tr>
15
+ <th>Add post excerpts</th>
16
+ <td><?php $controls->checkbox('theme_excerpts'); ?></td>
17
+ </tr>
18
  </table>
emails/themes/default/theme.php CHANGED
@@ -1,16 +1,24 @@
1
  <?php
2
- // TODO: Documentation!!!
 
 
 
 
 
 
 
3
 
4
- global $newsletter;
5
 
6
  $color = $theme_options['theme_color'];
7
  if (empty($color)) $color = '#0088cc';
8
 
9
- if (isset($theme_options['theme_posts'])) $posts = get_posts(array('shoposts'=>10));
10
 
11
  ?><!DOCTYPE html>
12
  <html>
13
  <head>
 
14
  <style type="text/css" media="all">
15
  a {
16
  text-decoration: none;
@@ -37,8 +45,13 @@ if (isset($theme_options['theme_posts'])) $posts = get_posts(array('shoposts'=>1
37
  <table cellpadding="5">
38
  <?php foreach ($posts as $post) { setup_postdata($post); ?>
39
  <tr>
 
40
  <td><a href="<?php echo get_permalink(); ?>"><img width="75" src="<?php echo newsletter_get_post_image($post->ID); ?>" alt="image"></a></td>
41
- <td valign="top"><a href="<?php echo get_permalink(); ?>" style="font-size: 20px; line-height: 26px"><?php the_title(); ?></a></td>
 
 
 
 
42
  </tr>
43
  <?php } ?>
44
  </table>
1
  <?php
2
+ /*
3
+ * Some variables are already defined:
4
+ *
5
+ * - $theme_options An array with all theme options
6
+ * - $theme_url Is the absolute URL to the theme folder used to reference images
7
+ * - $theme_subject Will be the email subject if set by this theme
8
+ *
9
+ */
10
 
11
+ global $newsletter, $post;
12
 
13
  $color = $theme_options['theme_color'];
14
  if (empty($color)) $color = '#0088cc';
15
 
16
+ if (isset($theme_options['theme_posts'])) $posts = get_posts(array('showposts'=>10));
17
 
18
  ?><!DOCTYPE html>
19
  <html>
20
  <head>
21
+ <!-- Not all email client take care of styles inserted here -->
22
  <style type="text/css" media="all">
23
  a {
24
  text-decoration: none;
45
  <table cellpadding="5">
46
  <?php foreach ($posts as $post) { setup_postdata($post); ?>
47
  <tr>
48
+ <?php if (isset($theme_options['theme_thumbnails'])) { ?>
49
  <td><a href="<?php echo get_permalink(); ?>"><img width="75" src="<?php echo newsletter_get_post_image($post->ID); ?>" alt="image"></a></td>
50
+ <?php } ?>
51
+ <td valign="top">
52
+ <a href="<?php echo get_permalink(); ?>" style="font-size: 20px; line-height: 26px"><?php the_title(); ?></a>
53
+ <?php if (isset($theme_options['theme_excerpts'])) the_excerpt(); ?>
54
+ </td>
55
  </tr>
56
  <?php } ?>
57
  </table>
emails/themes/pint/images/bg.jpg ADDED
Binary file
emails/themes/pint/screenshot.png ADDED
Binary file
emails/themes/pint/theme-options.php ADDED
@@ -0,0 +1 @@
 
1
+ <p>This theme has no options.</p>
emails/themes/pint/theme-text.php ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
1
+ This email requires a modern mail reader.
2
+
3
+ To view this email online:
4
+ {email_url}.
5
+
6
+ To change your subscription:
7
+ {profile_url}.
8
+
9
+ Thank you.
emails/themes/pint/theme.php ADDED
@@ -0,0 +1,68 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /*
3
+ * Some variables are already defined:
4
+ *
5
+ * - $theme_options An array with all theme options
6
+ * - $theme_url Is the absolute URL to the theme folder used to reference images
7
+ * - $theme_subject Will be the email subject if set by this theme
8
+ *
9
+ */
10
+
11
+ global $newsletter, $post;
12
+
13
+ $posts = get_posts(array('post_status'=>'publish', 'showposts'=>9));
14
+
15
+ ?><!DOCTYPE html>
16
+ <html>
17
+ <head>
18
+ </style>
19
+ </head>
20
+ <body style="background-color: #eee; background-image: url('<?php echo $theme_url; ?>/images/bg.jpg'); font-family: Helvetica Neue, Helvetica, Arial, sans-serif; font-size: 14px; color: #666; margin: 0 auto; padding: 0;">
21
+ <br>
22
+ <table align="center">
23
+ <tr>
24
+ <td align="center">
25
+ <small><a href="{email_url}" style="color: #666; text-decoration: none">View this email online</a></small>
26
+ <br>
27
+ <div style="color: #b00; font-size: 50px; font-family: serif; font-style: italic;">
28
+ <?php echo get_option('blogname'); ?>
29
+ </div>
30
+ <br>
31
+ <br>
32
+
33
+ <table cellpadding="5">
34
+ <tr>
35
+ <?php for ($i=0; $i<3; $i++) { $post = $posts[$i]; setup_postdata($post); ?>
36
+ <td align="center" valign="top">
37
+ <a href="<?php echo get_permalink(); ?>" style="font-size: 14px; line-height: 26px; font-weight: bold; color: #000; text-decoration: none"><?php echo substr(get_the_title(), 0, 25); ?>...</a><br>
38
+ <a href="<?php echo get_permalink(); ?>" style="display: block; width: 200px; height: 170px; overflow: hidden"><img width="200" src="<?php echo newsletter_get_post_image($post->ID, 'medium'); ?>" alt=""></a>
39
+ </td>
40
+ <?php } ?>
41
+ </tr>
42
+ <tr>
43
+ <?php for ($i=3; $i<6; $i++) { $post = $posts[$i]; setup_postdata($post); ?>
44
+ <td align="center" valign="top">
45
+ <a href="<?php echo get_permalink(); ?>" style="font-size: 14px; line-height: 26px; font-weight: bold; color: #000; text-decoration: none"><?php echo substr(get_the_title(), 0, 25); ?>...</a><br>
46
+ <a href="<?php echo get_permalink(); ?>" style="display: block; width: 200px; height: 170px; overflow: hidden"><img width="200" src="<?php echo newsletter_get_post_image($post->ID, 'medium'); ?>" alt=""></a>
47
+ </td>
48
+ <?php } ?>
49
+ </tr>
50
+ <tr>
51
+ <?php for ($i=6; $i<9; $i++) { $post = $posts[$i]; setup_postdata($post); ?>
52
+ <td align="center" valign="top">
53
+ <a href="<?php echo get_permalink(); ?>" style="font-size: 14px; line-height: 26px; font-weight: bold; color: #000; text-decoration: none"><?php echo substr(get_the_title(), 0, 25); ?>...</a><br>
54
+ <a href="<?php echo get_permalink(); ?>" style="display: block; width: 200px; height: 170px; overflow: hidden"><img width="200" src="<?php echo newsletter_get_post_image($post->ID, 'medium'); ?>" alt=""></a>
55
+ </td>
56
+ <?php } ?>
57
+ </tr>
58
+ </table>
59
+
60
+ <br><br>
61
+
62
+ <small>To change your subscription, <a href="{profile_url}" style="color: #666; text-decoration: none">click here</a></small>
63
+
64
+ </td>
65
+ </tr>
66
+ </table>
67
+ </body>
68
+ </html>
emails/themes/theme-1/screenshot.png ADDED
Binary file
emails/themes/theme-3/screenshot.png ADDED
Binary file
emails/themes/vimeo-like/screenshot.png ADDED
Binary file
feed/feed.php ADDED
@@ -0,0 +1,91 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * This is only demo code just to make the demo Feed by Mail panel work.
4
+ */
5
+ class NewsletterFeed extends NewsletterModule {
6
+
7
+ static $instance;
8
+
9
+ static function instance() {
10
+ if (self::$instance == null) {
11
+ self::$instance = new NewsletterFeed();
12
+ }
13
+ return self::$instance;
14
+ }
15
+
16
+ function __construct() {
17
+ $this->themes = new NewsletterThemes('feed');
18
+ parent::__construct('feed', '1.0.0');
19
+ add_filter('newsletter_user_subscribe', array($this, 'hook_user_subscribe'));
20
+ add_filter('newsletter_subscription_extra', array($this, 'hook_subscription_extra'));
21
+ }
22
+
23
+ function create_email($options) {
24
+ global $wpdb, $newsletter;
25
+
26
+ $posts = $this->get_posts();
27
+
28
+ $email = array();
29
+
30
+ $last_run = 0;
31
+ $theme_options = $this->themes->get_options($options['theme']);
32
+ $theme_url = $this->themes->get_theme_url($options['theme']);
33
+ $theme_subject = '';
34
+
35
+ ob_start();
36
+ require $this->themes->get_file_path($options['theme'], 'theme.php');
37
+ $email['message'] = ob_get_clean();
38
+
39
+ return $email;
40
+ }
41
+
42
+ function hook_user_subscribe($user) {
43
+ if ($this->options['subscription'] == 1 && isset($_REQUEST['feed'])) $user['feed'] = 1;
44
+ if ($this->options['subscription'] == 2) $user['feed'] = 1;
45
+ return $user;
46
+ }
47
+
48
+ function hook_subscription_extra($extra) {
49
+
50
+ if ($this->options['subscription'] == 1) {
51
+ $field = array();
52
+ $field['label'] = '&nbsp;';
53
+ $field['field'] = '<input type="checkbox" name="feed" value="1"/>&nbsp;' . $this->options['name'];
54
+ $extra[] = $field;
55
+ }
56
+ return $extra;
57
+ }
58
+
59
+ function admin_menu() {
60
+ $this->add_menu_page('index', 'Feed by Mail (Demo)');
61
+ }
62
+
63
+ function get_posts($options = null) {
64
+ if ($options == null) $options = $this->options;
65
+
66
+ $excluded_categories = '';
67
+ $categories = get_categories();
68
+ foreach ($categories as $c) {
69
+ if ($options['category_' . $c->cat_ID] == 1) {
70
+ $excluded_categories .= '-' . $c->cat_ID . ',';
71
+ }
72
+ }
73
+
74
+ $max_posts = $options['max_posts'];
75
+ if (!is_numeric($max_posts)) $max_posts = 10;
76
+
77
+ $filters = array('showposts' => $max_posts, 'post_status' => 'publish');
78
+ if ($excluded_categories != '') $filters['cat'] = $excluded_categories;
79
+
80
+ $posts = get_posts($filters);
81
+
82
+ $newsletter->feed_posts = $posts;
83
+ $newsletter->feed_max_posts = $max_posts;
84
+ $newsletter->feed_excluded_categories = $excluded_categories;
85
+ $newsletter->feed_options = $this->options;
86
+
87
+ return $posts;
88
+ }
89
+ }
90
+
91
+ NewsletterFeed::instance();
feed/index.php ADDED
@@ -0,0 +1,339 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ require_once NEWSLETTER_INCLUDES_DIR . '/controls.php';
3
+ $module = NewsletterFeed::instance();
4
+ $controls = new NewsletterControls();
5
+
6
+ if (!$controls->is_action()) {
7
+ $controls->data = $module->options;
8
+ }
9
+ else {
10
+
11
+ if ($controls->is_action('reset')) {
12
+ $controls->data = $module->reset_options();
13
+ $controls->messages = 'Options restored.';
14
+ }
15
+
16
+ if ($controls->is_action('save')) {
17
+ $controls->data['add_new'] = $controls->data['subscription'] == 2?1:0;
18
+ if (!is_numeric($controls->data['max_posts'])) $controls->data['max_posts'] = 10;
19
+ $module->save_options($controls->data);
20
+ }
21
+
22
+ if ($controls->is_action('add_all')) {
23
+ $result = $wpdb->query("update " . NEWSLETTER_USERS_TABLE . " set feed=1 where feed=0");
24
+ $controls->messages = $result . ' subscribers has been activated.';
25
+ }
26
+
27
+ if ($controls->is_action('remove_all')) {
28
+ $result = $wpdb->query("update " . NEWSLETTER_USERS_TABLE . " set feed=0 where feed=1");
29
+ $controls->messages = $result . ' subscribers has been deactivated.';
30
+ }
31
+
32
+ if ($controls->is_action('test')) {
33
+ $users = NewsletterUsers::instance()->get_test_users();
34
+ if (empty($users)) {
35
+ $controls->errors = 'There are no test subscribers. Read more about test subscribers <a href="http://www.satollo.net/plugins/newsletter/subscribers-module#test" target="_blank">here</a>.';
36
+ }
37
+ else {
38
+ $email = $module->create_email($controls->data);
39
+ Newsletter::instance()->send($email, $users);
40
+
41
+ $controls->messages = 'Test email sent to: ';
42
+ foreach ($users as &$user) $controls->messages .= $user->email . ' ';
43
+ }
44
+
45
+ }
46
+
47
+ if ($controls->is_action('delete')) {
48
+ $wpdb->query("delete from " . $wpdb->prefix . "newsletter_emails where id=" . $_POST['btn']);
49
+ }
50
+
51
+ if ($controls->is_action('reset_time')) {
52
+ $module->save_last_run(0);
53
+ $controls->messages = 'Reset. On next run all posts are considered as new';
54
+ }
55
+
56
+ if ($controls->is_action('back_time')) {
57
+ $module->add_to_last_run(-3600*24);
58
+ $controls->messages = 'Set.';
59
+ }
60
+
61
+ if ($controls->is_action('forward_time')) {
62
+ $module->add_to_last_run(3600*24);
63
+ $controls->messages = 'Set.';
64
+ }
65
+
66
+ if ($controls->is_action('now_time')) {
67
+ $module->save_last_run(time());
68
+ $controls->messages = 'Set.';
69
+ }
70
+ }
71
+
72
+ ?>
73
+
74
+ <div class="wrap">
75
+
76
+ <?php include NEWSLETTER_DIR . '/header.php'; ?>
77
+
78
+ <h5>Feed by Mail (Demo)</h5>
79
+
80
+ <h2>Main configuration</h2>
81
+
82
+ <?php $controls->show(); ?>
83
+
84
+ <div class="preamble">
85
+ <p>
86
+ <strong>This is a demo version of the real <a href="http://www.satollo.net/plugins/newsletter/feed-by-mail-module" target="_blank">Feed by Mail</a> module.</strong>
87
+ </p>
88
+ <p>
89
+ Anyway, options saved on this panel will be preserved if you install the real module and you can already offer to
90
+ subscribers the option to opt-in this service.
91
+ </p>
92
+ <p>
93
+ If you don't want to see this panel on menu, disable it on Welcome panel.
94
+ </p>
95
+ </div>
96
+
97
+ <form method="post" action="">
98
+ <?php $controls->init(); ?>
99
+
100
+ <div id="tabs">
101
+
102
+ <ul>
103
+ <li><a href="#tabs-1">Configuration</a></li>
104
+ <li><a href="#tabs-2">Theme options</a></li>
105
+ <li><a href="#tabs-3">Preview</a></li>
106
+ <li><a href="#tabs-4">New posts</a></li>
107
+ <li><a href="#tabs-5">Emails</a></li>
108
+ <li><a href="#tabs-6">Actions and statistics</a></li>
109
+ </ul>
110
+
111
+ <div id="tabs-1">
112
+
113
+ <table class="form-table">
114
+ <tr valign="top">
115
+ <th>Enabled?</th>
116
+ <td>
117
+ <?php $controls->yesno('enabled'); ?>
118
+ <div class="hints">
119
+ When disabled, no emails will be sent but subscription to this service will continue to work.
120
+ </div>
121
+ </td>
122
+ </tr>
123
+ <tr valign="top">
124
+ <th>Service name</th>
125
+ <td>
126
+ <?php $controls->text('name', 50); ?>
127
+ <div class="hints">
128
+ This name is shown on subscription and profile forms so user can subscribe or unsubscribe from it.
129
+ </div>
130
+ </td>
131
+ </tr>
132
+
133
+ <tr>
134
+ <th>On subscription...</th>
135
+ <td>
136
+ <?php $controls->select('subscription', array(0=>'Do nothing', 1=>'Show this service option', 2=>'Add it to every new subscriber')); ?>
137
+ <div class="hints">
138
+ This setting is valid even if the service is disabled, so users that subscribe will be added to the feed by mail service
139
+ but no feed by mail email will be sent.
140
+ </div>
141
+ </td>
142
+ </tr>
143
+
144
+ <tr valign="top">
145
+ <th>Days</th>
146
+ <td>
147
+ Monday&nbsp;<?php $controls->yesno('day_1'); ?>
148
+ Tuesday&nbsp;<?php $controls->yesno('day_2'); ?>
149
+ Wednesday&nbsp;<?php $controls->yesno('day_3'); ?>
150
+ Thursday&nbsp;<?php $controls->yesno('day_4'); ?>
151
+ Friday&nbsp;<?php $controls->yesno('day_5'); ?>
152
+ Saturday&nbsp;<?php $controls->yesno('day_6'); ?>
153
+ Sunday&nbsp;<?php $controls->yesno('day_7'); ?>
154
+ </td>
155
+ </tr>
156
+
157
+ <tr valign="top">
158
+ <th>Delivery hour</th>
159
+ <td>
160
+ <?php $controls->hours('hour'); ?>
161
+ </td>
162
+ </tr>
163
+
164
+ <tr valign="top">
165
+ <th>Max posts to extract</th>
166
+ <td>
167
+ <?php $controls->text('max_posts', 5); ?>
168
+ </td>
169
+ </tr>
170
+
171
+ <tr valign="top">
172
+ <th>Categories to EXCLUDE</th>
173
+ <td>
174
+ <?php $controls->categories(); ?>
175
+ </td>
176
+ </tr>
177
+
178
+ <tr valign="top">
179
+ <th>Track link clicks?</th>
180
+ <td>
181
+ <?php $controls->yesno('track'); ?>
182
+ </td>
183
+ </tr>
184
+
185
+ <tr valign="top">
186
+ <th>Subject</th>
187
+ <td>
188
+ <?php $controls->text('subject', 50); ?>
189
+ <div class="hints">
190
+ The subject of emails sent. If you leave it empty, the last post title is used. You can use the Newsletter tags.
191
+ </div>
192
+ </td>
193
+ </tr>
194
+ </table>
195
+ </div>
196
+
197
+
198
+ <div id="tabs-2">
199
+ <table class="form-table">
200
+ <tr valign="top">
201
+ <th>Theme</th>
202
+ <td>
203
+ <?php $controls->select('theme', $module->themes->get_all()); ?>
204
+ (save to load the new theme options and update the preview)
205
+ <?php //$controls->button('theme_change', 'Change'); ?>
206
+
207
+ <div class="hints">
208
+ Send a test to see the theme layout. Custom themes are stored on wp-content/plugins/newsletter-custom/themes-feed.
209
+ </div>
210
+ </td>
211
+ </tr>
212
+ </table>
213
+
214
+ <?php
215
+ $file = $module->themes->get_file_path($controls->data['theme'], 'theme-options.php');
216
+ if (is_file($file)) {
217
+ require $file;
218
+ }
219
+ ?>
220
+ </div>
221
+
222
+
223
+ <div id="tabs-3">
224
+ <div class="tab-preamble">
225
+ <p>
226
+ This is only a preview to see how the theme will generate emails, it's not the actual email that will be sent
227
+ next time.
228
+ </p>
229
+ </div>
230
+ <iframe src="<?php echo NEWSLETTER_URL; ?>/feed/preview.php?<?php echo time(); ?>" width="100%" height="700"></iframe>
231
+ </div>
232
+
233
+
234
+ <div id="tabs-4">
235
+ <div class="tab-preamble">
236
+ <p>
237
+ Posts below are the one will be included on next email (sheduled future posts are not counted so
238
+ more posts could be included).
239
+ </p>
240
+ </div>
241
+ <table class="form-table">
242
+ <tr valign="top">
243
+ <th>Last run</th>
244
+ <td>
245
+ <?php echo $module->date($module->get_last_run()); ?>
246
+ <?php $controls->button_confirm('reset_time', 'Reset as it never ran', 'Are you sure?'); ?>
247
+ <?php $controls->button('back_time', 'Back one day'); ?>
248
+ <?php $controls->button('forward_time', 'Forward one day'); ?>
249
+ <?php $controls->button('now_time', 'Set to now'); ?>
250
+ <div class="hints">
251
+ Moving the last run, you can include or exclude posts on next message. See the list below.
252
+ </div>
253
+ </td>
254
+ </tr>
255
+ <tr valign="top">
256
+ <th>New posts from last run</th>
257
+ <td>
258
+ <?php
259
+ global $post;
260
+ $posts = $module->get_posts();
261
+ list($new_posts, $old_posts) = $module->split_posts($posts, $module->get_last_run());
262
+ foreach ($new_posts as $post) {
263
+ setup_postdata($post);
264
+ ?>
265
+ [<?php echo the_ID(); ?>] <?php echo $module->date($module->m2t($post->post_date_gmt)); ?> <a target="_blank" href="<?php echo get_permalink(); ?>"><?php the_title(); ?></a><br />
266
+ <?php } ?>
267
+ </td>
268
+ </tr>
269
+ </table>
270
+ </div>
271
+
272
+
273
+ <div id="tabs-5">
274
+
275
+ <div class="tab-preamble">
276
+ <p>
277
+ <strong>No emails will be generated by this demo module.</strong>
278
+ </p>
279
+ </div>
280
+
281
+ <table class="widefat">
282
+ <thead>
283
+ <tr>
284
+ <th>Id</th>
285
+ <th>Subject</th>
286
+ <th>Date</th>
287
+ <th>Status</th>
288
+ <th>&nbsp;</th>
289
+ </tr>
290
+ </thead>
291
+
292
+ <tbody>
293
+ <tr>
294
+ <td>66</td>
295
+ <td>This week updates!</td>
296
+ <td>2013-02-23</td>
297
+ <td>
298
+ sent (2356/2356)
299
+ </td>
300
+ <td><a class="button" href="#">Statistics</a></td>
301
+ </tr>
302
+ </tbody>
303
+ </table>
304
+
305
+ </div>
306
+
307
+
308
+ <div id="tabs-6">
309
+ <?php
310
+ $total_feed = $wpdb->get_var("select count(*) from " . NEWSLETTER_USERS_TABLE . " where feed=1 and status='C'");
311
+ $total = $wpdb->get_var("select count(*) from " . NEWSLETTER_USERS_TABLE . " where status='C'");
312
+ ?>
313
+ <div class="tab-preamble">
314
+ <p>
315
+ Here you can run some massive actions on subscribers. These button works really!
316
+ </p>
317
+ </div>
318
+ <?php $controls->button_confirm('add_all', 'Add this service to all subscribers', 'Proceed?'); ?>
319
+ <?php $controls->button_confirm('remove_all', 'Remove this service from all subscribers', 'Proceed?'); ?>
320
+
321
+ <h3>Statistics</h3>
322
+ <p>
323
+ Active subscribers: <?php echo $total_feed; ?> of <?php echo $total; ?>
324
+ </p>
325
+ </div>
326
+
327
+ </div>
328
+
329
+ <div class="newsletter-buttons newsletter-buttons-bottom">
330
+ <?php $controls->button('save', 'Save'); ?>
331
+ <?php $controls->button('reset', 'Reset'); ?>
332
+ <?php $controls->button('test', 'Test'); ?>
333
+ </div>
334
+
335
+
336
+ </form>
337
+
338
+
339
+ </div>
feed/languages/en_US.php ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
1
+ <?php
2
+
3
+ $options = array(
4
+ 'theme'=>'default'
5
+ );
feed/preview.php ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ header('Content-Type: text/html;charset=UTF-8');
3
+ include '../../../../wp-load.php';
4
+
5
+ $user_info = get_userdata(get_current_user_id());
6
+ if ($user_info->user_level < 7) die('Only the administrator can view the preview');
7
+
8
+ $module = NewsletterFeed::instance();
9
+ $email = $module->create_email($module->options, 0);
10
+
11
+ echo $email['message'];
feed/themes/default/theme-options.php ADDED
@@ -0,0 +1,67 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /*
3
+ * This is a pre packaged theme options page. Every option name
4
+ * must start with "theme_" so Newsletter can distinguish them from other
5
+ * options that are specific to the object using the theme.
6
+ *
7
+ * An array of theme default options should always be present and that default options
8
+ * should be merged with the current complete set of options as shown below.
9
+ *
10
+ * Every theme can define its own set of options, the will be used in the theme.php
11
+ * file while composing the email body. Newsletter knows nothing about theme options
12
+ * (other than saving them) and does not use or relies on any of them.
13
+ *
14
+ * For multilanguage purpose you can actually check the constants "WP_LANG", until
15
+ * a decent system will be implemented.
16
+ */
17
+ $theme_defaults = array(
18
+ 'theme_title'=>get_option('blogname'),
19
+ 'theme_email_url'=>'You\'re receiving this email because you subscribed it at ' . get_option('blogname') .
20
+ ' as {email}. To read this email online <a href="{email_url}">click here</a>. To modify your subscription <a href="{profile_url}">click here</a>.',
21
+ 'theme_profile_url'=>'To modify your subscription, <a href="{profile_url}">click here</a>.',
22
+ 'theme_color' =>'#0088cc',
23
+ 'theme_max_posts' => '10',
24
+ 'theme_full_post' => '0',
25
+ );
26
+
27
+ // Mandatory!
28
+ $controls->merge_defaults($theme_defaults);
29
+ ?>
30
+ <table class="form-table">
31
+ <tr valign="top">
32
+ <th>Title</th>
33
+ <td>
34
+ <?php $controls->text('theme_title', 70); ?>
35
+ </td>
36
+ </tr>
37
+ <tr valign="top">
38
+ <th>Header message (small font)</th>
39
+ <td>
40
+ <?php $controls->textarea('theme_email_url'); ?>
41
+ </td>
42
+ </tr>
43
+ <tr valign="top">
44
+ <th>Preamble (before the post list)</th>
45
+ <td>
46
+ <?php $controls->wp_editor('theme_preamble'); ?>
47
+ </td>
48
+ </tr>
49
+ <tr valign="top">
50
+ <th>Footer message (small font)</th>
51
+ <td>
52
+ <?php $controls->textarea('theme_profile_url'); ?>
53
+ </td>
54
+ </tr>
55
+ <tr>
56
+ <th>Base color</th>
57
+ <td><?php $controls->color('theme_color'); ?></td>
58
+ </tr>
59
+ <tr>
60
+ <th>How to show posts</th>
61
+ <td><?php $controls->select('theme_full_post', array(0=>'Excerpt', 1=>'Full content')); ?></td>
62
+ </tr>
63
+ <tr>
64
+ <th>Show thumbnails</th>
65
+ <td><?php $controls->checkbox('theme_thumbnails'); ?></td>
66
+ </tr>
67
+ </table>
feed/themes/default/theme.php ADDED
@@ -0,0 +1,104 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ // Mandatory
4
+ global $post;
5
+
6
+ /*
7
+ * Some variables are already defined:
8
+ *
9
+ * - $posts Contains all the posts (new and old) with the maximum specified on Feed by Mail configuration.
10
+ * - $last_run Is the last time an email was sent and the time value to use to split the posts
11
+ * - $theme_options An array with all theme options
12
+ * - $theme_url Is the absolute URL to the theme folder used to reference images
13
+ * - $theme_subject Will be the email subject if set by this theme
14
+ *
15
+ * Pay attention that on this new version there is no more the user available: the theme is used once to compose the
16
+ * email and then sent to the delivery engine.
17
+ *
18
+ * Refer to http://codex.wordpress.org/Function_Reference/setup_postdata for the post cicle. It MUST be written as
19
+ *
20
+ * foreach($new_posts as $post) { setup_postdata($post)
21
+ *
22
+ */
23
+
24
+ // Get new an old posts
25
+ list($new_posts, $old_posts) = NewsletterModule::split_posts($posts, $last_run);
26
+ $color = $theme_options['theme_color'];
27
+ ?><!DOCTYPE html>
28
+ <html>
29
+ <head>
30
+ <style type="text/css" media="all">
31
+ a {
32
+ text-decoration: none;
33
+ color: <?php echo $color; ?>;
34
+ }
35
+ </style>
36
+ </head>
37
+ <body style="background-color: #ddd; font-family: Helvetica Neue, Helvetica, Arial, sans-serif; font-size: 14px; color: #666; margin: 0 auto; padding: 0;">
38
+ <br>
39
+ <table align="center">
40
+ <tr>
41
+ <td style="font-family: Helvetica Neue, Helvetica, Arial, sans-serif; font-size: 14px; color: #666;">
42
+ <div style="text-align: left; max-width: 500px; border-top: 10px solid <?php echo $color; ?>; border-bottom: 3px solid <?php echo $color; ?>;">
43
+ <p>This is a demo</p>
44
+ <div style="padding: 10px 20px; color: #000; font-size: 20px; background-color: #EFEFEF; border-bottom: 1px solid #ddd">
45
+ <?php echo $theme_options['theme_title']; ?>
46
+ </div>
47
+ <div style="padding: 20px; background-color: #fff; line-height: 18px">
48
+
49
+ <p><small><?php echo $options['theme_email_url']; ?></small></p>
50
+
51
+ <?php echo $options['theme_preamble']; ?>
52
+
53
+ <table>
54
+ <?php foreach($new_posts as $post) { setup_postdata($post); ?>
55
+
56
+ <tr>
57
+ <td colspan="2">
58
+ <br>
59
+ <a style="text-decoration: none; font-size: 18px" href="<?php echo get_permalink(); ?>"><?php the_title(); ?></a><br>
60
+ </td>
61
+ </tr>
62
+ <?php if ($theme_options['theme_full_post'] == 1) { ?>
63
+ <tr>
64
+ <td colspan="2">
65
+ <?php the_content(); ?>
66
+ </td>
67
+ </tr>
68
+ <?php } else { ?>
69
+ <tr>
70
+ <td valign="top" style="padding-right: 10px;">
71
+ <?php if (isset($theme_options['theme_thumbnails'])) { ?>
72
+ <a href="<?php echo get_permalink(); ?>"><img src="<?php echo NewsletterModule::get_post_image($post->ID, 'thumbnail', WP_CONTENT_URL . '/newsletter/feed/images/blank.png'); ?>" withd="100" height="100"></a>
73
+ <?php } ?>
74
+ </td>
75
+ <td valign="top">
76
+ <small><?php echo preg_replace('/<\\/*p>/i', '', get_the_excerpt()); ?></small>
77
+ </td>
78
+ </tr>
79
+ <?php } ?>
80
+
81
+ <?php } ?>
82
+
83
+ </table>
84
+
85
+ <?php if (!empty($old_posts)) { ?>
86
+ <table>
87
+ <?php foreach($old_posts as $post) { setup_postdata($post); ?>
88
+ <tr>
89
+ <td valign="top">
90
+ <a href="<?php echo get_permalink(); ?>"><?php the_title(); ?></a>
91
+ </td>
92
+ </tr>
93
+ <?php } ?>
94
+ </table>
95
+ <?php } ?>
96
+
97
+ <p><small><?php echo $theme_options['theme_profile_url']; ?></small></p>
98
+ </div>
99
+ </div>
100
+ </td>
101
+ </tr>
102
+ </table>
103
+ </body>
104
+ </html>
header.php CHANGED
@@ -1,38 +1,53 @@
1
- <?php
2
  $dismissed = get_option('newsletter_dismissed', array());
3
 
4
  if (isset($_REQUEST['dismiss']) && check_admin_referer()) {
5
  $dismissed[$_REQUEST['dismiss']] = 1;
6
  update_option('newsletter_dismissed', $dismissed);
7
  }
8
-
9
  ?>
 
10
  <div id="newsletter-header">
11
  <a href="<?php echo $help_url?$help_url:'http://www.satollo.net/plugins/newsletter/newsletter-configuration'; ?>" target="_blank">Get Help</a>
12
  <a href="http://www.satollo.net/plugins/newsletter/newsletter-faq" target="_blank">FAQ</a>
13
  <a href="http://www.satollo.net/forums" target="_blank">Forum</a>
14
- <a href="http://www.satollo.net/plugins/newsletter/newsletter-collaboration" target="_blank">Collaboration</a>
 
15
 
16
  <form style="display: inline; margin: 0;" action="http://www.satollo.net/wp-content/plugins/newsletter/do/subscribe.php" method="post" target="_blank">
17
- Subscribe to satollo.net <input type="email" name="ne" required placeholder="Your email">
18
  <input type="submit" value="Go">
19
  </form>
20
 
21
  <a href="https://www.facebook.com/satollo.net" target="_blank"><img style="vertical-align: bottom" src="<?php echo NEWSLETTER_URL; ?>/images/facebook.png"></a>
22
 
23
  <a href="https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=5Y6JXSA7BSU2L" target="_blank"><img style="vertical-align: bottom" src="<?php echo NEWSLETTER_URL; ?>/images/donate.png"></a>
24
- <a href="http://www.satollo.net/donations" target="_blank">Even <b>1$</b> helps: read more</a>
25
-
26
- Engine next run in <?php echo wp_next_scheduled('newsletter') - time(); ?> s
 
27
  </div>
 
28
 
29
  <?php if ($dismissed['rate'] != 1) { ?>
30
  <div class="newsletter-notice">
31
- I never asked before and I'm curious: <a href="http://wordpress.org/extend/plugins/newsletter/" target="_blank">would you rate this plugin</a>?
32
  (few seconds required). (account on WordPress.org required, every blog owner should have one...). <strong>Really appreciated, Stefano</strong>.
33
  <div class="newsletter-dismiss"><a href="<?php echo wp_nonce_url($_SERVER['REQUEST_URI'] . '&dismiss=rate')?>">Dismiss</a></div>
34
  <div style="clear: both"></div>
35
  </div>
36
  <?php } ?>
37
 
 
 
 
 
 
 
 
 
 
 
 
38
  <?php $newsletter->warnings(); ?>
1
+ <?php
2
  $dismissed = get_option('newsletter_dismissed', array());
3
 
4
  if (isset($_REQUEST['dismiss']) && check_admin_referer()) {
5
  $dismissed[$_REQUEST['dismiss']] = 1;
6
  update_option('newsletter_dismissed', $dismissed);
7
  }
8
+
9
  ?>
10
+ <?php if (NEWSLETTER_HEADER) { ?>
11
  <div id="newsletter-header">
12
  <a href="<?php echo $help_url?$help_url:'http://www.satollo.net/plugins/newsletter/newsletter-configuration'; ?>" target="_blank">Get Help</a>
13
  <a href="http://www.satollo.net/plugins/newsletter/newsletter-faq" target="_blank">FAQ</a>
14
  <a href="http://www.satollo.net/forums" target="_blank">Forum</a>
15
+ <a href="http://www.satollo.net/membership" target="_blank">Membership</a>
16
+ <!--<a href="http://www.satollo.net/plugins/newsletter/newsletter-collaboration" target="_blank">Collaboration</a>-->
17
 
18
  <form style="display: inline; margin: 0;" action="http://www.satollo.net/wp-content/plugins/newsletter/do/subscribe.php" method="post" target="_blank">
19
+ Subscribe<!-- to satollo.net--> <input type="email" name="ne" required placeholder="Your email">
20
  <input type="submit" value="Go">
21
  </form>
22
 
23
  <a href="https://www.facebook.com/satollo.net" target="_blank"><img style="vertical-align: bottom" src="<?php echo NEWSLETTER_URL; ?>/images/facebook.png"></a>
24
 
25
  <a href="https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=5Y6JXSA7BSU2L" target="_blank"><img style="vertical-align: bottom" src="<?php echo NEWSLETTER_URL; ?>/images/donate.png"></a>
26
+ <a href="http://www.satollo.net/donations" target="_blank">Even <b>1$</b> helps: why?</a>
27
+ <!--
28
+ <a href="http://www.satollo.net/plugins/newsletter/newsletter-delivery-engine" target="_blank">Engine next run in <?php echo wp_next_scheduled('newsletter') - time(); ?> s</a>
29
+ -->
30
  </div>
31
+ <?php } ?>
32
 
33
  <?php if ($dismissed['rate'] != 1) { ?>
34
  <div class="newsletter-notice">
35
+ I never asked before and I'm curious: <a href="http://wordpress.org/extend/plugins/newsletter/" target="_blank">would you rate this plugin</a>?
36
  (few seconds required). (account on WordPress.org required, every blog owner should have one...). <strong>Really appreciated, Stefano</strong>.
37
  <div class="newsletter-dismiss"><a href="<?php echo wp_nonce_url($_SERVER['REQUEST_URI'] . '&dismiss=rate')?>">Dismiss</a></div>
38
  <div style="clear: both"></div>
39
  </div>
40
  <?php } ?>
41
 
42
+ <?php if ($dismissed['newsletter-page'] != 1 && empty($newsletter->options['url'])) { ?>
43
+ <div class="newsletter-notice">
44
+ Do you know you can create a page in your blog used to show all Newsletter messages to subscribers? Go to the
45
+ <a href="?page=newsletter_subscription_options">subscription panel</a> to
46
+ configure it.
47
+ <div class="newsletter-dismiss"><a href="<?php echo wp_nonce_url($_SERVER['REQUEST_URI'] . '&dismiss=newsletter-page')?>">Dismiss</a></div>
48
+ <div style="clear: both"></div>
49
+ </div>
50
+ <?php } ?>
51
+
52
+
53
  <?php $newsletter->warnings(); ?>
images/errors.png ADDED
Binary file
images/messages.png ADDED
Binary file
images/preamble.png ADDED
Binary file
images/theme-screenshot.png ADDED
Binary file
includes/controls.php CHANGED
@@ -73,6 +73,15 @@ class NewsletterControls {
73
  }
74
  }
75
 
 
 
 
 
 
 
 
 
 
76
  function yesno($name) {
77
  $value = isset($this->data[$name]) ? (int) $this->data[$name] : 0;
78
 
@@ -99,6 +108,10 @@ class NewsletterControls {
99
  echo '</select>';
100
  }
101
 
 
 
 
 
102
  function checkbox_group($name, $value, $label = '') {
103
  echo '<input type="checkbox" id="' . $name . '" name="options[' . $name . '][]" value="' . $value . '"';
104
  if (is_array($this->data[$name]) && array_search($value, $this->data[$name]) !== false)
@@ -107,6 +120,32 @@ class NewsletterControls {
107
  if ($label != '') echo ' <label for="' . $name . '">' . $label . '</label>';
108
  }
109
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
110
  function select_group($name, $options) {
111
  echo '<select name="options[' . $name . '][]">';
112
 
@@ -158,47 +197,47 @@ class NewsletterControls {
158
  * Generated a select control with all available templates. From version 3 there are
159
  * only on kind of templates, they are no more separated by type.
160
  */
161
- function themes($name, $theme_dir, $theme_dir2 = null) {
162
- $list = array();
163
-
164
- $handle = @opendir($theme_dir);
165
-
166
- while ($file = readdir($handle)) {
167
- if ($file == '.' || $file == '..') continue;
168
- // TODO: optimize the string concatenation
169
- if (!is_dir($theme_dir . '/' . $file)) continue;
170
- if (!is_file($theme_dir . '/' . $file . '/theme.php')) continue;
171
- $list[$theme_dir . '/' . $file] = $file;
172
- }
173
- closedir($handle);
174
-
175
- if ($theme_dir2 != null && is_dir($theme_dir2)) {
176
- $handle = @opendir($theme_dir2);
177
- $list = array();
178
- while ($file = readdir($handle)) {
179
- if ($file == '.' || $file == '..') continue;
180
- // TODO: optimize the string concatenation
181
- if (!is_dir($theme_dir2 . '/' . $file)) continue;
182
- if (!is_file($theme_dir2 . '/' . $file . '/theme.php')) continue;
183
- $list[$theme_dir2 . '/' . $file] = $file;
184
  }
185
- closedir($handle);
 
186
  }
187
-
188
- $this->select($name, $list);
189
  }
190
 
191
  function value($name) {
192
  echo htmlspecialchars($this->data[$name]);
193
  }
194
 
195
- function value_date($name) {
196
  $time = $this->data[$name];
197
  echo gmdate(get_option('date_format') . ' ' . get_option('time_format'), $time + get_option('gmt_offset') * 3600);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
198
  }
199
 
200
- function text($name, $size = 20) {
201
- echo '<input name="options[' . $name . ']" type="text" size="' . $size . '" value="';
202
  echo htmlspecialchars($this->data[$name]);
203
  echo '"/>';
204
  }
@@ -222,10 +261,22 @@ class NewsletterControls {
222
  echo '<input class="button-secondary" type="button" value="' . $label . '" onclick="this.form.act.value=\'' . $action . '\';this.form.submit()"/>';
223
  }
224
  }
 
 
 
 
 
 
 
225
 
226
- function button_confirm($action, $label, $message, $data = '') {
227
- echo '<input class="button-secondary" type="button" value="' . $label . '" onclick="this.form.btn.value=\'' . $data . '\';this.form.act.value=\'' . $action . '\';if (confirm(\'' .
228
- htmlspecialchars($message) . '\')) this.form.submit()"/>';
 
 
 
 
 
229
  }
230
 
231
  function editor($name, $rows = 5, $cols = 75) {
@@ -233,9 +284,9 @@ class NewsletterControls {
233
  echo htmlspecialchars($this->data[$name]);
234
  echo '</textarea>';
235
  }
236
-
237
  function wp_editor($name, $settings = array()) {
238
- wp_editor($this->data[$name], $name, array_merge(array('textarea_name'=>'options[' . $name . ']', 'wpautop'=>false), $settings));
239
  }
240
 
241
  function textarea($name, $width = '100%', $height = '50') {
@@ -250,18 +301,25 @@ class NewsletterControls {
250
  echo '</textarea>';
251
  }
252
 
253
- function email($prefix) {
254
  echo 'Subject:<br />';
255
- $this->text($prefix . '_subject', 70);
256
- echo '<br />Message:<br />';
257
- $this->editor($prefix . '_message');
 
 
 
 
 
 
258
  }
259
 
260
  function checkbox($name, $label = '') {
 
261
  echo '<input type="checkbox" id="' . $name . '" name="options[' . $name . ']" value="1"';
262
  if (!empty($this->data[$name])) echo ' checked="checked"';
263
  echo '/>';
264
- if ($label != '') echo '&nbsp;<label for="' . $name . '">' . $label . '</label>';
265
  }
266
 
267
  function color($name) {
@@ -287,6 +345,58 @@ class NewsletterControls {
287
  echo '</div>';
288
  }
289
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
290
  function preferences($name = 'preferences', $skip_empty = false) {
291
  $options_profile = get_option('newsletter_profile');
292
  echo '<div class="newsletter-preferences-group">';
73
  }
74
  }
75
 
76
+ function hint($text, $url = '') {
77
+ echo '<div class="hints">';
78
+ echo $text;
79
+ if (!empty($url)) {
80
+ echo " <a href='$url' target='_blank'>Read more</a>.";
81
+ }
82
+ echo '</div>';
83
+ }
84
+
85
  function yesno($name) {
86
  $value = isset($this->data[$name]) ? (int) $this->data[$name] : 0;
87
 
108
  echo '</select>';
109
  }
110
 
111
+ /**
112
+ * Creates a checkbox named $name and checked if the internal data contains under
113
+ * the key $name an array containig the passed value.
114
+ */
115
  function checkbox_group($name, $value, $label = '') {
116
  echo '<input type="checkbox" id="' . $name . '" name="options[' . $name . '][]" value="' . $value . '"';
117
  if (is_array($this->data[$name]) && array_search($value, $this->data[$name]) !== false)
120
  if ($label != '') echo ' <label for="' . $name . '">' . $label . '</label>';
121
  }
122
 
123
+ /**
124
+ * Creates a set of checkbox all named as $name with values and labels extracted from
125
+ * $values_labels. A checkbox will be checked if internal data under key $name is an array
126
+ * and contains the value of the current (echoing) checkbox.
127
+ *
128
+ * On submit it produces an array under the name $name IF at least one checkbox has
129
+ * been checked. Otherwise the key won't be present.
130
+ *
131
+ * @param array $values
132
+ * @param string $name
133
+ * @param array $values_labels
134
+ */
135
+ function checkboxes_group($name, $values_labels) {
136
+ echo "<div class='newsletter-checkboxes-group'>";
137
+ foreach($values_labels as $value=>$label) {
138
+ echo "<div class='newsletter-checkboxes-item'>";
139
+ echo "<input type='checkbox' id='$name' name='options[$name][]' value='$value'";
140
+ if (is_array($this->data[$name]) && array_search($value, $this->data[$name]) !== false)
141
+ echo " checked";
142
+ echo '/>';
143
+ if ($label != '') echo " <label for='$name'>$label</label>";
144
+ echo "</div>";
145
+ }
146
+ echo "</div><div style='clear: both'></div>";
147
+ }
148
+
149
  function select_group($name, $options) {
150
  echo '<select name="options[' . $name . '][]">';
151
 
197
  * Generated a select control with all available templates. From version 3 there are
198
  * only on kind of templates, they are no more separated by type.
199
  */
200
+ function themes($name, $themes, $submit_on_click=true) {
201
+ foreach($themes as $key=>$data) {
202
+ echo '<label style="display: block; float: left; text-align: center; margin-right: 10px;">';
203
+ echo $key . '<br>';
204
+ echo '<img src="' . $data['screenshot'] . '" width="100" height="100" style="border: 1px solid #666; padding: 5px"><br>';
205
+ echo '<input style="position: relative; top: -40px" type="radio" onchange="this.form.act.value=\'theme\';this.form.submit()" name="options[' . $name . ']" value="' . $key . '"';
206
+ if ($this->data[$name] == $key) {
207
+ echo ' checked';
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
208
  }
209
+ echo '>';
210
+ echo '</label>';
211
  }
212
+ echo '<div style="clear: both"></div>';
213
+ echo 'Want to create a custom theme? <a href="http://www.satollo.net/plugins/newsletter/newsletter-themes" target="_blank">Read here</a>';
214
  }
215
 
216
  function value($name) {
217
  echo htmlspecialchars($this->data[$name]);
218
  }
219
 
220
+ function value_date($name, $show_remaining) {
221
  $time = $this->data[$name];
222
  echo gmdate(get_option('date_format') . ' ' . get_option('time_format'), $time + get_option('gmt_offset') * 3600);
223
+ $delta = $time - time();
224
+ if ($show_remaining && $delta > 0) {
225
+ echo 'Remaining: ';
226
+ $delta = $time - time();
227
+ $days = floor($delta / (24*3600));
228
+ $delta = $delta - $days*24*3600;
229
+ $hours = floor($delta / 3600);
230
+ $delta = $delta - $hours*3600;
231
+ $minutes = floor($delta / 60);
232
+
233
+ if ($days > 0) echo $days . ' days ';
234
+ echo $hours . ' hours ';
235
+ echo $minutes . ' minutes ';
236
+ }
237
  }
238
 
239
+ function text($name, $size = 20, $placeholder = '') {
240
+ echo '<input placeholder="' . $placeholder . '" name="options[' . $name . ']" type="text" size="' . $size . '" value="';
241
  echo htmlspecialchars($this->data[$name]);
242
  echo '"/>';
243
  }
261
  echo '<input class="button-secondary" type="button" value="' . $label . '" onclick="this.form.act.value=\'' . $action . '\';this.form.submit()"/>';
262
  }
263
  }
264
+ function button_primary($action, $label, $function = null) {
265
+ if ($function != null) {
266
+ echo '<input class="button-primary" type="button" value="' . $label . '" onclick="this.form.act.value=\'' . $action . '\';' . htmlspecialchars($function) . '"/>';
267
+ } else {
268
+ echo '<input class="button-primary" type="button" value="' . $label . '" onclick="this.form.act.value=\'' . $action . '\';this.form.submit()"/>';
269
+ }
270
+ }
271
 
272
+ function button_confirm($action, $label, $message='', $data = '') {
273
+ if (empty($message)) {
274
+ echo '<input class="button-secondary" type="button" value="' . $label . '" onclick="this.form.btn.value=\'' . $data . '\';this.form.act.value=\'' . $action . '\';this.form.submit()"/>';
275
+ }
276
+ else {
277
+ echo '<input class="button-secondary" type="button" value="' . $label . '" onclick="this.form.btn.value=\'' . $data . '\';this.form.act.value=\'' . $action . '\';if (confirm(\'' .
278
+ htmlspecialchars($message) . '\')) this.form.submit()"/>';
279
+ }
280
  }
281
 
282
  function editor($name, $rows = 5, $cols = 75) {
284
  echo htmlspecialchars($this->data[$name]);
285
  echo '</textarea>';
286
  }
287
+
288
  function wp_editor($name, $settings = array()) {
289
+ wp_editor($this->data[$name], $name, array_merge(array('textarea_name'=>'options[' . $name . ']', 'wpautop'=>false), $settings));
290
  }
291
 
292
  function textarea($name, $width = '100%', $height = '50') {
301
  echo '</textarea>';
302
  }
303
 
304
+ function email($prefix, $editor = null) {
305
  echo 'Subject:<br />';
306
+ $this->text($prefix . '_subject', 90);
307
+ //echo '<br />Message:<br />';
308
+ if ($editor == 'wordpress') {
309
+ $this->wp_editor($prefix . '_message');
310
+ } else if ($editor == 'textarea') {
311
+ $this->textarea($prefix . '_message');
312
+ } else {
313
+ $this->editor($prefix . '_message');
314
+ }
315
  }
316
 
317
  function checkbox($name, $label = '') {
318
+ if ($label != '') echo '<label>';
319
  echo '<input type="checkbox" id="' . $name . '" name="options[' . $name . ']" value="1"';
320
  if (!empty($this->data[$name])) echo ' checked="checked"';
321
  echo '/>';
322
+ if ($label != '') echo '&nbsp;' . $label . '</label>';
323
  }
324
 
325
  function color($name) {
345
  echo '</div>';
346
  }
347
 
348
+ /** Creates a set of checkbox named $name_[category id] (so they are posted with distinct names).
349
+ */
350
+ function categories($name='category') {
351
+ $categories = get_categories();
352
+ echo '<div class="newsletter-checkboxes-group">';
353
+ foreach ($categories as &$c) {
354
+ echo '<div class="newsletter-checkboxes-item">';
355
+ $this->checkbox($name . '_' . $c->cat_ID, esc_html($c->cat_name));
356
+ echo '</div>';
357
+ }
358
+ echo '<div style="clear: both"></div>';
359
+ echo '</div>';
360
+ }
361
+
362
+ /**
363
+ * Creates a set of checkbox to activate the profile preferences. Every checkbox has a DIV around to
364
+ * be formatted.
365
+ */
366
+ function categories_group($name, $show_mode=false) {
367
+ $categories = get_categories();
368
+ if ($show_mode) {
369
+ $this->select($name . '_mode', array('include'=>'To be included', 'exclude'=>'To be excluded'));
370
+ }
371
+ echo '<div class="newsletter-categories-group">';
372
+ foreach ($categories as &$c) {
373
+ echo '<div class="newsletter-categories-item">';
374
+ $this->checkbox_group($name, $c->cat_ID, esc_html($c->cat_name));
375
+ echo '</div>';
376
+ }
377
+ echo '<div style="clear: both"></div>';
378
+ echo '</div>';
379
+ }
380
+
381
+ function preferences_selects($name = 'preferences', $skip_empty = false) {
382
+ $options_profile = get_option('newsletter_profile');
383
+
384
+ echo '<div class="newsletter-preferences-group">';
385
+ for ($i = 1; $i <= NEWSLETTER_LIST_MAX; $i++) {
386
+ if (empty($options_profile['list_' . $i])) continue;
387
+
388
+ echo '<div class="newsletter-preferences-item">';
389
+
390
+ $this->select($name . '_' . $i, array(0=>'Any', 1=>'Yes', 2=>'No'));
391
+ echo '(' . $i . ') ' . htmlspecialchars($options_profile['list_' . $i]);
392
+
393
+ echo '</div>';
394
+ }
395
+ echo '<div style="clear: both"></div>';
396
+ echo '<a href="http://www.satollo.net/plugins/newsletter/newsletter-preferences" target="_blank">Click here know more about preferences.</a> They can be configured on Subscription/Form field panel.';
397
+ echo '</div>';
398
+ }
399
+
400
  function preferences($name = 'preferences', $skip_empty = false) {
401
  $options_profile = get_option('newsletter_profile');
402
  echo '<div class="newsletter-preferences-group">';
includes/logger.php CHANGED
@@ -23,7 +23,9 @@ class NewsletterLogger {
23
  update_option('newsletter_logger_secret', $secret);
24
  }
25
 
26
- @wp_mkdir_p(WP_CONTENT_DIR . '/logs/newsletter/');
 
 
27
 
28
  $this->file = WP_CONTENT_DIR . '/logs/newsletter/' . $module . '-' . $secret . '.txt';
29
  }
@@ -46,7 +48,10 @@ class NewsletterLogger {
46
  if (is_array($text) || is_object($text)) $text = print_r($text, true);
47
 
48
  // The "logs" dir is created on Newsletter constructor.
49
- file_put_contents($this->file, $time . ' - ' . $text . "\n", FILE_APPEND | FILE_TEXT);
 
 
 
50
  }
51
 
52
  function error($text) {
23
  update_option('newsletter_logger_secret', $secret);
24
  }
25
 
26
+ if (!wp_mkdir_p(WP_CONTENT_DIR . '/logs/newsletter/')) {
27
+ $this->level = self::NONE;
28
+ }
29
 
30
  $this->file = WP_CONTENT_DIR . '/logs/newsletter/' . $module . '-' . $secret . '.txt';
31
  }
48
  if (is_array($text) || is_object($text)) $text = print_r($text, true);
49
 
50
  // The "logs" dir is created on Newsletter constructor.
51
+ $res = file_put_contents($this->file, $time . ' - ' . memory_get_usage() . ' - ' . $text . "\n", FILE_APPEND | FILE_TEXT);
52
+ if ($res === false) {
53
+ $this->level = self::NONE;
54
+ }
55
  }
56
 
57
  function error($text) {
includes/module.php CHANGED
@@ -35,33 +35,48 @@ class NewsletterModule {
35
  */
36
  var $prefix;
37
 
 
 
 
 
 
38
  function __construct($module, $version) {
39
  $this->module = $module;
40
  $this->version = $version;
41
  $this->prefix = 'newsletter_' . $module;
42
 
43
- $this->options = $this->get_options();
44
 
45
  $this->logger = new NewsletterLogger($module);
 
46
  $this->store = NewsletterStore::singleton();
47
 
48
  //$this->logger->debug($module . ' constructed');
49
-
50
  // Version check
51
- if ($this->compare_version($this->version) != 0) {
52
- $this->logger->info('Version changed from ' . $this->get_version() . ' to ' . $this->version);
53
- // Do all the stuff for this version change
54
- $this->upgrade();
55
- $this->save_version($this->version);
 
 
 
 
56
  }
57
  }
58
 
 
 
 
 
 
59
  function upgrade() {
60
  $this->logger->info('upgrade> Start');
61
 
62
- if (empty($this->options)) {
63
  $this->options = $this->get_default_options();
64
  $this->save_options($this->options);
 
 
65
  }
66
  }
67
 
@@ -70,7 +85,26 @@ class NewsletterModule {
70
 
71
  $this->logger->info('upgrade_query> Executing ' . $query);
72
  $wpdb->query($query);
73
- if ($wpdb->last_error) $this->logger->error($wpdb->last_error);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
74
  }
75
 
76
  /** Returns a prefix to be used for option names and other things which need to be uniquely named. The parameter
@@ -80,7 +114,7 @@ class NewsletterModule {
80
  * @return string The prefix for names
81
  */
82
  function get_prefix($sub = '') {
83
- return $this->prefix . ($sub != '' ? '_' : '') . $sub;
84
  }
85
 
86
  /**
@@ -93,22 +127,43 @@ class NewsletterModule {
93
  }
94
 
95
  function get_default_options($sub = '') {
96
- if ($sub != '') $sub .= '-';
97
  @include NEWSLETTER_DIR . '/' . $this->module . '/languages/' . $sub . 'en_US.php';
 
98
  @include NEWSLETTER_DIR . '/' . $this->module . '/languages/' . $sub . WPLANG . '.php';
99
- if (!is_array($options)) return array();
 
 
 
100
  return $options;
101
  }
102
-
103
  function reset_options($sub = '') {
104
  $this->save_options(array_merge($this->get_options($sub), $this->get_default_options($sub)), $sub);
105
- return $this->get_options($sub);
106
  }
107
 
 
 
 
 
 
 
 
 
 
 
 
108
  function save_options($options, $sub = '') {
109
  update_option($this->get_prefix($sub), $options);
110
- if (isset($options['log_level']))
111
- update_option('newsletter_' . $this->module . '_log_level', $options['log_level']);
 
 
 
 
 
 
112
  }
113
 
114
  function backup_options($sub) {
@@ -121,38 +176,36 @@ class NewsletterModule {
121
  return get_option($this->get_prefix($sub) . '_last_run', 0);
122
  }
123
 
 
 
 
 
 
 
 
124
  function save_last_run($time, $sub = '') {
125
  update_option($this->get_prefix($sub) . '_last_run', $time);
126
  }
127
 
 
 
 
 
 
128
  function add_to_last_run($delta, $sub = '') {
129
  $time = $this->get_last_run($sub);
130
  $this->save_last_run($time + $delta, $sub);
131
  }
132
 
133
- function get_version() {
134
- return get_option($this->prefix . '_version');
135
- }
136
-
137
- function save_version($version) {
138
- update_option($this->prefix . '_version', $version);
139
- }
140
-
141
- function compare_version($new_version) {
142
- return strcmp($this->get_version(), $new_version);
143
- }
144
-
145
- function delete_transient($sub = '') {
146
- delete_transient($this->get_prefix($sub));
147
- }
148
-
149
  /**
150
- * Checks if the semaphore of that name (for this module) is still red giving that it should last only
151
- * $time seconds.
 
 
152
  *
153
- * @param string $name
154
  * @param int $time Max time in second this semaphore should stay red
155
- * @return boolean False if the semaphore is red and you should not proceed.
156
  */
157
  function check_transient($name, $time) {
158
  usleep(rand(0, 1000000));
@@ -164,6 +217,10 @@ class NewsletterModule {
164
  return true;
165
  }
166
 
 
 
 
 
167
  /** Returns a random token of the specified size (or 10 characters if size is not specified).
168
  *
169
  * @param int $size
@@ -173,6 +230,14 @@ class NewsletterModule {
173
  return substr(md5(rand()), 0, $size);
174
  }
175
 
 
 
 
 
 
 
 
 
176
  static function add_qs($url, $qs, $amp = true) {
177
  if (strpos($url, '?') !== false) {
178
  if ($amp) return $url . '&amp;' . $qs;
@@ -193,11 +258,19 @@ class NewsletterModule {
193
  return $name;
194
  }
195
 
 
 
 
 
 
 
196
  static function is_email($email, $empty_ok = false) {
197
  $email = strtolower(trim($email));
198
  if ($empty_ok && $email == '') return true;
199
 
200
  if (!is_email($email)) return false;
 
 
201
  if (strpos($email, 'mailinator.com') !== false) return false;
202
  if (strpos($email, 'guerrillamailblock.com') !== false) return false;
203
  if (strpos($email, 'emailtemporanea.net') !== false) return false;
@@ -205,10 +278,10 @@ class NewsletterModule {
205
  }
206
 
207
  /**
208
- * Converts a GMT date into timestamp.
209
  *
210
- * @param type $s
211
- * @return type
212
  */
213
  static function m2t($s) {
214
 
@@ -219,19 +292,59 @@ class NewsletterModule {
219
  return gmmktime((int) $t[0], (int) $t[1], (int) $t[2], (int) $d[1], (int) $d[2], (int) $d[0]);
220
  }
221
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
222
  static function date($time = null, $now = false, $left = false) {
223
- if (is_null($time)) $time = time();
224
- if ($time == false) $buffer = 'none';
225
- else
226
- $buffer = gmdate(get_option('date_format') . ' ' . get_option('time_format'), $time + get_option('gmt_offset') * 3600);
 
 
 
 
227
  if ($now) {
228
  $buffer .= ' (now: ' . gmdate(get_option('date_format') . ' ' .
229
  get_option('time_format'), time() + get_option('gmt_offset') * 3600);
230
- if ($left) {
231
- $buffer .= ', ' . gmdate('H:i:s', $time - time()) . ' left';
232
- }
233
  $buffer .= ')';
234
  }
 
 
 
235
  return $buffer;
236
  }
237
 
@@ -279,9 +392,13 @@ class NewsletterModule {
279
  }
280
  }
281
 
 
 
 
 
282
  function get_styles() {
283
 
284
- $list = array(''=>'none');
285
 
286
  $dir = NEWSLETTER_DIR . '/' . $this->module . '/styles';
287
  $handle = @opendir($dir);
@@ -311,11 +428,130 @@ class NewsletterModule {
311
  }
312
 
313
  function get_style_url($style) {
314
- if (is_file(WP_CONTENT_DIR . '/extensions/newsletter/' . $this->module . '/styles/' . $style))
315
- return WP_CONTENT_URL . '/extensions/newsletter/' . $this->module . '/styles/' . $style;
316
  else return NEWSLETTER_URL . '/' . $this->module . '/styles/' . $style;
317
  }
318
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
319
  }
320
 
321
  /**
35
  */
36
  var $prefix;
37
 
38
+ /**
39
+ * @var NewsletterThemes
40
+ */
41
+ var $themes;
42
+
43
  function __construct($module, $version) {
44
  $this->module = $module;
45
  $this->version = $version;
46
  $this->prefix = 'newsletter_' . $module;
47
 
 
48
 
49
  $this->logger = new NewsletterLogger($module);
50
+ $this->options = $this->get_options();
51
  $this->store = NewsletterStore::singleton();
52
 
53
  //$this->logger->debug($module . ' constructed');
 
54
  // Version check
55
+ if (is_admin()) {
56
+ $old_version = get_option($this->prefix . '_version', '');
57
+ if (strcmp($old_version, $this->version) != 0) {
58
+ $this->logger->info('Version changed from ' . $old_version . ' to ' . $this->version);
59
+ // Do all the stuff for this version change
60
+ $this->upgrade();
61
+ update_option($this->prefix . '_version', $this->version);
62
+ }
63
+ add_action('admin_menu', array($this, 'admin_menu'));
64
  }
65
  }
66
 
67
+ /**
68
+ * Does a basic upgrade work, checking if the options is already present and if not (first
69
+ * installation), recovering the defaults, saving them on database and initializing the
70
+ * internal $options.
71
+ */
72
  function upgrade() {
73
  $this->logger->info('upgrade> Start');
74
 
75
+ if (empty($this->options) || !is_array($this->options)) {
76
  $this->options = $this->get_default_options();
77
  $this->save_options($this->options);
78
+ } else {
79
+ // TODO: Try with an array_merge()?
80
  }
81
  }
82
 
85
 
86
  $this->logger->info('upgrade_query> Executing ' . $query);
87
  $wpdb->query($query);
88
+ if ($wpdb->last_error) {
89
+ $this->logger->info($wpdb->last_error);
90
+ }
91
+ }
92
+
93
+ /**
94
+ * Return, eventually, the version of this moduke available on satollo.net.
95
+ * @return string
96
+ */
97
+ static function get_available_version($module_id) {
98
+ $version = get_option('newsletter_module_' . $module_id . '_version', '');
99
+ $time = get_option('newsletter_module_' . $module_id . '_last_check', 0);
100
+ if (empty($version) || $time < time() - 86400) {
101
+ $version = @file_get_contents('http://www.satollo.net/wp-content/plugins/file-commerce-pro/version.php?f=' . $module_id);
102
+ add_option('newsletter_module_' . $module_id . '_last_check', time(), '', 'no');
103
+ update_option('newsletter_module_' . $module_id . '_last_check', time());
104
+ add_option('newsletter_module_' . $module_id . '_version', $version);
105
+ update_option('newsletter_module_' . $module_id . '_version', $version);
106
+ }
107
+ return $version;
108
  }
109
 
110
  /** Returns a prefix to be used for option names and other things which need to be uniquely named. The parameter
114
  * @return string The prefix for names
115
  */
116
  function get_prefix($sub = '') {
117
+ return $this->prefix . (!empty($sub) ? '_' : '') . $sub;
118
  }
119
 
120
  /**
127
  }
128
 
129
  function get_default_options($sub = '') {
130
+ if (!empty($sub)) $sub .= '-';
131
  @include NEWSLETTER_DIR . '/' . $this->module . '/languages/' . $sub . 'en_US.php';
132
+ @include WP_CONTENT_DIR . '/extensions/newsletter/' . $this->module . '/languages/' . $sub . 'en_US.php';
133
  @include NEWSLETTER_DIR . '/' . $this->module . '/languages/' . $sub . WPLANG . '.php';
134
+ @include WP_CONTENT_DIR . '/extensions/newsletter/' . $this->module . '/languages/' . $sub . WPLANG . '.php';
135
+ if (!is_array($options)) {
136
+ return array();
137
+ }
138
  return $options;
139
  }
140
+
141
  function reset_options($sub = '') {
142
  $this->save_options(array_merge($this->get_options($sub), $this->get_default_options($sub)), $sub);
143
+ return $this->options;
144
  }
145
 
146
+ /**
147
+ * Saves the module options (or eventually a subset names as per parameter $sub). $options
148
+ * should be an array (even if it can work with non array options.
149
+ * The internal module options variable IS initialized with those new options only for the main
150
+ * options (empty $sub parameter).
151
+ * If the options contain a "theme" value, the theme-related options contained are saved as well
152
+ * (used by some modules).
153
+ *
154
+ * @param array $options
155
+ * @param string $sub
156
+ */
157
  function save_options($options, $sub = '') {
158
  update_option($this->get_prefix($sub), $options);
159
+ if (empty($sub)) {
160
+ $this->options = $options;
161
+ if (isset($this->themes) && isset($options['theme'])) {
162
+ $this->themes->save_options($options['theme'], $options);
163
+ }
164
+ // TODO: To be remove since there is no more log level at module level (should it be reintroduced?)
165
+ if (isset($options['log_level'])) update_option('newsletter_' . $this->module . '_log_level', $options['log_level']);
166
+ }
167
  }
168
 
169
  function backup_options($sub) {
176
  return get_option($this->get_prefix($sub) . '_last_run', 0);
177
  }
178
 
179
+ /**
180
+ * Save the module last run value. Used to store a timestamp for some modules,
181
+ * for example the Feed by Mail module.
182
+ *
183
+ * @param int $time Unix timestamp (as returned by time() for example)
184
+ * @param string $sub Sub module name (default empty)
185
+ */
186
  function save_last_run($time, $sub = '') {
187
  update_option($this->get_prefix($sub) . '_last_run', $time);
188
  }
189
 
190
+ /**
191
+ * Sums $delta seconds to the last run time.
192
+ * @param int $delta Seconds
193
+ * @param string $sub Sub module name (default empty)
194
+ */
195
  function add_to_last_run($delta, $sub = '') {
196
  $time = $this->get_last_run($sub);
197
  $this->save_last_run($time + $delta, $sub);
198
  }
199
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
200
  /**
201
+ * Checks if the semaphore of that name (for this module) is still red. If it is active the method
202
+ * returns false. If it is not active, it will be activated for $time seconds.
203
+ *
204
+ * Since this method activate the semaphore when called, it's name is a bit confusing.
205
  *
206
+ * @param string $name Sempahore name (local to this module)
207
  * @param int $time Max time in second this semaphore should stay red
208
+ * @return boolean False if the semaphore is red and you should not proceed, true is it was not active and has been activated.
209
  */
210
  function check_transient($name, $time) {
211
  usleep(rand(0, 1000000));
217
  return true;
218
  }
219
 
220
+ function delete_transient($name = '') {
221
+ delete_transient($this->get_prefix() . '_' . $name);
222
+ }
223
+
224
  /** Returns a random token of the specified size (or 10 characters if size is not specified).
225
  *
226
  * @param int $size
230
  return substr(md5(rand()), 0, $size);
231
  }
232
 
233
+ /**
234
+ * Adds query string parameters to an URL checing id there are already other parameters.
235
+ *
236
+ * @param string $url
237
+ * @param string $qs The part of query-string to add (param1=value1&param2=value2...)
238
+ * @param boolean $amp If the method must use the &amp; instead of the plain & (default true)
239
+ * @return string
240
+ */
241
  static function add_qs($url, $qs, $amp = true) {
242
  if (strpos($url, '?') !== false) {
243
  if ($amp) return $url . '&amp;' . $qs;
258
  return $name;
259
  }
260
 
261
+ static function normalize_sex($sex) {
262
+ $sex = trim(strtolower($sex));
263
+ if ($sex != 'f' && $sex != 'm') $sex = 'n';
264
+ return $sex;
265
+ }
266
+
267
  static function is_email($email, $empty_ok = false) {
268
  $email = strtolower(trim($email));
269
  if ($empty_ok && $email == '') return true;
270
 
271
  if (!is_email($email)) return false;
272
+
273
+ // TODO: To be moved on the subscription module and make configurable
274
  if (strpos($email, 'mailinator.com') !== false) return false;
275
  if (strpos($email, 'guerrillamailblock.com') !== false) return false;
276
  if (strpos($email, 'emailtemporanea.net') !== false) return false;
278
  }
279
 
280
  /**
281
+ * Converts a GMT date from mysql (see the posts table columns) into a timestamp.
282
  *
283
+ * @param string $s GMT date with format yyyy-mm-dd hh:mm:ss
284
+ * @return int A timestamp
285
  */
286
  static function m2t($s) {
287
 
292
  return gmmktime((int) $t[0], (int) $t[1], (int) $t[2], (int) $d[1], (int) $d[2], (int) $d[0]);
293
  }
294
 
295
+ static function format_date($time) {
296
+ if (empty($time)) return '-';
297
+ return gmdate(get_option('date_format') . ' ' . get_option('time_format'), $time + get_option('gmt_offset') * 3600);
298
+ }
299
+
300
+ static function format_time_delta($delta) {
301
+ $days = floor($delta / (3600 * 24));
302
+ $hours = floor(($delta % (3600 * 24)) / 3600);
303
+ $minutes = floor(($delta % 3600) / 60);
304
+ $seconds = floor(($delta % 60));
305
+ $buffer = $days . ' days, ' . $hours . ' hours, ' . $minutes . ' minutes, ' . $seconds . ' seconds';
306
+ return $buffer;
307
+ }
308
+
309
+ /**
310
+ * Formats a scheduler returned "next execution" time, managing negative or false values. Many times
311
+ * used in conjuction with "last run".
312
+ *
313
+ * @param string $name The scheduler name
314
+ * @return string
315
+ */
316
+ static function format_scheduler_time($name) {
317
+ $time = wp_next_scheduled($name);
318
+ if ($time === false) {
319
+ return 'Not active';
320
+ }
321
+ $delta = $time - time();
322
+ // If less 10 minutes late it can be a cron problem but now it is working
323
+ if ($delta < 0 && $delta > -600) {
324
+ return 'Probably running now';
325
+ } else if ($delta <= -600) {
326
+ return 'It seems the cron system is not working. Reload the page to see if this message change.';
327
+ }
328
+ return 'Runs in ' . self::format_time_delta($delta);
329
+ }
330
+
331
  static function date($time = null, $now = false, $left = false) {
332
+ if (is_null($time)) {
333
+ $time = time();
334
+ }
335
+ if ($time == false) {
336
+ $buffer = 'none';
337
+ } else {
338
+ $buffer = gmdate(get_option('date_format') . ' ' . get_option('time_format'), $time + get_option('gmt_offset') * 3600);
339
+ }
340
  if ($now) {
341
  $buffer .= ' (now: ' . gmdate(get_option('date_format') . ' ' .
342
  get_option('time_format'), time() + get_option('gmt_offset') * 3600);
 
 
 
343
  $buffer .= ')';
344
  }
345
+ if ($left) {
346
+ $buffer .= ', ' . gmdate('H:i:s', $time - time()) . ' left';
347
+ }
348
  return $buffer;
349
  }
350
 
392
  }
393
  }
394
 
395
+ static function extension_exists($name) {
396
+ return is_file(WP_CONTENT_DIR . "/extensions/newsletter/$name/$name.php");
397
+ }
398
+
399
  function get_styles() {
400
 
401
+ $list = array('' => 'none');
402
 
403
  $dir = NEWSLETTER_DIR . '/' . $this->module . '/styles';
404
  $handle = @opendir($dir);
428
  }
429
 
430
  function get_style_url($style) {
431
+ if (is_file(WP_CONTENT_DIR . '/extensions/newsletter/' . $this->module . '/styles/' . $style)) return WP_CONTENT_URL . '/extensions/newsletter/' . $this->module . '/styles/' . $style;
 
432
  else return NEWSLETTER_URL . '/' . $this->module . '/styles/' . $style;
433
  }
434
 
435
+ function admin_menu() {
436
+
437
+ }
438
+
439
+ function add_menu_page($page, $title) {
440
+ global $newsletter;
441
+ $file = WP_CONTENT_DIR . '/extensions/newsletter/' . $this->module . '/' . $page . '.php';
442
+ if (!is_file($file)) {
443
+ $file = NEWSLETTER_DIR . '/' . $this->module . '/' . $page . '.php';
444
+ }
445
+ $name = 'newsletter_' . $this->module . '_' . $page;
446
+ eval('function ' . $name . '(){global $newsletter, $wpdb;require \'' . $file . '\';}');
447
+ add_submenu_page('newsletter_main_index', $title, $title, ($newsletter->options['editor'] == 1) ? 7 : 10, $name, $name);
448
+ }
449
+
450
+ function add_admin_page($page, $title) {
451
+ global $newsletter;
452
+ $file = WP_CONTENT_DIR . '/extensions/newsletter/' . $this->module . '/' . $page . '.php';
453
+ if (!is_file($file)) {
454
+ $file = NEWSLETTER_DIR . '/' . $this->module . '/' . $page . '.php';
455
+ }
456
+
457
+ $name = 'newsletter_' . $this->module . '_' . $page;
458
+ eval('function ' . $name . '(){global $newsletter, $wpdb;require \'' . $file . '\';}');
459
+ add_submenu_page(null, $title, $title, $newsletter->options['editor'] ? 7 : 10, $name, $name);
460
+ }
461
+
462
+ function get_admin_page_url($page) {
463
+ return '?page=newsletter_' . $this->module . '_' . $page;
464
+ }
465
+
466
+ /** Returns all the emails of the give type (message, feed, followup, ...) and in the given format
467
+ * (default as objects). Return false on error or at least an empty array. Errors should never
468
+ * occur.
469
+ *
470
+ * @global wpdb $wpdb
471
+ * @param string $type
472
+ * @return boolean|array
473
+ */
474
+ function get_emails($type = null, $format = OBJECT) {
475
+ global $wpdb;
476
+ if ($type == null) {
477
+ $list = $wpdb->get_results("select * from " . NEWSLETTER_EMAILS_TABLE . " order by id desc", $format);
478
+ } else {
479
+ $list = $wpdb->get_results($wpdb->prepare("select * from " . NEWSLETTER_EMAILS_TABLE . " where type=%s order by id desc", $type), $format);
480
+ }
481
+ if ($wpdb->last_error) {
482
+ $this->logger->error($wpdb->last_error);
483
+ return false;
484
+ }
485
+ if (empty($list)) {
486
+ return array();
487
+ }
488
+ return $list;
489
+ }
490
+
491
+ function get_email($id, $format = OBJECT) {
492
+ return $this->store->get_single(NEWSLETTER_EMAILS_TABLE, $id, $format);
493
+ }
494
+
495
+ /** Returns the user identify by an id or an email. If $id_or_email is an object or an array, it is assumed it contains
496
+ * the "id" attribute or key and that is used to load the user.
497
+ *
498
+ * @global type $wpdb
499
+ * @param string|int|object|array $id_or_email
500
+ * @param type $format
501
+ * @return boolean
502
+ */
503
+ function get_user($id_or_email, $format = OBJECT) {
504
+ global $wpdb;
505
+
506
+ // To simplify the reaload of a user passing the user it self.
507
+ if (is_object($id_or_email)) $id_or_email = $id_or_email->id;
508
+ else if (is_array($id_or_email)) $id_or_email = $id_or_email['id'];
509
+
510
+ $id_or_email = strtolower(trim($id_or_email));
511
+
512
+ if (is_numeric($id_or_email)) {
513
+ $r = $wpdb->get_row($wpdb->prepare("select * from " . NEWSLETTER_USERS_TABLE . " where id=%d limit 1", $id_or_email), $format);
514
+ } else {
515
+ $r = $wpdb->get_row($wpdb->prepare("select * from " . NEWSLETTER_USERS_TABLE . " where email=%s limit 1", $id_or_email), $format);
516
+ }
517
+
518
+ if ($wpdb->last_error) {
519
+ $this->logger->error($wpdb->last_error);
520
+ return false;
521
+ }
522
+ return $r;
523
+ }
524
+
525
+ /**
526
+ * NEVER CHANGE THIS METHOD SIGNATURE, USER BY THIRD PARTY PLUGINS.
527
+ *
528
+ * Saves a new user on the database. Return false if the email (that must be unique) is already
529
+ * there. For a new users set the token and creation time if not passed.
530
+ *
531
+ * @param array|object $user
532
+ */
533
+ function save_user($user, $return_format = OBJECT) {
534
+ if (is_object($user)) $user = (array) $user;
535
+ if (empty($user['id'])) {
536
+ $existing = $this->get_user($user['email']);
537
+ if ($existing != null) return false;
538
+ if (empty($user['token'])) $user['token'] = NewsletterModule::get_token();
539
+ //if (empty($user['created'])) $user['created'] = time();
540
+ // Database default
541
+ //if (empty($user['status'])) $user['status'] = 'S';
542
+ }
543
+ // Due to the unique index on email field, this can fail.
544
+ return $this->store->save(NEWSLETTER_USERS_TABLE, $user, $return_format);
545
+ }
546
+
547
+ function set_user_wp_user_id($user_id, $wp_user_id) {
548
+ $this->store->set_field(NEWSLETTER_USERS_TABLE, $user_id, 'wp_user_id', $wp_user_id);
549
+ }
550
+
551
+ function get_user_by_wp_user_id($wp_user_id, $format = OBJECT) {
552
+ return $this->store->get_single_by_field(NEWSLETTER_USERS_TABLE, 'wp_user_id', $wp_user_id, $format);
553
+ }
554
+
555
  }
556
 
557
  /**
includes/store.php CHANGED
@@ -32,6 +32,10 @@ class NewsletterStore {
32
 
33
  function get_field($table, $id, $field_name) {
34
  global $wpdb;
 
 
 
 
35
  $r = $wpdb->get_var($wpdb->prepare("select $field_name from $table where id=%d limit 1", $id));
36
  if ($wpdb->last_error) {
37
  $this->logger->error($wpdb->last_error);
@@ -45,7 +49,8 @@ class NewsletterStore {
45
  return $this->get_single_by_query($wpdb->prepare("select * from $table where id=%d limit 1", $id), $format);
46
  }
47
 
48
- function get_single_by_field($table, $field_name, $field_value) {
 
49
  return $this->get_single_by_query("select * from $table where $field_name='" . $wpdb->escape($field_value) . "' limit 1", $format);
50
  }
51
 
@@ -164,7 +169,10 @@ class NewsletterStore {
164
 
165
  function set_field($table, $id, $field, $value) {
166
  global $wpdb;
167
- // For security check the field name
 
 
 
168
  $result = $wpdb->query($wpdb->prepare("update $table set $field=%s where id=%d", $value, $id));
169
 
170
  if ($wpdb->last_error) {
32
 
33
  function get_field($table, $id, $field_name) {
34
  global $wpdb;
35
+ if (preg_match('/^[a-zA-Z]+$/', $field_name) == 0) {
36
+ $this->logger->error('Invalis field name: ' . $field_name);
37
+ return false;
38
+ }
39
  $r = $wpdb->get_var($wpdb->prepare("select $field_name from $table where id=%d limit 1", $id));
40
  if ($wpdb->last_error) {
41
  $this->logger->error($wpdb->last_error);
49
  return $this->get_single_by_query($wpdb->prepare("select * from $table where id=%d limit 1", $id), $format);
50
  }
51
 
52
+ function get_single_by_field($table, $field_name, $field_value, $format = OBJECT) {
53
+ global $wpdb;
54
  return $this->get_single_by_query("select * from $table where $field_name='" . $wpdb->escape($field_value) . "' limit 1", $format);
55
  }
56
 
169
 
170
  function set_field($table, $id, $field, $value) {
171
  global $wpdb;
172
+ if (preg_match('/^[a-zA-Z_]+$/', $field) == 0) {
173
+ $this->logger->error('Invalis field name: ' . $field_name);
174
+ return false;
175
+ }
176
  $result = $wpdb->query($wpdb->prepare("update $table set $field=%s where id=%d", $value, $id));
177
 
178
  if ($wpdb->last_error) {
includes/themes.php CHANGED
@@ -3,9 +3,11 @@
3
  class NewsletterThemes {
4
 
5
  var $module;
 
6
 
7
- function __construct($module) {
8
  $this->module = $module;
 
9
  }
10
 
11
  /** Loads all themes of a module (actually only "emails" module makes sense). Themes are located inside the subfolder
@@ -18,19 +20,40 @@ class NewsletterThemes {
18
  function get_all() {
19
  $list = array();
20
 
21
- $dir = NEWSLETTER_DIR . '/' . $this->module . '/themes';
22
  $handle = @opendir($dir);
23
 
24
  if ($handle !== false) {
25
  while ($file = readdir($handle)) {
26
  if ($file == '.' || $file == '..') continue;
27
  if (!is_file($dir . '/' . $file . '/theme.php')) continue;
28
-
29
  $list[$file] = $file;
30
  }
31
  closedir($handle);
32
  }
33
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
34
  $dir = WP_CONTENT_DIR . '/extensions/newsletter/' . $this->module . '/themes';
35
  $handle = @opendir($dir);
36
 
@@ -39,10 +62,42 @@ class NewsletterThemes {
39
  if ($file == '.' || $file == '..') continue;
40
  if (isset($list[$file])) continue;
41
  if (!is_file($dir . '/' . $file . '/theme.php')) continue;
42
- $list[$file] = $file;
 
 
 
 
 
 
 
 
43
  }
44
  closedir($handle);
45
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
46
  return $list;
47
  }
48
 
@@ -76,22 +131,31 @@ class NewsletterThemes {
76
  }
77
 
78
  function get_theme_url($theme) {
 
 
 
 
79
  $path = NEWSLETTER_DIR . '/' . $this->module . '/themes/' . $theme;
80
  if (is_dir($path)) {
81
  return NEWSLETTER_URL . '/' . $this->module . '/themes/' . $theme;
82
- }
83
- else {
84
  return WP_CONTENT_URL . '/extensions/newsletter/' . $this->module . '/themes/' . $theme;
85
  }
86
  }
87
 
88
  function get_default_options() {
89
- $path1 = NEWSLETTER_DIR . '/' . $this->module . '/themes/' . $theme . '/languages';
90
- $path2 = WP_CONTENT_DIR . '/extensions/newsletter/' . $this->module . '/themes/' . $theme . '/languages';
91
- @include $path1 . '/en_US.php';
92
- @include $path2 . '/en_US.php';
93
- @include $path1 . '/' . WPLANG . '.php';
94
- @include $path2 . '/' . WPLANG . '.php';
 
 
 
 
 
 
95
 
96
  if (!is_array($options)) return array();
97
  return $options;
3
  class NewsletterThemes {
4
 
5
  var $module;
6
+ var $is_extension = false;
7
 
8
+ function __construct($module, $is_extension = false) {
9
  $this->module = $module;
10
+ $this->is_extension = $is_extension;
11
  }
12
 
13
  /** Loads all themes of a module (actually only "emails" module makes sense). Themes are located inside the subfolder
20
  function get_all() {
21
  $list = array();
22
 
23
+ $dir = WP_CONTENT_DIR . '/extensions/newsletter/' . $this->module . '/themes';
24
  $handle = @opendir($dir);
25
 
26
  if ($handle !== false) {
27
  while ($file = readdir($handle)) {
28
  if ($file == '.' || $file == '..') continue;
29
  if (!is_file($dir . '/' . $file . '/theme.php')) continue;
 
30
  $list[$file] = $file;
31
  }
32
  closedir($handle);
33
  }
34
 
35
+ if (!$this->is_extension) {
36
+ $dir = NEWSLETTER_DIR . '/' . $this->module . '/themes';
37
+ $handle = @opendir($dir);
38
+
39
+ if ($handle !== false) {
40
+ while ($file = readdir($handle)) {
41
+ if ($file == '.' || $file == '..') continue;
42
+ if (isset($list[$file])) continue;
43
+ if (!is_file($dir . '/' . $file . '/theme.php')) continue;
44
+
45
+ $list[$file] = $file;
46
+ }
47
+ closedir($handle);
48
+ }
49
+ }
50
+
51
+ return $list;
52
+ }
53
+
54
+ function get_all_with_data() {
55
+ $list = array();
56
+
57
  $dir = WP_CONTENT_DIR . '/extensions/newsletter/' . $this->module . '/themes';
58
  $handle = @opendir($dir);
59
 
62
  if ($file == '.' || $file == '..') continue;
63
  if (isset($list[$file])) continue;
64
  if (!is_file($dir . '/' . $file . '/theme.php')) continue;
65
+ $data = array();
66
+ $data['name'] = $file;
67
+ $screenshot = $dir . '/' . $file . '/screenshot.png';
68
+ if (is_file($screenshot)) {
69
+ $data['screenshot'] = $this->get_theme_url($file) . '/screenshot.png';
70
+ } else {
71
+ $data['screenshot'] = NEWSLETTER_URL . '/images/theme-screenshot.png';
72
+ }
73
+ $list[$file] = $data;
74
  }
75
  closedir($handle);
76
  }
77
+
78
+ if (!$this->is_extension) {
79
+ $dir = NEWSLETTER_DIR . '/' . $this->module . '/themes';
80
+ $handle = @opendir($dir);
81
+
82
+ if ($handle !== false) {
83
+ while ($file = readdir($handle)) {
84
+ if ($file == '.' || $file == '..') continue;
85
+ if (!is_file($dir . '/' . $file . '/theme.php')) continue;
86
+ $data = array();
87
+ $data['name'] = $file;
88
+ $screenshot = $dir . '/' . $file . '/screenshot.png';
89
+ if (is_file($screenshot)) {
90
+ $data['screenshot'] = $this->get_theme_url($file) . '/screenshot.png';
91
+ } else {
92
+ $data['screenshot'] = NEWSLETTER_URL . '/images/theme-screenshot.png';
93
+ }
94
+ $list[$file] = $data;
95
+ }
96
+ closedir($handle);
97
+ }
98
+ }
99
+
100
+
101
  return $list;
102
  }
103
 
131
  }
132
 
133
  function get_theme_url($theme) {
134
+ if ($this->is_extension) {
135
+ return WP_CONTENT_URL . '/extensions/newsletter/' . $this->module . '/themes/' . $theme;
136
+ }
137
+
138
  $path = NEWSLETTER_DIR . '/' . $this->module . '/themes/' . $theme;
139
  if (is_dir($path)) {
140
  return NEWSLETTER_URL . '/' . $this->module . '/themes/' . $theme;
141
+ } else {
 
142
  return WP_CONTENT_URL . '/extensions/newsletter/' . $this->module . '/themes/' . $theme;
143
  }
144
  }
145
 
146
  function get_default_options() {
147
+ if ($this->is_extension) {
148
+ $path2 = WP_CONTENT_DIR . '/extensions/newsletter/' . $this->module . '/themes/' . $theme . '/languages';
149
+ @include $path2 . '/en_US.php';
150
+ @include $path2 . '/' . WPLANG . '.php';
151
+ } else {
152
+ $path1 = NEWSLETTER_DIR . '/' . $this->module . '/themes/' . $theme . '/languages';
153
+ $path2 = WP_CONTENT_DIR . '/extensions/newsletter/' . $this->module . '/themes/' . $theme . '/languages';
154
+ @include $path1 . '/en_US.php';
155
+ @include $path2 . '/en_US.php';
156
+ @include $path1 . '/' . WPLANG . '.php';
157
+ @include $path2 . '/' . WPLANG . '.php';
158
+ }
159
 
160
  if (!is_array($options)) return array();
161
  return $options;
diagnostic.php → main/diagnostic.php RENAMED
@@ -4,8 +4,8 @@
4
  $controls = new NewsletterControls();
5
 
6
  if ($controls->is_action('save')) {
7
- update_option('newsletter_log_level', $controls->data['log_level']);
8
- update_option('newsletter_diagnostic', $controls->data);
9
  $controls->messages = 'Loggin levels saved.';
10
  }
11
 
@@ -76,16 +76,14 @@ if ($controls->is_action('send_test')) {
76
 
77
 
78
  if ($r) $controls->messages .= 'Newsletter TEXT test email sent.<br />';
79
- else
80
- $controls->errors .= 'Newsletter TEXT test email NOT sent: try to change the sender data, remove the return path and the reply to settings.<br />';
81
 
82
  $text = '<p>This is a <strong>html</strong> email sent using the <i>sender data</i> set on Newsletter main setting.</p>';
83
  $text .= '<p>You should see some "mark up", like bold and italic characters.</p>';
84
  $text .= '<p>You should see it to come from the email address you set on basic Newsletter plugin setting.</p>';
85
  $r = $newsletter->mail($controls->data['test_email'], 'Newsletter: pure html email', $text);
86
  if ($r) $controls->messages .= 'Newsletter HTML test email sent.<br />';
87
- else
88
- $controls->errors .= 'Newsletter HTML test email NOT sent: try to change the sender data, remove the return path and the reply to settings.<br />';
89
 
90
 
91
  $text = array();
@@ -93,47 +91,43 @@ if ($controls->is_action('send_test')) {
93
  $text['text'] = 'This is a textual test email part sent using the sender data set on Newsletter main setting.';
94
  $r = $newsletter->mail($controls->data['test_email'], 'Newsletter: both textual and html email', $text);
95
  if ($r) $controls->messages .= 'Newsletter: both textual and html test email sent.<br />';
96
- else
97
- $controls->errors .= 'Newsletter both TEXT and HTML test email NOT sent: try to change the sender data, remove the return path and the reply to settings.<br />';
98
  }
99
 
100
  if (empty($controls->data)) $controls->data = get_option('newsletter_diagnostic');
101
-
102
  ?>
103
  <div class="wrap">
104
  <?php $help_url = 'http://www.satollo.net/plugins/newsletter/newsletter-diagnostic'; ?>
105
  <?php include NEWSLETTER_DIR . '/header.php'; ?>
106
 
107
- <h2>Newsletter Diagnostic</h2>
108
 
109
  <?php $controls->show(); ?>
110
 
 
111
  <p>
112
- If something is not working, here there are test procedures and diagnostic data. But before start take a little time to
113
- write down a list of modifications you coulf have made recently. Sender email or name? Return path? Reply to?
 
114
  </p>
 
115
 
116
  <form method="post" action="">
117
  <?php $controls->init(); ?>
118
 
119
  <h3>Test</h3>
120
- <table class="form-table">
121
- <tr>
122
- <th>Email test</th>
123
- <td>
124
- <?php $controls->text('test_email'); ?>
125
- <?php $controls->button('test_wp', 'Send an email with WordPress'); ?>
126
- <?php $controls->button('send_test', 'Send test emails to this address'); ?>
127
- <div class="hints">
128
- Some test emails will be sent to the specified address:<br />
129
- 1. One with the native mail functionality of WordPress as is, so the email should come fro wordpress@yourdomain.tld<br />
130
- 2. One with sender data/reply to/return path as configured on Newsletter main settings in TEXT format (some time those values can break the mail system)<br />
131
- 3. One with sender data/reply to/return path as configured on Newsletter main settings in HTML format (some time those values can break the mail system)<br />
132
- 4. One in multipart format (with html and text parts) managed directly by Newsletter
133
- </div>
134
- </td>
135
- </tr>
136
- </table>
137
 
138
  <h3>System Check and Upgrade</h3>
139
  <p>
@@ -144,52 +138,61 @@ if (empty($controls->data)) $controls->data = get_option('newsletter_diagnostic'
144
  <div id="tabs">
145
 
146
  <ul>
147
- <li><a href="#tabs-1">Modules and logging</a></li>
148
- <li><a href="#tabs-2">Sempahores and Crons</a></li>
149
  <li><a href="#tabs-4">System</a></li>
150
  <li><a href="#tabs-upgrade">Maintainance</a></li>
151
  </ul>
152
 
 
153
  <div id="tabs-1">
154
- <h4>Modules</h4>
155
 
156
- <p>Logs are store on wp-content/logs folder.</p>
157
-
158
- <?php $controls->log_level('log_level'); ?>
 
 
 
159
 
160
  <table class="widefat" style="width: auto">
161
  <thead>
162
  <tr>
163
- <th>Module</th>
164
- <th>Version</th>
165
  </tr>
166
  </thead>
167
- <!-- TODO: Should be a cicle of installed modules -->
168
  <tbody>
169
  <tr>
170
- <td>Main</td>
171
- <td><?php echo Newsletter::VERSION; ?></td>
172
- </tr>
173
- <tr>
174
- <td>Users</td>
175
- <td><?php echo NewsletterUsers::VERSION; ?></td>
176
- </tr>
177
- <tr>
178
- <td>Subscription</td>
179
- <td><?php echo NewsletterSubscription::VERSION; ?></td>
180
- </tr>
181
- <tr>
182
- <td>Newsletters</td>
183
- <td><?php echo NewsletterEmails::VERSION; ?></td>
184
  </tr>
185
  <tr>
186
- <td>Statistics</td>
187
- <td><?php echo NewsletterStatistics::VERSION; ?></td>
 
 
 
 
 
 
 
 
 
 
 
188
  </tr>
189
  </tbody>
190
  </table>
191
- <?php $controls->button('save', 'Save'); ?>
 
192
  </div>
 
 
193
  <div id="tabs-2">
194
  <h4>Semaphores</h4>
195
  <table class="widefat" style="width: auto">
@@ -222,7 +225,7 @@ if (empty($controls->data)) $controls->data = get_option('newsletter_diagnostic'
222
  <thead>
223
  <tr>
224
  <th>Function</th>
225
- <th>Runs in (seconds)</th>
226
  </tr>
227
  </thead>
228
 
@@ -233,30 +236,47 @@ if (empty($controls->data)) $controls->data = get_option('newsletter_diagnostic'
233
  </td>
234
  <td>
235
  <?php
236
- if (defined('DISABLE_WP_CRON') && DISABLE_WP_CRON)
237
- echo 'DISABLED. (really bad, see <a href="http://www.satollo.net/?p=2015" target="_tab">this page)</a>';
238
  else echo "ENABLED. (it's ok)";
239
  ?>
240
  </td>
241
  </tr>
 
242
  <tr>
243
  <td>
244
- Delivery Engine
245
  </td>
246
  <td>
247
  <?php
248
- $x = wp_next_scheduled('newsletter');
249
- if ($x === false) {
250
- echo 'Error! The delivery engine is off (it should never be off),';
251
- $controls->button('engine_on', 'Reactivate now');
 
 
 
 
 
 
 
 
 
 
 
252
  }
253
- echo 'next run on ';
254
- if ($x > 0) echo $x - time();
255
- echo ' seconds';
256
- if ($x < -1000)
257
- echo ' (not good, see <a href="http://www.satollo.net/?p=2015" target="_tab">this page)</a>)';
258
  ?>
 
 
 
 
 
 
 
 
 
259
  <?php $controls->button('trigger', 'Trigger now'); ?>
 
 
260
  </td>
261
  </tr>
262
  <tr>
@@ -264,20 +284,11 @@ if (empty($controls->data)) $controls->data = get_option('newsletter_diagnostic'
264
  Feed by Mail
265
  </td>
266
  <td>
267
- <?php
268
- $x = wp_next_scheduled('newsletter_feed');
269
- if ($x === false) {
270
- echo 'Not active';
271
- //$controls->button('engine_on', 'Reactivate now');
272
- } else {
273
- if ($x > 0) {
274
- echo 'Next run on ' . ($x - time()) . ' seconds';
275
- } else {
276
- echo 'Running now';
277
- }
278
- }
279
- ?>
280
  <?php //$controls->button('trigger_followup', 'Trigger now'); ?>
 
 
 
281
  </td>
282
  </tr>
283
  <tr>
@@ -285,25 +296,33 @@ if (empty($controls->data)) $controls->data = get_option('newsletter_diagnostic'
285
  Follow Up
286
  </td>
287
  <td>
288
- <?php
289
- $x = wp_next_scheduled('newsletter_followup');
290
- if ($x === false) {
291
- echo 'Not active';
292
- //$controls->button('engine_on', 'Reactivate now');
293
- } else {
294
- if ($x > 0) {
295
- echo 'Next run on ' . ($x - time()) . ' seconds';
296
- } else {
297
- echo 'Running now';
298
- }
299
- }
300
- ?>
301
- <?php $controls->button('trigger_followup', 'Trigger now'); ?>
 
 
 
 
 
 
302
  </td>
303
  </tr>
304
  </tbody>
305
  </table>
306
  </div>
 
 
307
  <div id="tabs-4">
308
  <h4>System parameters</h4>
309
 
@@ -328,6 +347,23 @@ if (empty($controls->data)) $controls->data = get_option('newsletter_diagnostic'
328
  <?php echo ini_get('max_execution_time'); ?> (seconds)
329
  </td>
330
  </tr>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
331
  <tr>
332
  <td>PHP Memory Limit</td>
333
  <td>
@@ -349,7 +385,7 @@ if (empty($controls->data)) $controls->data = get_option('newsletter_diagnostic'
349
  <tr>
350
  <td>Tables Prefix</td>
351
  <td>
352
- <?php echo $table_prefix; ?>
353
  </td>
354
  </tr>
355
  <tr>
@@ -368,8 +404,7 @@ if (empty($controls->data)) $controls->data = get_option('newsletter_diagnostic'
368
  else {
369
  foreach ($filters as &$filter) {
370
  foreach ($filter as &$entry) {
371
- if (is_array($entry['function']))
372
- echo get_class($entry['function'][0]) . '->' . $entry['function'][1];
373
  else echo $entry['function'];
374
  echo '<br />';
375
  }
@@ -386,12 +421,12 @@ if (empty($controls->data)) $controls->data = get_option('newsletter_diagnostic'
386
  $subscribe_permissions = fileperms(NEWSLETTER_DIR . '/do/subscribe.php');
387
  if ($index_permissions != $subscribe_permissions) {
388
  echo 'Plugin file permissions differ from blog index.php permissions, that may compromise the subscription process';
389
- }else {
390
  echo 'OK';
391
  }
392
  ?>
393
  </td>
394
- </tr>
395
  </tbody>
396
  </table>
397
 
@@ -404,7 +439,7 @@ if (empty($controls->data)) $controls->data = get_option('newsletter_diagnostic'
404
  <p>
405
  <?php $controls->button('upgrade', 'Force an upgrade'); ?>
406
  </p>
407
-
408
  <p>
409
  Restore al dismissed messages
410
  </p>
4
  $controls = new NewsletterControls();
5
 
6
  if ($controls->is_action('save')) {
7
+ update_option('newsletter_log_level', $controls->data['log_level']);
8
+ update_option('newsletter_diagnostic', $controls->data);
9
  $controls->messages = 'Loggin levels saved.';
10
  }
11
 
76
 
77
 
78
  if ($r) $controls->messages .= 'Newsletter TEXT test email sent.<br />';
79
+ else $controls->errors .= 'Newsletter TEXT test email NOT sent: try to change the sender data, remove the return path and the reply to settings.<br />';
 
80
 
81
  $text = '<p>This is a <strong>html</strong> email sent using the <i>sender data</i> set on Newsletter main setting.</p>';
82
  $text .= '<p>You should see some "mark up", like bold and italic characters.</p>';
83
  $text .= '<p>You should see it to come from the email address you set on basic Newsletter plugin setting.</p>';
84
  $r = $newsletter->mail($controls->data['test_email'], 'Newsletter: pure html email', $text);
85
  if ($r) $controls->messages .= 'Newsletter HTML test email sent.<br />';
86
+ else $controls->errors .= 'Newsletter HTML test email NOT sent: try to change the sender data, remove the return path and the reply to settings.<br />';
 
87
 
88
 
89
  $text = array();
91
  $text['text'] = 'This is a textual test email part sent using the sender data set on Newsletter main setting.';
92
  $r = $newsletter->mail($controls->data['test_email'], 'Newsletter: both textual and html email', $text);
93
  if ($r) $controls->messages .= 'Newsletter: both textual and html test email sent.<br />';
94
+ else $controls->errors .= 'Newsletter both TEXT and HTML test email NOT sent: try to change the sender data, remove the return path and the reply to settings.<br />';
 
95
  }
96
 
97
  if (empty($controls->data)) $controls->data = get_option('newsletter_diagnostic');
 
98
  ?>
99
  <div class="wrap">
100
  <?php $help_url = 'http://www.satollo.net/plugins/newsletter/newsletter-diagnostic'; ?>
101
  <?php include NEWSLETTER_DIR . '/header.php'; ?>
102
 
103
+ <h2>Diagnostic</h2>
104
 
105
  <?php $controls->show(); ?>
106
 
107
+ <div class="preamble">
108
  <p>
109
+ If something is not working, here are some test procedures and diagnostics. But before you try these,
110
+ write down any modifications or configuration changes that you may have made.
111
+ For example: Did you use sender email or name? What was the return path? What was the reply to?
112
  </p>
113
+ </div>
114
 
115
  <form method="post" action="">
116
  <?php $controls->init(); ?>
117
 
118
  <h3>Test</h3>
119
+ Email: <?php $controls->text('test_email'); ?>
120
+ <?php $controls->button('test_wp', 'Send an email with WordPress'); ?>
121
+ <?php $controls->button('send_test', 'Send few emails with Newsletter'); ?>
122
+ <div class="hints">
123
+ First test emailing with WordPress if it does not work you need to contact your provider. Test on different addresses.
124
+ <br>
125
+ Second test emailing with Newsletter. You must receive three distinct email in different formats.
126
+ <br>
127
+ If the WordPress test works but Newsletter test doesn't, check the main configuration and try to change the sender,
128
+ return path and reply to email addresses.
129
+ </div>
130
+
 
 
 
 
 
131
 
132
  <h3>System Check and Upgrade</h3>
133
  <p>
138
  <div id="tabs">
139
 
140
  <ul>
141
+ <li><a href="#tabs-1">Logging</a></li>
142
+ <li><a href="#tabs-2">Semaphores and Crons</a></li>
143
  <li><a href="#tabs-4">System</a></li>
144
  <li><a href="#tabs-upgrade">Maintainance</a></li>
145
  </ul>
146
 
147
+ <!-- LOGGING -->
148
  <div id="tabs-1">
 
149
 
150
+ <h4>Logging</h4>
151
+ <p>
152
+ The logging feature of Newsletter, when enabled, writes detailed information of the working
153
+ status inside some (so called) log files. Log files, one per module, are stored inside the folder
154
+ <code>wp-content/logs/newsletter</code>.
155
+ </p>
156
 
157
  <table class="widefat" style="width: auto">
158
  <thead>
159
  <tr>
160
+ <th>Name</th>
161
+ <th>Active since</th>
162
  </tr>
163
  </thead>
164
+
165
  <tbody>
166
  <tr>
167
+ <td>
168
+ Log level
169
+ </td>
170
+ <td>
171
+ <?php $controls->log_level('log_level'); ?>
172
+ </td>
 
 
 
 
 
 
 
 
173
  </tr>
174
  <tr>
175
+ <td>
176
+ Log folder
177
+ </td>
178
+ <td>
179
+ <?php
180
+ $dir = WP_CONTENT_DIR . '/logs/newsletter';
181
+ if (!is_dir($dir)) {
182
+ echo '<span class="newsletter-error-span">The log folder does not exists, no logging possible!</span>';
183
+ } else {
184
+ echo 'The log folder exists.';
185
+ }
186
+ ?>
187
+ </td>
188
  </tr>
189
  </tbody>
190
  </table>
191
+
192
+ <p><?php $controls->button('save', 'Save'); ?></p>
193
  </div>
194
+
195
+ <!-- SEMAPHORES -->
196
  <div id="tabs-2">
197
  <h4>Semaphores</h4>
198
  <table class="widefat" style="width: auto">
225
  <thead>
226
  <tr>
227
  <th>Function</th>
228
+ <th>Status</th>
229
  </tr>
230
  </thead>
231
 
236
  </td>
237
  <td>
238
  <?php
239
+ if (defined('DISABLE_WP_CRON') && DISABLE_WP_CRON) echo 'DISABLED. (really bad, see <a href="http://www.satollo.net/?p=2015" target="_tab">this page)</a>';
 
240
  else echo "ENABLED. (it's ok)";
241
  ?>
242
  </td>
243
  </tr>
244
+
245
  <tr>
246
  <td>
247
+ WordPress schedules
248
  </td>
249
  <td>
250
  <?php
251
+ $schedules = wp_get_schedules();
252
+ if (empty($schedules)) {
253
+ echo 'Really bad, no schedules found, missing even the WordPress default schedules!';
254
+ } else {
255
+ $found = false;
256
+
257
+ foreach ($schedules as $key=>&$data) {
258
+ if ($key == 'newsletter') $found = true;
259
+ echo $key . ' - ' . $data['interval'] . ' s<br>';
260
+
261
+ }
262
+
263
+ if (!$found) {
264
+ echo 'The "newsletter" schedule was not found, email delivery won\'t work.';
265
+ }
266
  }
 
 
 
 
 
267
  ?>
268
+ </td>
269
+ </tr>
270
+
271
+ <tr>
272
+ <td>
273
+ Delivery Engine
274
+ </td>
275
+ <td>
276
+ <?php echo NewsletterModule::format_scheduler_time('newsletter'); ?>
277
  <?php $controls->button('trigger', 'Trigger now'); ?>
278
+ <br>
279
+ If inactive or always in "running now" status your blog has a problem: <a href="http://www.satollo.net/?p=2015" target="_blank">read more here</a>.
280
  </td>
281
  </tr>
282
  <tr>
284
  Feed by Mail
285
  </td>
286
  <td>
287
+ <?php echo NewsletterModule::format_scheduler_time('newsletter_feed'); ?>
 
 
 
 
 
 
 
 
 
 
 
 
288
  <?php //$controls->button('trigger_followup', 'Trigger now'); ?>
289
+ <br>
290
+ This time is not necessarily when the email will be sent but when Feed by Mail does its check to see if
291
+ this is a planned day and if there is something to send.
292
  </td>
293
  </tr>
294
  <tr>
296
  Follow Up
297
  </td>
298
  <td>
299
+ <?php echo NewsletterModule::format_scheduler_time('newsletter_followup'); ?>
300
+ <br>
301
+ Indicates when the Follow Up system runs again (usually every hour) to check for new follow up to send out.
302
+ <?php //$controls->button('trigger_followup', 'Trigger now'); ?>
303
+ </td>
304
+ </tr>
305
+ <tr>
306
+ <td>
307
+ SendGrid bounce checking
308
+ </td>
309
+ <td>
310
+ <?php echo NewsletterModule::format_scheduler_time('newsletter_sendgrid_bounce'); ?>
311
+ </td>
312
+ </tr>
313
+ <tr>
314
+ <td>
315
+ MailJet bounce checking
316
+ </td>
317
+ <td>
318
+ <?php echo NewsletterModule::format_scheduler_time('newsletter_mailjet_bounce'); ?>
319
  </td>
320
  </tr>
321
  </tbody>
322
  </table>
323
  </div>
324
+
325
+ <!-- SYSTEM -->
326
  <div id="tabs-4">
327
  <h4>System parameters</h4>
328
 
347
  <?php echo ini_get('max_execution_time'); ?> (seconds)
348
  </td>
349
  </tr>
350
+ <tr>
351
+ <td>NEWSLETTER_MAX_EXECUTION_TIME</td>
352
+ <td>
353
+ <?php if (defined('NEWSLETTER_MAX_EXECUTION_TIME')) {
354
+ echo NEWSLETTER_MAX_EXECUTION_TIME . 'seconds';
355
+ } else {
356
+ echo 'Not set';
357
+ }
358
+ ?>
359
+ </td>
360
+ </tr>
361
+ <tr>
362
+ <td>NEWSLETTER_CRON_INTERVAL</td>
363
+ <td>
364
+ <?php echo NEWSLETTER_CRON_INTERVAL . 'seconds'; ?>
365
+ </td>
366
+ </tr>
367
  <tr>
368
  <td>PHP Memory Limit</td>
369
  <td>
385
  <tr>
386
  <td>Tables Prefix</td>
387
  <td>
388
+ <?php echo $wpdb->prefix; ?>
389
  </td>
390
  </tr>
391
  <tr>
404
  else {
405
  foreach ($filters as &$filter) {
406
  foreach ($filter as &$entry) {
407
+ if (is_array($entry['function'])) echo get_class($entry['function'][0]) . '->' . $entry['function'][1];
 
408
  else echo $entry['function'];
409
  echo '<br />';
410
  }
421
  $subscribe_permissions = fileperms(NEWSLETTER_DIR . '/do/subscribe.php');
422
  if ($index_permissions != $subscribe_permissions) {
423
  echo 'Plugin file permissions differ from blog index.php permissions, that may compromise the subscription process';
424
+ } else {
425
  echo 'OK';
426
  }
427
  ?>
428
  </td>
429
+ </tr>
430
  </tbody>
431
  </table>
432
 
439
  <p>
440
  <?php $controls->button('upgrade', 'Force an upgrade'); ?>
441
  </p>
442
+
443
  <p>
444
  Restore al dismissed messages
445
  </p>
main/index.php ADDED
@@ -0,0 +1,259 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ @include_once NEWSLETTER_INCLUDES_DIR . '/controls.php';
3
+
4
+ $controls = new NewsletterControls();
5
+
6
+ if ($controls->is_action('feed_enable')) {
7
+ delete_option('newsletter_feed_demo_disable');
8
+ $controls->messages = 'Feed by Mail demo panels enabled. On next page reload it will show up.';
9
+ }
10
+
11
+ if ($controls->is_action('feed_disable')) {
12
+ update_option('newsletter_feed_demo_disable', 1);
13
+ $controls->messages = 'Feed by Mail demo panel disabled. On next page reload it will disappear.';
14
+ }
15
+
16
+ ?>
17
+ <div class="wrap main-index">
18
+
19
+
20
+ <?php $help_url = 'http://www.satollo.net/plugins/newsletter'; ?>
21
+ <?php include NEWSLETTER_DIR . '/header.php'; ?>
22
+
23
+ <h2>Welcome and Support</h2>
24
+
25
+ <?php $controls->show(); ?>
26
+
27
+ <form method="post" action="">
28
+ <?php $controls->init(); ?>
29
+
30
+ <h3>Documentation?</h3>
31
+
32
+ <p>
33
+ With my horrible English, everything can be found starting from <a href="http://www.satollo.net/plugins/newsletter" target="_blank">Newsletter Official page</a>
34
+ and every configuration panel has some included documentation just to avoid the most common mistakes.
35
+ </p>
36
+
37
+ <h3>A few minutes to get the most from Newsletter</h3>
38
+
39
+ <ol>
40
+ <li>
41
+ <em>It (should) work!</em> Newsletter <strong>works out of the box</strong>, you should only
42
+ <a href="widgets.php"><strong>add the Newsletter Widget</strong></a> to the sidebar and subscriptions will start to get in.
43
+ </li>
44
+
45
+ <li>
46
+ <em>Subscription page.</em> If you feel more confortable with a <strong>subscription page</strong>, let Newsletter create one for you: on
47
+ the <a href="admin.php?page=newsletter_subscription_options">subscription configuration panel</a>. You can keep both the
48
+ widget and the page, of course.
49
+ </li>
50
+
51
+ <li>
52
+ <em>Translations.</em> The <strong>administrative panels</strong> are only in (my bad) English but any other public
53
+ message and label and button can be translated on <a href="admin.php?page=newsletter_subscription_options">subscription configuration panel</a>:
54
+ please <strong>explore it</strong>.
55
+ </li>
56
+
57
+ <li>
58
+ <em>More about subscription.</em> The subscription and unsubscription processes to a mailing
59
+ list <strong>must be clear</strong> to the blog owner. <a href="http://www.satollo.net/plugins/newsletter/subscription-module" target="_blank">You can find more on Satollo.net</a>.
60
+ </li>
61
+ </ol>
62
+
63
+ <h3>Something is not working (it could happen)</h3>
64
+
65
+ <ol>
66
+ <li>
67
+ <em>No emails are sent.</em> This is mostly a problem of your provider. <strong>Make a test</strong> using the instructions you find on
68
+ the diagnostic panel.
69
+ </li>
70
+ <li>
71
+ <em>I get a 500/fatal error during subscription.</em> This is mostly a problem of file permissions. On the diagnostic
72
+ panel there is a check and on
73
+ <a target="_blank" href="http://www.satollo.net/plugins/newsletter/subscription-module#errors">Satollo.net there are some solutions</a>.
74
+ </li>
75
+ </ol>
76
+
77
+ <h3>I want to create and send a newsletter</h3>
78
+
79
+ <ol>
80
+ <li>
81
+ <em>I want to create a newsletter.</em> Use the <a href="http://www.satollo.net/wp-admin/admin.php?page=newsletter_emails_index">newsletters panel</a>
82
+ <strong>choose a theme</strong>, preview, twick it if needed and create your message.
83
+ </li>
84
+ <li>
85
+ <em>I want to test my newsletter.</em> Save the newsletter and move to the
86
+ <a href="http://www.satollo.net/wp-admin/admin.php?page=newsletter_users_index">subscribers panel</a>.
87
+ Create some subscribers manually using your own email addresses and mark them as test subscribers. They will be
88
+ used for newsletter tests.
89
+ </li>
90
+ <li>
91
+ <em>I want to send my newsletter.</em> Simple, press the send button. The email is created and put on
92
+ <a href="http://www.satollo.net/plugins/newsletter/newsletter-delivery-engine" target="_blank">delivery engine queue</a>.
93
+ On newsletter list, it will be shown as "sending".
94
+ </li>
95
+ <li>
96
+ <em>The newsletter is going out too slowly.</em> The <a href="http://www.satollo.net/plugins/newsletter/newsletter-delivery-engine" target="_blank">delivery engine</a> sends
97
+ emails as quickly as configured, see the <a href="admin.php?page=newsletter_main_main">main
98
+ configuration panel</a>. Look at your provider documentation as well, since it surely has a hourly limit.
99
+ </li>
100
+ </ol>
101
+
102
+ <h3>Modules</h3>
103
+ <p>
104
+ Below is the list of available modules that can be used with Newsletter plugin. Some modules are the "core" part
105
+ of Newsletter and are automatically updated with Newsletter official updates. Other modules are extensions and
106
+ can be downloaded from <a href="http://www.satollo.net/downloads" target="_blank">www.satollo.net/downloads</a>.
107
+ Some of them are commercial and others are still under development (here for testers).
108
+ </p>
109
+
110
+ <table class="widefat" style="width: auto">
111
+ <thead>
112
+ <tr>
113
+ <th>Module</th>
114
+ <th>Version</th>
115
+ <th>Available version</th>
116
+ </tr>
117
+ </thead>
118
+ <!-- TODO: Should be a cicle of installed modules -->
119
+ <tbody>
120
+ <tr>
121
+ <td>
122
+ <a href="http://www.satollo.net/plugins/newsletter/reports-module" target="_blank">Reports</a>
123
+ <br><small>Extends the statistics system with a better report</small>
124
+ </td>
125
+ <?php if (class_exists('NewsletterReports')) { ?>
126
+ <td><?php echo NewsletterReports::instance()->version; ?></td>
127
+ <?php } else { ?>
128
+ <td>Not installed</td>
129
+ <?php } ?>
130
+ <td><?php echo NewsletterModule::get_available_version(34); ?></td>
131
+ </tr>
132
+ <tr>
133
+ <td>
134
+ <a href="http://www.satollo.net/plugins/newsletter/feed-by-mail-module" target="_blank">Feed by Mail (Demo)</a>
135
+ <br><small>Demostrative panels of the Feed by Mail module</small>
136
+ </td>
137
+ <?php if (get_option('newsletter_feed_demo_disable') != 1) { ?>
138
+ <td><?php $controls->button('feed_disable', 'Disable'); ?></td>
139
+ <?php } else { ?>
140
+ <td><?php $controls->button('feed_enable', 'Enable'); ?></td>
141
+ <?php } ?>
142
+ <td>&nbsp;</td>
143
+ </tr>
144
+ <tr>
145
+ <td>
146
+ <a href="http://www.satollo.net/plugins/newsletter/feed-by-mail-module" target="_blank">Feed by Mail</a>
147
+ <br><small>Automatically generate and send email with blog contents</small>
148
+ </td>
149
+ <?php if (NewsletterModule::extension_exists('feed') && class_exists('NewsletterFeed')) { ?>
150
+ <td><?php echo NewsletterFeed::instance()->version; ?></td>
151
+ <?php } else { ?>
152
+ <td>Not installed</td>
153
+ <?php } ?>
154
+ <td><?php echo NewsletterModule::get_available_version(35); ?></td>
155
+ </tr>
156
+ <tr>
157
+ <td>
158
+ <a href="http://www.satollo.net/plugins/newsletter/follow-up-module" target="_blank">Follow Up</a>
159
+ <br><small>Sends email series after a subscriber signs up</small>
160
+ </td>
161
+ <?php if (NewsletterModule::extension_exists('followup') && class_exists('NewsletterFollowup')) { ?>
162
+ <td><?php echo NewsletterFollowup::instance()->version; ?></td>
163
+ <?php } else { ?>
164
+ <td>Not installed</td>
165
+ <?php } ?>
166
+ <td><?php echo NewsletterModule::get_available_version(37); ?></td>
167
+ </tr>
168
+ <tr>
169
+ <td>
170
+ <a href="http://www.satollo.net/plugins/newsletter/facebook-up-module" target="_blank">Facebook</a>
171
+ <br><small>Newsletter sign up (easy) with Facebook</small>
172
+ </td>
173
+ <?php if (class_exists('NewsletterFacebook')) { ?>
174
+ <td><?php echo NewsletterFacebook::instance()->version; ?></td>
175
+ <?php } else { ?>
176
+ <td>Not installed</td>
177
+ <?php } ?>
178
+ <td><?php echo NewsletterModule::get_available_version(41); ?></td>
179
+ </tr>
180
+ <tr>
181
+ <td>
182
+ <a href="http://www.satollo.net/plugins/newsletter/sendgrid-up-module" target="_blank">SendGrid</a>
183
+ <br><small>Integrates with <a href="http://www.satollo.net/affiliate/sendgrid" target="_blank">SendGrid</a> SMTP and bounce report</small>
184
+ </td>
185
+ <?php if (class_exists('NewsletterSendgrid')) { ?>
186
+ <td><?php echo NewsletterSendgrid::instance()->version; ?></td>
187
+ <?php } else { ?>
188
+ <td>Not installed</td>
189
+ <?php } ?>
190
+ <td><?php echo NewsletterModule::get_available_version(40); ?></td>
191
+ </tr>
192
+ <tr>
193
+ <td>
194
+ <a href="http://www.satollo.net/plugins/newsletter/mailjet-module" target="_blank">MailJet</a>
195
+ <br><small>Integrates with MailJet SMTP service.
196
+ </td>
197
+ <?php if (class_exists('NewsletterMailjet')) { ?>
198
+ <td><?php echo NewsletterMailjet::instance()->version; ?></td>
199
+ <?php } else { ?>
200
+ <td>Not installed</td>
201
+ <?php } ?>
202
+ <td><?php echo NewsletterModule::get_available_version(38); ?></td>
203
+ </tr>
204
+ </tbody>
205
+ </table>
206
+
207
+
208
+ <h3>Support</h3>
209
+ <p>
210
+ There are few options to find or ask for support:
211
+ </p>
212
+ <ul>
213
+ <li><a href="http://www.satollo.net/plugins/newsletter" target="_blank">The official Newsletter page</a> contains information and links to documentation and FAQ</li>
214
+ <li><a href="http://www.satollo.net/forums/forum/newsletter-plugin" target="_blank">The official Newsletter forum</a> where to find solutions or create new requests</li>
215
+ <li><a href="http://www.satollo.net/tag/newsletter" target="_blank">Newsletter articles and comments</a> are a source of solutions</li>
216
+ <li>Only for <a href="http://www.satollo.net/membership" target="_blank">members</a> the <a href="http://www.satollo.net/support-form" target="_blank">support page</a>
217
+ <li>Write directly to me at stefano@satollo.net</li>
218
+ </ul>
219
+
220
+ <h3>Collaboration</h3>
221
+ <p>
222
+ Any kind of collaboration for this free plugin is welcome (of course). I set up a
223
+ <a href="http://www.satollo.net/plugins/newsletter/newsletter-collaboration" target="_blank">How to collaborate</a>
224
+ page.
225
+ </p>
226
+
227
+ <h3>Documentation</h3>
228
+ <p>
229
+ Below are the pages on www.satollo.net which document Newsletter. Since the site evolves, more pages can be available and
230
+ the full list is always up-to-date on main Newsletter page.
231
+ </p>
232
+
233
+ <ul>
234
+ <li><a href="http://www.satollo.net/plugins/newsletter" target="_blank">Official Newsletter page</a></li>
235
+ <li><a href="http://www.satollo.net/plugins/newsletter/newsletter-configuration" target="_blank">Main configuration</a></li>
236
+ <li><a href="http://www.satollo.net/plugins/newsletter/newsletter-diagnostic" target="_blank">Diagnostic</a></li>
237
+ <li><a href="http://www.satollo.net/plugins/newsletter/newsletter-faq" target="_blank">FAQ</a></li>
238
+ <li><a href="http://www.satollo.net/plugins/newsletter/newsletter-delivery-engine" target="_blank">Delivery Engine</a></li>
239
+
240
+
241
+ <li><a href="http://www.satollo.net/plugins/newsletter/subscription-module" target="_blank">Subscription Module</a></li>
242
+ <li><a href="http://www.satollo.net/plugins/newsletter/newsletter-forms" target="_blank">Subscription Forms</a></li>
243
+ <li><a href="http://www.satollo.net/plugins/newsletter/newsletter-preferences" target="_blank">Subscriber's preferences</a></li>
244
+
245
+ <li><a href="http://www.satollo.net/plugins/newsletter/newsletters-module" target="_blank">Newsletters Module</a></li>
246
+ <li><a href="http://www.satollo.net/plugins/newsletter/newsletter-themes" target="_blank">Themes</a></li>
247
+
248
+ <li><a href="http://www.satollo.net/plugins/newsletter/subscribers-module" target="_blank">Subscribers Module</a></li>
249
+ <li><a href="http://www.satollo.net/plugins/newsletter/statistics-module" target="_blank">Statistics Module</a></li>
250
+
251
+ <li><a href="http://www.satollo.net/plugins/newsletter/feed-by-mail-module" target="_blank">Feed by Mail Module</a></li>
252
+ <!--<li><a href="http://www.satollo.net/plugins/newsletter/follow-up-module" target="_blank">Follow Up Module</a></li>
253
+ -->
254
+ </ul>
255
+
256
+
257
+ </form>
258
+
259
+ </div>
main/languages/en_US.php CHANGED
@@ -10,8 +10,7 @@ $options = array(
10
  'reply_to'=>'',
11
  'sender_email'=>'newsletter@' . $sitename,
12
  'sender_name'=>get_option('blogname'),
13
- 'lock_message'=>'<div style="margin: 15px; padding: 15px; background-color: #ff9; border-color: 1px solid #000">
14
- This content is protected, only newsletter subscribers can access it. Subscribe now!
15
- [newsletter_form]
16
- </div>'
17
  );
10
  'reply_to'=>'',
11
  'sender_email'=>'newsletter@' . $sitename,
12
  'sender_name'=>get_option('blogname'),
13
+ 'editor' => 0,
14
+ 'lock_message'=>'<p>This content is protected, only newsletter subscribers can access it. Subscribe now!</p>
15
+ {subscription_form}'
 
16
  );
main.php → main/main.php RENAMED
@@ -11,7 +11,7 @@ if (!$controls->is_action()) {
11
  $wpdb->query("delete from " . $wpdb->prefix . "options where option_name like 'newsletter%'");
12
 
13
  $wpdb->query("drop table " . $wpdb->prefix . "newsletter, " . $wpdb->prefix . "newsletter_stats, " .
14
- $wpdb->prefix . "newsletter_emails, " . $wpdb->prefix . "newsletter_profiles, " .
15
  $wpdb->prefix . "newsletter_work");
16
 
17
  echo 'Newsletter plugin destroyed. Please, deactivate it now.';
@@ -107,7 +107,8 @@ if (!$controls->is_action()) {
107
  <div class="preamble">
108
  <p>
109
  Do not be scared by all those configurations. Only <strong>basic settings</strong> are important and should be reviewed to
110
- make Newsletter plugin to work correctly. If something seems to now work, run a test reading what you should expect from it.
 
111
  </p>
112
  </div>
113
 
@@ -126,29 +127,33 @@ if (!$controls->is_action()) {
126
  <div id="tabs-1">
127
 
128
  <!-- Main settings -->
129
-
130
- <p class="intro">
131
- Configurations on this sub panel can block emails sent by Newsletter Pro. It's not a plugin limit but odd restrictions imposed by
132
- hosting providers. It's advisable to careful read the detailed documentation you'll found under every options, specially on the "return path"
133
- field. Try different combination of setting below before send a support request and do it in this way: one single change - test - other single
134
- change - test, and so on. Thank you for your collaboration.
135
  </p>
 
136
 
137
  <table class="form-table">
138
 
139
  <tr valign="top">
140
- <th>Sender name and address</th>
141
  <td>
142
- email address (required): <?php $controls->text_email('sender_email', 40); ?>
143
- name (optional): <?php $controls->text('sender_name', 40); ?>
144
 
145
  <div class="hints">
146
- These are the name and email address a subscriber will see on emails he'll receive.
147
- Be aware that hosting providers can block email with a sender address not of the same domain of the blog.<br />
148
- For example, if your blog is www.myblog.com, using as sender email "info@myblog.com" or
149
- "newsletter@myblog.com" is safer than using "myaccount@gmail.com". The name is optional but is more professional
150
- to set it (even if some providers with bugged mail server do not send email with a sender name set as reported by
151
- a customer).
 
 
 
 
 
 
 
 
152
  </div>
153
  </td>
154
  </tr>
@@ -157,28 +162,20 @@ if (!$controls->is_action()) {
157
  <td>
158
  <?php $controls->text('scheduler_max', 5); ?>
159
  <div class="hints">
160
- The internal engine of Newsletter Pro sends email with the specified rate to stay under
161
- provider limits. The default value is 100 a very low value. The right value for you
162
- depends on your provider or server capacity.<br />
163
- Some examples. Hostgator: 500. Dreamhost: 100, asking can be raised to 200. Go Daddy: 1000 per day using their SMTP,
164
- unknown per hour rate. Gmail: 500 per day using their SMTP, unknown per hour rate.<br />
165
- My sites are on Hostgator or Linode VPS.<br />
166
- If you have a service with no limits on the number of emails, still PHP have memory and time limits. Newsletter Pro
167
- does it's best to detect those limits and to respect them so it can send out less emails per hour than excepted.
168
  </div>
169
  </td>
170
  </tr>
171
  <tr valign="top">
172
  <th>Return path</th>
173
  <td>
174
- <?php $controls->text_email('return_path', 40); ?> (valid email address)
175
  <div class="hints">
176
- This is the email address where delivery error messages are sent. Error message are sent back from mail systems when
177
- an email cannot be delivered to the receiver (full mailbox, unrecognized user and invalid address are the most common
178
- errors).<br />
179
- <strong>Some providers do not accept this field and block emails is present or if the email address has a
180
- different domain of the blog</strong> (see above the sender field notes). If you experience problem sending emails
181
- (just do some tests), try to leave it blank.
182
  </div>
183
  </td>
184
  </tr>
@@ -188,8 +185,9 @@ if (!$controls->is_action()) {
188
  <?php $controls->text_email('reply_to', 40); ?> (valid email address)
189
  <div class="hints">
190
  This is the email address where subscribers will reply (eg. if they want to reply to a newsletter). Leave it blank if
191
- you don't want to specify a different address from the sender email above. As for return path, come provider do not like this
192
- setting active.
 
193
  </div>
194
  </td>
195
  </tr>
@@ -237,7 +235,8 @@ if (!$controls->is_action()) {
237
  <td>
238
  <?php $controls->select('content_transfer_encoding', array('' => 'Default', '8bit' => '8 bit', 'base64' => 'Base 64')); ?>
239
  <div class="hints">
240
- Used only by some modules. Choose base64 to have chunked email body when server reports too long email line.
 
241
  </div>
242
  </td>
243
  </tr>
@@ -249,17 +248,21 @@ if (!$controls->is_action()) {
249
 
250
  <div id="tabs-5">
251
  <div class="tab-preamble">
 
 
 
 
252
  <p>
253
  To use an external SMTP (mail sending service), fill in the SMTP data and activate it. SMTP will be used for any
254
  messages sent by Newsletter (subscription messages and newsletters). SMTP is required to send email with Gmail or
255
  GoDaddy hosting account.
256
  Read more <a href="http://www.satollo.net/godaddy-using-smtp-external-server-on-shared-hosting" target="_blank">here</a>.
257
- Test button below sends an email to the first test address configured above and works even if SMTP is not enabled. If you get a "connection refused"
258
- message, check the SMTP settings if they are correct and then contact your hosting provider. If you get a "relay denied" contact your
259
  SMTP service provider.
260
  </p>
261
  <p>
262
- Consider <a href="http://sendgrid.tellapal.com/a/clk/3ZVbH7" target="_blank">SendGrid</a> for a serious and reliable SMTP service.
263
  </p>
264
  </div>
265
 
@@ -298,7 +301,7 @@ if (!$controls->is_action()) {
298
  SMTP test will be addressed to this email
299
  </div>
300
  </td>
301
- </tr>
302
  </table>
303
  <?php $controls->button('smtp_test', 'Test'); ?>
304
 
@@ -308,55 +311,44 @@ if (!$controls->is_action()) {
308
  <div id="tabs-3">
309
  <!-- Content locking -->
310
  <div class="tab-preamble">
311
- <p><a href="http://www.satollo.net/plugins/newsletter/newsletter-locked-content" target="_blank">Read more about locked content</a>.</p>
312
- <p>
313
- Content locking is a special feature that permits to "lock out" pieces of post content hiding them and unveiling
314
- them only to newsletter subscribers. I use it to hide special content on some post inviting the reader to subscribe the newsletter
315
- to read them.<br />
316
- Content on post can be hidden surrounding it with [newsletter_lock] and [/newsletter_lock] short codes.<br />
317
- A subscribe can see the hidden content after sign up or following a link on newsletters and welcome email generated by
318
- {unlock_url} tag. That link bring the user to the URL below that should be a single premium post/page where there is the hidden
319
- content or a list of premium posts with hidden content. The latter option can be implemented tagging all premium posts with a
320
- WordPress tag or adding them to a specific WordPress category.
321
- </p>
322
  </div>
323
  <table class="form-table">
 
 
 
 
 
 
 
 
 
 
324
  <tr valign="top">
325
  <th>Unlock destination URL</th>
326
  <td>
327
  <?php $controls->text('lock_url', 70); ?>
328
  <div class="hints">
329
  This is a web address (URL) where users are redirect when they click on unlocking URL ({unlock_url})
330
- inserted in newsletters and welcome message. Usually you will redirect the user on a URL with with locked content
331
- (that will become visible) or in a place with a list of link to premium content. I send them on a tag page
332
- (http://www.satollo.net/tag/reserved) since I tag every premium content with "reserved".
333
  </div>
334
  </td>
335
  </tr>
336
  <tr valign="top">
337
  <th>Denied content message</th>
338
  <td>
339
- <?php $controls->textarea('lock_message'); ?>
 
 
340
  <div class="hints">
341
  This message is shown in place of protected post or page content which is surrounded with
342
- [newsletter_lock] and [/newsletter_lock] short codes.<br />
343
- Use HTML to format the message. PHP code is accepted and executed. WordPress short codes provided
344
- by other plugins work as well. It's a good
345
- practice to add the short code [newsletter_embed] to show a subscription form so readers can sign
346
- up the newsletter directly.<br />
347
- You can also add a subscription HTML form right here, like:<br />
348
- <br />
349
- &lt;form&gt;<br />
350
- Your email: &lt;input type="text" name="ne"/&gt;<br />
351
- &lt;input type="submit" value="Subscribe now!"/&gt;<br />
352
- &lt;/form&gt;<br />
353
- <br />
354
- There is no need to specify a form method or action, Newsletter Pro will take care of. To give more evidence of your
355
- alternative content you can style it:<br />
356
- <br />
357
- &lt;div style="margin: 15px; padding: 15px; background-color: #ff9; border-color: 1px solid #000"&gt;<br />
358
- blah, blah, blah...<br />
359
- &lt;/div&gt;
360
  </div>
361
  </td>
362
  </tr>
11
  $wpdb->query("delete from " . $wpdb->prefix . "options where option_name like 'newsletter%'");
12
 
13
  $wpdb->query("drop table " . $wpdb->prefix . "newsletter, " . $wpdb->prefix . "newsletter_stats, " .
14
+ $wpdb->prefix . "newsletter_emails, " .
15
  $wpdb->prefix . "newsletter_work");
16
 
17
  echo 'Newsletter plugin destroyed. Please, deactivate it now.';
107
  <div class="preamble">
108
  <p>
109
  Do not be scared by all those configurations. Only <strong>basic settings</strong> are important and should be reviewed to
110
+ make Newsletter plugin work correctly. If something doesn't work, run a test from
111
+ <a href="admin.php?page=newsletter_main_diagnostic">diagnostic panel</a>.
112
  </p>
113
  </div>
114
 
127
  <div id="tabs-1">
128
 
129
  <!-- Main settings -->
130
+ <div class="tab-preamble">
131
+ <p>
 
 
 
 
132
  </p>
133
+ </div>
134
 
135
  <table class="form-table">
136
 
137
  <tr valign="top">
138
+ <th>Sender email address</th>
139
  <td>
140
+ <?php $controls->text_email('sender_email', 40); ?> (valid email address)
 
141
 
142
  <div class="hints">
143
+ Insert here the email address from which subscribers will se your email coming. Since this setting can
144
+ affect the reliability of delivery,
145
+ <a href="http://www.satollo.net/plugins/newsletter/newsletter-configuration#sender" target="_blank">read my notes here</a> (important).
146
+ Generally use an address within your domain name.
147
+ </div>
148
+ </td>
149
+ </tr>
150
+ <th>Sender name</th>
151
+ <td>
152
+ <?php $controls->text('sender_name', 40); ?> (optional)
153
+
154
+ <div class="hints">
155
+ Insert here the name which subscribers will see as the sender of your email (for example your blog or website's name). Since this setting can affect the reliability of delivery (usually under Windows)
156
+ <a href="http://www.satollo.net/plugins/newsletter/newsletter-configuration#sender" target="_blank">read my notes here</a>.
157
  </div>
158
  </td>
159
  </tr>
162
  <td>
163
  <?php $controls->text('scheduler_max', 5); ?>
164
  <div class="hints">
165
+ Newsletter delivery engine respects this limit and it should be set to a value less than the maximum allowed by your provider
166
+ (Hostgator: 500 per hour, Dreamhost: 100 per hour, Go Daddy: 1000 per day using their SMTP, Gmail: 500 per day).
167
+ Read <a href="http://www.satollo.net/plugins/newsletter/newsletter-delivery-engine" target="_blank">more on delivery engine</a> (important).
 
 
 
 
 
168
  </div>
169
  </td>
170
  </tr>
171
  <tr valign="top">
172
  <th>Return path</th>
173
  <td>
174
+ <?php $controls->text_email('return_path', 40); ?> (valid email address, default empty)
175
  <div class="hints">
176
+ Email address where delivery error messages are sent by mailing systems (eg. mailbox full, invalid address, ...).<br>
177
+ Some providers do not accept this field: they can block emails or force it to a different value affecting the delivery reliability.
178
+ <a href="http://www.satollo.net/plugins/newsletter/newsletter-configuration#return-path" target="_blank">Read my notes here</a> (important).
 
 
 
179
  </div>
180
  </td>
181
  </tr>
185
  <?php $controls->text_email('reply_to', 40); ?> (valid email address)
186
  <div class="hints">
187
  This is the email address where subscribers will reply (eg. if they want to reply to a newsletter). Leave it blank if
188
+ you don't want to specify a different address from the sender email above. Since this setting can
189
+ affect the reliability of delivery,
190
+ <a href="http://www.satollo.net/plugins/newsletter/newsletter-configuration#reply-to" target="_blank">read my notes here</a> (important).
191
  </div>
192
  </td>
193
  </tr>
235
  <td>
236
  <?php $controls->select('content_transfer_encoding', array('' => 'Default', '8bit' => '8 bit', 'base64' => 'Base 64')); ?>
237
  <div class="hints">
238
+ Sometimes setting it to Base 64 solves problem with old mail servers (for example truncated or unformatted emails.
239
+ <a href="http://www.satollo.net/plugins/newsletter/newsletter-configuration#enconding" target="_blank">Read more here</a>.
240
  </div>
241
  </td>
242
  </tr>
248
 
249
  <div id="tabs-5">
250
  <div class="tab-preamble">
251
+ <p>
252
+ <strong>These options can be overridden by modules which integrates with external
253
+ SMTPs (like MailJet, SendGrid, ...) if installed and activated.</strong>
254
+ </p>
255
  <p>
256
  To use an external SMTP (mail sending service), fill in the SMTP data and activate it. SMTP will be used for any
257
  messages sent by Newsletter (subscription messages and newsletters). SMTP is required to send email with Gmail or
258
  GoDaddy hosting account.
259
  Read more <a href="http://www.satollo.net/godaddy-using-smtp-external-server-on-shared-hosting" target="_blank">here</a>.
260
+ The "test" button below sends an email to the first test address configured above and works even if SMTP is not enabled. If you get a "connection refused"
261
+ message, check the SMTP settings if they are correct, then contact your hosting provider. If you get a "relay denied" contact your
262
  SMTP service provider.
263
  </p>
264
  <p>
265
+ Consider <a href="http://www.satollo.net/affiliate/sendgrid" target="_blank">SendGrid</a> for a serious and reliable SMTP service.
266
  </p>
267
  </div>
268
 
301
  SMTP test will be addressed to this email
302
  </div>
303
  </td>
304
+ </tr>
305
  </table>
306
  <?php $controls->button('smtp_test', 'Test'); ?>
307
 
311
  <div id="tabs-3">
312
  <!-- Content locking -->
313
  <div class="tab-preamble">
314
+ <p>
315
+ Please, <a href="http://www.satollo.net/plugins/newsletter/newsletter-locked-content" target="_blank">read more here how to use and configure</a>,
316
+ since it can incredibly increase your subscription rate.
317
+ </p>
 
 
 
 
 
 
 
318
  </div>
319
  <table class="form-table">
320
+ <tr valign="top">
321
+ <th>Tags or categories to lock</th>
322
+ <td>
323
+ <?php $controls->text('lock_ids', 70); ?>
324
+ <div class="hints">
325
+ Use tag or category slug or id, comma separated.
326
+ </div>
327
+ </td>
328
+ </tr>
329
+
330
  <tr valign="top">
331
  <th>Unlock destination URL</th>
332
  <td>
333
  <?php $controls->text('lock_url', 70); ?>
334
  <div class="hints">
335
  This is a web address (URL) where users are redirect when they click on unlocking URL ({unlock_url})
336
+ inserted in newsletters and welcome message.
 
 
337
  </div>
338
  </td>
339
  </tr>
340
  <tr valign="top">
341
  <th>Denied content message</th>
342
  <td>
343
+ <?php wp_editor( $controls->data['lock_message'], 'lock_message', array('textarea_name'=>'options[lock_message]') ); ?>
344
+
345
+ <?php //$controls->textarea('lock_message'); ?>
346
  <div class="hints">
347
  This message is shown in place of protected post or page content which is surrounded with
348
+ [newsletter_lock] and [/newsletter_lock] short codes or in place of the full content if they are
349
+ in categories or have tags as specified above.<br />
350
+ You can use the {subscription_form} tag to display the subscription form.<br>
351
+ <strong>Remeber to add the {unlock_url} on the welcome email so the user can unlock the content.</strong>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
352
  </div>
353
  </td>
354
  </tr>
plugin-menu.inc.php DELETED
@@ -1,45 +0,0 @@
1
- <?php
2
-
3
- $level = $this->options['editor'] ? 7 : 10;
4
-
5
- add_menu_page('Newsletter', 'Newsletter', $level, 'newsletter/welcome.php', '', '');
6
- //add_submenu_page('newsletter/welcome.php', 'User Guide', 'User Guide', $level, 'newsletter/main.php');
7
-
8
- add_submenu_page('newsletter/welcome.php', 'Welcome & Support', 'Welcome & Support', $level, 'newsletter/welcome.php');
9
-
10
- add_submenu_page('newsletter/welcome.php', 'Configuration', 'Configuration', $level, 'newsletter/main.php');
11
-
12
- add_submenu_page('newsletter/welcome.php', 'Subscription', 'Subscription', $level, 'newsletter/subscription/options.php');
13
- add_submenu_page(null, 'Subscription Form', 'Subscription Form', $level, 'newsletter/subscription/profile.php');
14
- add_submenu_page('newsletter/subscription/options.php', 'Forms', 'Forms', $level, 'newsletter/subscription/forms.php');
15
- add_submenu_page('newsletter/subscription/options.php', 'Forms', 'Forms', $level, 'newsletter/subscription/form-code.php');
16
-
17
- add_submenu_page('newsletter/welcome.php', 'Newsletters', 'Newsletters', $level, 'newsletter/emails/index.php');
18
- add_submenu_page(null, 'Email Edit', 'Email Edit', $level, 'newsletter/emails/old-emails.php');
19
- add_submenu_page(null, 'Email Edit', 'Email Edit', $level, 'newsletter/emails/old-edit.php');
20
-
21
- add_submenu_page(null, 'Email List', 'Email List', $level, 'newsletter/emails/list.php');
22
- add_submenu_page(null, 'Email New', 'Email New', $level, 'newsletter/emails/new.php');
23
- add_submenu_page(null, 'Email Edit', 'Email Edit', $level, 'newsletter/emails/edit.php');
24
- add_submenu_page(null, 'Email Theme', 'Email Theme', $level, 'newsletter/emails/theme.php');
25
-
26
- add_submenu_page(null, 'Email statistics', 'Email statistics', $level, 'newsletter/statistics/statistics-email.php');
27
-
28
- add_submenu_page('newsletter/welcome.php', 'Subscribers', 'Subscribers', $level, 'newsletter/users/index.php');
29
- add_submenu_page('newsletter/users/index.php', 'New subscriber', 'New subscriber', $level, 'newsletter/users/new.php');
30
- add_submenu_page('newsletter/users/index.php', 'Subscribers Edit', 'Subscribers Edit', $level, 'newsletter/users/edit.php');
31
- add_submenu_page('newsletter/users/index.php', 'Subscribers Statistics', 'Subscribers Statistics', $level, 'newsletter/users/stats.php');
32
- add_submenu_page('newsletter/users/index.php', 'Massive Management', 'Massive Management', $level, 'newsletter/users/massive.php');
33
- add_submenu_page('newsletter/users/index.php', 'Import', 'Import', $level, 'newsletter/users/import.php');
34
- add_submenu_page('newsletter/users/index.php', 'Export', 'Export', $level, 'newsletter/users/export.php');
35
-
36
- // Statistics
37
- //add_submenu_page('newsletter/welcome.php', 'Statistics', 'Statistics', $level, 'newsletter/statistics/statistics-index.php');
38
- //add_submenu_page('newsletter/statistics/statistics-index.php', 'Statistics', 'Statistics', $level, 'newsletter/statistics/statistics-view.php');
39
-
40
- // Updates
41
- //add_submenu_page('newsletter/welcome.php', 'Updates', 'Updates', $level, 'newsletter/updates/updates-index.php');
42
- //add_submenu_page('newsletter/updates/updates-index.php', 'Updates', 'Updates', $level, 'newsletter/updates/updates-edit.php');
43
- //add_submenu_page('newsletter/updates/updates-index.php', 'Updates', 'Updates', $level, 'newsletter/updates/updates-emails.php');
44
-
45
- ?>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
plugin.php CHANGED
@@ -3,8 +3,8 @@
3
  /*
4
  Plugin Name: Newsletter
5
  Plugin URI: http://www.satollo.net/plugins/newsletter
6
- Description: Newsletter is a cool plugin to create your own subscriber list, to send newsletters, to build your business. Please, do not update while the plugin is delivering a newsletter.
7
- Version: 3.0.9
8
  Author: Stefano Lissa
9
  Author URI: http://www.satollo.net
10
  Disclaimer: Use at your own risk. No warranty expressed or implied is provided.
@@ -13,7 +13,7 @@
13
  */
14
 
15
  // Useed as dummy parameter on css and js links
16
- define('NEWSLETTER_VERSION', '3.0.9');
17
 
18
  global $wpdb, $newsletter;
19
 
@@ -28,24 +28,15 @@ define('NEWSLETTER_SLUG', 'newsletter');
28
 
29
  define('NEWSLETTER_DIR', WP_PLUGIN_DIR . '/' . NEWSLETTER_SLUG);
30
  define('NEWSLETTER_INCLUDES_DIR', WP_PLUGIN_DIR . '/' . NEWSLETTER_SLUG . '/includes');
31
- define('NEWSLETTER_URL', WP_PLUGIN_URL . '/' . NEWSLETTER_SLUG);
32
- define('NEWSLETTER_SUBSCRIPTION_POPUP_URL', NEWSLETTER_URL . '/do/subscription-popup.php');
33
- define('NEWSLETTER_SUBSCRIBE_URL', NEWSLETTER_URL . '/do/subscribe.php');
34
- define('NEWSLETTER_SUBSCRIBE_POPUP_URL', NEWSLETTER_URL . '/do/subscribe-popup.php');
35
- define('NEWSLETTER_PROFILE_URL', NEWSLETTER_URL . '/do/profile.php');
36
- define('NEWSLETTER_SAVE_URL', NEWSLETTER_URL . '/do/save.php');
37
- define('NEWSLETTER_CONFIRM_URL', NEWSLETTER_URL . '/do/confirm.php');
38
- define('NEWSLETTER_CHANGE_URL', NEWSLETTER_URL . '/do/change.php');
39
- define('NEWSLETTER_UNLOCK_URL', NEWSLETTER_URL . '/do/unlock.php');
40
- define('NEWSLETTER_UNSUBSCRIBE_URL', NEWSLETTER_URL . '/do/unsubscribe.php');
41
- define('NEWSLETTER_UNSUBSCRIPTION_URL', NEWSLETTER_URL . '/do/unsubscription.php');
42
-
43
- define('NEWSLETTER_EMAIL_URL', NEWSLETTER_URL . '/do/view.php');
44
 
45
  if (!defined('NEWSLETTER_LIST_MAX')) define('NEWSLETTER_LIST_MAX', 20);
46
  if (!defined('NEWSLETTER_PROFILE_MAX')) define('NEWSLETTER_PROFILE_MAX', 20);
47
  if (!defined('NEWSLETTER_FORMS_MAX')) define('NEWSLETTER_FORMS_MAX', 10);
48
 
 
 
 
 
49
  // Force the whole system log level to this value
50
  //define('NEWSLETTER_LOG_LEVEL', 4);
51
 
@@ -56,8 +47,6 @@ require_once NEWSLETTER_INCLUDES_DIR . '/themes.php';
56
 
57
  class Newsletter extends NewsletterModule {
58
 
59
- const VERSION = '1.1.0';
60
-
61
  // Limits to respect to avoid memory, time or provider limits
62
  var $time_limit;
63
  var $email_limit = 10; // Per run, every 5 minutes
@@ -78,6 +67,7 @@ class Newsletter extends NewsletterModule {
78
  var $theme_excluded_categories; // comma separated ids (eventually negative to exclude)
79
  var $theme_posts; // WP_Query object
80
  // Secret key to create a unique log file name (and may be other)
 
81
  static $instance;
82
 
83
  /**
@@ -92,47 +82,69 @@ class Newsletter extends NewsletterModule {
92
 
93
  function __construct() {
94
  // Early possible
95
- $max_time = (int) (@ini_get('max_execution_time') * 0.9);
96
- if ($max_time == 0) $max_time = 600;
 
 
 
 
 
 
 
 
 
97
  $this->time_limit = time() + $max_time;
98
 
99
  // Here because the upgrade is called by the parent constructor and uses the scheduler
100
- add_filter('cron_schedules', array(&$this, 'hook_cron_schedules'), 1000);
101
 
102
- parent::__construct('main', self::VERSION);
103
 
104
  $max = $this->options['scheduler_max'];
105
  if (!is_numeric($max)) $max = 100;
106
  $this->max_emails = max(floor($max / 12), 1);
107
 
108
- add_action('init', array(&$this, 'hook_init'));
109
- add_action('newsletter', array(&$this, 'hook_newsletter'), 1);
110
 
111
  // This specific event is created by "Feed by mail" panel on configuration
112
- add_action('shutdown', array(&$this, 'hook_shutdown'));
113
 
114
  if (defined('DOING_CRON') && DOING_CRON) return;
115
 
116
  // TODO: Meditation on how to use those ones...
117
- //register_activation_hook(__FILE__, array(&$this, 'hook_activate'));
118
  //register_deactivation_hook(__FILE__, array(&$this, 'hook_deactivate'));
119
 
120
- add_action('admin_init', array(&$this, 'hook_admin_init'));
121
 
122
- add_action('wp_head', array(&$this, 'hook_wp_head'));
123
 
124
- add_shortcode('newsletter_lock', array(&$this, 'shortcode_newsletter_lock'));
125
- add_shortcode('newsletter_profile', array(&$this, 'shortcode_newsletter_profile'));
 
126
 
127
  if (is_admin()) {
128
- add_action('admin_menu', array(&$this, 'hook_admin_menu'));
129
- add_action('admin_head', array(&$this, 'hook_admin_head'));
 
 
 
 
 
 
 
 
 
 
130
  }
131
  }
132
 
133
  function upgrade() {
134
  global $wpdb, $charset_collate;
135
 
 
 
136
  $this->upgrade_query("create table if not exists " . $wpdb->prefix . "newsletter_emails (id int auto_increment, primary key (id)) $charset_collate");
137
  $this->upgrade_query("alter table " . $wpdb->prefix . "newsletter_emails add column message longtext");
138
  $this->upgrade_query("alter table " . $wpdb->prefix . "newsletter_emails add column message_text longtext");
@@ -148,11 +160,12 @@ class Newsletter extends NewsletterModule {
148
  $this->upgrade_query("alter table " . $wpdb->prefix . "newsletter_emails add column send_on int not null default 0");
149
  $this->upgrade_query("alter table " . $wpdb->prefix . "newsletter_emails add column track tinyint not null default 0");
150
  $this->upgrade_query("alter table " . $wpdb->prefix . "newsletter_emails add column editor tinyint not null default 0");
151
- $this->upgrade_query("alter table " . $wpdb->prefix . "newsletter_emails add column sex varchar(10) not null default ''");
152
- $this->upgrade_query("alter table " . $wpdb->prefix . "newsletter_emails change column sex sex varchar(10) not null default ''");
153
 
154
  $this->upgrade_query("alter table " . $wpdb->prefix . "newsletter_emails add column query text");
155
  $this->upgrade_query("alter table " . $wpdb->prefix . "newsletter_emails add column preferences text");
 
156
 
157
  // Cleans up old installations
158
  $this->upgrade_query("alter table " . $wpdb->prefix . "newsletter_emails drop column name");
@@ -162,6 +175,8 @@ class Newsletter extends NewsletterModule {
162
  // TODO: To be moved on users module.
163
  $this->upgrade_query("alter table " . $wpdb->prefix . "newsletter convert to character set utf8");
164
 
 
 
165
  // Some setting check to avoid the common support request for mis-configurations
166
  $options = $this->get_options();
167
 
@@ -174,6 +189,11 @@ class Newsletter extends NewsletterModule {
174
  $this->save_options($options);
175
  }
176
 
 
 
 
 
 
177
  if (empty($options['api_key'])) {
178
  $options['api_key'] = self::get_token();
179
  $this->save_options($options);
@@ -187,19 +207,21 @@ class Newsletter extends NewsletterModule {
187
  wp_clear_scheduled_hook('newsletter');
188
  wp_schedule_event(time() + 30, 'newsletter', 'newsletter');
189
 
190
- // $sql = 'create table if not exists ' . $wpdb->prefix . 'newsletter_profiles (
191
- // `newsletter_id` int NOT NULL,
192
- // `name` varchar (100) NOT NULL DEFAULT \'\',
193
- // `value` text,
194
- // primary key (newsletter_id, name)
195
- // ) DEFAULT charset=utf8';
196
-
197
  wp_mkdir_p(WP_CONTENT_DIR . '/extensions/newsletter');
198
  wp_mkdir_p(WP_CONTENT_DIR . '/cache/newsletter');
199
 
200
  return true;
201
  }
202
 
 
 
 
 
 
 
 
 
 
203
  /**
204
  * Returns a set of warnings about this installtion the suser should be aware of. Return an empty string
205
  * if there are no warnings.
@@ -220,14 +242,38 @@ class Newsletter extends NewsletterModule {
220
  }
221
  }
222
 
223
- // TODO: Remove almost anything...
224
  function hook_init() {
225
  global $cache_stop, $hyper_cache_stop, $wpdb;
226
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
227
 
228
- $action = $_REQUEST['na'];
229
  if (empty($action) || is_admin()) return;
230
 
 
231
  $cache_stop = true;
232
  $hyper_cache_stop = true;
233
 
@@ -236,11 +282,9 @@ class Newsletter extends NewsletterModule {
236
  die();
237
  }
238
 
239
- // Actions below need a user. This code loads the user checking parameter or cookies.
240
- $user = $this->check_user();
241
- if ($user == null) die('No user');
242
-
243
  if ($action == 'fu') {
 
 
244
  $wpdb->query("update " . $wpdb->prefix . "newsletter set followup=2 where id=" . $user->id);
245
  $options_followup = get_option('newsletter_followup');
246
  $this->message = $options_followup['unsubscribed_text'];
@@ -250,17 +294,14 @@ class Newsletter extends NewsletterModule {
250
 
251
  function is_admin_page() {
252
  // TODO: Use the module list to detect that...
253
- return strpos($_GET['page'], 'newsletter_') === 0 || strpos($_GET['page'], 'newsletter-statistics/') === 0 || strpos($_GET['page'], 'newsletter/') === 0 ||
254
- strpos($_GET['page'], 'newsletter-updates/') === 0 || strpos($_GET['page'], 'newsletter-flows/') === 0;
 
 
255
  }
256
 
257
  function hook_admin_init() {
258
- if ($this->is_admin_page()) {
259
- wp_enqueue_script('jquery-ui-tabs');
260
- wp_enqueue_script('media-upload');
261
- wp_enqueue_script('thickbox');
262
- wp_enqueue_style('thickbox');
263
- }
264
  }
265
 
266
  function hook_admin_head() {
@@ -270,14 +311,6 @@ class Newsletter extends NewsletterModule {
270
  }
271
  }
272
 
273
- function hook_admin_menu() {
274
- include 'plugin-menu.inc.php';
275
-
276
- do_action('newsletter_admin_menu');
277
-
278
- add_submenu_page('newsletter/welcome.php', 'Diagnostic', 'Diagnostic', $level, 'newsletter/diagnostic.php');
279
- }
280
-
281
  function hook_wp_head() {
282
  if (!empty($this->options['css'])) {
283
  echo "<style type='text/css'>\n";
@@ -308,21 +341,17 @@ class Newsletter extends NewsletterModule {
308
  $this->logger->debug('hook_newsletter> Starting');
309
 
310
  // Do not accept job activation before at least 4 minutes are elapsed from the last run.
311
- if (!$this->check_transient('engine', 240)) return;
312
 
313
  // Retrieve all email in "sending" status
314
  $emails = $wpdb->get_results("select * from " . NEWSLETTER_EMAILS_TABLE . " where status='sending' and send_on<" . time() . " order by id asc");
315
  $this->logger->debug('hook_newsletter> Emails found in sending status: ' . count($emails));
316
  foreach ($emails as &$email) {
317
  $this->logger->debug('hook_newsletter> Sending email ' . $email->id);
318
- if (!$this->send($email)) return;
319
- }
320
-
321
- // TODO: Manage the follow-up with Newsletter 3.0.
322
- if (defined('NEWSLETTER_FOLLOWUP_VERSION')) {
323
- //global $newsletter_followup;
324
- //$newsletter_followup->send();
325
  }
 
 
326
  }
327
 
328
  /**
@@ -344,7 +373,9 @@ class Newsletter extends NewsletterModule {
344
  $test = $users != null;
345
 
346
  if ($users == null) {
347
- if (empty($email->query)) $email->query = "select * from " . NEWSLETTER_EMAILS_TABLE . " where status='C'";
 
 
348
  $query = $email->query . " and id>" . $email->last_id . " order by id limit " . $this->max_emails;
349
  $users = $wpdb->get_results($query);
350
 
@@ -356,7 +387,7 @@ class Newsletter extends NewsletterModule {
356
 
357
  if (empty($users)) {
358
  $this->logger->info('No more users');
359
- $wpdb->query("update " . NEWSLETTER_EMAILS_TABLE . " set status='sent' where id=" . $email->id . " limit 1");
360
  return true;
361
  }
362
  }
@@ -380,17 +411,23 @@ class Newsletter extends NewsletterModule {
380
 
381
  $s = $this->replace($email->subject, $user);
382
 
 
 
 
 
 
 
 
 
 
 
 
 
383
  $this->mail($user->email, $s, array('html' => $m, 'text' => $mt), $headers);
384
 
385
  $this->email_limit--;
386
  }
387
 
388
- // TODO: Integrate the feed by mail
389
- if (defined('NEWSLETTER_FEED_VERSION')) {
390
- //global $newsletter_feed;
391
- //if ($email->type == 'feed') return $newsletter_feed->feed_send($email, $users);
392
- }
393
-
394
  return true;
395
  }
396
 
@@ -511,27 +548,44 @@ class Newsletter extends NewsletterModule {
511
  require_once ABSPATH . WPINC . '/class-smtp.php';
512
  $this->mailer = new PHPMailer();
513
 
514
- if ($this->options['smtp_enabled'] == 1) {
 
 
 
 
 
 
 
 
 
 
515
  $this->mailer->IsSMTP();
516
- $this->mailer->Host = $this->options['smtp_host'];
517
- if (!empty($this->options['smtp_port'])) $this->mailer->Port = (int) $this->options['smtp_port'];
518
 
519
- if (!empty($this->options['smtp_user'])) {
520
  $this->mailer->SMTPAuth = true;
521
- $this->mailer->Username = $this->options['smtp_user'];
522
- $this->mailer->Password = $this->options['smtp_pass'];
523
  }
524
  $this->mailer->SMTPKeepAlive = true;
525
- $this->mailer->SMTPSecure = $this->options['smtp_secure'];
 
 
526
  }
527
- else $this->mailer->IsMail();
528
 
529
- if (!empty($this->options['content_transfer_encoding'])) $this->mailer->Encoding = $this->options['content_transfer_encoding'];
 
 
530
 
531
  $this->mailer->CharSet = 'UTF-8';
532
  $this->mailer->From = $this->options['sender_email'];
533
- if (!empty($this->options['return_path'])) $this->mailer->Sender = $this->options['return_path'];
534
- if (!empty($this->options['reply_to'])) $this->mailer->AddReplyTo($this->options['reply_to']);
 
 
 
 
535
 
536
  $this->mailer->FromName = $this->options['sender_name'];
537
  }
@@ -543,7 +597,7 @@ class Newsletter extends NewsletterModule {
543
 
544
  function hook_cron_schedules($schedules) {
545
  $schedules['newsletter'] = array(
546
- 'interval' => 300, // seconds
547
  'display' => 'Newsletter'
548
  );
549
  return $schedules;
@@ -595,42 +649,48 @@ class Newsletter extends NewsletterModule {
595
  return $wpdb->get_row($wpdb->prepare("select * from " . $wpdb->prefix . "newsletter where id=%d and token=%s limit 1", $id, $token));
596
  }
597
 
598
- if ($this->options_main['wp_integration'] != 1) {
599
- return null;
600
- }
601
-
602
- get_currentuserinfo();
603
-
604
- // Retrieve the related newsletter user
605
- $user = $wpdb->get_row("select * from " . NEWSLETTER_USERS_TABLE . " where wp_user_id=" . $current_user->ID . " limit 1");
606
- // There is an email matching?
607
- if (empty($user)) {
608
- $user = $wpdb->get_row($wpdb->prepare("select * from " . NEWSLETTER_USERS_TABLE . " where email=%s limit 1", strtolower($current_user->user_email)));
609
- // If not found, create a new Newsletter user, else update the wp_user_id since this email must be linked
610
- // to the WP user email.
611
- if (empty($user)) {
612
- return null;
613
- //echo 'WP user not found';
614
- $user = array();
615
- $user['status'] = 'C';
616
- $user['wp_user_id'] = $current_user->ID;
617
- $user['token'] = $this->get_token();
618
- $user['email'] = strtolower($current_user->user_email);
619
-
620
- $id = $wpdb->insert(NEWSLETTER_USERS_TABLE, $user);
621
- $user = NewsletterUsers::instance()->get_user($id);
622
- } else {
623
- //echo 'WP user found via email';
624
- $wpdb->query($wpdb->prepare("update " . NEWSLETTER_USERS_TABLE . " set wp_user_id=" . $current_user->ID . ", email=%s", $current_user->user_email));
625
- }
626
- } else {
627
- //echo 'WP user found via id';
628
- }
629
-
630
- return $user;
 
 
 
 
631
  }
632
 
633
  function replace_date($text) {
 
 
634
  // Date processing
635
  $x = 0;
636
  while (($x = strpos($text, '{date_', $x)) !== false) {
@@ -645,14 +705,20 @@ class Newsletter extends NewsletterModule {
645
  /**
646
  * Replace any kind of newsletter placeholder in a text.
647
  */
648
- function replace($text, $user = null, $email_id = null) {
649
  global $wpdb;
650
 
651
- if (is_array($user)) $user = NewsletterUsers::instance()->get_user($user['id']);
 
 
 
 
 
 
652
  $text = str_replace('{home_url}', get_option('home'), $text);
 
653
  $text = str_replace('{blog_title}', get_option('blogname'), $text);
654
  $text = str_replace('{blog_description}', get_option('blogdescription'), $text);
655
- $text = str_replace('{date}', date_i18n(get_option('date_format')), $text);
656
 
657
  $text = $this->replace_date($text);
658
 
@@ -680,12 +746,12 @@ class Newsletter extends NewsletterModule {
680
  $text = str_replace('{profile_' . $i . '}', $user->$p, $text);
681
  }
682
 
683
- $profile = $wpdb->get_results("select name,value from " . $wpdb->prefix . "newsletter_profiles where newsletter_id=" . $user->id);
684
- foreach ($profile as $field) {
685
- $text = str_ireplace('{np_' . $field->name . '}', htmlspecialchars($field->value), $text);
686
- }
687
-
688
- $text = preg_replace('/\\{np_.+\}/i', '', $text);
689
 
690
  $base = (empty($this->options_main['url']) ? get_option('home') : $this->options_main['url']);
691
  $id_token = '&amp;ni=' . $user->id . '&amp;nt=' . $user->token;
@@ -722,11 +788,26 @@ class Newsletter extends NewsletterModule {
722
  // Profile fields change links
723
  $text = $this->replace_url($text, 'SET_SEX_MALE', NEWSLETTER_CHANGE_URL . '?nk=' . $nk . '&nf=sex&nv=m');
724
  $text = $this->replace_url($text, 'SET_SEX_FEMALE', NEWSLETTER_CHANGE_URL . '?nk=' . $nk . '&nf=sex&nv=f');
725
- $text = $this->replace_url($text, 'SET_FEED', NEWSLETTER_CHANGE_URL . '?nk=' . $nk . '&nf=feed');
 
726
  for ($i = 1; $i <= NEWSLETTER_LIST_MAX; $i++) {
727
- $text = $this->replace_url($text, 'SET_PREFERENCE_' . $i, NEWSLETTER_CHANGE_URL . '?nk=' . $nk . '&nf=preference_' . $i);
 
728
  }
729
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
730
  return $text;
731
  }
732
 
@@ -748,24 +829,55 @@ class Newsletter extends NewsletterModule {
748
  if ($this->mailer != null) $this->mailer->SmtpClose();
749
  }
750
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
751
  function shortcode_newsletter_lock($attrs, $content = null) {
752
  global $hyper_cache_stop, $cache_stop;
753
 
 
754
  $hyper_cache_stop = true;
755
  $cache_stop = true;
756
 
 
 
757
  $user = $this->check_user();
758
- if ($user != null && $user->status == 'C') {
759
  return do_shortcode($content);
760
  }
761
 
762
- $buffer = $this->options_main['lock_message'];
763
- ob_start();
764
- eval('?>' . $buffer . "\n");
765
- $buffer = ob_get_clean();
766
  // TODO: add the newsletter check on submit
767
  $buffer = str_ireplace('<form', '<form method="post" action="' . NEWSLETTER_SUBSCRIBE_URL . '"', $buffer);
768
- return do_shortcode($buffer);
 
 
 
 
 
769
  }
770
 
771
  function shortcode_newsletter_profile($attrs, $content) {
@@ -814,7 +926,7 @@ class Newsletter extends NewsletterModule {
814
 
815
  $message .= "token: " . $user->token . "\n" .
816
  "status: " . $user->status . "\n" .
817
- "\nYours, Newsletter Pro.";
818
 
819
  wp_mail(get_option('admin_email'), '[' . get_option('blogname') . '] ' . $subject, $message, "Content-type: text/plain; charset=UTF-8\n");
820
  }
@@ -826,7 +938,7 @@ class Newsletter extends NewsletterModule {
826
  $id = (int) $_REQUEST['ni'];
827
  $token = $_REQUEST['nt'];
828
  }
829
- $user = NewsletterUsers::instance()->get_user($id);
830
 
831
  if ($user == null || $token != $user->token) {
832
  if ($required) die('No subscriber found.');
@@ -835,45 +947,6 @@ class Newsletter extends NewsletterModule {
835
  return $user;
836
  }
837
 
838
- function add_menu_page($module, $page, $title) {
839
- //var_dump($this);
840
- //$this->menu_pages[] = array($module, $page, $title);
841
- $file = WP_CONTENT_DIR . '/extensions/newsletter/' . $module . '/' . $page . '.php';
842
- if (!is_file($file)) {
843
- $file = NEWSLETTER_DIR . '/' . $module . '/' . $page . '.php';
844
- }
845
- $name = 'newsletter_' . $module . '_' . $page;
846
- eval('function ' . $name . '(){global $newsletter;require \'' . $file . '\';}');
847
- add_submenu_page('newsletter/welcome.php', $title, $title, $this->options['editor'] ? 7 : 10, $name, $name);
848
- }
849
-
850
- function add_admin_page($module, $page, $title) {
851
-
852
- $file = WP_CONTENT_DIR . '/extensions/newsletter/' . $module . '/' . $page . '.php';
853
- if (!is_file($file)) {
854
- $file = NEWSLETTER_DIR . '/' . $module . '/' . $page . '.php';
855
- }
856
-
857
- $name = 'newsletter_' . $module . '_' . $page;
858
- eval('function ' . $name . '(){global $newsletter;require \'' . $file . '\';}');
859
- add_submenu_page(null, $title, $title, $this->options['editor'] ? 7 : 10, $name, $name);
860
- }
861
-
862
- function get_emails($type = null, $format = OBJECT) {
863
- global $wpdb;
864
- if ($type == null) {
865
- $list = $wpdb->get_results("select * from " . NEWSLETTER_EMAILS_TABLE . " order by id desc", $format);
866
- } else {
867
- $list = $wpdb->get_results($wpdb->prepare("select * from " . NEWSLETTER_EMAILS_TABLE . " where type=%s order by id desc", $type), $format);
868
- }
869
- if ($wpdb->last_error) {
870
- $this->logger->error($wpdb->last_error);
871
- return false;
872
- }
873
- if (empty($list)) return array();
874
- return $list;
875
- }
876
-
877
  function save_email($email) {
878
  return $this->store->save(NEWSLETTER_EMAILS_TABLE, $email);
879
  }
@@ -882,35 +955,10 @@ class Newsletter extends NewsletterModule {
882
  return $this->store->delete(NEWSLETTER_EMAILS_TABLE, $id);
883
  }
884
 
885
- function get_email($id, $format = OBJECT) {
886
- return $this->store->get_single(NEWSLETTER_EMAILS_TABLE, $id, $format);
887
- }
888
-
889
  function get_email_field($id, $field_name) {
890
  return $this->store->get_field(NEWSLETTER_EMAILS_TABLE, $id, $field_name);
891
  }
892
 
893
- /**
894
- * NEVER CHANGE THIS METHOD SIGNATURE, USER BY THIRD PARTY PLUGINS.
895
- *
896
- * Saves a new user on the database. Return false if the email (that must be unique) is already
897
- * there. For a new users set the token and creation time if not passed.
898
- *
899
- * @param type $user
900
- * @return type
901
- */
902
- function save_user($user, $return_format = OBJECT) {
903
- if (is_object($user)) $user = (array) $user;
904
- if (empty($user['id'])) {
905
- if (empty($user['token'])) $user['token'] = NewsletterModule::get_token();
906
- //if (empty($user['created'])) $user['created'] = time();
907
- // Database default
908
- //if (empty($user['status'])) $user['status'] = 'S';
909
- }
910
- // Due to the unique index on email field, this can fail.
911
- return $this->store->save(NEWSLETTER_USERS_TABLE, $user, $return_format);
912
- }
913
-
914
  /**
915
  * Returns a list of users marked as "test user".
916
  * @return array
@@ -919,36 +967,6 @@ class Newsletter extends NewsletterModule {
919
  return $this->store->get_all(NEWSLETTER_USERS_TABLE, "where test=1");
920
  }
921
 
922
- /** Returns the user identify by an id or an email. If $id_or_email is an object or an array, it is assumed it contains
923
- * the "id" attribute or key and that is used to load the user.
924
- *
925
- * @global type $wpdb
926
- * @param string|int|object|array $id_or_email
927
- * @param type $format
928
- * @return boolean
929
- */
930
- function get_user($id_or_email, $format = OBJECT) {
931
- global $wpdb;
932
-
933
- // To simplify the reaload of a user passing the user it self.
934
- if (is_object($id_or_email)) $id_or_email = $id_or_email->id;
935
- else if (is_array($id_or_email)) $id_or_email = $id_or_email['id'];
936
-
937
- $id_or_email = strtolower(trim($id_or_email));
938
-
939
- if (is_numeric($id_or_email)) {
940
- $r = $wpdb->get_row($wpdb->prepare("select * from " . NEWSLETTER_USERS_TABLE . " where id=%d limit 1", $id_or_email), $format);
941
- } else {
942
- $r = $wpdb->get_row($wpdb->prepare("select * from " . NEWSLETTER_USERS_TABLE . " where email=%s limit 1", $id_or_email), $format);
943
- }
944
-
945
- if ($wpdb->last_error) {
946
- $this->logger->error($wpdb->last_error);
947
- return false;
948
- }
949
- return $r;
950
- }
951
-
952
  function delete_user($id) {
953
  global $wpdb;
954
  $r = $this->store->delete(NEWSLETTER_USERS_TABLE, $id);
@@ -976,25 +994,45 @@ class Newsletter extends NewsletterModule {
976
 
977
  }
978
 
979
- // Newsletter will be always instantiated.
980
  $newsletter = Newsletter::instance();
981
 
982
- // Module loading
983
- require_once NEWSLETTER_DIR . '/users/users.php';
984
  require_once NEWSLETTER_DIR . '/subscription/subscription.php';
985
  require_once NEWSLETTER_DIR . '/emails/emails.php';
 
986
  require_once NEWSLETTER_DIR . '/statistics/statistics.php';
987
- //require_once NEWSLETTER_DIR . '/bounce/bounce.php';
988
- // Extended module loading
989
- //if (is_file(WP_CONTENT_DIR . '/newsletter/updates/updates.php')) {
990
- // require_once WP_CONTENT_DIR . '/newsletter/updates/updates.php';
991
- //}
992
- //if (is_file(WP_CONTENT_DIR . '/newsletter/followup/followup.php')) {
993
- // require_once WP_CONTENT_DIR . '/newsletter/followup/followup.php';
994
- //}
995
- //
996
  if (is_file(WP_CONTENT_DIR . '/extensions/newsletter/feed/feed.php')) {
997
  require_once WP_CONTENT_DIR . '/extensions/newsletter/feed/feed.php';
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
998
  }
999
 
1000
  require_once(dirname(__FILE__) . '/widget.php');
@@ -1002,29 +1040,16 @@ require_once(dirname(__FILE__) . '/widget.php');
1002
  register_activation_hook(__FILE__, 'newsletter_activate');
1003
 
1004
  function newsletter_activate() {
1005
- // TODO: May be it's better to declare an "activate" method?
1006
  Newsletter::instance()->upgrade();
1007
 
1008
- // Modules
1009
  NewsletterUsers::instance()->upgrade();
1010
  NewsletterEmails::instance()->upgrade();
1011
  NewsletterSubscription::instance()->upgrade();
1012
  NewsletterStatistics::instance()->upgrade();
1013
-
1014
- // Extended modules
1015
- //NewsletterUpdates::instance()->upgrade();
1016
- //NewsletterFollowup::instance()->upgrade();
1017
- // TODO: Scan for other modules or use the found modules above
1018
  }
1019
 
1020
  register_activation_hook(__FILE__, 'newsletter_deactivate');
1021
 
1022
  function newsletter_deactivate() {
1023
- // Newsletter::instance()->deactivate();
1024
- // NewsletterUsers::instance()->deactivate();
1025
- // NewsletterEmails::instance()->deactivate();
1026
- // NewsletterSubscription::instance()->deactivate();
1027
- // NewsletterStatistics::instance()->deactivate();
1028
- // NewsletterUpdates::instance()->deactivate();
1029
- // TODO: Scan for other modules or use the found modules above
1030
  }
 
3
  /*
4
  Plugin Name: Newsletter
5
  Plugin URI: http://www.satollo.net/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="http://www.satollo.net/plugins/newsletter#update">this page</a> to know what's changed.</strong>
7
+ Version: 3.2.3
8
  Author: Stefano Lissa
9
  Author URI: http://www.satollo.net
10
  Disclaimer: Use at your own risk. No warranty expressed or implied is provided.
13
  */
14
 
15
  // Useed as dummy parameter on css and js links
16
+ define('NEWSLETTER_VERSION', '3.2.3');
17
 
18
  global $wpdb, $newsletter;
19
 
28
 
29
  define('NEWSLETTER_DIR', WP_PLUGIN_DIR . '/' . NEWSLETTER_SLUG);
30
  define('NEWSLETTER_INCLUDES_DIR', WP_PLUGIN_DIR . '/' . NEWSLETTER_SLUG . '/includes');
 
 
 
 
 
 
 
 
 
 
 
 
 
31
 
32
  if (!defined('NEWSLETTER_LIST_MAX')) define('NEWSLETTER_LIST_MAX', 20);
33
  if (!defined('NEWSLETTER_PROFILE_MAX')) define('NEWSLETTER_PROFILE_MAX', 20);
34
  if (!defined('NEWSLETTER_FORMS_MAX')) define('NEWSLETTER_FORMS_MAX', 10);
35
 
36
+ if (!defined('NEWSLETTER_CRON_INTERVAL')) define('NEWSLETTER_CRON_INTERVAL', 300);
37
+
38
+ if (!defined('NEWSLETTER_HEADER')) define('NEWSLETTER_HEADER', true);
39
+
40
  // Force the whole system log level to this value
41
  //define('NEWSLETTER_LOG_LEVEL', 4);
42
 
47
 
48
  class Newsletter extends NewsletterModule {
49
 
 
 
50
  // Limits to respect to avoid memory, time or provider limits
51
  var $time_limit;
52
  var $email_limit = 10; // Per run, every 5 minutes
67
  var $theme_excluded_categories; // comma separated ids (eventually negative to exclude)
68
  var $theme_posts; // WP_Query object
69
  // Secret key to create a unique log file name (and may be other)
70
+ var $lock_found = false;
71
  static $instance;
72
 
73
  /**
82
 
83
  function __construct() {
84
  // Early possible
85
+ if (defined('NEWSLETTER_MAX_EXECUTION_TIME')) {
86
+ $max_time = NEWSLETTER_MAX_EXECUTION_TIME * 0.9;
87
+ @set_time_limit(NEWSLETTER_MAX_EXECUTION_TIME);
88
+ } else {
89
+ $max_time = (int) (@ini_get('max_execution_time') * 0.9);
90
+ }
91
+
92
+ if ($max_time == 0) {
93
+ $max_time = 60;
94
+ }
95
+
96
  $this->time_limit = time() + $max_time;
97
 
98
  // Here because the upgrade is called by the parent constructor and uses the scheduler
99
+ add_filter('cron_schedules', array($this, 'hook_cron_schedules'), 1000);
100
 
101
+ parent::__construct('main', '1.1.5');
102
 
103
  $max = $this->options['scheduler_max'];
104
  if (!is_numeric($max)) $max = 100;
105
  $this->max_emails = max(floor($max / 12), 1);
106
 
107
+ add_action('init', array($this, 'hook_init'));
108
+ add_action('newsletter', array($this, 'hook_newsletter'), 1);
109
 
110
  // This specific event is created by "Feed by mail" panel on configuration
111
+ add_action('shutdown', array($this, 'hook_shutdown'));
112
 
113
  if (defined('DOING_CRON') && DOING_CRON) return;
114
 
115
  // TODO: Meditation on how to use those ones...
116
+ register_activation_hook(__FILE__, array($this, 'hook_activate'));
117
  //register_deactivation_hook(__FILE__, array(&$this, 'hook_deactivate'));
118
 
119
+ add_action('admin_init', array($this, 'hook_admin_init'));
120
 
121
+ add_action('wp_head', array($this, 'hook_wp_head'));
122
 
123
+ add_shortcode('newsletter_lock', array($this, 'shortcode_newsletter_lock'));
124
+ add_filter('the_content', array($this, 'hook_the_content'), 99);
125
+ add_shortcode('newsletter_profile', array($this, 'shortcode_newsletter_profile'));
126
 
127
  if (is_admin()) {
128
+ add_action('admin_head', array($this, 'hook_admin_head'));
129
+ }
130
+ }
131
+
132
+ function hook_activate() {
133
+ // Ok, why? When the plugin is not active WordPress may remove the scheduled "newsletter" action because
134
+ // the every-five-minutes schedule named "newsletter" is not present.
135
+ // Since the activation does not forces an upgrade, that schedule must be reactivated here. It is activated on
136
+ // the upgrade method as well for the user which upgrade the plugin without deactivte it (many).
137
+ $time = wp_next_scheduled('newsletter');
138
+ if ($time === false) {
139
+ wp_schedule_event(time() + 30, 'newsletter', 'newsletter');
140
  }
141
  }
142
 
143
  function upgrade() {
144
  global $wpdb, $charset_collate;
145
 
146
+ parent::upgrade();
147
+
148
  $this->upgrade_query("create table if not exists " . $wpdb->prefix . "newsletter_emails (id int auto_increment, primary key (id)) $charset_collate");
149
  $this->upgrade_query("alter table " . $wpdb->prefix . "newsletter_emails add column message longtext");
150
  $this->upgrade_query("alter table " . $wpdb->prefix . "newsletter_emails add column message_text longtext");
160
  $this->upgrade_query("alter table " . $wpdb->prefix . "newsletter_emails add column send_on int not null default 0");
161
  $this->upgrade_query("alter table " . $wpdb->prefix . "newsletter_emails add column track tinyint not null default 0");
162
  $this->upgrade_query("alter table " . $wpdb->prefix . "newsletter_emails add column editor tinyint not null default 0");
163
+ $this->upgrade_query("alter table " . $wpdb->prefix . "newsletter_emails add column sex char(1) not null default ''");
164
+ $this->upgrade_query("alter table " . $wpdb->prefix . "newsletter_emails change column sex sex char(1) not null default ''");
165
 
166
  $this->upgrade_query("alter table " . $wpdb->prefix . "newsletter_emails add column query text");
167
  $this->upgrade_query("alter table " . $wpdb->prefix . "newsletter_emails add column preferences text");
168
+ $this->upgrade_query("alter table " . $wpdb->prefix . "newsletter_emails add column options longtext");
169
 
170
  // Cleans up old installations
171
  $this->upgrade_query("alter table " . $wpdb->prefix . "newsletter_emails drop column name");
175
  // TODO: To be moved on users module.
176
  $this->upgrade_query("alter table " . $wpdb->prefix . "newsletter convert to character set utf8");
177
 
178
+ $this->upgrade_query("update " . $wpdb->prefix . "newsletter set sex='n' where sex='' or sex=' '");
179
+
180
  // Some setting check to avoid the common support request for mis-configurations
181
  $options = $this->get_options();
182
 
189
  $this->save_options($options);
190
  }
191
 
192
+ if (empty($options['scheduler_max']) || !is_numeric($options['scheduler_max'])) {
193
+ $options['scheduler_max'] = 100;
194
+ $this->save_options($options);
195
+ }
196
+
197
  if (empty($options['api_key'])) {
198
  $options['api_key'] = self::get_token();
199
  $this->save_options($options);
207
  wp_clear_scheduled_hook('newsletter');
208
  wp_schedule_event(time() + 30, 'newsletter', 'newsletter');
209
 
 
 
 
 
 
 
 
210
  wp_mkdir_p(WP_CONTENT_DIR . '/extensions/newsletter');
211
  wp_mkdir_p(WP_CONTENT_DIR . '/cache/newsletter');
212
 
213
  return true;
214
  }
215
 
216
+ function admin_menu() {
217
+ // This adds the main menu page
218
+ add_menu_page('Newsletter', 'Newsletter', $this->options['editor'] ? 7 : 10, 'newsletter_main_index');
219
+
220
+ $this->add_menu_page('index', 'Welcome');
221
+ $this->add_menu_page('main', 'Configuration');
222
+ $this->add_menu_page('diagnostic', 'Diagnostic');
223
+ }
224
+
225
  /**
226
  * Returns a set of warnings about this installtion the suser should be aware of. Return an empty string
227
  * if there are no warnings.
242
  }
243
  }
244
 
 
245
  function hook_init() {
246
  global $cache_stop, $hyper_cache_stop, $wpdb;
247
 
248
+ if (!defined('NEWSLETTER_URL')) {
249
+ define('NEWSLETTER_URL', plugins_url('', __FILE__));
250
+ }
251
+
252
+ define('NEWSLETTER_SUBSCRIPTION_POPUP_URL', NEWSLETTER_URL . '/do/subscription-popup.php');
253
+ define('NEWSLETTER_SUBSCRIBE_URL', NEWSLETTER_URL . '/do/subscribe.php');
254
+ define('NEWSLETTER_SUBSCRIBE_POPUP_URL', NEWSLETTER_URL . '/do/subscribe-popup.php');
255
+ define('NEWSLETTER_PROFILE_URL', NEWSLETTER_URL . '/do/profile.php');
256
+ define('NEWSLETTER_SAVE_URL', NEWSLETTER_URL . '/do/save.php');
257
+ define('NEWSLETTER_CONFIRM_URL', NEWSLETTER_URL . '/do/confirm.php');
258
+ define('NEWSLETTER_CHANGE_URL', NEWSLETTER_URL . '/do/change.php');
259
+ define('NEWSLETTER_UNLOCK_URL', NEWSLETTER_URL . '/do/unlock.php');
260
+ define('NEWSLETTER_UNSUBSCRIBE_URL', NEWSLETTER_URL . '/do/unsubscribe.php');
261
+ define('NEWSLETTER_UNSUBSCRIPTION_URL', NEWSLETTER_URL . '/do/unsubscription.php');
262
+ define('NEWSLETTER_EMAIL_URL', NEWSLETTER_URL . '/do/view.php');
263
+
264
+ if (is_admin()) {
265
+ if ($this->is_admin_page()) {
266
+ wp_enqueue_script('jquery-ui-tabs');
267
+ wp_enqueue_script('media-upload');
268
+ wp_enqueue_script('thickbox');
269
+ wp_enqueue_style('thickbox');
270
+ }
271
+ }
272
 
273
+ $action = isset($_REQUEST['na']) ? $_REQUEST['na'] : '';
274
  if (empty($action) || is_admin()) return;
275
 
276
+ // TODO: Remove!
277
  $cache_stop = true;
278
  $hyper_cache_stop = true;
279
 
282
  die();
283
  }
284
 
 
 
 
 
285
  if ($action == 'fu') {
286
+ $user = $this->check_user();
287
+ if ($user == null) die('No user');
288
  $wpdb->query("update " . $wpdb->prefix . "newsletter set followup=2 where id=" . $user->id);
289
  $options_followup = get_option('newsletter_followup');
290
  $this->message = $options_followup['unsubscribed_text'];
294
 
295
  function is_admin_page() {
296
  // TODO: Use the module list to detect that...
297
+ if (!isset($_GET['page'])) return false;
298
+ $page = $_GET['page'];
299
+ return strpos($page, 'newsletter_') === 0 || strpos($page, 'newsletter-statistics/') === 0 || strpos($page, 'newsletter/') === 0 ||
300
+ strpos($page, 'newsletter-updates/') === 0 || strpos($page, 'newsletter-flows/') === 0;
301
  }
302
 
303
  function hook_admin_init() {
304
+
 
 
 
 
 
305
  }
306
 
307
  function hook_admin_head() {
311
  }
312
  }
313
 
 
 
 
 
 
 
 
 
314
  function hook_wp_head() {
315
  if (!empty($this->options['css'])) {
316
  echo "<style type='text/css'>\n";
341
  $this->logger->debug('hook_newsletter> Starting');
342
 
343
  // Do not accept job activation before at least 4 minutes are elapsed from the last run.
344
+ if (!$this->check_transient('engine', NEWSLETTER_CRON_INTERVAL)) return;
345
 
346
  // Retrieve all email in "sending" status
347
  $emails = $wpdb->get_results("select * from " . NEWSLETTER_EMAILS_TABLE . " where status='sending' and send_on<" . time() . " order by id asc");
348
  $this->logger->debug('hook_newsletter> Emails found in sending status: ' . count($emails));
349
  foreach ($emails as &$email) {
350
  $this->logger->debug('hook_newsletter> Sending email ' . $email->id);
351
+ if (!$this->send($email)) break;
 
 
 
 
 
 
352
  }
353
+ // Remove the semaphore so the delivery engine can be activated again
354
+ $this->delete_transient('engine');
355
  }
356
 
357
  /**
373
  $test = $users != null;
374
 
375
  if ($users == null) {
376
+ if (empty($email->query)) {
377
+ $email->query = "select * from " . NEWSLETTER_USERS_TABLE . " where status='C'";
378
+ }
379
  $query = $email->query . " and id>" . $email->last_id . " order by id limit " . $this->max_emails;
380
  $users = $wpdb->get_results($query);
381
 
387
 
388
  if (empty($users)) {
389
  $this->logger->info('No more users');
390
+ $wpdb->query("update " . NEWSLETTER_EMAILS_TABLE . " set status='sent', total=sent where id=" . $email->id . " limit 1");
391
  return true;
392
  }
393
  }
411
 
412
  $s = $this->replace($email->subject, $user);
413
 
414
+ if (isset($user->wp_user_id) && $user->wp_user_id != 0) {
415
+ $this->logger->debug('Have wp_user_id: ' . $user->wp_user_id);
416
+ $wp_user_email = $wpdb->get_var($wpdb->prepare("select user_email from $wpdb->users where id=%d limit 1", $user->wp_user_id));
417
+ if (!empty($wp_user_email)) {
418
+ $user->email = $wp_user_email;
419
+ $this->logger->debug('Email replaced with: ' . $user->email);
420
+ }
421
+ else {
422
+ $this->logger->debug('WP user has not an email?!');
423
+ }
424
+ }
425
+
426
  $this->mail($user->email, $s, array('html' => $m, 'text' => $mt), $headers);
427
 
428
  $this->email_limit--;
429
  }
430
 
 
 
 
 
 
 
431
  return true;
432
  }
433
 
548
  require_once ABSPATH . WPINC . '/class-smtp.php';
549
  $this->mailer = new PHPMailer();
550
 
551
+ $smtp_options = array();
552
+ $smtp_options['enabled'] = $this->options['smtp_enabled'];
553
+ $smtp_options['host'] = $this->options['smtp_host'];
554
+ $smtp_options['port'] = $this->options['smtp_port'];
555
+ $smtp_options['user'] = $this->options['smtp_user'];
556
+ $smtp_options['pass'] = $this->options['smtp_pass'];
557
+ $smtp_options['secure'] = $this->options['smtp_secure'];
558
+
559
+ $smtp_options = apply_filters('newsletter_smtp', $smtp_options);
560
+
561
+ if ($smtp_options['enabled'] == 1) {
562
  $this->mailer->IsSMTP();
563
+ $this->mailer->Host = $smtp_options['host'];
564
+ if (!empty($smtp_options['port'])) $this->mailer->Port = (int) $smtp_options['port'];
565
 
566
+ if (!empty($smtp_options['user'])) {
567
  $this->mailer->SMTPAuth = true;
568
+ $this->mailer->Username = $smtp_options['user'];
569
+ $this->mailer->Password = $smtp_options['pass'];
570
  }
571
  $this->mailer->SMTPKeepAlive = true;
572
+ $this->mailer->SMTPSecure = $smtp_options['secure'];
573
+ } else {
574
+ $this->mailer->IsMail();
575
  }
 
576
 
577
+ if (!empty($this->options['content_transfer_encoding'])) {
578
+ $this->mailer->Encoding = $this->options['content_transfer_encoding'];
579
+ }
580
 
581
  $this->mailer->CharSet = 'UTF-8';
582
  $this->mailer->From = $this->options['sender_email'];
583
+ if (!empty($this->options['return_path'])) {
584
+ $this->mailer->Sender = $this->options['return_path'];
585
+ }
586
+ if (!empty($this->options['reply_to'])) {
587
+ $this->mailer->AddReplyTo($this->options['reply_to']);
588
+ }
589
 
590
  $this->mailer->FromName = $this->options['sender_name'];
591
  }
597
 
598
  function hook_cron_schedules($schedules) {
599
  $schedules['newsletter'] = array(
600
+ 'interval' => NEWSLETTER_CRON_INTERVAL, // seconds
601
  'display' => 'Newsletter'
602
  );
603
  return $schedules;
649
  return $wpdb->get_row($wpdb->prepare("select * from " . $wpdb->prefix . "newsletter where id=%d and token=%s limit 1", $id, $token));
650
  }
651
 
652
+ return null;
653
+
654
+ /*
655
+ if ($this->options_main['wp_integration'] != 1) {
656
+ return null;
657
+ }
658
+
659
+ get_currentuserinfo();
660
+
661
+ // Retrieve the related newsletter user
662
+ $user = $wpdb->get_row("select * from " . NEWSLETTER_USERS_TABLE . " where wp_user_id=" . $current_user->ID . " limit 1");
663
+ // There is an email matching?
664
+ if (empty($user)) {
665
+ $user = $wpdb->get_row($wpdb->prepare("select * from " . NEWSLETTER_USERS_TABLE . " where email=%s limit 1", strtolower($current_user->user_email)));
666
+ // If not found, create a new Newsletter user, else update the wp_user_id since this email must be linked
667
+ // to the WP user email.
668
+ if (empty($user)) {
669
+ return null;
670
+ //echo 'WP user not found';
671
+ $user = array();
672
+ $user['status'] = 'C';
673
+ $user['wp_user_id'] = $current_user->ID;
674
+ $user['token'] = $this->get_token();
675
+ $user['email'] = strtolower($current_user->user_email);
676
+
677
+ $id = $wpdb->insert(NEWSLETTER_USERS_TABLE, $user);
678
+ $user = NewsletterUsers::instance()->get_user($id);
679
+ } else {
680
+ //echo 'WP user found via email';
681
+ $wpdb->query($wpdb->prepare("update " . NEWSLETTER_USERS_TABLE . " set wp_user_id=" . $current_user->ID . ", email=%s", $current_user->user_email));
682
+ }
683
+ } else {
684
+ //echo 'WP user found via id';
685
+ }
686
+
687
+ return $user;
688
+ */
689
  }
690
 
691
  function replace_date($text) {
692
+ $text = str_replace('{date}', date_i18n(get_option('date_format')), $text);
693
+
694
  // Date processing
695
  $x = 0;
696
  while (($x = strpos($text, '{date_', $x)) !== false) {
705
  /**
706
  * Replace any kind of newsletter placeholder in a text.
707
  */
708
+ function replace($text, $user = null, $email_id = null, $referrer = null) {
709
  global $wpdb;
710
 
711
+ $this->logger->debug('Replace start');
712
+ if (is_array($user)) {
713
+ $user = $this->get_user($user['id']);
714
+ }
715
+
716
+ $text = apply_filters('newsletter_replace', $text, $user_id, $email_id);
717
+
718
  $text = str_replace('{home_url}', get_option('home'), $text);
719
+ $text = str_replace('{blog_url}', get_option('home'), $text);
720
  $text = str_replace('{blog_title}', get_option('blogname'), $text);
721
  $text = str_replace('{blog_description}', get_option('blogdescription'), $text);
 
722
 
723
  $text = $this->replace_date($text);
724
 
746
  $text = str_replace('{profile_' . $i . '}', $user->$p, $text);
747
  }
748
 
749
+ // $profile = $wpdb->get_results("select name,value from " . $wpdb->prefix . "newsletter_profiles where newsletter_id=" . $user->id);
750
+ // foreach ($profile as $field) {
751
+ // $text = str_ireplace('{np_' . $field->name . '}', htmlspecialchars($field->value), $text);
752
+ // }
753
+ //
754
+ // $text = preg_replace('/\\{np_.+\}/i', '', $text);
755
 
756
  $base = (empty($this->options_main['url']) ? get_option('home') : $this->options_main['url']);
757
  $id_token = '&amp;ni=' . $user->id . '&amp;nt=' . $user->token;
788
  // Profile fields change links
789
  $text = $this->replace_url($text, 'SET_SEX_MALE', NEWSLETTER_CHANGE_URL . '?nk=' . $nk . '&nf=sex&nv=m');
790
  $text = $this->replace_url($text, 'SET_SEX_FEMALE', NEWSLETTER_CHANGE_URL . '?nk=' . $nk . '&nf=sex&nv=f');
791
+ $text = $this->replace_url($text, 'SET_FEED', NEWSLETTER_CHANGE_URL . '?nk=' . $nk . '&nv=1&nf=feed');
792
+ $text = $this->replace_url($text, 'UNSET_FEED', NEWSLETTER_CHANGE_URL . '?nk=' . $nk . '&nv=0&nf=feed');
793
  for ($i = 1; $i <= NEWSLETTER_LIST_MAX; $i++) {
794
+ $text = $this->replace_url($text, 'SET_PREFERENCE_' . $i, NEWSLETTER_CHANGE_URL . '?nk=' . $nk . '&nv=1&nf=preference_' . $i);
795
+ $text = $this->replace_url($text, 'UNSET_PREFERENCE_' . $i, NEWSLETTER_CHANGE_URL . '?nk=' . $nk . '&nv=0&nf=preference_' . $i);
796
  }
797
  }
798
+
799
+ if (strpos($text, '{subscription_form}') !== false) {
800
+ $text = str_replace('{subscription_form}', NewsletterSubscription::instance()->get_subscription_form($referrer), $text);
801
+ } else {
802
+ for ($i = 1; $i <= 10; $i++) {
803
+ if (strpos($text, "{subscription_form_$i}") !== false) {
804
+ $text = str_replace("{subscription_form_$i}", NewsletterSubscription::instance()->get_form($i), $text);
805
+ break;
806
+ }
807
+ }
808
+ }
809
+
810
+ $this->logger->debug('Replace end');
811
  return $text;
812
  }
813
 
829
  if ($this->mailer != null) $this->mailer->SmtpClose();
830
  }
831
 
832
+ function hook_the_content($content) {
833
+ global $post, $cache_stop;
834
+
835
+ if ($this->lock_found || !is_singular() || is_user_logged_in()) {
836
+ return $content;
837
+ }
838
+
839
+ if (!empty($this->options['lock_ids'])) {
840
+ $ids = explode(',', $this->options['lock_ids']);
841
+ }
842
+
843
+ if (!empty($ids) && (has_tag($ids) || in_category($ids) || in_array($post->post_name, $ids))) {
844
+ $cache_stop = true;
845
+ $user = $this->check_user();
846
+ if ($user == null || $user->status != 'C') {
847
+ $buffer = $this->replace($this->options['lock_message']);
848
+ return '<div class="newsletter-lock">' . do_shortcode($buffer) . '</div>';
849
+ }
850
+ }
851
+
852
+ return $content;
853
+ }
854
+
855
  function shortcode_newsletter_lock($attrs, $content = null) {
856
  global $hyper_cache_stop, $cache_stop;
857
 
858
+ $this->logger->debug('Lock short code start');
859
  $hyper_cache_stop = true;
860
  $cache_stop = true;
861
 
862
+ $this->lock_found = true;
863
+
864
  $user = $this->check_user();
865
+ if (is_user_logged_in() || ($user != null && $user->status == 'C')) {
866
  return do_shortcode($content);
867
  }
868
 
869
+ $buffer = $this->options['lock_message'];
870
+ // ob_start();
871
+ // eval('? >' . $buffer . "\n");
872
+ // $buffer = ob_get_clean();
873
  // TODO: add the newsletter check on submit
874
  $buffer = str_ireplace('<form', '<form method="post" action="' . NEWSLETTER_SUBSCRIBE_URL . '"', $buffer);
875
+ $buffer = $this->replace($buffer, null, null, 'lock');
876
+
877
+ $buffer = do_shortcode($buffer);
878
+ $this->logger->debug('Lock short code end');
879
+
880
+ return '<div class="newsletter-lock">' . $buffer . '</div>';
881
  }
882
 
883
  function shortcode_newsletter_profile($attrs, $content) {
926
 
927
  $message .= "token: " . $user->token . "\n" .
928
  "status: " . $user->status . "\n" .
929
+ "\nYours, Newsletter.";
930
 
931
  wp_mail(get_option('admin_email'), '[' . get_option('blogname') . '] ' . $subject, $message, "Content-type: text/plain; charset=UTF-8\n");
932
  }
938
  $id = (int) $_REQUEST['ni'];
939
  $token = $_REQUEST['nt'];
940
  }
941
+ $user = $this->get_user($id);
942
 
943
  if ($user == null || $token != $user->token) {
944
  if ($required) die('No subscriber found.');
947
  return $user;
948
  }
949
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
950
  function save_email($email) {
951
  return $this->store->save(NEWSLETTER_EMAILS_TABLE, $email);
952
  }
955
  return $this->store->delete(NEWSLETTER_EMAILS_TABLE, $id);
956
  }
957
 
 
 
 
 
958
  function get_email_field($id, $field_name) {
959
  return $this->store->get_field(NEWSLETTER_EMAILS_TABLE, $id, $field_name);
960
  }
961
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
962
  /**
963
  * Returns a list of users marked as "test user".
964
  * @return array
967
  return $this->store->get_all(NEWSLETTER_USERS_TABLE, "where test=1");
968
  }
969
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
970
  function delete_user($id) {
971
  global $wpdb;
972
  $r = $this->store->delete(NEWSLETTER_USERS_TABLE, $id);
994
 
995
  }
996
 
 
997
  $newsletter = Newsletter::instance();
998
 
 
 
999
  require_once NEWSLETTER_DIR . '/subscription/subscription.php';
1000
  require_once NEWSLETTER_DIR . '/emails/emails.php';
1001
+ require_once NEWSLETTER_DIR . '/users/users.php';
1002
  require_once NEWSLETTER_DIR . '/statistics/statistics.php';
1003
+
 
 
 
 
 
 
 
 
1004
  if (is_file(WP_CONTENT_DIR . '/extensions/newsletter/feed/feed.php')) {
1005
  require_once WP_CONTENT_DIR . '/extensions/newsletter/feed/feed.php';
1006
+ } else {
1007
+ if (get_option('newsletter_feed_demo_disable') != 1) {
1008
+ if (is_file(NEWSLETTER_DIR . '/feed/feed.php')) {
1009
+ require_once NEWSLETTER_DIR . '/feed/feed.php';
1010
+ }
1011
+ }
1012
+ }
1013
+
1014
+ if (is_file(WP_CONTENT_DIR . '/extensions/newsletter/updates/updates.php')) {
1015
+ require_once WP_CONTENT_DIR . '/extensions/newsletter/updates/updates.php';
1016
+ }
1017
+
1018
+ if (is_file(WP_CONTENT_DIR . '/extensions/newsletter/followup/followup.php')) {
1019
+ require_once WP_CONTENT_DIR . '/extensions/newsletter/followup/followup.php';
1020
+ }
1021
+
1022
+ if (is_file(WP_CONTENT_DIR . '/extensions/newsletter/reports/reports.php')) {
1023
+ require_once WP_CONTENT_DIR . '/extensions/newsletter/reports/reports.php';
1024
+ }
1025
+
1026
+ if (is_file(WP_CONTENT_DIR . '/extensions/newsletter/mailjet/mailjet.php')) {
1027
+ require_once WP_CONTENT_DIR . '/extensions/newsletter/mailjet/mailjet.php';
1028
+ }
1029
+
1030
+ if (is_file(WP_CONTENT_DIR . '/extensions/newsletter/sendgrid/sendgrid.php')) {
1031
+ require_once WP_CONTENT_DIR . '/extensions/newsletter/sendgrid/sendgrid.php';
1032
+ }
1033
+
1034
+ if (is_file(WP_CONTENT_DIR . '/extensions/newsletter/facebook/facebook.php')) {
1035
+ require_once WP_CONTENT_DIR . '/extensions/newsletter/facebook/facebook.php';
1036
  }
1037
 
1038
  require_once(dirname(__FILE__) . '/widget.php');
1040
  register_activation_hook(__FILE__, 'newsletter_activate');
1041
 
1042
  function newsletter_activate() {
 
1043
  Newsletter::instance()->upgrade();
1044
 
 
1045
  NewsletterUsers::instance()->upgrade();
1046
  NewsletterEmails::instance()->upgrade();
1047
  NewsletterSubscription::instance()->upgrade();
1048
  NewsletterStatistics::instance()->upgrade();
 
 
 
 
 
1049
  }
1050
 
1051
  register_activation_hook(__FILE__, 'newsletter_deactivate');
1052
 
1053
  function newsletter_deactivate() {
 
 
 
 
 
 
 
1054
  }
1055
+
readme.txt CHANGED
@@ -1,8 +1,8 @@
1
  === Newsletter ===
2
  Tags: newsletter,email,subscription,mass mail,list build,email marketing,direct mailing
3
  Requires at least: 3.0.0
4
- Tested up to: 3.5
5
- Stable tag: trunk
6
  Donate link: http://www.satollo.net/donations
7
 
8
  Add a real newsletter to your blog. In seconds. For free.
@@ -56,12 +56,121 @@ No screen shots are available at this time.
56
 
57
  == Changelog ==
58
 
59
- = 3.1.0 (not released) =
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
60
 
61
  * Added link to change preferences/sex from emails
62
  * Added tag reference on email composer
63
  * Added "negative" preference selection on email targeting
64
  * Improved the subscription during WordPress user registration
 
 
 
 
 
 
 
 
 
 
 
65
 
66
  = 3.0.9 =
67
 
@@ -275,7 +384,7 @@ should be done in this way:
275
 
276
  For example, when I released the version 3.0 of this plugin, I should have created
277
  a 3.0 folder inside the branches and fixed it when bug were reported. From time to
278
- time from that branch I should have created a tag, for example 3.0.4.
279
 
280
  Actually, to make this tag available it should have been reported on the readme.txt
281
  committed on the trunk.
1
  === Newsletter ===
2
  Tags: newsletter,email,subscription,mass mail,list build,email marketing,direct mailing
3
  Requires at least: 3.0.0
4
+ Tested up to: 3.5.1
5
+ Stable tag: 3.2.3
6
  Donate link: http://www.satollo.net/donations
7
 
8
  Add a real newsletter to your blog. In seconds. For free.
56
 
57
  == Changelog ==
58
 
59
+ = 3.2.3 =
60
+
61
+ * Added schedule list on Diagnostic panel
62
+ * Removed the enable/disable resubscription option
63
+ * Added a check for the delivery engine shutdown on some particular situations
64
+ * Revisited the WordPress registration integration
65
+ * Revisited the WordPress user import and moved on subscriber massive action panel
66
+ * Added links to new documentation chapter
67
+ * Removed a survived reference to an old table
68
+ * Reactivated the replacement of the {blog_url} tag
69
+ * Fixed the tracking code injection
70
+ * Fixed a default query generation for compatibility with 2.5 version
71
+ * Fixed the tag replacements when using the old forms
72
+
73
+ = 3.2.2 =
74
+
75
+ * Fixed the subscription options change problem during the upgrade
76
+ * English corrections by Rita Vaccaro
77
+ * Added the Feed by Mail demo module
78
+ * Added support for the Facebook module
79
+
80
+ = 3.2.1 =
81
+
82
+ * Fixed fatal error with old form formats
83
+
84
+ = 3.2.0 =
85
+
86
+ * Added hint() method to NewsletterControls
87
+ * Fixed the Newsletter::replace_date() to replace even the {date} tag without a format
88
+ * Added NewsletterModule::format_time_delta()
89
+ * Added NewsletterModule::format_scheduler_time
90
+ * Improved the diagnostic panel
91
+ * Fixed an error on subscription with old forms
92
+ * Fixed the unsubscription with old formats
93
+ * Fixed the confirmation for multiple calls
94
+ * Fixed user saving on new installation (column missing for followup module)
95
+ * Added compatibility code with domain remaping plugin
96
+ * Added a setting to let unsubscribed users to subscribe again
97
+ * Added the re-subscription option
98
+
99
+ = 3.1.9 =
100
+
101
+ * Added the NEWSLETTER_MAX_EXECUTION_TIME
102
+ * Added the NEWSLETTER_CRON_INTERVAL
103
+ * Improved the delivery engine performances
104
+ * Improved the newsletter list panel
105
+ * Change the subscription in case of unsubscribed, bounced or confirmed address with a configurable error message
106
+ * Some CSS review
107
+ * Fixed the unsubscription procedure with a check on user status
108
+ * Added Pint theme
109
+
110
+ = 3.1.7 =
111
+
112
+ * Added better support for Follow Up for Newsletter
113
+ * Fixed integration with Feed by Mail for Newsletter
114
+ * Fixed a bug on profile save
115
+ * Fixed a message about log folder on diagnostic panel
116
+ * Fixed the sex field on user creation
117
+
118
+ = 3.1.6 =
119
+
120
+ * Fixed the subscription form absent on some configurations
121
+
122
+ = 3.1.5 =
123
+
124
+ * Content locking deactivated if a user is logged in
125
+ * Added a button to create a newsletter dedicated page
126
+ * Added top message is the newsletter dedicated page is not configured
127
+ * Fixed the subscription process with the old "na" action
128
+ * Added a new option with wp registration integration
129
+ * Added the opt-in mode to wp registration integration
130
+
131
+ = 3.1.4 =
132
+
133
+ * Fixed a bug on post/page preview
134
+
135
+ = 3.1.3 =
136
+
137
+ * Added support for SendGrid Module
138
+ * Fixed a fatal error on new installations on emails.php
139
+
140
+ = 3.1.2 =
141
+
142
+ * Fixed the access control for editors
143
+ * Improved to the log system to block it when the log folder cannot be created
144
+ * Moved all menu voices to the new format
145
+ * Improved the diagnostic panel
146
+ * Added ability to send and email to not confirmed subscribers
147
+ * Fixed a problem with internal module versions
148
+
149
+ = 3.1.1 =
150
+
151
+ * Fixed the copy and delete buttons on newsletter list
152
+ * Removed the old trigger button on newsletter list
153
+ * Fixed the edit button on old user search
154
+ * Improved the module version checking
155
+ * Added the "unconfirm" button on massive subscriber management panel
156
+
157
+ = 3.1.0 =
158
 
159
  * Added link to change preferences/sex from emails
160
  * Added tag reference on email composer
161
  * Added "negative" preference selection on email targeting
162
  * Improved the subscription during WordPress user registration
163
+ * Fixed the preference saving from profile page
164
+ * Fixed the default value for the gender field to "n"
165
+ * Added loading of the Feed by Mail module
166
+ * Added loading of the Follow Up module
167
+ * Added loading of the MailJet module
168
+ * Changed the administrative page header
169
+ * Changed the subscriber list and search panel
170
+ * Improved the locked content feature
171
+ * Fixed the good bye email not using the standard email template
172
+ * Changed the diagnostics panel with module versions checking
173
+ * Fixed some code on NewsletterModule
174
 
175
  = 3.0.9 =
176
 
384
 
385
  For example, when I released the version 3.0 of this plugin, I should have created
386
  a 3.0 folder inside the branches and fixed it when bug were reported. From time to
387
+ time from that branch I should have created a tag, for example 3.0.4.
388
 
389
  Actually, to make this tag available it should have been reported on the readme.txt
390
  committed on the trunk.
statistics/index.php CHANGED
@@ -12,43 +12,55 @@ if ($controls->is_action('save')) {
12
 
13
  <div class="wrap">
14
  <?php $help_url = 'http://www.satollo.net/plugins/newsletter/statistics-module'; ?>
 
15
  <?php include NEWSLETTER_DIR . '/header.php'; ?>
16
- <h2>Statistics Module</h2>
17
- <p><em>This is a brief introduction waiting for an official page.</em></p>
 
 
 
18
  <p>
19
- The Newsletter Statistics Module adds to Newsletter the ability to collect messages opening and link clicks on
20
- those messages.
21
  </p>
22
  <p>
23
- Statistic data is collected per email, so on panels listing emals there should always be a "statistics" button
24
- which leads to the analytics panel for that email.
 
 
 
 
 
25
  </p>
26
 
27
- <h3>Summary of collected data</h3>
28
- <p><em>To do...</em></p>
29
  <table class="widefat" style="width: auto">
30
  <thead>
31
  <tr>
32
- <th>Parameter</th>
33
- <th>Value</th>
 
 
 
 
34
  </tr>
35
  </thead>
36
 
37
  <tbody>
38
- <tr>
39
- <td>Total email sent</td>
40
- <td>-</td>
41
- </tr>
42
- <tr>
43
- <td>Total clicks</td>
44
- <td>-</td>
45
- </tr>
46
- <tr>
47
- <td>Total unique users which read or clicked</td>
48
- <td>-</td>
49
- </tr>
 
 
 
50
  </tbody>
51
- </table>
52
-
53
-
54
  </div>
12
 
13
  <div class="wrap">
14
  <?php $help_url = 'http://www.satollo.net/plugins/newsletter/statistics-module'; ?>
15
+
16
  <?php include NEWSLETTER_DIR . '/header.php'; ?>
17
+
18
+ <h5>Statistics Module</h5>
19
+
20
+ <h2>Configuration and Email List</h2>
21
+
22
  <p>
23
+ This module is a core part of Newsletter that collects statistics about sent emails: how many have
24
+ been read, how many have been clicked and so on.
25
  </p>
26
  <p>
27
+ To see the statistics of each single email, you should click the "statistics" button
28
+ you will find near each message where they are listed (like on Newsletters panel). For your
29
+ convenience, below there is a list of each email sent by Newsletter till now.
30
+ </p>
31
+ <p>
32
+ A more advanced report for each email can be generated installing the Advanced Statistics Module
33
+ from <a href="http://www.satollo.net/downloads" target="_blank">this page</a>.
34
  </p>
35
 
 
 
36
  <table class="widefat" style="width: auto">
37
  <thead>
38
  <tr>
39
+ <th>Id</th>
40
+ <th>Subject</th>
41
+ <th>Date</th>
42
+ <th>Type</th>
43
+ <th>Status</th>
44
+ <th>&nbsp;</th>
45
  </tr>
46
  </thead>
47
 
48
  <tbody>
49
+ <?php foreach ($emails as &$email) { ?>
50
+ <tr>
51
+ <td><?php echo $email->id; ?></td>
52
+ <td><?php echo htmlspecialchars($email->subject); ?></td>
53
+ <td><?php echo $email->date; ?></td>
54
+ <td><?php echo $email->type; ?></td>
55
+ <td>
56
+ <?php echo $email->status; ?>
57
+ (<?php echo $email->sent; ?>/<?php echo $email->total; ?>)
58
+ </td>
59
+ <td>
60
+ <a class="button" href="<?php echo NewsletterStatistics::instance()->get_statistics_url($email->id); ?>">statistics</a>
61
+ </td>
62
+ </tr>
63
+ <?php } ?>
64
  </tbody>
65
+ </table>
 
 
66
  </div>
statistics/statistics.php CHANGED
@@ -19,12 +19,13 @@ class NewsletterStatistics extends NewsletterModule {
19
  }
20
 
21
  function __construct() {
22
- parent::__construct('statistics', self::VERSION);
23
  }
24
 
25
  function upgrade() {
26
  global $wpdb, $charset_collate;
27
 
 
28
 
29
  // This before table creation or update for compatibility
30
  $this->upgrade_query("alter table {$wpdb->prefix}newsletter_stats change column newsletter_id user_id int not null default 0");
@@ -47,10 +48,15 @@ class NewsletterStatistics extends NewsletterModule {
47
  $this->upgrade_query("alter table {$wpdb->prefix}newsletter_stats add column anchor varchar(200) not null default ''");
48
 
49
  // Stores the link of every email to create short links
50
- $this->upgrade_query("create table if not exists {$wpdb->prefix}newsletter_links (id int auto_increment, primary key (id)) $charset_collate");
51
- $this->upgrade_query("alter table {$wpdb->prefix}newsletter_links add column email_id int not null default 0");
52
- $this->upgrade_query("alter table {$wpdb->prefix}newsletter_links add column token varchar(10) not null default ''");
53
- $this->upgrade_query("alter table {$wpdb->prefix}newsletter_links add column text varchar(255) not null default ''");
 
 
 
 
 
54
  }
55
 
56
  function relink($text, $email_id, $user_id) {
@@ -66,8 +72,10 @@ class NewsletterStatistics extends NewsletterModule {
66
  function relink_callback($matches) {
67
  $href = str_replace('&amp;', '&', $matches[2]);
68
  // Do not replace the tracking or subscription/unsubscription links.
69
- if (strpos($href, '/newsletter/') !== false) return $matches[0];
70
- if (substr($href, 0, 1) == '#') return $matches[0];
 
 
71
 
72
  $anchor = '';
73
  if ($this->options['anchor'] == 1) {
@@ -85,7 +93,8 @@ class NewsletterStatistics extends NewsletterModule {
85
  }
86
 
87
  function get_statistics_url($email_id) {
88
- return 'admin.php?page=newsletter_statistics_view&amp;id=' . $email_id;
 
89
  }
90
 
91
  function get_read_count($email_id) {
@@ -96,15 +105,5 @@ class NewsletterStatistics extends NewsletterModule {
96
 
97
  }
98
 
99
- add_action('newsletter_admin_menu', 'newsletter_statistics_admin_menu');
100
-
101
- /**
102
- * Add menu pages for this module.
103
- * @global Newsletter $newsletter
104
- */
105
- function newsletter_statistics_admin_menu() {
106
- global $newsletter;
107
- $newsletter->add_menu_page('statistics', 'index', 'Statistics');
108
- $newsletter->add_admin_page('statistics', 'view', 'Statistics');
109
- }
110
 
19
  }
20
 
21
  function __construct() {
22
+ parent::__construct('statistics', self::VERSION, 34);
23
  }
24
 
25
  function upgrade() {
26
  global $wpdb, $charset_collate;
27
 
28
+ parent::upgrade();
29
 
30
  // This before table creation or update for compatibility
31
  $this->upgrade_query("alter table {$wpdb->prefix}newsletter_stats change column newsletter_id user_id int not null default 0");
48
  $this->upgrade_query("alter table {$wpdb->prefix}newsletter_stats add column anchor varchar(200) not null default ''");
49
 
50
  // Stores the link of every email to create short links
51
+ // $this->upgrade_query("create table if not exists {$wpdb->prefix}newsletter_links (id int auto_increment, primary key (id)) $charset_collate");
52
+ // $this->upgrade_query("alter table {$wpdb->prefix}newsletter_links add column email_id int not null default 0");
53
+ // $this->upgrade_query("alter table {$wpdb->prefix}newsletter_links add column token varchar(10) not null default ''");
54
+ // $this->upgrade_query("alter table {$wpdb->prefix}newsletter_links add column text varchar(255) not null default ''");
55
+ }
56
+
57
+ function admin_menu() {
58
+ $this->add_menu_page('index', 'Statistics');
59
+ $this->add_admin_page('view', 'Statistics');
60
  }
61
 
62
  function relink($text, $email_id, $user_id) {
72
  function relink_callback($matches) {
73
  $href = str_replace('&amp;', '&', $matches[2]);
74
  // Do not replace the tracking or subscription/unsubscription links.
75
+ if (strpos($href, '/newsletter/') !== false)
76
+ return $matches[0];
77
+ if (substr($href, 0, 1) == '#')
78
+ return $matches[0];
79
 
80
  $anchor = '';
81
  if ($this->options['anchor'] == 1) {
93
  }
94
 
95
  function get_statistics_url($email_id) {
96
+ $page = apply_filters('newsletter_statistics_view', 'newsletter_statistics_view');
97
+ return 'admin.php?page=' . $page . '&amp;id=' . $email_id;
98
  }
99
 
100
  function get_read_count($email_id) {
105
 
106
  }
107
 
108
+ NewsletterStatistics::instance();
 
 
 
 
 
 
 
 
 
 
109
 
statistics/view.php CHANGED
@@ -1,31 +1,38 @@
1
  <?php
2
  $module = NewsletterStatistics::instance();
3
- $email = Newsletter::instance()->get_email($_GET['id']);
4
  ?>
5
  <div class="wrap">
6
  <?php $help_url = 'http://www.satollo.net/plugins/newsletter/statistics-module'; ?>
7
  <?php include NEWSLETTER_DIR . '/header.php'; ?>
8
 
9
- <h2>Statistics Module</h2>
10
 
11
- <h3><?php echo esc_html($email->subject); ?></h3>
 
 
 
 
 
 
 
12
 
13
  <table class="widefat" style="width: auto">
14
  <thead>
15
  <tr>
16
- <td>Field</td>
17
- <td>Value</td>
18
  </tr>
19
  </thead>
20
 
21
  <tbody>
22
  <tr>
23
- <td>Total sent</td>
24
- <td><?php echo $email->sent; ?></td>
25
  </tr>
26
  <tr>
27
- <td>Email open</td>
28
- <td><?php echo $module->get_read_count($email->id); ?></td>
29
  </tr>
30
  </tbody>
31
  </table>
1
  <?php
2
  $module = NewsletterStatistics::instance();
3
+ $email = $module->get_email($_GET['id']);
4
  ?>
5
  <div class="wrap">
6
  <?php $help_url = 'http://www.satollo.net/plugins/newsletter/statistics-module'; ?>
7
  <?php include NEWSLETTER_DIR . '/header.php'; ?>
8
 
9
+ <h5>Statistics Module</h5>
10
 
11
+ <h2>Statistics for "<?php echo esc_html($email->subject); ?>"</h2>
12
+
13
+ <div class="preamble">
14
+ <p>
15
+ Complete statistics for this email are available with
16
+ <a href="http://www.satollo.net/plugins/newsletter/reports-module-for-newsletter" target="_blank">Reports for Newsletter</a>.
17
+ </p>
18
+ </div>
19
 
20
  <table class="widefat" style="width: auto">
21
  <thead>
22
  <tr>
23
+ <td>Field</td>
24
+ <td>Value</td>
25
  </tr>
26
  </thead>
27
 
28
  <tbody>
29
  <tr>
30
+ <td>Total sent</td>
31
+ <td><?php echo $email->sent; ?></td>
32
  </tr>
33
  <tr>
34
+ <td>Email open</td>
35
+ <td><?php echo $module->get_read_count($email->id); ?></td>
36
  </tr>
37
  </tbody>
38
  </table>
subscription/email.php CHANGED
@@ -20,8 +20,7 @@ if (is_file(WP_CONTENT_DIR . '/extensions/newsletter/subscription/email.php')) {
20
  return;
21
  }
22
 
23
- ?>
24
- <!DOCTYPE html>
25
  <html>
26
  <head>
27
  <style type="text/css" media="all">
20
  return;
21
  }
22
 
23
+ ?><!DOCTYPE html>
 
24
  <html>
25
  <head>
26
  <style type="text/css" media="all">
subscription/forms.php CHANGED
@@ -1,6 +1,7 @@
1
  <?php
2
  @include_once NEWSLETTER_INCLUDES_DIR . '/controls.php';
3
  $controls = new NewsletterControls();
 
4
 
5
  if (!$controls->is_action()) {
6
  $controls->data = get_option('newsletter_forms');
@@ -17,6 +18,8 @@ if ($controls->is_action('save')) {
17
  <?php include NEWSLETTER_DIR . '/header.php'; ?>
18
 
19
  <?php include NEWSLETTER_DIR . '/subscription/menu.inc.php'; ?>
 
 
20
 
21
  <?php $controls->show(); ?>
22
 
1
  <?php
2
  @include_once NEWSLETTER_INCLUDES_DIR . '/controls.php';
3
  $controls = new NewsletterControls();
4
+ $module = NewsletterSubscription::instance();
5
 
6
  if (!$controls->is_action()) {
7
  $controls->data = get_option('newsletter_forms');
18
  <?php include NEWSLETTER_DIR . '/header.php'; ?>
19
 
20
  <?php include NEWSLETTER_DIR . '/subscription/menu.inc.php'; ?>
21
+
22
+ <h2>Alternative Hand-Coded Forms</h2>
23
 
24
  <?php $controls->show(); ?>
25
 
subscription/languages/en_US.php CHANGED
@@ -11,7 +11,9 @@
11
  // langiage dependant.
12
 
13
  $options = array();
14
- $options['profile_text'] = '{profile_form}<p>If you want to cancel your subscription, <a href="{unsubscription_confirm_url}">click here</a></p>';
 
 
15
 
16
  // Subscription page introductory text (befor the subscription form)
17
  $options['subscription_text'] =
@@ -19,53 +21,59 @@ $options['subscription_text'] =
19
 
20
  // Message show after a subbscription request has made.
21
  $options['confirmation_text'] =
22
- "<p>You successfully subscribed to my newsletter.
23
- You'll receive in few minutes a confirmation email. Follow the link
24
- in it to confirm the subscription. If the email takes more than 15
25
- minutes to appear in your mailbox, check the spam folder.</p>";
 
26
 
27
  // Confirmation email subject (double opt-in)
28
  $options['confirmation_subject'] =
29
- "Confirm now your subscription to {blog_title}";
30
 
31
  // Confirmation email body (double opt-in)
32
  $options['confirmation_message'] =
33
  "<p>Hi {name},</p>
34
- <p>I received a subscription request for this email address. You can confirm it
35
- <a href=\"{subscription_confirm_url}\"><strong>clicking here</strong></a>.
36
- If you cannot click the link, use the following link:</p>
 
37
  <p>{subscription_confirm_url}</p>
38
- <p>If this subscription request has not been made from you, just ignore this message.</p>
39
- <p>Thank you.</p>";
 
 
 
 
40
 
41
 
42
  // Subscription confirmed text (after a user clicked the confirmation link
43
  // on the email he received
44
  $options['confirmed_text'] =
45
- "<p>Your subscription has been confirmed!
46
- Thank you {name}!</p>";
47
 
48
  $options['confirmed_subject'] =
49
  "Welcome aboard, {name}";
50
 
51
  $options['confirmed_message'] =
52
- "<p>The message confirm your subscription to {blog_title} newsletter.</p>
53
- <p>Thank you!</p>
54
- <p>If you want to cancel your unsubscription, <a href=\"{unsubscription_url}\">click here</a>, if you want to change your
55
- subscription data, <a href=\"{profile_url}\">click here</a>.</p>";
 
56
 
57
  // Unsubscription request introductory text
58
- $options['unsubscription_text'] =
59
- "<p>Please confirm you want to unsubscribe my newsletter
60
- <a href=\"{unsubscription_confirm_url}\">clicking here</a>.";
61
 
62
  // When you finally loosed your subscriber
63
  $options['unsubscribed_text'] =
64
- "<p>That make me cry, but I have removed your subscription...</p>";
65
 
66
  $options['unsubscribed_subject'] =
67
  "Goodbye, {name}";
68
 
69
  $options['unsubscribed_message'] =
70
- "<p>The message confirm your unsubscription to {blog_title} newsletter.</p>
71
- <p>Good bye!</p>";
 
 
11
  // langiage dependant.
12
 
13
  $options = array();
14
+ $options['profile_text'] = "{profile_form}<p>To cancel your subscription, <a href='{unsubscription_confirm_url}'>click here</a>.</p>";
15
+
16
+ $options['error_text'] = '<p>This subscription can\'t be completed, sorry. The email address is blocked or already subscribed. You should contact the owner to unlock that email address. Thank you.</p>';
17
 
18
  // Subscription page introductory text (befor the subscription form)
19
  $options['subscription_text'] =
21
 
22
  // Message show after a subbscription request has made.
23
  $options['confirmation_text'] =
24
+ "<p>You have successfully subscribed to the newsletter. You'll
25
+ receive a confirmation email in few minutes. Please follow the
26
+ link in it to confirm your subscription. If the email takes
27
+ more than 15 minutes to appear in your mailbox, please check
28
+ your spam folder.</p>";
29
 
30
  // Confirmation email subject (double opt-in)
31
  $options['confirmation_subject'] =
32
+ "Please confirm subscription - {blog_title} newsletter";
33
 
34
  // Confirmation email body (double opt-in)
35
  $options['confirmation_message'] =
36
  "<p>Hi {name},</p>
37
+ <p>A newsletter subscription request for this email address was
38
+ received. Please confirm it by clicking here. If you cannot
39
+ click the link, please use the following link.</p>
40
+
41
  <p>{subscription_confirm_url}</p>
42
+
43
+ <p>If you did not make this subscription request, just ignore this
44
+ message.</p>
45
+ <p>Thank you!<br>
46
+ <a href='{blog_url}'>{blog_url}</a></p>";
47
+
48
 
49
 
50
  // Subscription confirmed text (after a user clicked the confirmation link
51
  // on the email he received
52
  $options['confirmed_text'] =
53
+ "<p>Your subscription has been confirmed! Thank you {name}!</p>";
 
54
 
55
  $options['confirmed_subject'] =
56
  "Welcome aboard, {name}";
57
 
58
  $options['confirmed_message'] =
59
+ "<p>This message confirms your subscription to the {blog_title} newsletter.</p>
60
+ <p>Thank you!<br>
61
+ <a href='{blog_url}'>{blog_url}</a></p>
62
+ <p>To unsubscribe, <a href='{unsubscription_url}'>click here</a>. To change subscriber options,
63
+ <a href='{profile_url}'>click here</a>.</p>";
64
 
65
  // Unsubscription request introductory text
66
+ $options['unsubscription_text'] = "<p>Please confirm that you want to unsubscribe by <a href='{unsubscription_confirm_url}'>clicking here</a>.</p>";
 
 
67
 
68
  // When you finally loosed your subscriber
69
  $options['unsubscribed_text'] =
70
+ "<p>Your subscription has been deleted. Thank you.</p>";
71
 
72
  $options['unsubscribed_subject'] =
73
  "Goodbye, {name}";
74
 
75
  $options['unsubscribed_message'] =
76
+ "<p>This message confirms that you have unsubscribed from the {blog_title} newsletter.</p>
77
+ <p>You're welcome to sign up again anytime.</p>
78
+ <p>Thank you!<br>
79
+ <a href='{blog_url}'>{blog_url}</a></p>";
subscription/menu.inc.php CHANGED
@@ -1,7 +1,6 @@
1
- <h2>Subscription</h2>
2
  <div id="newsletter-nav">
3
- <a class="button" href="?page=newsletter/subscription/options.php">Subscription and unsubscription</a>
4
- <a class="button" href="?page=newsletter/subscription/profile.php">Form fields and layout</a>
5
- <!--<a class="button" href="?page=newsletter/subscription/form-code.php">The form code</a>-->
6
- <a class="button" href="?page=newsletter/subscription/forms.php">Other forms</a>
7
  </div>
1
+ <h5>Subscription Module</h5>
2
  <div id="newsletter-nav">
3
+ <a class="button" href="<?php echo $module->get_admin_page_url('options'); ?>">Subscription and unsubscription</a>
4
+ <a class="button" href="<?php echo $module->get_admin_page_url('profile'); ?>">Form fields and layout</a>
5
+ <a class="button" href="<?php echo $module->get_admin_page_url('forms'); ?>">Alternative forms</a>
 
6
  </div>
subscription/options.php CHANGED
@@ -10,7 +10,7 @@ if ($controls->is_action()) {
10
  if ($controls->is_action('save')) {
11
 
12
  $defaults = $module->get_default_options();
13
-
14
  if (empty($controls->data['profile_text'])) {
15
  $controls->data['profile_text'] = $defaults['profile_text'];
16
  }
@@ -23,11 +23,11 @@ if ($controls->is_action()) {
23
  if (empty($controls->data['confirmation_text'])) {
24
  $controls->data['confirmation_text'] = $defaults['confirmation_text'];
25
  }
26
-
27
  if (empty($controls->data['confirmation_subject'])) {
28
  $controls->data['confirmation_subject'] = $defaults['confirmation_subject'];
29
  }
30
-
31
  if (empty($controls->data['confirmation_message'])) {
32
  $controls->data['confirmation_message'] = $defaults['confirmation_message'];
33
  }
@@ -35,11 +35,11 @@ if ($controls->is_action()) {
35
  if (empty($controls->data['confirmed_text'])) {
36
  $controls->data['confirmed_text'] = $defaults['confirmed_text'];
37
  }
38
-
39
  if (empty($controls->data['confirmed_subject'])) {
40
  $controls->data['confirmed_subject'] = $defaults['confirmed_subject'];
41
  }
42
-
43
  if (empty($controls->data['confirmed_message'])) {
44
  $controls->data['confirmed_message'] = $defaults['confirmed_message'];
45
  }
@@ -54,34 +54,27 @@ if ($controls->is_action()) {
54
  $controls->messages = 'Saved.';
55
  }
56
 
57
- if ($controls->is_action('reset')) {
58
- $controls->data = $module->reset_options();
59
- }
60
-
61
- if ($controls->is_action('align_wp_users')) {
62
-
63
- NewsletterUsers::instance();
 
 
64
 
65
- // TODO: check if the user is already there
66
- $wp_users = $wpdb->get_results("select * from $wpdb->users");
67
- foreach ($wp_users as &$wp_user) {
68
- $module->logger->info('Adding a registered WordPress user (' . $wp_user->ID . ')');
69
- $nl_user = array();
70
- $nl_user['email'] = $module->normalize_email($wp_user->user_email);
71
- $nl_user['name'] = $wp_user->user_login;
72
- $nl_user['status'] = 'C';
73
- $nl_user['wp_user_id'] = $wp_user->ID;
74
 
75
- if (is_array($module->options['preferences'])) {
76
- foreach ($module->options['preferences'] as $p) {
77
- $nl_user['list_' . $p] = 1;
78
- }
79
- }
80
 
81
- NewsletterUsers::instance()->save_user($nl_user);
82
- }
83
- $controls->messages = 'Done.';
84
  }
 
85
  } else {
86
  $controls->data = get_option('newsletter', array());
87
 
@@ -121,21 +114,23 @@ if ($controls->is_action()) {
121
 
122
  <?php include NEWSLETTER_DIR . '/subscription/menu.inc.php'; ?>
123
 
 
124
 
125
  <?php $controls->show(); ?>
126
 
 
127
  <p>
128
- In this panel you can configure the subscription and cancellation process, setting every message, the single or double opt in and
129
  even a customized subscription form.
130
  </p>
131
  <p>
132
- Emails sent during subscription process are themed with the file subscription/email.php which contains instructions on
133
- how customize it.
134
  </p>
135
  <p>
136
  Page layout where messages are shown is managed by subscription/page.php file which contains instruction on how to
137
  customize it OR use a WordPress page for messages as described on subscription configuration.
138
  </p>
 
139
 
140
 
141
  <form method="post" action="">
@@ -166,15 +161,26 @@ if ($controls->is_action()) {
166
  </td>
167
  </tr>
168
  <tr valign="top">
169
- <th>WordPress page URL for messages</th>
170
  <td>
171
- <?php $controls->text('url', 70); ?> (eg. <?php echo get_option('home') . '/newsletter'; ?>, optional)
 
 
 
 
 
172
 
173
  <div class="hints">
174
- Newsletter Pro needs to interact with subscribers: subscription form, welcome messages, cancellation messages,
175
- profile editing form. If you want all those interactions within you blog theme, create a WordPress page and put
176
- in its body <strong>only</strong> the short code [newsletter] (as is). Then open that page in your browser and copy the
177
- page address (URL) in this field.<br />
 
 
 
 
 
 
178
  </div>
179
  </td>
180
  </tr>
@@ -183,14 +189,32 @@ if ($controls->is_action()) {
183
  <td>
184
  <?php $controls->yesno('novisual'); ?>
185
  </td>
 
186
  <tr valign="top">
187
- <th>Automatically subscribe WordPress users</th>
188
  <td>
189
- <?php $controls->yesno('subscribe_wp_users'); ?>
190
- <div class="hints">
191
- It works only on new registration. To align old registration, press the alignment button.
192
- <?php $controls->button_confirm('align_wp_users', 'Align WP Users', 'Proceed?'); ?>
193
- </div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
194
  </td>
195
  </tr>
196
  <tr valign="top">
@@ -229,6 +253,16 @@ if ($controls->is_action()) {
229
  </div>
230
  </td>
231
  </tr>
 
 
 
 
 
 
 
 
 
 
232
  </table>
233
  </div>
234
 
@@ -342,10 +376,8 @@ if ($controls->is_action()) {
342
  <th>Profile page</th>
343
  <td>
344
  <?php $controls->editor('profile_text'); ?>
345
- <div class="hints">
346
- This is the page where subscribers edit their data. Must contain at least the {profile_form} tag. Empty the field
347
- and save to reset it to its default.
348
- </div>
349
  </td>
350
  </tr>
351
  <tr>
10
  if ($controls->is_action('save')) {
11
 
12
  $defaults = $module->get_default_options();
13
+
14
  if (empty($controls->data['profile_text'])) {
15
  $controls->data['profile_text'] = $defaults['profile_text'];
16
  }
23
  if (empty($controls->data['confirmation_text'])) {
24
  $controls->data['confirmation_text'] = $defaults['confirmation_text'];
25
  }
26
+
27
  if (empty($controls->data['confirmation_subject'])) {
28
  $controls->data['confirmation_subject'] = $defaults['confirmation_subject'];
29
  }
30
+
31
  if (empty($controls->data['confirmation_message'])) {
32
  $controls->data['confirmation_message'] = $defaults['confirmation_message'];
33
  }
35
  if (empty($controls->data['confirmed_text'])) {
36
  $controls->data['confirmed_text'] = $defaults['confirmed_text'];
37
  }
38
+
39
  if (empty($controls->data['confirmed_subject'])) {
40
  $controls->data['confirmed_subject'] = $defaults['confirmed_subject'];
41
  }
42
+
43
  if (empty($controls->data['confirmed_message'])) {
44
  $controls->data['confirmed_message'] = $defaults['confirmed_message'];
45
  }
54
  $controls->messages = 'Saved.';
55
  }
56
 
57
+ if ($controls->is_action('create')) {
58
+ $page = array();
59
+ $page['post_title'] = 'Newsletter';
60
+ $page['post_content'] = '[newsletter]';
61
+ $page['post_status'] = 'publish';
62
+ $page['post_type'] = 'page';
63
+ $page['comment_status'] = 'closed';
64
+ $page['ping_status'] = 'closed';
65
+ $page['post_category'] = array(1);
66
 
67
+ // Insert the post into the database
68
+ $page_id = wp_insert_post($page);
 
 
 
 
 
 
 
69
 
70
+ $controls->data['url'] = get_permalink($page_id);
71
+ $module->save_options($controls->data);
72
+ }
 
 
73
 
74
+ if ($controls->is_action('reset')) {
75
+ $controls->data = $module->reset_options();
 
76
  }
77
+
78
  } else {
79
  $controls->data = get_option('newsletter', array());
80
 
114
 
115
  <?php include NEWSLETTER_DIR . '/subscription/menu.inc.php'; ?>
116
 
117
+ <h2>Subscription, Unsubscription, Profile Page Configuration</h2>
118
 
119
  <?php $controls->show(); ?>
120
 
121
+ <div class="preamble">
122
  <p>
123
+ In this panel you can configure the subscription and cancellation process, set up every message, the single or double opt in and
124
  even a customized subscription form.
125
  </p>
126
  <p>
127
+ Emails sent during subscription process are themed with the file subscription/email.php. Open that file to learn how to customize it.
 
128
  </p>
129
  <p>
130
  Page layout where messages are shown is managed by subscription/page.php file which contains instruction on how to
131
  customize it OR use a WordPress page for messages as described on subscription configuration.
132
  </p>
133
+ </div>
134
 
135
 
136
  <form method="post" action="">
161
  </td>
162
  </tr>
163
  <tr valign="top">
164
+ <th>Newsletter dedicated page</th>
165
  <td>
166
+ <?php $controls->text('url', 70); ?>
167
+ <?php
168
+ if (empty($controls->data['url'])) {
169
+ $controls->button('create', 'Create a page for me');
170
+ }
171
+ ?>
172
 
173
  <div class="hints">
174
+ Optionally (but recommended) and address of a WordPress page (eg. <?php echo get_option('home') . '/newsletter'; ?>)
175
+ you set up for subscription and messages.
176
+ <br>
177
+ The page must have in its body <strong>only</strong> the short code <strong>[newsletter]</strong> (as is).
178
+
179
+ <?php if (!empty($controls->data['url'])) { ?>
180
+ <br>
181
+ If something is not working as expected with this address you can empty the field above and save: a button will appear
182
+ to create that page automatically.
183
+ <?php } ?>
184
  </div>
185
  </td>
186
  </tr>
189
  <td>
190
  <?php $controls->yesno('novisual'); ?>
191
  </td>
192
+ </tr>
193
  <tr valign="top">
194
+ <th>Subscription on registration</th>
195
  <td>
196
+ <?php $controls->select('subscribe_wp_users', array(0=>'No', 1=>'Yes, force subscription', 2=>'Yes, show the option', 3=>'Yes, show the option already checked')); ?>
197
+ <?php $controls->hint('Adds a newsletter subscription option on registration.', 'http://www.satollo.net/plugins/newsletter/subscription-module#registration'); ?>
198
+ </td>
199
+ </tr>
200
+ <tr valign="top">
201
+ <th>Check box label</th>
202
+ <td>
203
+ <?php $controls->text('subscribe_wp_users_label', 30); ?>
204
+ </td>
205
+ </tr>
206
+ <!--
207
+ <tr valign="top">
208
+ <th>Opt-in mode for WordPress registrated users</th>
209
+ <td>
210
+ <?php //$controls->select('optin_wp_users', array(0=>'As for regular subscriptions', 1=>'Force single opt-in')); ?>
211
+ </td>
212
+ </tr>
213
+ -->
214
+ <tr valign="top">
215
+ <th>Send welcome email to registered users</th>
216
+ <td>
217
+ <?php $controls->yesno('wp_welcome'); ?>
218
  </td>
219
  </tr>
220
  <tr valign="top">
253
  </div>
254
  </td>
255
  </tr>
256
+ <tr valign="top">
257
+ <th>Error page content</th>
258
+ <td>
259
+ <?php $controls->editor('error_text'); ?>
260
+ <div class="hints">
261
+ This message is shown whenever a subscription is attempted with an address bounced, already registered but not confirmed or
262
+ already subscribed. Consider all those three options while writing this message.
263
+ </div>
264
+ </td>
265
+ </tr>
266
  </table>
267
  </div>
268
 
376
  <th>Profile page</th>
377
  <td>
378
  <?php $controls->editor('profile_text'); ?>
379
+ <?php $controls->hint('This is the ppage where subscribers can edit their data and it must contain the {profile_form} tag.',
380
+ 'http://www.satollo.net/plugins/newsletter/subscription-module#profile'); ?>
 
 
381
  </td>
382
  </tr>
383
  <tr>
subscription/page.php CHANGED
@@ -18,6 +18,7 @@ $module = NewsletterSubscription::instance();
18
  $user = $module->get_user_from_request();
19
  $message_key = $module->get_message_key_from_request();
20
  $message = $newsletter->replace($module->options[$message_key . '_text'], $user);
 
21
  $alert = stripslashes($_REQUEST['alert']);
22
 
23
  // Force the UTF-8 charset
18
  $user = $module->get_user_from_request();
19
  $message_key = $module->get_message_key_from_request();
20
  $message = $newsletter->replace($module->options[$message_key . '_text'], $user);
21
+ $message .= $module->options[$message_key . '_tracking'];
22
  $alert = stripslashes($_REQUEST['alert']);
23
 
24
  // Force the UTF-8 charset
subscription/profile.php CHANGED
@@ -10,7 +10,7 @@ else {
10
  if ($controls->is_action('save')) {
11
  update_option('newsletter_profile', $controls->data);
12
  }
13
-
14
  if ($controls->is_action('reset')) {
15
  // TODO: Move this inside the module
16
  @include NEWSLETTER_DIR . '/subscription/languages/profile-en_US.php';
@@ -20,7 +20,7 @@ else {
20
  }
21
  }
22
 
23
- $status = array(0=>'Disabled/Private', 1=>'Only on profile page', 2=>'Even on subscription page');
24
  $rules = array(0=>'Optional', 1=>'Required');
25
  ?>
26
  <script type="text/javascript" src="<?php echo get_option('siteurl'); ?>/wp-content/plugins/newsletter/tiny_mce/tiny_mce.js"></script>
@@ -47,15 +47,13 @@ $rules = array(0=>'Optional', 1=>'Required');
47
 
48
  <?php include NEWSLETTER_DIR . '/subscription/menu.inc.php'; ?>
49
 
 
 
50
  <div class="preamble">
51
  <p>
52
- User profile is the whole set of user data that he can edit accessing the profile page (usually via the {profile_url} link you
53
- should add in any newsletter or welcome message.<br />
54
- Some of this data (at least the email) is collected on subscription and you can decide here what to ask the user on sign up for your
55
- newsletter.<br />
56
- It's a good practice to let the subscriber to sign up with a small set of data (eg. only his email or email and name) and then let him to
57
- add more information on a profile page.<br />
58
- The form seems complex, but it's not! On first approach, skip profiles and preferences.
59
  </p>
60
  </div>
61
 
10
  if ($controls->is_action('save')) {
11
  update_option('newsletter_profile', $controls->data);
12
  }
13
+
14
  if ($controls->is_action('reset')) {
15
  // TODO: Move this inside the module
16
  @include NEWSLETTER_DIR . '/subscription/languages/profile-en_US.php';
20
  }
21
  }
22
 
23
+ $status = array(0=>'Disabled/Private', 1=>'Only on profile page', 2=>'Even on subscription forms');
24
  $rules = array(0=>'Optional', 1=>'Required');
25
  ?>
26
  <script type="text/javascript" src="<?php echo get_option('siteurl'); ?>/wp-content/plugins/newsletter/tiny_mce/tiny_mce.js"></script>
47
 
48
  <?php include NEWSLETTER_DIR . '/subscription/menu.inc.php'; ?>
49
 
50
+ <h2>Subscription Form Fields and Layout</h2>
51
+
52
  <div class="preamble">
53
  <p>
54
+ This panel contains the configuration of the subscription and profile editing forms which collect the subscriber data you want to have.<br>
55
+ And let you to <strong>translate</strong> every single button and label.<br>
56
+ <strong>Preferences</strong> can be an important setting for your newsletter: <a href="http://www.satollo.net/plugins/newsletter/newsletter-preferences" target="_blank">here you can read more about them</a>.
 
 
 
 
57
  </p>
58
  </div>
59
 
subscription/subscription.php CHANGED
@@ -4,7 +4,7 @@ require_once NEWSLETTER_INCLUDES_DIR . '/module.php';
4
 
5
  class NewsletterSubscription extends NewsletterModule {
6
 
7
- const VERSION = '1.0.1';
8
  const MESSAGE_CONFIRMED = 'confirmed';
9
 
10
  static $instance;
@@ -21,58 +21,118 @@ class NewsletterSubscription extends NewsletterModule {
21
 
22
  function __construct() {
23
  parent::__construct('subscription', self::VERSION);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
24
  }
25
 
26
  function upgrade() {
27
- global $wpdb, $charset_collate;
28
 
29
  parent::upgrade();
30
 
31
  // Migrate the profile_text from profile to subscription options
32
  $options_profile = $this->get_options('profile');
33
-
34
  if (empty($options_profile)) {
35
  update_option('newsletter_profile', $this->get_default_options('profile'));
36
  }
37
-
38
- $options = $this->get_options();
39
- if (empty($options)) {
40
- update_option('newsletter', $this->get_default_options());
 
 
41
  }
42
-
43
-
44
- $options = get_option('newsletter', array());
45
-
46
-
47
  if (isset($options_profile['profile_text'])) {
48
- $options['profile_text'] = $options_profile['profile_text'];
49
- update_option('newsletter', $options);
 
 
 
 
50
  unset($options_profile['profile_text']);
51
  update_option('newsletter_profile', $options_profile);
52
  }
53
 
54
  if (isset($options_profile['profile_saved'])) {
55
- $options['profile_saved'] = $options_profile['profile_saved'];
56
- update_option('newsletter', $options);
57
  unset($options_profile['profile_saved']);
58
  update_option('newsletter_profile', $options_profile);
59
  }
60
 
61
- // TODO: Remove since it's only useful for first time migration
62
- if (empty($options['profile_text'])) {
63
- $options['profile_text'] = '{profile_form}<p><a href="{unsubscription_url}">I want unsubscribe?</a>';
64
- }
65
-
66
- if (!isset($options['url']) && !empty(Newsletter::instance()->options['url'])) {
67
- $options['url'] = Newsletter::instance()->options['url'];
68
- update_option('newsletter', $options);
69
  }
70
 
 
71
  wp_mkdir_p(WP_CONTENT_DIR . '/extensions/newsletter/subscription');
72
  return true;
73
  }
74
 
75
- function save_options($options, $sub='') {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
76
  if ($sub == '') {
77
  // For compatibility the options are wrongly named
78
  return update_option('newsletter', $options);
@@ -82,7 +142,7 @@ class NewsletterSubscription extends NewsletterModule {
82
  }
83
  return parent::save_options($sub);
84
  }
85
-
86
  function get_options($sub = '') {
87
  if ($sub == '') {
88
  // For compatibility the options are wrongly named
@@ -95,126 +155,134 @@ class NewsletterSubscription extends NewsletterModule {
95
  return parent::get_options($sub);
96
  }
97
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
98
  /**
99
  * Return the subscribed user.
100
  *
101
- * @global type $newsletter
 
102
  */
103
- function subscribe() {
104
  global $newsletter;
105
 
106
  $options = get_option('newsletter', array());
107
  $options_profile = get_option('newsletter_profile', array());
108
 
109
- // Can be set externally
110
- if (!isset($opt_in)) {
111
- $opt_in = (int) $this->options['noconfirmation']; // 0 - double, 1 - single
112
- }
113
 
114
  $email = $newsletter->normalize_email(stripslashes($_REQUEST['ne']));
115
- if ($email == null) die('Wrong email');
 
116
 
117
- $user = NewsletterUsers::instance()->get_user($email);
118
 
119
- if ($user != null && $user->status == 'B') {
120
- $this->logger->error('Subscription attempo of a bounced address');
121
- echo 'This address is bounced, cannot be subscribed. Contact the blog owner.';
122
- die();
 
 
123
  }
124
-
125
- // This address is new or was it previously collected but never confirmed?
126
- if ($user == null || $user->status == 'S' || $user->status == 'U') {
127
 
128
- if ($user != null) {
129
- $this->logger->info("Email address subscribed but not confirmed");
130
- $user = array('id' => $user->id);
131
- } else {
132
- $this->logger->info("New email address");
133
- $user = array('email' => $email);
134
- }
135
 
136
- $user['name'] = $newsletter->normalize_name(stripslashes($_REQUEST['nn']));
137
- // TODO: required checking
138
 
139
- $user['surname'] = $newsletter->normalize_name(stripslashes($_REQUEST['ns']));
140
- // TODO: required checking
141
 
142
- if (!empty($_REQUEST['nx'])) $user['sex'] = $_REQUEST['nx'][0];
143
- // TODO: valid values check
 
144
 
145
- $user['referrer'] = $_REQUEST['nr'];
146
- $user['http_referer'] = $_SERVER['HTTP_REFERER'];
147
 
148
- // New profiles
149
- for ($i = 1; $i <= NEWSLETTER_PROFILE_MAX; $i++) {
150
- // If the profile cannot be set by subscriber, skiyp it.
151
- if ($options_profile['profile_' . $i . '_status'] == 0) continue;
 
152
 
153
- $user['profile_' . $i] = trim(stripslashes($_REQUEST['np' . $i]));
154
- }
155
 
156
- // Preferences (field names are nl[] and values the list number so special forms with radio button can work)
157
- if (is_array($_REQUEST['nl'])) {
158
- for ($i = 1; $i <= NEWSLETTER_LIST_MAX; $i++) {
159
- // If not zero it is selectable by user (on subscription or on profile)
160
- if ($options_profile['list_' . $i . '_status'] == 0) continue;
161
- if (in_array($i, $_REQUEST['nl'])) $user['list_' . $i] = 1;
162
- }
 
163
  }
 
164
 
165
- // Forced preferences as set on subscription configuration
166
- if (is_array($options['preferences'])) {
167
- foreach ($options['preferences'] as $p) {
168
- $user['list_' . $p] = 1;
169
- }
170
  }
 
171
 
172
- $user['token'] = $newsletter->get_token();
173
- $user['ip'] = $_SERVER['REMOTE_ADDR'];
 
 
 
174
  $user['status'] = $opt_in == 1 ? 'C' : 'S';
175
 
176
- // TODO: add the flow integration?
177
-
178
- if (isset($flow)) {
179
- $user['flow'] = $flow;
180
- }
181
 
182
- // TODO: use a filter
183
- if (class_exists('NewsletterFollowup')) {
184
- if (NewsletterFollowup::instance()->options['add_new'] == 1) {
185
- $user['followup'] = 1;
186
- $user['followup_time'] = time() + NewsletterFollowup::instance()->options['interval'] * 3600;
187
- }
188
- }
189
 
190
- $user = apply_filters('newsletter_user_subscribe', $user);
191
 
192
- if (defined('NEWSLETTER_FEED_VERSION')) {
193
- $options_feed = get_option('newsletter_feed', array());
194
- if ($options_feed['add_new'] == 1) $user['feed'] = 1;
195
- }
 
 
196
 
197
- $user = NewsletterUsers::instance()->save_user($user);
198
 
199
- // Notification to admin (only for new confirmed subscriptions)
200
- if ($user->status == 'C') {
201
- $this->notify_admin($user, 'Newsletter subscription');
202
- }
203
- } else {
204
- // If the subscriber already exists, update it
205
- // TODO: as second option, only a welcome/confirmation email should be sent with invitation to edit
206
- // the profile
207
- // $delta = array();
208
- // if (is_array($_REQUEST['nl'])) {
209
- // for ($i = 1; $i <= NEWSLETTER_LIST_MAX; $i++) {
210
- // if ($options_profile['list_' . $i . '_status'] == 0) continue;
211
- // if (in_array($i, $_REQUEST['nl'])) $delta['list_' . $i] = 1;
212
- // }
213
- // }
214
- // $delta['id'] = $user->id;
215
- // $user = $this->store->save_user($delta);
216
  }
217
 
 
 
 
218
 
219
  $prefix = ($user->status == 'C') ? 'confirmed_' : 'confirmation_';
220
  $message = $options[$prefix . 'message'];
@@ -223,10 +291,6 @@ class NewsletterSubscription extends NewsletterModule {
223
  $message_text = $options[$prefix . 'message_text'];
224
  $subject = $options[$prefix . 'subject'];
225
 
226
- if ($user->status == 'C') {
227
- setcookie('newsletter', $user->id . '-' . $user->token, time() + 60 * 60 * 24 * 365, '/');
228
- }
229
-
230
  $this->mail($user->email, $newsletter->replace($subject, $user), $newsletter->replace($message, $user));
231
 
232
  return $user;
@@ -246,12 +310,32 @@ class NewsletterSubscription extends NewsletterModule {
246
  Newsletter::instance()->mail($to, $subject, $message);
247
  }
248
 
249
- function confirm() {
 
 
 
 
 
 
250
  global $newsletter;
251
- $user = $this->get_user_from_request();
252
- if ($user == null) die('No subscriber found.');
 
 
 
 
 
 
 
 
 
 
253
  setcookie('newsletter', $user->id . '-' . $user->token, time() + 60 * 60 * 24 * 365, '/');
254
- NewsletterUsers::instance()->set_user_status($user->id, 'C');
 
 
 
 
255
 
256
  $message = $this->options['confirmed_message'];
257
 
@@ -263,7 +347,7 @@ class NewsletterSubscription extends NewsletterModule {
263
 
264
  $this->notify_admin($user, 'Newsletter subscription');
265
 
266
- $user->status = 'C';
267
  return $user;
268
  }
269
 
@@ -276,15 +360,18 @@ class NewsletterSubscription extends NewsletterModule {
276
  function unsubscribe() {
277
  global $newsletter;
278
  $user = $this->get_user_from_request();
279
- if ($user == null) die('No subscriber found.');
280
-
281
  setcookie('newsletter', '', time() - 3600);
282
- NewsletterUsers::instance()->set_user_status($user->id, 'U');
 
 
 
 
 
 
283
 
284
- $options = get_option('newsletter', array());
285
- $options_main = get_option('newsletter_main', array());
286
 
287
- $newsletter->mail($user->email, $newsletter->replace($options['unsubscribed_subject'], $user), $newsletter->replace($options['unsubscribed_message'], $user));
288
  $this->notify_admin($user, 'Newsletter unsubscription');
289
 
290
  return $user;
@@ -294,13 +381,15 @@ class NewsletterSubscription extends NewsletterModule {
294
  global $newsletter;
295
 
296
  $user = $this->get_user_from_request();
297
- if ($user == null) die('No subscriber found.');
 
298
 
299
 
300
  $options_profile = get_option('newsletter_profile', array());
301
  $options_main = get_option('newsletter_main', array());
302
 
303
- if (!$newsletter->is_email($_REQUEST['ne'])) die('Wrong email address.');
 
304
 
305
  // General data
306
  $data['email'] = $newsletter->normalize_email(stripslashes($_REQUEST['ne']));
@@ -309,49 +398,57 @@ class NewsletterSubscription extends NewsletterModule {
309
  if ($options_profile['sex_status'] >= 1) {
310
  $data['sex'] = $_REQUEST['nx'][0];
311
  // Wrong data injection check
312
- if ($data['sex'] != 'm' && $data['sex'] != 'f' && $data['sex'] != 'n') die('Wrong sex field');
 
313
  }
314
 
315
- // Lists
316
- if (is_array($_REQUEST['nl'])) {
317
- for ($i = 1; $i <= NEWSLETTER_LIST_MAX; $i++) {
318
- if ($options_profile['list_' . $i . '_status'] == 0) continue;
319
- $data['list_' . $i] = in_array($i, $_REQUEST['nl']) ? 1 : 0;
320
- }
 
 
 
 
321
  }
322
 
323
  // Profile
324
  for ($i = 1; $i <= NEWSLETTER_PROFILE_MAX; $i++) {
325
- if ($options_profile['profile_' . $i . '_status'] == 0) continue;
 
326
  $data['profile_' . $i] = stripslashes($_REQUEST['np' . $i]);
327
  }
328
 
329
- // Follow up
330
- $options_followup = get_option('newsletter_followup');
331
- if ($options_followup['enabled'] == 1 && $options_profile['followup_status'] > 0) {
332
- if (isset($_POST['followup'])) $data['followup'] = 1;
333
- else $data['followup'] = 0;
334
- }
335
  $data['id'] = $user->id;
336
 
337
  // Feed by Mail service is saved here
338
  $data = apply_filters('newsletter_profile_save', $data);
 
339
 
340
- $user = NewsletterUsers::instance()->save_user($data);
341
  return $user;
342
  }
343
 
344
  /**
345
  * Finds the right way to show the message identified by $key (welcome, unsubscription, ...) redirecting the user to the
346
  * WordPress page or loading the configured url or activating the standard page.
 
 
347
  */
348
  function show_message($key, $user, $alert = '') {
 
 
349
  if (!is_object($user)) {
350
- if (is_array($user)) $user = (object) $user;
351
- else $user = NewsletterUsers::instance()->get_user($user);
 
 
352
  }
353
 
354
- if (!empty($alert)) $params = '&alert=' . urlencode($alert);
 
355
 
356
  // Add exceptions for "profile" key.
357
  // Is there a custom url?
@@ -374,23 +471,28 @@ class NewsletterSubscription extends NewsletterModule {
374
  /**
375
  * Loads the user using the request parameters (nk or nt and ni).
376
  *
 
377
  * @return null
378
  */
379
  function get_user_from_request() {
 
 
380
  if (isset($_REQUEST['nk'])) {
381
  list($id, $token) = @explode('-', $_REQUEST['nk'], 2);
382
  } else if (isset($_REQUEST['ni'])) {
383
  $id = (int) $_REQUEST['ni'];
384
  $token = $_REQUEST['nt'];
385
  }
386
- $user = NewsletterUsers::instance()->get_user($id);
387
 
388
- if ($user == null || $token != $user->token) return null;
 
389
  return $user;
390
  }
391
 
392
  function get_message_key_from_request() {
393
- if (empty($_GET['nm'])) return 'subscription';
 
394
  $key = $_GET['nm'];
395
  switch ($key) {
396
  case 's': return 'confirmation';
@@ -410,10 +512,11 @@ class NewsletterSubscription extends NewsletterModule {
410
  *
411
  * @global wpdb $wpdb
412
  * @global type $current_user
 
413
  * @return null
414
  */
415
  function check_user() {
416
- global $wpdb, $current_user;
417
 
418
  if (isset($_REQUEST['nk'])) {
419
  list($id, $token) = @explode('-', $_REQUEST['nk'], 2);
@@ -428,6 +531,9 @@ class NewsletterSubscription extends NewsletterModule {
428
  return $wpdb->get_row($wpdb->prepare("select * from " . $wpdb->prefix . "newsletter where id=%d and token=%s limit 1", $id, $token));
429
  }
430
 
 
 
 
431
  if ($this->options_main['wp_integration'] != 1) {
432
  return null;
433
  }
@@ -451,7 +557,7 @@ class NewsletterSubscription extends NewsletterModule {
451
  $user['email'] = strtolower($current_user->user_email);
452
 
453
  $id = $wpdb->insert(NEWSLETTER_USERS_TABLE, $user);
454
- $user = NewsletterUsers::instance()->get_user($id);
455
  } else {
456
  //echo 'WP user found via email';
457
  $wpdb->query($wpdb->prepare("update " . NEWSLETTER_USERS_TABLE . " set wp_user_id=" . $current_user->ID . ", email=%s", $current_user->user_email));
@@ -505,7 +611,7 @@ class NewsletterSubscription extends NewsletterModule {
505
  *
506
  * @return string The html code of the subscription form
507
  */
508
- function get_subscription_form() {
509
  $options_profile = get_option('newsletter_profile');
510
  $options = get_option('newsletter');
511
 
@@ -518,22 +624,27 @@ class NewsletterSubscription extends NewsletterModule {
518
  } else {
519
  $buffer .= '<form method="post" action="' . $action . '" onsubmit="return newsletter_check(this)">' . "\n\n";
520
  }
 
 
 
521
  $buffer .= '<table cellspacing="0" cellpadding="3" border="0">' . "\n\n";
522
  if ($options_profile['name_status'] == 2) {
523
  $buffer .= "<!-- first name -->\n";
524
- $buffer .= "<tr>\n\t" . '<th>' . $options_profile['name'] . '</th>' . "\n\t" . '<td><input class="newsletter-firstname" type="text" name="nn" size="30"/></td>' . "\n" . '</tr>' . "\n\n";
525
  }
 
526
  if ($options_profile['surname_status'] == 2) {
527
  $buffer .= "<!-- last name -->\n";
528
- $buffer .= "<tr>\n\t" . '<th>' . $options_profile['surname'] . '</th>' . "\n\t" . '<td><input class="newsletter-lastname" type="text" name="ns" size="30"/></td>' . "\n" . '</tr>' . "\n\n";
529
  }
530
 
531
  $buffer .= "<!-- email -->\n";
532
- $buffer .= "<tr>\n\t" . '<th>' . $options_profile['email'] . '</th>' . "\n\t" . '<td align="left"><input class="newsletter-email" type="text" name="ne" size="30"/></td>' . "\n" . '</tr>' . "\n\n";
533
 
534
  if ($options_profile['sex_status'] == 2) {
535
  $buffer .= "<!-- sex -->\n";
536
- $buffer .= "<tr>\n\t" . '<th>' . $options_profile['sex'] . "</th>\n\t<td>\n\t" . '<select name="nx" class="newsletter-sex">' . "\n";
 
537
  $buffer .= "\t\t" . '<option value="m">' . $options_profile['sex_male'] . '</option>' . "\n";
538
  $buffer .= "\t\t" . '<option value="f">' . $options_profile['sex_female'] . '</option>' . "\n";
539
  $buffer .= "\t</select>\n\t</td></tr>\n";
@@ -541,16 +652,18 @@ class NewsletterSubscription extends NewsletterModule {
541
 
542
  $lists = '';
543
  for ($i = 1; $i <= NEWSLETTER_LIST_MAX; $i++) {
544
- if ($options_profile['list_' . $i . '_status'] != 2) continue;
 
545
  $lists .= "\t\t" . '<input type="checkbox" name="nl[]" value="' . $i . '"/>&nbsp;' . $options_profile['list_' . $i] . '<br />' . "\n";
546
  }
547
  if (!empty($lists))
548
- $buffer .= "<!-- preferences -->\n<tr>\n\t<th>&nbsp;</th>\n\t<td>\n" . $lists . "\t</td>\n</tr>\n\n";
549
 
550
  // Extra profile fields
551
  for ($i = 1; $i <= NEWSLETTER_PROFILE_MAX; $i++) {
552
  // Not for subscription form
553
- if ($options_profile['profile_' . $i . '_status'] != 2) continue;
 
554
 
555
  // Text field
556
  if ($options_profile['profile_' . $i . '_type'] == 'text') {
@@ -576,7 +689,7 @@ class NewsletterSubscription extends NewsletterModule {
576
 
577
  if ($options_profile['privacy_status'] == 1) {
578
  $buffer .= "<tr>\n\t" . '<td colspan="2" class="newsletter-td-privacy">' . "\n";
579
- $buffer .= "\t\t" . '<input type="checkbox" name="ny"/>&nbsp;';
580
  if (!empty($options_profile['privacy_url'])) {
581
  $buffer .= '<a target="_blank" href="' . $options_profile['privacy_url'] . '">';
582
  $buffer .= $options_profile['privacy'] . '</a>';
@@ -589,7 +702,7 @@ class NewsletterSubscription extends NewsletterModule {
589
  $buffer .= "<tr>\n\t" . '<td colspan="2" class="newsletter-td-submit">' . "\n";
590
 
591
  if (strpos($options_profile['subscribe'], 'http://') !== false) {
592
- $buffer .= "\t\t" . '<input class="newsletter-submit" type="image" src="' . $options_profile['subscribe'] . '"/>' . "\n\t</td>\n</tr>\n\n";
593
  } else {
594
  $buffer .= "\t\t" . '<input class="newsletter-submit" type="submit" value="' . $options_profile['subscribe'] . '"/>' . "\n\t</td>\n</tr>\n\n";
595
  }
@@ -629,7 +742,8 @@ class NewsletterSubscription extends NewsletterModule {
629
 
630
  // Profile
631
  for ($i = 1; $i <= NEWSLETTER_PROFILE_MAX; $i++) {
632
- if ($options['profile_' . $i . '_status'] == 0) continue;
 
633
 
634
  $buffer .= '<tr><th align="right">' . $options['profile_' . $i] . '</th><td>';
635
  //if ($options['list_type_' . $i] != 'public') continue;
@@ -645,7 +759,8 @@ class NewsletterSubscription extends NewsletterModule {
645
  for ($j = 0; $j < count($opts); $j++) {
646
  $opts[$j] = trim($opts[$j]);
647
  $buffer .= '<option';
648
- if ($opts[$j] == $user->$field) $buffer .= ' selected';
 
649
  $buffer .= '>' . $opts[$j] . '</option>';
650
  }
651
  $buffer .= '</select>';
@@ -657,25 +772,16 @@ class NewsletterSubscription extends NewsletterModule {
657
  // Lists
658
  $buffer .= '<tr><th>&nbsp;</th><td>';
659
  for ($i = 1; $i <= NEWSLETTER_LIST_MAX; $i++) {
660
- if ($options['list_' . $i . '_status'] == 0) continue;
 
661
  $buffer .= '<input type="checkbox" name="nl[]" value="' . $i . '"';
662
  $list = 'list_' . $i;
663
- if ($user->$list == 1) $buffer .= ' checked';
 
664
  $buffer .= '/> ' . htmlspecialchars($options['list_' . $i]) . '<br />';
665
  }
666
  $buffer .= '</td></tr>';
667
 
668
- // Follow up
669
- if (defined('NEWSLETTER_FOLLOWUP_VERSION')) {
670
- $options_followup = get_option('newsletter_followup');
671
- if ($options_followup['enabled'] == 1 && $options['followup_status'] >= 1) {
672
- $buffer .= '<tr><th align="right">' . $options['followup'] . '</th><td>';
673
- $buffer .= '<input type="checkbox" name="followup"';
674
- if ($user->followup == 1) $buffer .= ' checked';
675
- $buffer .= '/></td></tr>';
676
- }
677
- }
678
-
679
  $extra = apply_filters('newsletter_profile_extra', array(), $user);
680
  foreach ($extra as &$x) {
681
  $buffer .= "<tr>\n\t<th>" . $x['label'] . "</th>\n\t<td>\n\t\t";
@@ -683,13 +789,13 @@ class NewsletterSubscription extends NewsletterModule {
683
  }
684
 
685
  $buffer .= '<tr><td colspan="2" class="newsletter-td-submit">';
686
-
687
  if (strpos($options['save'], 'http://') !== false) {
688
  $buffer .= '<input class="newsletter-submit" type="image" src="' . $options['save'] . '"/></td></tr>';
689
  } else {
690
  $buffer .= '<input class="newsletter-submit" type="submit" value="' . $options['save'] . '"/></td></tr>';
691
  }
692
-
693
  $buffer .= '</table></form></div>';
694
 
695
  return $buffer;
@@ -723,7 +829,8 @@ class NewsletterSubscription extends NewsletterModule {
723
  $options_profile = get_option('newsletter_profile');
724
  $lists = '';
725
  for ($i = 1; $i <= NEWSLETTER_LIST_MAX; $i++) {
726
- if ($options_profile['list_' . $i . '_status'] != 2) continue;
 
727
  $lists .= '<input type="checkbox" name="nl[]" value="' . $i . '"/>&nbsp;' . $options_profile['list_' . $i] . '<br />';
728
  }
729
  $buffer = str_replace('{lists}', $lists, $buffer);
@@ -733,7 +840,8 @@ class NewsletterSubscription extends NewsletterModule {
733
 
734
  function notify_admin($user, $subject) {
735
 
736
- if ($this->options['notify'] != 1) return;
 
737
 
738
  $message = "Subscriber details:\n\n" .
739
  "email: " . $user->email . "\n" .
@@ -744,13 +852,15 @@ class NewsletterSubscription extends NewsletterModule {
744
  $options_profile = get_option('newsletter_profile');
745
 
746
  for ($i = 0; $i < NEWSLETTER_PROFILE_MAX; $i++) {
747
- if ($options_profile['profile_' . $i] == '') continue;
 
748
  $field = 'profile_' . $i;
749
  $message .= $options_profile['profile_' . $i] . ': ' . $user->$field . "\n";
750
  }
751
 
752
  for ($i = 0; $i < NEWSLETTER_LIST_MAX; $i++) {
753
- if ($options_profile['list_' . $i] == '') continue;
 
754
  $field = 'list_' . $i;
755
  $message .= $options_profile['list_' . $i] . ': ' . $user->$field . "\n";
756
  }
@@ -759,12 +869,15 @@ class NewsletterSubscription extends NewsletterModule {
759
  "status: " . $user->status . "\n" .
760
  "\nYours, Newsletter Pro.";
761
  $email = trim($this->options['notify_email']);
762
- if (empty($email)) $email = get_option('admin_email');
 
763
  wp_mail($email, '[' . get_option('blogname') . '] ' . $subject, $message, "Content-type: text/plain; charset=UTF-8\n");
764
  }
765
 
766
  }
767
 
 
 
768
  // TODO: Remove in version 3.5. For compatibility.
769
  add_shortcode('newsletter_embed', 'newsletter_shortcode_form');
770
 
@@ -782,6 +895,15 @@ function newsletter_shortcode_form($attrs, $content) {
782
 
783
  add_shortcode('newsletter', 'newsletter_shortcode');
784
 
 
 
 
 
 
 
 
 
 
785
  function newsletter_shortcode($attrs, $content) {
786
  global $wpdb, $cache_stop, $newsletter;
787
 
@@ -792,7 +914,12 @@ function newsletter_shortcode($attrs, $content) {
792
  $message_key = $module->get_message_key_from_request();
793
  $alert = stripslashes($_REQUEST['alert']);
794
 
795
- $message = $newsletter->replace($module->options[$message_key . '_text'], $user);
 
 
 
 
 
796
 
797
  // Now check what form must be added
798
  if ($message_key == 'subscription') {
@@ -807,24 +934,16 @@ function newsletter_shortcode($attrs, $content) {
807
  $message .= '{subscription_form}';
808
  }
809
 
810
- if (strpos($message, '{subscription_form}') !== false) {
811
- // TODO: Remove on version 3.1. For compatibility.
812
- if (isset($attrs['form'])) {
813
- $message = str_replace('{subscription_form}', $module->get_form($attrs['form']), $message);
814
- } else {
815
- $message = str_replace('{subscription_form}', $module->get_subscription_form(), $message);
816
- }
817
  } else {
818
- for ($i = 1; $i <= 10; $i++) {
819
- if (strpos($message, "{subscription_form_$i}") !== false) {
820
- $message = str_replace("{subscription_form_$i}", $module->get_form($i), $message);
821
- break;
822
- }
823
- }
824
  }
825
  }
826
  }
827
 
 
 
828
  if (!empty($alert)) {
829
  $message .= '<script>alert("' . addslashes($alert) . '");</script>';
830
  }
@@ -836,32 +955,36 @@ function newsletter_shortcode($attrs, $content) {
836
  // option on every page load. The registration code should be moved inside the module...
837
  add_action('user_register', 'newsletter_subscription_user_register');
838
 
839
- function newsletter_subscription_user_register($user_id) {
840
- global $wpdb;
841
 
842
  $module = NewsletterSubscription::instance();
843
 
844
- if ($module->options['subscribe_wp_users'] != 1) return;
 
 
 
 
 
 
 
 
845
 
846
- $module->logger->info('Adding a registered WordPress user (' . $user_id . ')');
847
- $wp_user = $wpdb->get_row($wpdb->prepare("select * from $wpdb->users where id=%d limit 1", $user_id));
848
  if (empty($wp_user)) {
849
  $module->logger->error('User not found?!');
850
  return;
851
  }
852
- $user = array();
853
- $user['email'] = $module->normalize_email($wp_user->user_email);
854
- $user['name'] = $wp_user->user_login;
855
- $user['status'] = 'C';
856
- $user['wp_user_id'] = $wp_user->ID;
857
 
858
- if (is_array($module->options['preferences'])) {
859
- foreach ($module->options['preferences'] as $p) {
860
- $user['list_' . $p] = 1;
861
- }
862
- }
863
 
864
- NewsletterUsers::instance()->save_user($user);
 
865
  }
866
 
867
  // Compatibility code
@@ -874,30 +997,19 @@ function newsletter_form($number = null) {
874
  }
875
  }
876
 
877
- if ($_REQUEST['na'] == 's') {
878
- $user = NewsletterSubscription::instance()->subscribe();
879
- if ($user->status == 'C') NewsletterSubscription::instance()->show_message('confirmation', $user->id);
880
- if ($user->status == 'S') NewsletterSubscription::instance()->show_message('confirmed', $user->id);
881
- }
882
-
883
- if ($_REQUEST['na'] == 'c') {
884
- $user = NewsletterSubscription::instance()->confirm();
885
- NewsletterSubscription::instance()->show_message('confirmed', $user);
886
- }
887
-
888
- if ($_REQUEST['na'] == 'u') {
889
- $user = NewsletterSubscription::instance()->get_user_from_request();
890
- if ($user == null) die('No subscriber found.');
891
- NewsletterSubscription::instance()->show_message('unsubscription', $user->id);
892
- }
893
 
894
- if ($_REQUEST['na'] == 'uc') {
895
- $user = NewsletterSubscription::instance()->unsubscribe();
896
- NewsletterSubscription::instance()->show_message('unsubscribed', $user);
 
 
 
 
 
 
 
 
 
897
  }
898
 
899
- if ($_REQUEST['na'] == 'p' || $_REQUEST['na'] == 'pe') {
900
- $user = NewsletterSubscription::instance()->get_user_from_request();
901
- if ($user == null) die('No subscriber found.');
902
- NewsletterSubscription::instance()->show_message('profile', $user);
903
- }
4
 
5
  class NewsletterSubscription extends NewsletterModule {
6
 
7
+ const VERSION = '1.0.2';
8
  const MESSAGE_CONFIRMED = 'confirmed';
9
 
10
  static $instance;
21
 
22
  function __construct() {
23
  parent::__construct('subscription', self::VERSION);
24
+
25
+ add_action('wp_login', array($this, 'hook_wp_login'));
26
+
27
+ // Must be called after the Newsletter::hook_init, since some constants are defined
28
+ // there.
29
+ add_action('init', array($this, 'hook_init'), 90);
30
+ }
31
+
32
+ function hook_init() {
33
+ $action = isset($_REQUEST['na']) ? $_REQUEST['na'] : '';
34
+ if (empty($action) || is_admin()) return;
35
+
36
+ if ($action == 's') {
37
+ $user = $this->subscribe();
38
+ if ($user->status == 'E')
39
+ $this->show_message('error', $user->id);
40
+ if ($user->status == 'C')
41
+ $this->show_message('confirmation', $user->id);
42
+ if ($user->status == 'S')
43
+ $this->show_message('confirmed', $user->id);
44
+ }
45
+ else if ($action == 'c') {
46
+ $user = NewsletterSubscription::instance()->confirm();
47
+ $this->show_message('confirmed', $user);
48
+ } else if ($action == 'u') {
49
+ $user = $this->get_user_from_request();
50
+ if ($user == null)
51
+ die('No subscriber found.');
52
+ $this->show_message('unsubscription', $user->id);
53
+ }
54
+ else if ($action == 'uc') {
55
+ $user = $this->unsubscribe();
56
+ if ($user->status == 'E') {
57
+ $this->show_message('error', $user->id);
58
+ } else {
59
+ $this->show_message('unsubscribed', $user);
60
+ }
61
+ } else if ($action == 'p' || $action == 'pe') {
62
+ $user = $this->get_user_from_request();
63
+ if ($user == null)
64
+ die('No subscriber found.');
65
+ $this->show_message('profile', $user);
66
+ }
67
  }
68
 
69
  function upgrade() {
70
+ global $wpdb, $charset_collate, $newsletter;
71
 
72
  parent::upgrade();
73
 
74
  // Migrate the profile_text from profile to subscription options
75
  $options_profile = $this->get_options('profile');
76
+
77
  if (empty($options_profile)) {
78
  update_option('newsletter_profile', $this->get_default_options('profile'));
79
  }
80
+
81
+ $default_options = $this->get_default_options();
82
+
83
+ if (empty($this->options['error_text'])) {
84
+ $this->options['error_text'] = $default_options['error_text'];
85
+ $this->save_options($this->options);
86
  }
87
+
88
+ // Old migration code
 
 
 
89
  if (isset($options_profile['profile_text'])) {
90
+ $this->options['profile_text'] = $options_profile['profile_text'];
91
+ if (empty($this->options['profile_text'])) {
92
+ $this->options['profile_text'] = '{profile_form}<p><a href="{unsubscription_url}">I want to unsubscribe.</a>';
93
+ }
94
+
95
+ $this->save_options($this->options);
96
  unset($options_profile['profile_text']);
97
  update_option('newsletter_profile', $options_profile);
98
  }
99
 
100
  if (isset($options_profile['profile_saved'])) {
101
+ $this->options['profile_saved'] = $options_profile['profile_saved'];
102
+ $this->save_options($this->options);
103
  unset($options_profile['profile_saved']);
104
  update_option('newsletter_profile', $options_profile);
105
  }
106
 
107
+ // Very old...
108
+ if (!isset($this->options['url']) && !empty($newsletter->options['url'])) {
109
+ $this->options['url'] = $newsletter->options['url'];
110
+ $this->save_options($this->options);
 
 
 
 
111
  }
112
 
113
+ // Because users do not understand how to create an "extensions" folder...
114
  wp_mkdir_p(WP_CONTENT_DIR . '/extensions/newsletter/subscription');
115
  return true;
116
  }
117
 
118
+ function admin_menu() {
119
+ $this->add_menu_page('options', 'Subscription');
120
+ $this->add_admin_page('profile', 'Profile');
121
+ $this->add_admin_page('forms', 'Forms');
122
+ }
123
+
124
+ /**
125
+ * This method has been redefined for compatibility with the old options naming. It would
126
+ * be better to change them instead. The subscription options should be named
127
+ * "newsletter_subscription" while the form field options, actually named
128
+ * "newsletter_profile", should be renamed "newsletter_subscription_profile" (since
129
+ * they are retrived with get_options('profile')) or "newsletter_subscription_fields" or
130
+ * "newsletter_subscription_form".
131
+ *
132
+ * @param array $options
133
+ * @param string $sub
134
+ */
135
+ function save_options($options, $sub = '') {
136
  if ($sub == '') {
137
  // For compatibility the options are wrongly named
138
  return update_option('newsletter', $options);
142
  }
143
  return parent::save_options($sub);
144
  }
145
+
146
  function get_options($sub = '') {
147
  if ($sub == '') {
148
  // For compatibility the options are wrongly named
155
  return parent::get_options($sub);
156
  }
157
 
158
+ /**
159
+ * See wp-includes/user.php function wp_signon().
160
+ */
161
+ function hook_wp_login($user_login) {
162
+ global $newsletter;
163
+
164
+ $this->logger->info(__METHOD__ . '> Start with ' . $user_login);
165
+ $wp_user = get_user_by('login', $user_login);
166
+ if (!empty($wp_user)) {
167
+ $this->logger->info($wp_user);
168
+ // We have a user able to login, so his subscription can be confirmed if not confirmed
169
+ $user = $newsletter->get_user($wp_user->user_email);
170
+ if (!empty($user)) {
171
+ $this->confirm($user->id, $this->options['wp_welcome'] == 1);
172
+ }
173
+ }
174
+ $this->logger->info(__METHOD__ . '> End');
175
+ }
176
+
177
  /**
178
  * Return the subscribed user.
179
  *
180
+ * @param bool $registration If invoked from the registration process
181
+ * @global Newsletter $newsletter
182
  */
183
+ function subscribe($status = null, $emails = true) {
184
  global $newsletter;
185
 
186
  $options = get_option('newsletter', array());
187
  $options_profile = get_option('newsletter_profile', array());
188
 
189
+ $opt_in = (int) $this->options['noconfirmation']; // 0 - double, 1 - single
 
 
 
190
 
191
  $email = $newsletter->normalize_email(stripslashes($_REQUEST['ne']));
192
+ if ($email == null)
193
+ die('Wrong email');
194
 
195
+ $user = $newsletter->get_user($email);
196
 
197
+ if ($user != null) {
198
+ if ($user->status == 'B' || $user->status == 'C' || $user->status == 'S') {
199
+ $this->logger->error('Subscription of an address with status ' . $user->status);
200
+ $user->status = 'E';
201
+ return $user;
202
+ }
203
  }
 
 
 
204
 
205
+ if ($user != null) {
206
+ $this->logger->info("Email address subscribed but not confirmed");
207
+ $user = array('id' => $user->id);
208
+ } else {
209
+ $this->logger->info("New email address");
210
+ $user = array('email' => $email);
211
+ }
212
 
213
+ $user['name'] = $newsletter->normalize_name(stripslashes($_REQUEST['nn']));
214
+ // TODO: required checking
215
 
216
+ $user['surname'] = $newsletter->normalize_name(stripslashes($_REQUEST['ns']));
217
+ // TODO: required checking
218
 
219
+ if (!empty($_REQUEST['nx']))
220
+ $user['sex'] = $_REQUEST['nx'][0];
221
+ // TODO: valid values check
222
 
223
+ $user['referrer'] = $_REQUEST['nr'];
224
+ $user['http_referer'] = $_SERVER['HTTP_REFERER'];
225
 
226
+ // New profiles
227
+ for ($i = 1; $i <= NEWSLETTER_PROFILE_MAX; $i++) {
228
+ // If the profile cannot be set by subscriber, skiyp it.
229
+ if ($options_profile['profile_' . $i . '_status'] == 0)
230
+ continue;
231
 
232
+ $user['profile_' . $i] = trim(stripslashes($_REQUEST['np' . $i]));
233
+ }
234
 
235
+ // Preferences (field names are nl[] and values the list number so special forms with radio button can work)
236
+ if (is_array($_REQUEST['nl'])) {
237
+ for ($i = 1; $i <= NEWSLETTER_LIST_MAX; $i++) {
238
+ // If not zero it is selectable by user (on subscription or on profile)
239
+ if ($options_profile['list_' . $i . '_status'] == 0)
240
+ continue;
241
+ if (in_array($i, $_REQUEST['nl']))
242
+ $user['list_' . $i] = 1;
243
  }
244
+ }
245
 
246
+ // Forced preferences as set on subscription configuration
247
+ if (is_array($options['preferences'])) {
248
+ foreach ($options['preferences'] as $p) {
249
+ $user['list_' . $p] = 1;
 
250
  }
251
+ }
252
 
253
+ $user['token'] = $newsletter->get_token();
254
+ $user['ip'] = $_SERVER['REMOTE_ADDR'];
255
+ if ($status != null)
256
+ $user['status'] = $status;
257
+ else
258
  $user['status'] = $opt_in == 1 ? 'C' : 'S';
259
 
260
+ // TODO: add the flow integration?
 
 
 
 
261
 
262
+ if (isset($flow)) {
263
+ $user['flow'] = $flow;
264
+ }
 
 
 
 
265
 
266
+ $user = apply_filters('newsletter_user_subscribe', $user);
267
 
268
+ // TODO: should be removed!!!
269
+ if (defined('NEWSLETTER_FEED_VERSION')) {
270
+ $options_feed = get_option('newsletter_feed', array());
271
+ if ($options_feed['add_new'] == 1)
272
+ $user['feed'] = 1;
273
+ }
274
 
275
+ $user = $newsletter->save_user($user);
276
 
277
+ // Notification to admin (only for new confirmed subscriptions)
278
+ if ($user->status == 'C') {
279
+ $this->notify_admin($user, 'Newsletter subscription');
280
+ setcookie('newsletter', $user->id . '-' . $user->token, time() + 60 * 60 * 24 * 365, '/');
 
 
 
 
 
 
 
 
 
 
 
 
 
281
  }
282
 
283
+ if (!$emails)
284
+ return $user;
285
+
286
 
287
  $prefix = ($user->status == 'C') ? 'confirmed_' : 'confirmation_';
288
  $message = $options[$prefix . 'message'];
291
  $message_text = $options[$prefix . 'message_text'];
292
  $subject = $options[$prefix . 'subject'];
293
 
 
 
 
 
294
  $this->mail($user->email, $newsletter->replace($subject, $user), $newsletter->replace($message, $user));
295
 
296
  return $user;
310
  Newsletter::instance()->mail($to, $subject, $message);
311
  }
312
 
313
+ /**
314
+ *
315
+ * @global Newsletter $newsletter
316
+ * @param type $user
317
+ * @return type
318
+ */
319
+ function confirm($user_id = null, $emails = true) {
320
  global $newsletter;
321
+ if ($user_id == null) {
322
+ $user = $this->get_user_from_request();
323
+ } else {
324
+ $user = $newsletter->get_user($user_id);
325
+ }
326
+
327
+ if ($user == null)
328
+ die('No subscriber found.');
329
+ if ($user->status != 'S') {
330
+ $user->status = 'E';
331
+ return $user;
332
+ }
333
  setcookie('newsletter', $user->id . '-' . $user->token, time() + 60 * 60 * 24 * 365, '/');
334
+ $newsletter->set_user_status($user->id, 'C');
335
+ $user->status = 'C';
336
+
337
+ if (!$emails)
338
+ return $user;
339
 
340
  $message = $this->options['confirmed_message'];
341
 
347
 
348
  $this->notify_admin($user, 'Newsletter subscription');
349
 
350
+
351
  return $user;
352
  }
353
 
360
  function unsubscribe() {
361
  global $newsletter;
362
  $user = $this->get_user_from_request();
 
 
363
  setcookie('newsletter', '', time() - 3600);
364
+ if ($user == null) {
365
+ die('Subscriber not found');
366
+ }
367
+ if ($user->status != 'C') {
368
+ $user->status = 'E';
369
+ return $user;
370
+ }
371
 
372
+ $newsletter->set_user_status($user->id, 'U');
 
373
 
374
+ $this->mail($user->email, $newsletter->replace($this->options['unsubscribed_subject'], $user), $newsletter->replace($this->options['unsubscribed_message'], $user));
375
  $this->notify_admin($user, 'Newsletter unsubscription');
376
 
377
  return $user;
381
  global $newsletter;
382
 
383
  $user = $this->get_user_from_request();
384
+ if ($user == null)
385
+ die('No subscriber found.');
386
 
387
 
388
  $options_profile = get_option('newsletter_profile', array());
389
  $options_main = get_option('newsletter_main', array());
390
 
391
+ if (!$newsletter->is_email($_REQUEST['ne']))
392
+ die('Wrong email address.');
393
 
394
  // General data
395
  $data['email'] = $newsletter->normalize_email(stripslashes($_REQUEST['ne']));
398
  if ($options_profile['sex_status'] >= 1) {
399
  $data['sex'] = $_REQUEST['nx'][0];
400
  // Wrong data injection check
401
+ if ($data['sex'] != 'm' && $data['sex'] != 'f' && $data['sex'] != 'n')
402
+ die('Wrong sex field');
403
  }
404
 
405
+ // Lists. If not list is present or there is no list to choose or all are unchecked.
406
+ $nl = $_REQUEST['nl'];
407
+ if (!is_array($nl))
408
+ $nl = array();
409
+
410
+ // For each preference which an be edited (and so is present on profile form)...
411
+ for ($i = 1; $i <= NEWSLETTER_LIST_MAX; $i++) {
412
+ if ($options_profile['list_' . $i . '_status'] == 0)
413
+ continue;
414
+ $data['list_' . $i] = in_array($i, $nl) ? 1 : 0;
415
  }
416
 
417
  // Profile
418
  for ($i = 1; $i <= NEWSLETTER_PROFILE_MAX; $i++) {
419
+ if ($options_profile['profile_' . $i . '_status'] == 0)
420
+ continue;
421
  $data['profile_' . $i] = stripslashes($_REQUEST['np' . $i]);
422
  }
423
 
 
 
 
 
 
 
424
  $data['id'] = $user->id;
425
 
426
  // Feed by Mail service is saved here
427
  $data = apply_filters('newsletter_profile_save', $data);
428
+ //var_dump($data);
429
 
430
+ $user = $newsletter->save_user($data);
431
  return $user;
432
  }
433
 
434
  /**
435
  * Finds the right way to show the message identified by $key (welcome, unsubscription, ...) redirecting the user to the
436
  * WordPress page or loading the configured url or activating the standard page.
437
+ *
438
+ * @global Newsletter $newsletter
439
  */
440
  function show_message($key, $user, $alert = '') {
441
+ global $newsletter;
442
+
443
  if (!is_object($user)) {
444
+ if (is_array($user))
445
+ $user = (object) $user;
446
+ else
447
+ $user = $newsletter->get_user($user);
448
  }
449
 
450
+ if (!empty($alert))
451
+ $params = '&alert=' . urlencode($alert);
452
 
453
  // Add exceptions for "profile" key.
454
  // Is there a custom url?
471
  /**
472
  * Loads the user using the request parameters (nk or nt and ni).
473
  *
474
+ * @global Newsletter $newsletter
475
  * @return null
476
  */
477
  function get_user_from_request() {
478
+ global $newsletter;
479
+
480
  if (isset($_REQUEST['nk'])) {
481
  list($id, $token) = @explode('-', $_REQUEST['nk'], 2);
482
  } else if (isset($_REQUEST['ni'])) {
483
  $id = (int) $_REQUEST['ni'];
484
  $token = $_REQUEST['nt'];
485
  }
486
+ $user = $newsletter->get_user($id);
487
 
488
+ if ($user == null || $token != $user->token)
489
+ return null;
490
  return $user;
491
  }
492
 
493
  function get_message_key_from_request() {
494
+ if (empty($_GET['nm']))
495
+ return 'subscription';
496
  $key = $_GET['nm'];
497
  switch ($key) {
498
  case 's': return 'confirmation';
512
  *
513
  * @global wpdb $wpdb
514
  * @global type $current_user
515
+ * @global Newsletter $newsletter
516
  * @return null
517
  */
518
  function check_user() {
519
+ global $wpdb, $current_user, $newsletter;
520
 
521
  if (isset($_REQUEST['nk'])) {
522
  list($id, $token) = @explode('-', $_REQUEST['nk'], 2);
531
  return $wpdb->get_row($wpdb->prepare("select * from " . $wpdb->prefix . "newsletter where id=%d and token=%s limit 1", $id, $token));
532
  }
533
 
534
+ return null;
535
+
536
+ // TODO: Remove!
537
  if ($this->options_main['wp_integration'] != 1) {
538
  return null;
539
  }
557
  $user['email'] = strtolower($current_user->user_email);
558
 
559
  $id = $wpdb->insert(NEWSLETTER_USERS_TABLE, $user);
560
+ $user = $newsletter->get_user($id);
561
  } else {
562
  //echo 'WP user found via email';
563
  $wpdb->query($wpdb->prepare("update " . NEWSLETTER_USERS_TABLE . " set wp_user_id=" . $current_user->ID . ", email=%s", $current_user->user_email));
611
  *
612
  * @return string The html code of the subscription form
613
  */
614
+ function get_subscription_form($referrer = null) {
615
  $options_profile = get_option('newsletter_profile');
616
  $options = get_option('newsletter');
617
 
624
  } else {
625
  $buffer .= '<form method="post" action="' . $action . '" onsubmit="return newsletter_check(this)">' . "\n\n";
626
  }
627
+ if (!empty($referrer)) {
628
+ $buffer .= "<input type='hidden' name='nr' value='$referrer'>\n";
629
+ }
630
  $buffer .= '<table cellspacing="0" cellpadding="3" border="0">' . "\n\n";
631
  if ($options_profile['name_status'] == 2) {
632
  $buffer .= "<!-- first name -->\n";
633
+ $buffer .= "<tr>\n\t" . '<th>' . $options_profile['name'] . '</th>' . "\n\t" . '<td><input class="newsletter-firstname" type="text" name="nn" size="30"' . ($options_profile['name_rules'] == 1 ? 'required' : '') . '></td>' . "\n" . '</tr>' . "\n\n";
634
  }
635
+
636
  if ($options_profile['surname_status'] == 2) {
637
  $buffer .= "<!-- last name -->\n";
638
+ $buffer .= "<tr>\n\t" . '<th>' . $options_profile['surname'] . '</th>' . "\n\t" . '<td><input class="newsletter-lastname" type="text" name="ns" size="30"' . ($options_profile['surname_rules'] == 1 ? 'required' : '') . '></td>' . "\n" . '</tr>' . "\n\n";
639
  }
640
 
641
  $buffer .= "<!-- email -->\n";
642
+ $buffer .= "<tr>\n\t" . '<th>' . $options_profile['email'] . '</th>' . "\n\t" . '<td align="left"><input class="newsletter-email" type="email" name="ne" size="30" required></td>' . "\n" . '</tr>' . "\n\n";
643
 
644
  if ($options_profile['sex_status'] == 2) {
645
  $buffer .= "<!-- sex -->\n";
646
+ $buffer .= "<tr>\n\t<th>" . $options_profile['sex'] . "</th>\n";
647
+ $buffer .= "\t<td>\n\t" . '<select name="nx" class="newsletter-sex">' . "\n";
648
  $buffer .= "\t\t" . '<option value="m">' . $options_profile['sex_male'] . '</option>' . "\n";
649
  $buffer .= "\t\t" . '<option value="f">' . $options_profile['sex_female'] . '</option>' . "\n";
650
  $buffer .= "\t</select>\n\t</td></tr>\n";
652
 
653
  $lists = '';
654
  for ($i = 1; $i <= NEWSLETTER_LIST_MAX; $i++) {
655
+ if ($options_profile['list_' . $i . '_status'] != 2)
656
+ continue;
657
  $lists .= "\t\t" . '<input type="checkbox" name="nl[]" value="' . $i . '"/>&nbsp;' . $options_profile['list_' . $i] . '<br />' . "\n";
658
  }
659
  if (!empty($lists))
660
+ $buffer .= "<!-- preferences -->\n<tr>\n\t<th>&nbsp;</th>\n\t<td>\n" . $lists . "\t</td>\n</tr>\n\n";
661
 
662
  // Extra profile fields
663
  for ($i = 1; $i <= NEWSLETTER_PROFILE_MAX; $i++) {
664
  // Not for subscription form
665
+ if ($options_profile['profile_' . $i . '_status'] != 2)
666
+ continue;
667
 
668
  // Text field
669
  if ($options_profile['profile_' . $i . '_type'] == 'text') {
689
 
690
  if ($options_profile['privacy_status'] == 1) {
691
  $buffer .= "<tr>\n\t" . '<td colspan="2" class="newsletter-td-privacy">' . "\n";
692
+ $buffer .= "\t\t" . '<input type="checkbox" name="ny" required>&nbsp;';
693
  if (!empty($options_profile['privacy_url'])) {
694
  $buffer .= '<a target="_blank" href="' . $options_profile['privacy_url'] . '">';
695
  $buffer .= $options_profile['privacy'] . '</a>';
702
  $buffer .= "<tr>\n\t" . '<td colspan="2" class="newsletter-td-submit">' . "\n";
703
 
704
  if (strpos($options_profile['subscribe'], 'http://') !== false) {
705
+ $buffer .= "\t\t" . '<input class="newsletter-submit-image" type="image" src="' . $options_profile['subscribe'] . '"/>' . "\n\t</td>\n</tr>\n\n";
706
  } else {
707
  $buffer .= "\t\t" . '<input class="newsletter-submit" type="submit" value="' . $options_profile['subscribe'] . '"/>' . "\n\t</td>\n</tr>\n\n";
708
  }
742
 
743
  // Profile
744
  for ($i = 1; $i <= NEWSLETTER_PROFILE_MAX; $i++) {
745
+ if ($options['profile_' . $i . '_status'] == 0)
746
+ continue;
747
 
748
  $buffer .= '<tr><th align="right">' . $options['profile_' . $i] . '</th><td>';
749
  //if ($options['list_type_' . $i] != 'public') continue;
759
  for ($j = 0; $j < count($opts); $j++) {
760
  $opts[$j] = trim($opts[$j]);
761
  $buffer .= '<option';
762
+ if ($opts[$j] == $user->$field)
763
+ $buffer .= ' selected';
764
  $buffer .= '>' . $opts[$j] . '</option>';
765
  }
766
  $buffer .= '</select>';
772
  // Lists
773
  $buffer .= '<tr><th>&nbsp;</th><td>';
774
  for ($i = 1; $i <= NEWSLETTER_LIST_MAX; $i++) {
775
+ if ($options['list_' . $i . '_status'] == 0)
776
+ continue;
777
  $buffer .= '<input type="checkbox" name="nl[]" value="' . $i . '"';
778
  $list = 'list_' . $i;
779
+ if ($user->$list == 1)
780
+ $buffer .= ' checked';
781
  $buffer .= '/> ' . htmlspecialchars($options['list_' . $i]) . '<br />';
782
  }
783
  $buffer .= '</td></tr>';
784
 
 
 
 
 
 
 
 
 
 
 
 
785
  $extra = apply_filters('newsletter_profile_extra', array(), $user);
786
  foreach ($extra as &$x) {
787
  $buffer .= "<tr>\n\t<th>" . $x['label'] . "</th>\n\t<td>\n\t\t";
789
  }
790
 
791
  $buffer .= '<tr><td colspan="2" class="newsletter-td-submit">';
792
+
793
  if (strpos($options['save'], 'http://') !== false) {
794
  $buffer .= '<input class="newsletter-submit" type="image" src="' . $options['save'] . '"/></td></tr>';
795
  } else {
796
  $buffer .= '<input class="newsletter-submit" type="submit" value="' . $options['save'] . '"/></td></tr>';
797
  }
798
+
799
  $buffer .= '</table></form></div>';
800
 
801
  return $buffer;
829
  $options_profile = get_option('newsletter_profile');
830
  $lists = '';
831
  for ($i = 1; $i <= NEWSLETTER_LIST_MAX; $i++) {
832
+ if ($options_profile['list_' . $i . '_status'] != 2)
833
+ continue;
834
  $lists .= '<input type="checkbox" name="nl[]" value="' . $i . '"/>&nbsp;' . $options_profile['list_' . $i] . '<br />';
835
  }
836
  $buffer = str_replace('{lists}', $lists, $buffer);
840
 
841
  function notify_admin($user, $subject) {
842
 
843
+ if ($this->options['notify'] != 1)
844
+ return;
845
 
846
  $message = "Subscriber details:\n\n" .
847
  "email: " . $user->email . "\n" .
852
  $options_profile = get_option('newsletter_profile');
853
 
854
  for ($i = 0; $i < NEWSLETTER_PROFILE_MAX; $i++) {
855
+ if ($options_profile['profile_' . $i] == '')
856
+ continue;
857
  $field = 'profile_' . $i;
858
  $message .= $options_profile['profile_' . $i] . ': ' . $user->$field . "\n";
859
  }
860
 
861
  for ($i = 0; $i < NEWSLETTER_LIST_MAX; $i++) {
862
+ if ($options_profile['list_' . $i] == '')
863
+ continue;
864
  $field = 'list_' . $i;
865
  $message .= $options_profile['list_' . $i] . ': ' . $user->$field . "\n";
866
  }
869
  "status: " . $user->status . "\n" .
870
  "\nYours, Newsletter Pro.";
871
  $email = trim($this->options['notify_email']);
872
+ if (empty($email))
873
+ $email = get_option('admin_email');
874
  wp_mail($email, '[' . get_option('blogname') . '] ' . $subject, $message, "Content-type: text/plain; charset=UTF-8\n");
875
  }
876
 
877
  }
878
 
879
+ NewsletterSubscription::instance();
880
+
881
  // TODO: Remove in version 3.5. For compatibility.
882
  add_shortcode('newsletter_embed', 'newsletter_shortcode_form');
883
 
895
 
896
  add_shortcode('newsletter', 'newsletter_shortcode');
897
 
898
+ /**
899
+ *
900
+ * @global type $wpdb
901
+ * @global boolean $cache_stop
902
+ * @global Newsletter $newsletter
903
+ * @param type $attrs
904
+ * @param type $content
905
+ * @return string
906
+ */
907
  function newsletter_shortcode($attrs, $content) {
908
  global $wpdb, $cache_stop, $newsletter;
909
 
914
  $message_key = $module->get_message_key_from_request();
915
  $alert = stripslashes($_REQUEST['alert']);
916
 
917
+ $message = $module->options[$message_key . '_text'];
918
+
919
+ // TODO: the if can be removed
920
+ if ($message_key == 'confirmed') {
921
+ $message .= $module->options[$message_key . '_tracking'];
922
+ }
923
 
924
  // Now check what form must be added
925
  if ($message_key == 'subscription') {
934
  $message .= '{subscription_form}';
935
  }
936
 
937
+ if (isset($attrs['form'])) {
938
+ $message = str_replace('{subscription_form}', $module->get_form($attrs['form']), $message);
 
 
 
 
 
939
  } else {
940
+ $message = str_replace('{subscription_form}', $module->get_subscription_form('page'), $message);
 
 
 
 
 
941
  }
942
  }
943
  }
944
 
945
+ $message = $newsletter->replace($message, $user, null, 'page');
946
+
947
  if (!empty($alert)) {
948
  $message .= '<script>alert("' . addslashes($alert) . '");</script>';
949
  }
955
  // option on every page load. The registration code should be moved inside the module...
956
  add_action('user_register', 'newsletter_subscription_user_register');
957
 
958
+ function newsletter_subscription_user_register($wp_user_id) {
959
+ global $wpdb, $newsletter;
960
 
961
  $module = NewsletterSubscription::instance();
962
 
963
+ // If the integration is disabled...
964
+ if ($module->options['subscribe_wp_users'] == 0)
965
+ return;
966
+
967
+ // If not forced and the user didn't choose the newsletter...
968
+ if ($module->options['subscribe_wp_users'] != 1) {
969
+ if (!isset($_REQUEST['newsletter']))
970
+ return;
971
+ }
972
 
973
+ $module->logger->info('Adding a registered WordPress user (' . $wp_user_id . ')');
974
+ $wp_user = $wpdb->get_row($wpdb->prepare("select * from $wpdb->users where id=%d limit 1", $wp_user_id));
975
  if (empty($wp_user)) {
976
  $module->logger->error('User not found?!');
977
  return;
978
  }
 
 
 
 
 
979
 
980
+ $_REQUEST['ne'] = $wp_user->user_email;
981
+ $_REQUEST['nr'] = 'registration';
982
+ // Upon registration there is no last name and first name, sorry.
983
+ // With registration always store as unconfirmed, it will be confirmed on first login
984
+ $user = $module->subscribe('S', false);
985
 
986
+ // Now we associate it with wp
987
+ $module->set_user_wp_user_id($user->id, $wp_user_id);
988
  }
989
 
990
  // Compatibility code
997
  }
998
  }
999
 
1000
+ add_action('register_form', 'newsletter_register_form');
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1001
 
1002
+ function newsletter_register_form() {
1003
+ $module = NewsletterSubscription::instance();
1004
+ if ($module->options['subscribe_wp_users'] == 2 || $module->options['subscribe_wp_users'] == 3) {
1005
+ echo '<p>';
1006
+ echo '<input type="checkbox" value="1" name="newsletter"';
1007
+ if ($module->options['subscribe_wp_users'] == 3) {
1008
+ echo ' checked';
1009
+ }
1010
+ echo '>&nbsp;';
1011
+ echo $module->options['subscribe_wp_users_label'];
1012
+ echo '</p>';
1013
+ }
1014
  }
1015
 
 
 
 
 
 
users/edit.php CHANGED
@@ -24,7 +24,7 @@ if ($controls->is_action('save')) {
24
 
25
  if ($controls->is_action('delete')) {
26
  $module->delete_user($id);
27
- $controls->js_redirect('admin.php?page=newsletter/users/index.php');
28
  return;
29
  }
30
 
@@ -39,9 +39,11 @@ $options_profile = get_option('newsletter_profile');
39
  <?php include NEWSLETTER_DIR . '/header.php'; ?>
40
  <?php include NEWSLETTER_DIR . '/users/menu.inc.php'; ?>
41
 
 
 
42
  <?php $controls->show(); ?>
43
 
44
- <form method="post" action="admin.php?page=newsletter/users/edit.php&id=<?php echo $id; ?>">
45
  <?php $controls->init(); ?>
46
 
47
  <div id="tabs">
@@ -99,12 +101,9 @@ $options_profile = get_option('newsletter_profile');
99
  </div>
100
  </td>
101
  </tr>
102
- <tr valign="top">
103
- <th>Follow up</th>
104
- <td>
105
- <?php $controls->yesno('followup'); ?> step: <?php $controls->text('followup_step'); ?> (next step on: <?php $controls->value_date('followup_time'); ?>)
106
- </td>
107
- </tr>
108
  <tr valign="top">
109
  <th>Feed by mail</th>
110
  <td>
24
 
25
  if ($controls->is_action('delete')) {
26
  $module->delete_user($id);
27
+ $controls->js_redirect($module->get_admin_page_url('index'));
28
  return;
29
  }
30
 
39
  <?php include NEWSLETTER_DIR . '/header.php'; ?>
40
  <?php include NEWSLETTER_DIR . '/users/menu.inc.php'; ?>
41
 
42
+ <h2>Subscriber Edit</h2>
43
+
44
  <?php $controls->show(); ?>
45
 
46
+ <form method="post" action="">
47
  <?php $controls->init(); ?>
48
 
49
  <div id="tabs">
101
  </div>
102
  </td>
103
  </tr>
104
+
105
+ <?php do_action('newsletter_user_edit_extra', $controls); ?>
106
+
 
 
 
107
  <tr valign="top">
108
  <th>Feed by mail</th>
109
  <td>
users/export.php CHANGED
@@ -1,10 +1,9 @@
1
  <?php
2
-
3
  @include_once NEWSLETTER_INCLUDES_DIR . '/controls.php';
4
 
5
  $options_profile = get_option('newsletter_profile');
6
-
7
  $controls = new NewsletterControls();
 
8
 
9
  $lists = array('0' => 'All');
10
  for ($i = 1; $i <= NEWSLETTER_LIST_MAX; $i++) {
@@ -13,18 +12,27 @@ for ($i = 1; $i <= NEWSLETTER_LIST_MAX; $i++) {
13
  ?>
14
 
15
  <div class="wrap">
16
- <?php include NEWSLETTER_DIR . '/users/menu.inc.php'; ?>
 
 
 
 
 
 
 
 
 
17
 
18
- <form method="post" action="<?php echo NEWSLETTER_URL; ?>/users/csv.php">
19
- <?php $controls->init(); ?>
20
- <table class="form-table">
21
- <tr>
22
- <td>
23
- <?php $controls->select('list', $lists); ?>
24
- <?php $controls->button('export', 'Export'); ?>
25
- </td>
26
- </tr>
27
- </table>
28
- </form>
29
 
30
  </div>
1
  <?php
 
2
  @include_once NEWSLETTER_INCLUDES_DIR . '/controls.php';
3
 
4
  $options_profile = get_option('newsletter_profile');
 
5
  $controls = new NewsletterControls();
6
+ $module = NewsletterUsers::instance();
7
 
8
  $lists = array('0' => 'All');
9
  for ($i = 1; $i <= NEWSLETTER_LIST_MAX; $i++) {
12
  ?>
13
 
14
  <div class="wrap">
15
+ <?php include NEWSLETTER_DIR . '/users/menu.inc.php'; ?>
16
+
17
+ <h2>Export</h2
18
+
19
+ <div class="preamble">
20
+ <p>
21
+ The import and export functions <strong>ARE NOT for backup</strong>. If you want to backup you should consider to backup the
22
+ wp_newsletter* tables.
23
+ </p>
24
+ </div>
25
 
26
+ <form method="post" action="<?php echo NEWSLETTER_URL; ?>/users/csv.php">
27
+ <?php $controls->init(); ?>
28
+ <table class="form-table">
29
+ <tr>
30
+ <td>
31
+ <?php $controls->select('list', $lists); ?>
32
+ <?php $controls->button('export', 'Export'); ?>
33
+ </td>
34
+ </tr>
35
+ </table>
36
+ </form>
37
 
38
  </div>
users/import.php CHANGED
@@ -1,6 +1,7 @@
1
  <?php
2
  require_once NEWSLETTER_INCLUDES_DIR . '/controls.php';
3
  $controls = new NewsletterControls();
 
4
 
5
  $options_profile = get_option('newsletter_profile');
6
 
@@ -97,8 +98,17 @@ if ($controls->is_action('import')) {
97
  <?php include NEWSLETTER_DIR . '/header.php'; ?>
98
 
99
  <?php include NEWSLETTER_DIR . '/users/menu.inc.php'; ?>
 
 
 
100
  <?php $controls->show(); ?>
101
 
 
 
 
 
 
 
102
  <p>
103
  Please consider to break up your input list if you get errors, blank pages or partially imported lists: it can be a time/resource limit
104
  of your provider. It's safe to import the same list a second time, no duplications will occur.
@@ -111,6 +121,7 @@ if ($controls->is_action('import')) {
111
  where [separator] must be selected from the available ones. Empty lines and lines starting with "#" will be skipped. There is
112
  no separator essaping mechanism, so be sure that field values do not contain the selected separator.
113
  </p>
 
114
 
115
  <?php if (!empty($results)) { ?>
116
 
1
  <?php
2
  require_once NEWSLETTER_INCLUDES_DIR . '/controls.php';
3
  $controls = new NewsletterControls();
4
+ $module = NewsletterUsers::instance();
5
 
6
  $options_profile = get_option('newsletter_profile');
7
 
98
  <?php include NEWSLETTER_DIR . '/header.php'; ?>
99
 
100
  <?php include NEWSLETTER_DIR . '/users/menu.inc.php'; ?>
101
+
102
+ <h2>Import</h2>
103
+
104
  <?php $controls->show(); ?>
105
 
106
+ <div class="preamble">
107
+ <p>
108
+ The import and export functions <strong>ARE NOT for backup</strong>. If you want to backup you should consider to backup the
109
+ wp_newsletter* tables.
110
+ </p>
111
+
112
  <p>
113
  Please consider to break up your input list if you get errors, blank pages or partially imported lists: it can be a time/resource limit
114
  of your provider. It's safe to import the same list a second time, no duplications will occur.
121
  where [separator] must be selected from the available ones. Empty lines and lines starting with "#" will be skipped. There is
122
  no separator essaping mechanism, so be sure that field values do not contain the selected separator.
123
  </p>
124
+ </div>
125
 
126
  <?php if (!empty($results)) { ?>
127
 
users/index-old.php ADDED
@@ -0,0 +1,274 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ require_once NEWSLETTER_INCLUDES_DIR . '/controls.php';
4
+
5
+ $controls = new NewsletterControls();
6
+ $module = NewsletterUsers::instance();
7
+
8
+ $options = stripslashes_deep($_POST['options']);
9
+ $options_lists = get_option('newsletter_profile');
10
+ $options_profile = get_option('newsletter_profile');
11
+ $options_main = get_option('newsletter_main');
12
+
13
+ $lists = array(''=>'Any');
14
+ for ($i=1; $i<=NEWSLETTER_LIST_MAX; $i++)
15
+ {
16
+ if (empty($options_lists['list_' . $i])) continue;
17
+ $lists[''.$i] = '(' . $i . ') ' . $options_lists['list_' . $i];
18
+ }
19
+
20
+ if ($controls->is_action('resend')) {
21
+ $user = NewsletterUsers::instance()->get_user($controls->button_data);
22
+ $opts = get_option('newsletter');
23
+ $newsletter->mail($user->email, $newsletter->replace($opts['confirmation_subject'], $user), $newsletter->replace($opts['confirmation_message'], $user));
24
+ $controls->messages = 'Activation email resent to ' . $user->email;
25
+ }
26
+
27
+ if ($controls->is_action('resend_welcome')) {
28
+ $user = NewsletterUsers::instance()->get_user($controls->button_data);
29
+ $opts = get_option('newsletter');
30
+ $newsletter->mail($user->email, $newsletter->replace($opts['confirmed_subject'], $user), $newsletter->replace($opts['confirmed_message'], $user));
31
+ $controls->messages = 'Welcome email resent.';
32
+ }
33
+
34
+ if ($controls->is_action('remove')) {
35
+ $wpdb->query($wpdb->prepare("delete from " . $wpdb->prefix . "newsletter where id=%d", $controls->button_data));
36
+ unset($controls->data['subscriber_id']);
37
+ }
38
+
39
+ if ($action == 'status') {
40
+ newsletter_set_status($controls->data['subscriber_id'], $controls->data['subscriber_status']);
41
+ }
42
+
43
+
44
+ if ($controls->is_action('search')) {
45
+
46
+ if (empty($controls->data['search_order'])) $order = 'email';
47
+ if ($controls->data['search_order'] == 'id') $order = 'id desc';
48
+
49
+ $query = "select * from " . $wpdb->prefix . "newsletter where 1=1";
50
+
51
+ if (!empty($controls->data['search_status'])) {
52
+ $query .= " and status='" . $wpdb->escape($controls->data['search_status']) . "'";
53
+ }
54
+
55
+ if (!empty($controls->data['search_test'])) {
56
+ $query .= " and test=1";
57
+ }
58
+
59
+ if (trim($controls->data['search_text']) != '') {
60
+ $query .= " and (email like '%" .
61
+ $wpdb->escape($controls->data['search_text']) . "%' or name like '%" . $wpdb->escape($controls->data['search_text']) . "%')";
62
+ }
63
+
64
+ if (!empty($controls->data['search_list'])) {
65
+ $query .= " and list_" . ((int) $controls->data['search_list']) . "=1";
66
+ }
67
+
68
+ if (!empty($controls->data['search_link'])) {
69
+ list($newsletter, $url) = explode('|', $link);
70
+ $query .= " and id in (select distinct user_id from " . $wpdb->prefix . "newsletter_stats where newsletter='" .
71
+ $wpdb->escape($newsletter) . "' and url='" . $wpdb->escape($url) . "')";
72
+ }
73
+
74
+ $query .= ' order by ' . $order;
75
+
76
+ if (!empty($options['search_limit'])) {
77
+ $query .= ' limit ' . $limit;
78
+ }
79
+
80
+ //if (empty($link)) $query .= ' limit 100';
81
+
82
+
83
+ $list = $wpdb->get_results($query);
84
+
85
+ }
86
+ else {
87
+ $list = array();
88
+ }
89
+
90
+ ?>
91
+
92
+ <div class="wrap">
93
+
94
+ <?php $help_url = 'http://www.satollo.net/plugins/newsletter/subscribers-module'; ?>
95
+ <?php include NEWSLETTER_DIR . '/header.php'; ?>
96
+
97
+ <?php include NEWSLETTER_DIR . '/users/menu.inc.php'; ?>
98
+
99
+ <?php $controls->show(); ?>
100
+
101
+ <form id="channel" method="post" action="">
102
+ <?php $controls->init(); ?>
103
+ <input type="hidden" name="options[subscriber_id]"/>
104
+ <input type="hidden" name="options[subscriber_status]"/>
105
+
106
+ <?php
107
+ $tmp = $wpdb->get_results("select distinct newsletter, url from " . $wpdb->prefix . "newsletter_stats order by newsletter,url");
108
+ $links = array(''=>'Unfiltered');
109
+ foreach ($tmp as $t) {
110
+ $links[$t->newsletter . '|' . $t->url] = $t->newsletter . ': ' . substr($t->url, 0, min(strlen($t->url), 50)) . '...';
111
+ }
112
+ ?>
113
+
114
+ <div style="padding: .6em; border: 1px solid #ddd; background-color: #f4f4f4; border-radius: 3px;">
115
+ <?php $controls->text('search_text', 80); ?>
116
+ <?php $controls->button('search', 'Search'); ?>
117
+ </div>
118
+
119
+ <table class="form-table">
120
+ <tr valign="top">
121
+ <td>
122
+ <?php $controls->select('search_status', array(''=>'Any status', 'C'=>'Confirmed', 'S'=>'Not confirmed', 'U'=>'Unsubscribed', 'B'=>'Bounced')); ?>
123
+ <?php
124
+ $order_fields = array('id'=>'Order by id', 'email'=>'Order by email', 'name'=>'Order by name');
125
+ for ($i=1; $i<20; $i++) {
126
+ if ($options_profile['profile_' . $i] == '') continue;
127
+ $order_fields['profile_' . $i] = $options_profile['profile_' . $i];
128
+ }
129
+ ?>
130
+
131
+ <?php $controls->select('search_order', $order_fields); ?>
132
+
133
+ <?php $controls->select('search_limit', array(100=>'Max 100 results', '1000'=>'Max 1000 result', ''=>'No limit')); ?>
134
+
135
+ <?php $controls->select('search_list', $lists); ?>
136
+ <?php $controls->checkbox('search_test'); ?> Test subscribers
137
+ <br />
138
+ <?php _e('show clicks', 'newsletter'); ?>:&nbsp;<?php $controls->yesno('search_clicks'); ?>
139
+ who&nbsp;clicked:&nbsp;&nbsp;
140
+ <?php $controls->select('search_link', $links); ?>
141
+
142
+ <div class="hints">
143
+ Press without filter to show all. Max 100 results will be shown. Use export panel to get all subscribers.
144
+ </div>
145
+ </td>
146
+ </tr>
147
+ <tr valign="top">
148
+ <td>
149
+ <?php $controls->checkbox('show_profile', 'Show profile fields'); ?>
150
+ <?php $controls->checkbox('show_preferences', 'Show preferences'); ?>
151
+ </td>
152
+ </tr>
153
+ </table>
154
+
155
+
156
+ <h3>Search results</h3>
157
+
158
+ <?php if (empty($list)) { ?>
159
+ <p>No search results (or you did not search at all)</p>
160
+ <?php } ?>
161
+
162
+
163
+ <?php if (!empty($list)) { ?>
164
+
165
+ <table class="widefat">
166
+ <thead>
167
+ <tr>
168
+ <th>Id</th>
169
+ <th>Email/Name</th>
170
+ <?php if ($options['show_profile'] == 1) { ?>
171
+ <th>Profile</th>
172
+ <?php } ?>
173
+ <th>Status</th>
174
+ <?php if ($options['show_preferences'] == 1) { ?>
175
+ <th>Preferences</th>
176
+ <?php } ?>
177
+ <th>Actions</th>
178
+ <th>Others</th>
179
+ <?php if ($options['search_clicks'] == 1) { ?>
180
+ <th>Clicks</th>
181
+ <?php } ?>
182
+ </tr>
183
+ </thead>
184
+ <?php foreach($list as $s) { ?>
185
+ <tr class="<?php echo ($i++%2==0)?'alternate':''; ?>">
186
+
187
+ <td>
188
+ <?php echo $s->id; ?>
189
+ </td>
190
+
191
+ <td>
192
+ <?php echo $s->email; ?><br /><?php echo $s->name; ?> <?php echo $s->surname; ?>
193
+ </td>
194
+
195
+
196
+ <?php if ($options['show_profile'] == 1) { ?>
197
+ <td>
198
+ <small>
199
+ <?php
200
+ for ($i=1; $i<NEWSLETTER_PROFILE_MAX; $i++) {
201
+ if ($options_profile['profile_' . $i] == '') continue;
202
+ echo $options_profile['profile_' . $i];
203
+ echo ':';
204
+ $key = 'profile_' . $i;
205
+ echo htmlspecialchars($s->$key);
206
+ echo '<br />';
207
+ }
208
+ ?>
209
+ </small>
210
+ </td>
211
+ <?php } ?>
212
+
213
+ <td>
214
+ <small>
215
+ <?php
216
+ switch ($s->status) {
217
+ case 'S': echo 'NOT CONFIRMED'; break;
218
+ case 'C': echo 'CONFIRMED'; break;
219
+ case 'U': echo 'UNSUBSCRIBED'; break;
220
+ case 'B': echo 'BOUNCED'; break;
221
+ }
222
+ ?>
223
+ <br />
224
+ Feed: <?php echo ($s->feed!=1?'NO':'YES'); ?><br />
225
+ Follow Up: <?php echo ($s->followup!=1?'NO':'YES'); ?> (<?php echo $s->followup_step; ?>)
226
+ </small>
227
+ </td>
228
+
229
+ <?php if ($options['show_preferences'] == 1) { ?>
230
+ <td>
231
+ <small>
232
+ <?php
233
+ for ($i=1; $i<=NEWSLETTER_LIST_MAX; $i++) {
234
+ $l = 'list_' . $i;
235
+ if ($s->$l == 1) echo $lists['' . $i] . '<br />';
236
+ }
237
+ ?>
238
+ </small>
239
+ </td>
240
+ <?php } ?>
241
+
242
+ <td>
243
+ <a class="button-secondary" href="admin.php?page=newsletter_users_edit&amp;id=<?php echo $s->id; ?>">Edit</a>
244
+ <?php $controls->button_confirm('remove', 'Remove', 'Proceed?', $s->id); ?>
245
+
246
+ <?php //$controls->button('status', 'Confirm', 'newsletter_set_status(this.form,' . $s->id . ',\'C\')'); ?>
247
+ <?php //$controls->button('status', 'Unconfirm', 'newsletter_set_status(this.form,' . $s->id . ',\'S\')'); ?>
248
+
249
+ <?php $controls->button_confirm('resend', 'Resend confirmation', 'Proceed?', $s->id); ?>
250
+ <?php $controls->button_confirm('resend_welcome', 'Resend welcome', 'Proceed?', $s->id); ?>
251
+ <a href="<?php echo NEWSLETTER_PROFILE_URL; ?>?nk=<?php echo $s->id . '-' . $s->token; ?>" class="button" target="_blank">Profile page</a>
252
+ </td>
253
+ <td><small>
254
+ date: <?php echo $s->created; ?><br />
255
+
256
+ </small></td>
257
+
258
+ <?php if ($options['search_clicks'] == 1) { ?>
259
+ <td><small>
260
+ <?php
261
+ $clicks = $wpdb->get_results($wpdb->prepare("select * from " . $wpdb->prefix . "newsletter_stats where user_id=%d order by newsletter", $s->id));
262
+ foreach ($clicks as &$click) {
263
+ ?>
264
+ <?php echo $click->newsletter; ?>: <?php echo $click->url; ?><br />
265
+ <?php } ?>
266
+ </small></td>
267
+ <?php } ?>
268
+
269
+ </tr>
270
+ <?php } ?>
271
+ </table>
272
+ <?php } ?>
273
+ </form>
274
+ </div>
users/index.php CHANGED
@@ -3,6 +3,7 @@
3
  require_once NEWSLETTER_INCLUDES_DIR . '/controls.php';
4
 
5
  $controls = new NewsletterControls();
 
6
 
7
  $options = stripslashes_deep($_POST['options']);
8
  $options_lists = get_option('newsletter_profile');
@@ -35,57 +36,68 @@ if ($controls->is_action('remove')) {
35
  unset($controls->data['subscriber_id']);
36
  }
37
 
38
- if ($action == 'status') {
39
- newsletter_set_status($controls->data['subscriber_id'], $controls->data['subscriber_status']);
 
 
 
40
  }
41
 
 
 
 
42
 
43
- if ($controls->is_action('search')) {
44
-
45
- if (empty($controls->data['search_order'])) $order = 'email';
46
- if ($controls->data['search_order'] == 'id') $order = 'id desc';
47
-
48
- $query = "select * from " . $wpdb->prefix . "newsletter where 1=1";
49
-
50
- if (!empty($controls->data['search_status'])) {
51
- $query .= " and status='" . $wpdb->escape($controls->data['search_status']) . "'";
52
- }
53
-
54
- if (!empty($controls->data['search_test'])) {
55
- $query .= " and test=1";
56
- }
57
-
58
- if (trim($controls->data['search_text']) != '') {
59
- $query .= " and (email like '%" .
60
- $wpdb->escape($controls->data['search_text']) . "%' or name like '%" . $wpdb->escape($controls->data['search_text']) . "%')";
61
- }
62
-
63
- if (!empty($controls->data['search_list'])) {
64
- $query .= " and list_" . ((int) $controls->data['search_list']) . "=1";
65
- }
66
-
67
- if (!empty($controls->data['search_link'])) {
68
- list($newsletter, $url) = explode('|', $link);
69
- $query .= " and id in (select distinct user_id from " . $wpdb->prefix . "newsletter_stats where newsletter='" .
70
- $wpdb->escape($newsletter) . "' and url='" . $wpdb->escape($url) . "')";
71
- }
72
-
73
- $query .= ' order by ' . $order;
74
-
75
- if (!empty($options['search_limit'])) {
76
- $query .= ' limit ' . $limit;
77
- }
78
 
79
- //if (empty($link)) $query .= ' limit 100';
 
 
 
 
 
 
 
 
 
 
 
 
 
 
80
 
 
 
 
81
 
82
- $list = $wpdb->get_results($query);
83
 
84
- }
85
- else {
86
- $list = array();
87
- }
88
 
 
 
89
  ?>
90
 
91
  <div class="wrap">
@@ -94,73 +106,31 @@ else {
94
  <?php include NEWSLETTER_DIR . '/header.php'; ?>
95
 
96
  <?php include NEWSLETTER_DIR . '/users/menu.inc.php'; ?>
 
 
97
 
98
  <?php $controls->show(); ?>
99
 
100
  <form id="channel" method="post" action="">
101
  <?php $controls->init(); ?>
102
- <input type="hidden" name="options[subscriber_id]"/>
103
- <input type="hidden" name="options[subscriber_status]"/>
104
-
105
- <?php
106
- $tmp = $wpdb->get_results("select distinct newsletter, url from " . $wpdb->prefix . "newsletter_stats order by newsletter,url");
107
- $links = array(''=>'Unfiltered');
108
- foreach ($tmp as $t) {
109
- $links[$t->newsletter . '|' . $t->url] = $t->newsletter . ': ' . substr($t->url, 0, min(strlen($t->url), 50)) . '...';
110
- }
111
- ?>
112
 
113
  <div style="padding: .6em; border: 1px solid #ddd; background-color: #f4f4f4; border-radius: 3px;">
114
- <?php $controls->text('search_text', 80); ?>
115
- <?php $controls->button('search', 'Search'); ?>
 
 
 
116
  </div>
117
 
118
- <table class="form-table">
119
- <tr valign="top">
120
- <td>
121
- <?php $controls->select('search_status', array(''=>'Any status', 'C'=>'Confirmed', 'S'=>'Not confirmed', 'U'=>'Unsubscribed', 'B'=>'Bounced')); ?>
122
- <?php
123
- $order_fields = array('id'=>'Order by id', 'email'=>'Order by email', 'name'=>'Order by name');
124
- for ($i=1; $i<20; $i++) {
125
- if ($options_profile['profile_' . $i] == '') continue;
126
- $order_fields['profile_' . $i] = $options_profile['profile_' . $i];
127
- }
128
- ?>
129
-
130
- <?php $controls->select('search_order', $order_fields); ?>
131
-
132
- <?php $controls->select('search_limit', array(100=>'Max 100 results', '1000'=>'Max 1000 result', ''=>'No limit')); ?>
133
-
134
- <?php $controls->select('search_list', $lists); ?>
135
- <?php $controls->checkbox('search_test'); ?> Test subscribers
136
- <br />
137
- <?php _e('show clicks', 'newsletter'); ?>:&nbsp;<?php $controls->yesno('search_clicks'); ?>
138
- who&nbsp;clicked:&nbsp;&nbsp;
139
- <?php $controls->select('search_link', $links); ?>
140
-
141
- <div class="hints">
142
- Press without filter to show all. Max 100 results will be shown. Use export panel to get all subscribers.
143
- </div>
144
- </td>
145
- </tr>
146
- <tr valign="top">
147
- <td>
148
- <?php $controls->checkbox('show_profile', 'Show profile fields'); ?>
149
- <?php $controls->checkbox('show_preferences', 'Show preferences'); ?>
150
- </td>
151
- </tr>
152
- </table>
153
-
154
-
155
- <h3>Search results</h3>
156
-
157
- <?php if (empty($list)) { ?>
158
- <p>No search results (or you did not search at all)</p>
159
- <?php } ?>
160
-
161
-
162
- <?php if (!empty($list)) { ?>
163
 
 
 
 
 
 
 
 
 
164
  <table class="widefat">
165
  <thead>
166
  <tr>
@@ -174,7 +144,6 @@ else {
174
  <th>Preferences</th>
175
  <?php } ?>
176
  <th>Actions</th>
177
- <th>Others</th>
178
  <?php if ($options['search_clicks'] == 1) { ?>
179
  <th>Clicks</th>
180
  <?php } ?>
@@ -219,9 +188,6 @@ else {
219
  case 'B': echo 'BOUNCED'; break;
220
  }
221
  ?>
222
- <br />
223
- Feed: <?php echo ($s->feed!=1?'NO':'YES'); ?><br />
224
- Follow Up: <?php echo ($s->followup!=1?'NO':'YES'); ?> (<?php echo $s->followup_step; ?>)
225
  </small>
226
  </td>
227
 
@@ -239,7 +205,7 @@ else {
239
  <?php } ?>
240
 
241
  <td>
242
- <a class="button-secondary" href="admin.php?page=newsletter/users/edit.php&amp;id=<?php echo $s->id; ?>">Edit</a>
243
  <?php $controls->button_confirm('remove', 'Remove', 'Proceed?', $s->id); ?>
244
 
245
  <?php //$controls->button('status', 'Confirm', 'newsletter_set_status(this.form,' . $s->id . ',\'C\')'); ?>
@@ -249,31 +215,11 @@ else {
249
  <?php $controls->button_confirm('resend_welcome', 'Resend welcome', 'Proceed?', $s->id); ?>
250
  <a href="<?php echo NEWSLETTER_PROFILE_URL; ?>?nk=<?php echo $s->id . '-' . $s->token; ?>" class="button" target="_blank">Profile page</a>
251
  </td>
252
- <td><small>
253
- date: <?php echo $s->created; ?><br />
254
- <?php
255
- $query = $wpdb->prepare("select name,value from " . $wpdb->prefix . "newsletter_profiles where newsletter_id=%d", $s->id);
256
- $profile = $wpdb->get_results($query);
257
- foreach ($profile as $field) {
258
- echo htmlspecialchars($field->name) . ': ' . htmlspecialchars($field->value) . '<br />';
259
- }
260
- ?>
261
- </small></td>
262
 
263
- <?php if ($options['search_clicks'] == 1) { ?>
264
- <td><small>
265
- <?php
266
- $clicks = $wpdb->get_results($wpdb->prepare("select * from " . $wpdb->prefix . "newsletter_stats where user_id=%d order by newsletter", $s->id));
267
- foreach ($clicks as &$click) {
268
- ?>
269
- <?php echo $click->newsletter; ?>: <?php echo $click->url; ?><br />
270
- <?php } ?>
271
- </small></td>
272
- <?php } ?>
273
 
274
  </tr>
275
  <?php } ?>
276
  </table>
277
- <?php } ?>
278
  </form>
279
  </div>
3
  require_once NEWSLETTER_INCLUDES_DIR . '/controls.php';
4
 
5
  $controls = new NewsletterControls();
6
+ $module = NewsletterUsers::instance();
7
 
8
  $options = stripslashes_deep($_POST['options']);
9
  $options_lists = get_option('newsletter_profile');
36
  unset($controls->data['subscriber_id']);
37
  }
38
 
39
+ // We build the query condition
40
+ $where = "where 1=1";
41
+ $text = $wpdb->escape(trim($controls->data['search_text']));
42
+ if ($text != '') {
43
+ $where .= " and (email like '%$text%' or name like '%$text%' or surname like '%$text%')";
44
  }
45
 
46
+ //if (isset($controls->data['search_test'])) {
47
+ // $where .= " and test=1";
48
+ //}
49
 
50
+ if (!empty($controls->data['search_status'])) {
51
+ if ($controls->data['search_status'] == 'T') {
52
+ $where .= " and test=1";
53
+ } else {
54
+ $where .= " and status='" . $wpdb->escape($controls->data['search_status']) . "'";
55
+ }
56
+ }
57
+
58
+ // Total items, total pages
59
+ $items_per_page = 20;
60
+ $count = Newsletter::instance()->store->get_count($wpdb->prefix . 'newsletter', $where);
61
+ $last_page = floor($count / $items_per_page) - ($count % $items_per_page == 0 ? 1 : 0);
62
+ if ($last_page < 0) $last_page = 0;
63
+
64
+ // Move to base zero
65
+ if ($controls->is_action()) {
66
+ $controls->data['search_page'] = (int)$controls->data['search_page']-1;
67
+ $module->save_options($controls->data, 'search');
68
+ }
69
+ else {
70
+ $controls->data = $module->get_options('search');
71
+ if (empty($controls->data['search_page'])) $controls->data['search_page'] = 0;
72
+ }
 
 
 
 
 
 
 
 
 
 
 
 
73
 
74
+ if ($controls->is_action('last')) {
75
+ $controls->data['search_page'] = $last_page;
76
+ }
77
+ if ($controls->is_action('first')) {
78
+ $controls->data['search_page'] = 0;
79
+ }
80
+ if ($controls->is_action('next')) {
81
+ $controls->data['search_page'] = (int)$controls->data['search_page']+1;
82
+ }
83
+ if ($controls->is_action('prev')) {
84
+ $controls->data['search_page'] = (int)$controls->data['search_page']-1;
85
+ }
86
+ if ($controls->is_action('search')) {
87
+ $controls->data['search_page'] = 0;
88
+ }
89
 
90
+ // Eventually fix the page
91
+ if ($controls->data['search_page'] < 0) $controls->data['search_page'] = 0;
92
+ if ($controls->data['search_page'] > $last_page) $controls->data['search_page'] = $last_page;
93
 
 
94
 
95
+ $query .= "select * from " . $wpdb->prefix . "newsletter " . $where . " order by id desc";
96
+ $query .= " limit " . ($controls->data['search_page']*$items_per_page) . "," . $items_per_page;
97
+ $list = $wpdb->get_results($query);
 
98
 
99
+ // Move to base 1
100
+ $controls->data['search_page']++;
101
  ?>
102
 
103
  <div class="wrap">
106
  <?php include NEWSLETTER_DIR . '/header.php'; ?>
107
 
108
  <?php include NEWSLETTER_DIR . '/users/menu.inc.php'; ?>
109
+
110
+ <h2>Subscriber Search</h2>
111
 
112
  <?php $controls->show(); ?>
113
 
114
  <form id="channel" method="post" action="">
115
  <?php $controls->init(); ?>
 
 
 
 
 
 
 
 
 
 
116
 
117
  <div style="padding: .6em; border: 1px solid #ddd; background-color: #f4f4f4; border-radius: 3px;">
118
+ <?php $controls->text('search_text', 80); ?>
119
+
120
+ <!--<?php $controls->checkbox('search_test'); ?> show subscriber with "test" flag on-->
121
+ <?php $controls->select('search_status', array(''=>'Any status', 'T'=>'Test subscribers', 'C'=>'Confirmed', 'S'=>'Not confirmed', 'U'=>'Unsubscribed', 'B'=>'Bounced')); ?>
122
+ <?php $controls->button('search', 'Search'); ?>
123
  </div>
124
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
125
 
126
+ <div class="newsletter-paginator">
127
+ <?php echo $count ?> subscribers found
128
+ <?php $controls->button('first', '«'); ?>
129
+ <?php $controls->button('prev', '‹'); ?>
130
+ <?php $controls->text('search_page', 3); ?> of <?php echo $last_page+1 ?> <?php $controls->button('go', 'Go'); ?>
131
+ <?php $controls->button('next', '›'); ?>
132
+ <?php $controls->button('last', '»'); ?>
133
+ </div>
134
  <table class="widefat">
135
  <thead>
136
  <tr>
144
  <th>Preferences</th>
145
  <?php } ?>
146
  <th>Actions</th>
 
147
  <?php if ($options['search_clicks'] == 1) { ?>
148
  <th>Clicks</th>
149
  <?php } ?>
188
  case 'B': echo 'BOUNCED'; break;
189
  }
190
  ?>
 
 
 
191
  </small>
192
  </td>
193
 
205
  <?php } ?>
206
 
207
  <td>
208
+ <a class="button-secondary" href="<?php echo $module->get_admin_page_url('edit'); ?>&amp;id=<?php echo $s->id; ?>">Edit</a>
209
  <?php $controls->button_confirm('remove', 'Remove', 'Proceed?', $s->id); ?>
210
 
211
  <?php //$controls->button('status', 'Confirm', 'newsletter_set_status(this.form,' . $s->id . ',\'C\')'); ?>
215
  <?php $controls->button_confirm('resend_welcome', 'Resend welcome', 'Proceed?', $s->id); ?>
216
  <a href="<?php echo NEWSLETTER_PROFILE_URL; ?>?nk=<?php echo $s->id . '-' . $s->token; ?>" class="button" target="_blank">Profile page</a>
217
  </td>
 
 
 
 
 
 
 
 
 
 
218
 
 
 
 
 
 
 
 
 
 
 
219
 
220
  </tr>
221
  <?php } ?>
222
  </table>
223
+
224
  </form>
225
  </div>
users/massive.php CHANGED
@@ -2,6 +2,7 @@
2
  @include_once NEWSLETTER_INCLUDES_DIR . '/controls.php';
3
 
4
  $controls = new NewsletterControls();
 
5
 
6
  $options_profile = get_option('newsletter_profile');
7
 
@@ -24,6 +25,11 @@ if ($controls->is_action('remove_bounced')) {
24
  $controls->messages = $r . ' bounced deleted.';
25
  }
26
 
 
 
 
 
 
27
  if ($controls->is_action('confirm_all')) {
28
  $r = $wpdb->query("update " . NEWSLETTER_USERS_TABLE . " set status='C' where status='S'");
29
  $controls->messages = $r . ' confirmed.';
@@ -70,7 +76,7 @@ if ($controls->is_action('resend_all')) {
70
 
71
  if ($list) {
72
  $controls->messages = 'Confirmation email sent to: ';
73
- foreach ($list as $user) {
74
  $controls->messages .= $user->email . ' ';
75
  $newsletter->mail($user->email, $newsletter->replace($opts['confirmation_subject'], $user), $newsletter->replace($opts['confirmation_message'], $user));
76
  }
@@ -80,6 +86,58 @@ if ($controls->is_action('resend_all')) {
80
 
81
  }
82
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
83
 
84
  if ($controls->is_action('bounces')) {
85
  $lines = explode("\n", $controls->data['bounced_emails']);
@@ -137,6 +195,7 @@ if ($controls->is_action('bounces')) {
137
  <?php include NEWSLETTER_DIR . '/header.php'; ?>
138
  <?php include NEWSLETTER_DIR . '/users/menu.inc.php'; ?>
139
 
 
140
  <p>A bug or an error using this panel can scramble the subscribers database. Please, backup before run a massive operation.</p>
141
 
142
  <?php $controls->show(); ?>
@@ -179,6 +238,7 @@ if ($controls->is_action('bounces')) {
179
  <?php echo $wpdb->get_var("select count(*) from " . NEWSLETTER_USERS_TABLE . " where status='C'"); ?>
180
  </td>
181
  <td nowrap>
 
182
  </td>
183
  </tr>
184
  <tr>
@@ -189,26 +249,32 @@ if ($controls->is_action('bounces')) {
189
  <td nowrap>
190
  <?php $controls->button_confirm('remove_unconfirmed', 'Delete all not confirmed', 'Are you sure you want to delete ALL not confirmed subscribers?'); ?>
191
  <?php $controls->button_confirm('confirm_all', 'Confirm all', 'Are you sure you want to mark ALL subscribers as confirmed?'); ?>
192
- <?php $controls->button_confirm('resend_all', 'Resend confirmation message to all', 'Are you sure?'); ?>
 
193
  </td>
194
  </tr>
195
  <tr>
196
- <td>Subscribed to feed by mail</td>
197
- <td nowrap>
198
- <?php echo $wpdb->get_var("select count(*) from " . NEWSLETTER_USERS_TABLE . " where status='C' and feed=1"); ?>
199
  </td>
200
- <td nowrap>
 
201
  </td>
202
  </tr>
203
  <tr>
204
- <td>Unsubscribed</td>
205
  <td>
206
- <?php echo $wpdb->get_var("select count(*) from " . NEWSLETTER_USERS_TABLE . " where status='U'"); ?>
207
  </td>
208
  <td>
209
- <?php $controls->button_confirm('remove_unsubscribed', 'Delete all unsubscribed', 'Are you sure you want to delete ALL unsubscribed?'); ?>
 
 
 
210
  </td>
211
  </tr>
 
212
  <tr>
213
  <td>Bounced</td>
214
  <td>
2
  @include_once NEWSLETTER_INCLUDES_DIR . '/controls.php';
3
 
4
  $controls = new NewsletterControls();
5
+ $module = NewsletterUsers::instance();
6
 
7
  $options_profile = get_option('newsletter_profile');
8
 
25
  $controls->messages = $r . ' bounced deleted.';
26
  }
27
 
28
+ if ($controls->is_action('unconfirm_all')) {
29
+ $r = $wpdb->query("update " . NEWSLETTER_USERS_TABLE . " set status='S' where status='C'");
30
+ $controls->messages = $r . ' unconfirmed.';
31
+ }
32
+
33
  if ($controls->is_action('confirm_all')) {
34
  $r = $wpdb->query("update " . NEWSLETTER_USERS_TABLE . " set status='C' where status='S'");
35
  $controls->messages = $r . ' confirmed.';
76
 
77
  if ($list) {
78
  $controls->messages = 'Confirmation email sent to: ';
79
+ foreach ($list as &$user) {
80
  $controls->messages .= $user->email . ' ';
81
  $newsletter->mail($user->email, $newsletter->replace($opts['confirmation_subject'], $user), $newsletter->replace($opts['confirmation_message'], $user));
82
  }
86
 
87
  }
88
 
89
+ if ($controls->is_action('align_wp_users')) {
90
+
91
+ // TODO: check if the user is already there
92
+ $wp_users = $wpdb->get_results("select id, user_email, user_login from $wpdb->users");
93
+ $count = 0;
94
+ foreach ($wp_users as &$wp_user) {
95
+ $module->logger->info('Adding a registered WordPress user (' . $wp_user->id . ')');
96
+
97
+ // A subscriber is already there with the same wp_user_id? Do Nothing.
98
+ $nl_user = $module->get_user_by_wp_user_id($wp_user->id);
99
+ if (!empty($nl_user)) {
100
+ $module->logger->info('Subscriber already associated');
101
+ continue;
102
+ }
103
+
104
+ $module->logger->info('WP user email: ', $wp_user->user_email);
105
+
106
+ // A subscriber has the same email? Align them if not already associated to another wordpress user
107
+ $nl_user = $module->get_user($module->normalize_email($wp_user->user_email));
108
+ if (!empty($nl_user)) {
109
+ $module->logger->info('Subscriber already present with that email');
110
+ if (empty($nl_user->wp_user_id)) {
111
+ $module->logger->info('Linked');
112
+ $module->set_user_wp_user_id($nl_user->id, $wp_user->id);
113
+ continue;
114
+ }
115
+ }
116
+
117
+ $module->logger->info('New subscriber created');
118
+
119
+ // Create a new subscriber
120
+ $nl_user = array();
121
+ $nl_user['email'] = $module->normalize_email($wp_user->user_email);
122
+ $nl_user['name'] = $wp_user->user_login;
123
+ $nl_user['status'] = $controls->data['align_wp_users_status'];
124
+ $nl_user['wp_user_id'] = $wp_user->id;
125
+ $nl_user['referrer'] = 'wordpress';
126
+
127
+ // Adds the force subscription preferences
128
+ $preferences = NewsletterSubscription::instance()->options['preferences'];
129
+ if (is_array($preferences)) {
130
+ foreach ($preferences as $p) {
131
+ $nl_user['list_' . $p] = 1;
132
+ }
133
+ }
134
+
135
+ $module->save_user($nl_user);
136
+ $count++;
137
+ }
138
+ $controls->messages = 'Total WP users aligned ' . count($wp_users) . ', total new subscribers ' . $count . '.';
139
+ }
140
+
141
 
142
  if ($controls->is_action('bounces')) {
143
  $lines = explode("\n", $controls->data['bounced_emails']);
195
  <?php include NEWSLETTER_DIR . '/header.php'; ?>
196
  <?php include NEWSLETTER_DIR . '/users/menu.inc.php'; ?>
197
 
198
+ <h2>Massive Actions on Subscribers</h2>
199
  <p>A bug or an error using this panel can scramble the subscribers database. Please, backup before run a massive operation.</p>
200
 
201
  <?php $controls->show(); ?>
238
  <?php echo $wpdb->get_var("select count(*) from " . NEWSLETTER_USERS_TABLE . " where status='C'"); ?>
239
  </td>
240
  <td nowrap>
241
+ <?php $controls->button_confirm('unconfirm_all', 'Unconfirm all', 'Are you sure? No way back.'); ?>
242
  </td>
243
  </tr>
244
  <tr>
249
  <td nowrap>
250
  <?php $controls->button_confirm('remove_unconfirmed', 'Delete all not confirmed', 'Are you sure you want to delete ALL not confirmed subscribers?'); ?>
251
  <?php $controls->button_confirm('confirm_all', 'Confirm all', 'Are you sure you want to mark ALL subscribers as confirmed?'); ?>
252
+ <?php $controls->hint('To send a comfirmation email to all, you can create a special newsletter.', 'http://www.satollo.net/plugins/newsletter/subscribers-module#resend-confirm'); ?>
253
+ <?php //$controls->button_confirm('resend_all', 'Resend confirmation message to all', 'Are you sure?'); ?>
254
  </td>
255
  </tr>
256
  <tr>
257
+ <td>Unsubscribed</td>
258
+ <td>
259
+ <?php echo $wpdb->get_var("select count(*) from " . NEWSLETTER_USERS_TABLE . " where status='U'"); ?>
260
  </td>
261
+ <td>
262
+ <?php $controls->button_confirm('remove_unsubscribed', 'Delete all unsubscribed', 'Are you sure you want to delete ALL unsubscribed?'); ?>
263
  </td>
264
  </tr>
265
  <tr>
266
+ <td>Import WP user</td>
267
  <td>
268
+ &nbsp;
269
  </td>
270
  <td>
271
+ Link WordPress users with status
272
+ <?php $controls->select('align_wp_users_status', array('C'=>'Confirmed', 'S'=>'Not confirmed')); ?>
273
+ <?php $controls->button_confirm('align_wp_users', 'Go', 'Proceed?'); ?>
274
+ <?php $controls->hint('Please, carefully read the documentation before taking this action!', 'http://www.satollo.net/plugins/newsletter/subscribers-module#import-wp-users'); ?>
275
  </td>
276
  </tr>
277
+
278
  <tr>
279
  <td>Bounced</td>
280
  <td>
users/menu.inc.php CHANGED
@@ -1,10 +1,11 @@
1
- <h2>Subscribers Module</h2>
2
 
3
  <div id="newsletter-nav">
4
- <a class="button" href="?page=newsletter/users/index.php">Search and edit</a>
5
- <a class="button" href="?page=newsletter/users/new.php">New subscriber</a>
6
- <a class="button" href="?page=newsletter/users/massive.php">Massive changes</a>
7
- <a class="button" href="?page=newsletter/users/stats.php">Statistics</a>
8
- <a class="button" href="?page=newsletter/users/import.php">Import</a>
9
- <a class="button" href="?page=newsletter/users/export.php">Export</a>
 
10
  </div>
1
+ <h5>Subscribers Management Module</h5>
2
 
3
  <div id="newsletter-nav">
4
+ <a class="button" href="<?php echo $module->get_admin_page_url('index'); ?>">Search</a>
5
+ <!--<a class="button" href="<?php echo $module->get_admin_page_url('index'); ?>">Old search</a>-->
6
+ <a class="button" href="<?php echo $module->get_admin_page_url('new'); ?>">New subscriber</a>
7
+ <a class="button" href="<?php echo $module->get_admin_page_url('massive'); ?>">Massive changes</a>
8
+ <a class="button" href="<?php echo $module->get_admin_page_url('stats'); ?>">Statistics</a>
9
+ <a class="button" href="<?php echo $module->get_admin_page_url('import'); ?>">Import</a>
10
+ <a class="button" href="<?php echo $module->get_admin_page_url('export'); ?>">Export</a>
11
  </div>
users/new.php CHANGED
@@ -6,12 +6,13 @@ $module = NewsletterUsers::instance();
6
  if ($controls->is_action('save')) {
7
 
8
  $controls->data['status'] = 'C';
 
9
 
10
  $user = $module->save_user($controls->data);
11
  if ($user === false) {
12
  $controls->errors = 'This email already exists.';
13
  } else {
14
- $controls->js_redirect('admin.php?page=newsletter/users/edit.php&id=' . $user->id);
15
  return;
16
  }
17
  }
@@ -21,6 +22,8 @@ if ($controls->is_action('save')) {
21
  <?php include NEWSLETTER_DIR . '/header.php'; ?>
22
  <?php include NEWSLETTER_DIR . '/users/menu.inc.php'; ?>
23
 
 
 
24
  <?php $controls->show(); ?>
25
 
26
  <form method="post" action="">
6
  if ($controls->is_action('save')) {
7
 
8
  $controls->data['status'] = 'C';
9
+ $controls->data['sex'] = 'n';
10
 
11
  $user = $module->save_user($controls->data);
12
  if ($user === false) {
13
  $controls->errors = 'This email already exists.';
14
  } else {
15
+ $controls->js_redirect($module->get_admin_page_url('edit') . '&id=' . $user->id);
16
  return;
17
  }
18
  }
22
  <?php include NEWSLETTER_DIR . '/header.php'; ?>
23
  <?php include NEWSLETTER_DIR . '/users/menu.inc.php'; ?>
24
 
25
+ <h2>New subscriber</h2>
26
+
27
  <?php $controls->show(); ?>
28
 
29
  <form method="post" action="">
users/stats.php CHANGED
@@ -1,12 +1,18 @@
1
  <?php
2
  $all_count = $wpdb->get_var("select count(*) from " . $wpdb->prefix . "newsletter");
3
  $options_profile = get_option('newsletter_profile');
 
 
4
  ?>
 
 
5
  <div class="wrap">
6
  <?php $help_url = 'http://www.satollo.net/plugins/newsletter/subscribers-module'; ?>
7
  <?php include NEWSLETTER_DIR . '/header.php'; ?>
8
  <?php include NEWSLETTER_DIR . '/users/menu.inc.php'; ?>
9
 
 
 
10
  <p>Counts are limited to confirmed subscribers.</p>
11
 
12
  <h3>Overview</h3>
@@ -78,7 +84,7 @@
78
 
79
  <h3>Source</h3>
80
  <?php
81
- $list = $wpdb->get_results("select http_referer, count(*) as total from " . $wpdb->prefix . "newsletter where status='C' group by http_referer order by http_referer");
82
  ?>
83
  <table class="widefat" style="width: 300px">
84
  <thead><tr><th>URL</th><th>Total</th></thead>
@@ -101,24 +107,18 @@
101
  </table>
102
 
103
  <p>
104
- <img alt="chart" src="http://chart.apis.google.com/chart?chtt=Sex&chds=0,<?php echo $all_count; ?>&cht=p3&chco=00ff00,0000ff&chs=600x300&chd=t:<?php echo $male_count; ?>,<?php echo $female_count; ?>,<?php echo $other_count; ?>&chl=Male|Female|Other" />
105
  </p>
106
 
 
107
  <h3>Subscriptions over time</h3>
108
 
109
  <h4>Subscriptions by month</h4>
110
  <?php
111
- $list = $wpdb->get_results("select count(*) as c, concat(year(created), '-', date_format(created, '%m')) as d from " . $wpdb->prefix . "newsletter where status='C' group by concat(year(created), '-', date_format(created, '%m')) order by d desc limit 24");
112
- $max = 0;
113
- for ($i=count($list)-1; $i>=0; $i--) {
114
- $month = $list[$i];
115
- $y .= $month->c . ','; $x .= substr($month->d, 5) . '|';
116
- $max = max($max, $month->c);
117
- }
118
  ?>
119
- <p>
120
- <img alt="chart" src="http://chart.apis.google.com/chart?chds=0,<?php echo $max; ?>&chtt=Subscription rate&cht=bvg&chco=00ff00,0000ff&chs=600x300&chd=t:<?php echo substr($y, 0, -1); ?>&chl=<?php echo substr($x, 0, -1); ?>" />
121
- </p>
122
 
123
  <table class="widefat" style="width: 300px">
124
  <thead>
@@ -127,7 +127,7 @@
127
  <th>Subscribers</th>
128
  </tr>
129
  </thead>
130
- <?php foreach ($list as $day) { ?>
131
  <tr valign="top">
132
  <td><?php echo $day->d; ?></td>
133
  <td><?php echo $day->c; ?></td>
@@ -156,4 +156,49 @@
156
  </table>
157
 
158
 
159
- </div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  <?php
2
  $all_count = $wpdb->get_var("select count(*) from " . $wpdb->prefix . "newsletter");
3
  $options_profile = get_option('newsletter_profile');
4
+
5
+ $module = NewsletterUsers::instance();
6
  ?>
7
+
8
+
9
  <div class="wrap">
10
  <?php $help_url = 'http://www.satollo.net/plugins/newsletter/subscribers-module'; ?>
11
  <?php include NEWSLETTER_DIR . '/header.php'; ?>
12
  <?php include NEWSLETTER_DIR . '/users/menu.inc.php'; ?>
13
 
14
+ <h2>Subscriber Statistics</h2>
15
+
16
  <p>Counts are limited to confirmed subscribers.</p>
17
 
18
  <h3>Overview</h3>
84
 
85
  <h3>Source</h3>
86
  <?php
87
+ $list = $wpdb->get_results("select http_referer, count(*) as total from " . $wpdb->prefix . "newsletter where status='C' group by http_referer order by count(*) desc");
88
  ?>
89
  <table class="widefat" style="width: 300px">
90
  <thead><tr><th>URL</th><th>Total</th></thead>
107
  </table>
108
 
109
  <p>
110
+ <div id="sex-chart" style="width:400; height:300"></div>
111
  </p>
112
 
113
+
114
  <h3>Subscriptions over time</h3>
115
 
116
  <h4>Subscriptions by month</h4>
117
  <?php
118
+ $months = $wpdb->get_results("select count(*) as c, concat(year(created), '-', date_format(created, '%m')) as d from " . $wpdb->prefix . "newsletter where status='C' group by concat(year(created), '-', date_format(created, '%m')) order by d desc limit 24");
 
 
 
 
 
 
119
  ?>
120
+
121
+ <div id="months-chart" style="width:400; height:300"></div>
 
122
 
123
  <table class="widefat" style="width: 300px">
124
  <thead>
127
  <th>Subscribers</th>
128
  </tr>
129
  </thead>
130
+ <?php foreach ($months as $day) { ?>
131
  <tr valign="top">
132
  <td><?php echo $day->d; ?></td>
133
  <td><?php echo $day->c; ?></td>
156
  </table>
157
 
158
 
159
+ </div>
160
+
161
+ <script type="text/javascript" src="https://www.google.com/jsapi"></script>
162
+ <script type="text/javascript">
163
+
164
+ // Load the Visualization API and the piechart package.
165
+ google.load('visualization', '1.0', {'packages':['corechart']});
166
+
167
+ // Set a callback to run when the Google Visualization API is loaded.
168
+ google.setOnLoadCallback(drawChart);
169
+
170
+ function drawChart() {
171
+
172
+ // Create the data table.
173
+ var data = new google.visualization.DataTable();
174
+ data.addColumn('string', 'Topping');
175
+ data.addColumn('number', 'Slices');
176
+ data.addRows([
177
+ ['None', <?php echo $other_count; ?>],
178
+ ['Female', <?php echo $female_count; ?>],
179
+ ['Male', <?php echo $male_count; ?>]
180
+ ]);
181
+
182
+ // Set chart options
183
+ var options = {'title':'Gender',
184
+ 'width':400,
185
+ 'height':300};
186
+
187
+ var chart = new google.visualization.PieChart(document.getElementById('sex-chart'));
188
+ chart.draw(data, options);
189
+
190
+ var months = new google.visualization.DataTable();
191
+ months.addColumn('string', 'Topping');
192
+ months.addColumn('number', 'Slices');
193
+
194
+ <?php foreach ($months as $day) { ?>
195
+ months.addRow(['<?php echo $day->d; ?>', <?php echo $day->c; ?>]);
196
+ <?php } ?>
197
+
198
+ var options = {'title':'By months', 'width':400, 'height':300};
199
+
200
+ var chart = new google.visualization.BarChart(document.getElementById('months-chart'));
201
+ chart.draw(months, options);
202
+ }
203
+
204
+ </script>
users/users.php CHANGED
@@ -4,7 +4,7 @@ require_once NEWSLETTER_INCLUDES_DIR . '/module.php';
4
 
5
  class NewsletterUsers extends NewsletterModule {
6
 
7
- const VERSION = '1.0.2';
8
 
9
  static $instance;
10
 
@@ -25,22 +25,20 @@ class NewsletterUsers extends NewsletterModule {
25
  function upgrade() {
26
  global $wpdb, $charset_collate;
27
 
 
 
28
  $this->upgrade_query("create table if not exists " . $wpdb->prefix . "newsletter (id int auto_increment, `email` varchar(100) not null default '', primary key (id), unique key email (email)) $charset_collate");
29
 
30
  // User personal data
31
  $this->upgrade_query("alter table " . $wpdb->prefix . "newsletter add column name varchar(100) not null default ''");
32
  $this->upgrade_query("alter table " . $wpdb->prefix . "newsletter add column surname varchar(100) not null default ''");
33
- $this->upgrade_query("alter table " . $wpdb->prefix . "newsletter add column sex char(1) not null default ''");
 
34
 
35
  $this->upgrade_query("alter table " . $wpdb->prefix . "newsletter add column status char(1) not null default 'S'");
36
  $this->upgrade_query("alter table " . $wpdb->prefix . "newsletter add column created timestamp not null default current_timestamp");
37
  $this->upgrade_query("alter table " . $wpdb->prefix . "newsletter add column token varchar(50) not null default ''");
38
 
39
- // Follow up
40
- $this->upgrade_query("alter table " . $wpdb->prefix . "newsletter add column followup_time bigint(20) not null default 0");
41
- $this->upgrade_query("alter table " . $wpdb->prefix . "newsletter add column followup_step tinyint(4) not null default 0");
42
- $this->upgrade_query("alter table " . $wpdb->prefix . "newsletter add column followup tinyint(4) not null default 0");
43
-
44
  // Feed by mail
45
  $this->upgrade_query("alter table " . $wpdb->prefix . "newsletter add column feed tinyint(4) not null default 0");
46
  $this->upgrade_query("alter table " . $wpdb->prefix . "newsletter add column feed_time bigint(20) not null default 0");
@@ -64,14 +62,18 @@ class NewsletterUsers extends NewsletterModule {
64
 
65
  // TODO: Flow module should add that it self (?)
66
  $this->upgrade_query("alter table {$wpdb->prefix}newsletter add column flow tinyint(4) not null default 0");
 
67
 
68
- // This is an old table that should be no more used
69
- //$sql = 'create table if not exists ' . $wpdb->prefix . 'newsletter_profiles (
70
- // `newsletter_id` int NOT NULL,
71
- // `name` varchar (100) NOT NULL DEFAULT \'\',
72
- // `value` text,
73
- // primary key (newsletter_id, name)
74
- // ) DEFAULT charset=utf8';
 
 
 
75
  }
76
 
77
  function export() {
@@ -80,8 +82,6 @@ class NewsletterUsers extends NewsletterModule {
80
  header('Content-Type: application/octet-stream');
81
  header('Content-Disposition: attachment; filename="newsletter-subscribers.csv"');
82
 
83
- $keys = $wpdb->get_results("select distinct name from " . $wpdb->prefix . "newsletter_profiles order by name");
84
-
85
  // CSV header
86
  echo '"Email";"Name";"Surname";"Sex";"Status";"Date";"Token";';
87
 
@@ -97,11 +97,6 @@ class NewsletterUsers extends NewsletterModule {
97
 
98
  echo '"Feed by mail";"Follow up"';
99
 
100
- // Old profiles
101
- foreach ($keys as $key) {
102
- // Remove some keys?
103
- echo $key->name . ';';
104
- }
105
  echo "\n";
106
 
107
  $page = 0;
@@ -130,22 +125,11 @@ class NewsletterUsers extends NewsletterModule {
130
  echo $recipients[$i]->feed . ';';
131
  echo $recipients[$i]->followup . ';';
132
 
133
- $profile = $wpdb->get_results("select name,value from " . $wpdb->prefix . "newsletter_profiles where newsletter_id=" . $recipients[$i]->id . " order by name");
134
- $map = array();
135
- foreach ($profile as $field) {
136
- $map[$field->name] = $field->value;
137
- }
138
-
139
- foreach ($keys as $key) {
140
- if (isset($map[$key->name])) {
141
- echo '"' . $this->sanitize_csv($map[$key->name]) . '";';
142
- }
143
- else echo '"";';
144
- }
145
  echo "\n";
146
  flush();
147
  }
148
- if (count($recipients) < 500) break;
 
149
  $page++;
150
  }
151
  die();
@@ -167,7 +151,7 @@ class NewsletterUsers extends NewsletterModule {
167
  * @param type $user
168
  * @return type
169
  */
170
- function save_user($user, $return_format=OBJECT) {
171
  global $newsletter;
172
  return $newsletter->save_user($user, $return_format);
173
  }
@@ -191,7 +175,7 @@ class NewsletterUsers extends NewsletterModule {
191
  * @param type $format
192
  * @return boolean
193
  */
194
- function get_user($id_or_email, $format=OBJECT) {
195
  global $wpdb, $newsletter;
196
  return $newsletter->get_user($id_or_email, $format);
197
  }
@@ -222,3 +206,5 @@ class NewsletterUsers extends NewsletterModule {
222
 
223
  }
224
 
 
 
4
 
5
  class NewsletterUsers extends NewsletterModule {
6
 
7
+ const VERSION = '1.0.3';
8
 
9
  static $instance;
10
 
25
  function upgrade() {
26
  global $wpdb, $charset_collate;
27
 
28
+ parent::upgrade();
29
+
30
  $this->upgrade_query("create table if not exists " . $wpdb->prefix . "newsletter (id int auto_increment, `email` varchar(100) not null default '', primary key (id), unique key email (email)) $charset_collate");
31
 
32
  // User personal data
33
  $this->upgrade_query("alter table " . $wpdb->prefix . "newsletter add column name varchar(100) not null default ''");
34
  $this->upgrade_query("alter table " . $wpdb->prefix . "newsletter add column surname varchar(100) not null default ''");
35
+ $this->upgrade_query("alter table " . $wpdb->prefix . "newsletter add column sex char(1) not null default 'n'");
36
+ $this->upgrade_query("alter table " . $wpdb->prefix . "newsletter change column sex sex char(1) not null default 'n'");
37
 
38
  $this->upgrade_query("alter table " . $wpdb->prefix . "newsletter add column status char(1) not null default 'S'");
39
  $this->upgrade_query("alter table " . $wpdb->prefix . "newsletter add column created timestamp not null default current_timestamp");
40
  $this->upgrade_query("alter table " . $wpdb->prefix . "newsletter add column token varchar(50) not null default ''");
41
 
 
 
 
 
 
42
  // Feed by mail
43
  $this->upgrade_query("alter table " . $wpdb->prefix . "newsletter add column feed tinyint(4) not null default 0");
44
  $this->upgrade_query("alter table " . $wpdb->prefix . "newsletter add column feed_time bigint(20) not null default 0");
62
 
63
  // TODO: Flow module should add that it self (?)
64
  $this->upgrade_query("alter table {$wpdb->prefix}newsletter add column flow tinyint(4) not null default 0");
65
+ }
66
 
67
+ function admin_menu() {
68
+ $this->add_menu_page('index', 'Subscribers');
69
+ $this->add_admin_page('new', 'New subscriber');
70
+ $this->add_admin_page('edit', 'Subscribers Edit');
71
+
72
+ $this->add_admin_page('massive', 'Massive Management');
73
+ $this->add_admin_page('export', 'Export');
74
+ $this->add_admin_page('import', 'Import');
75
+ $this->add_admin_page('stats', 'Statistics');
76
+ //$this->add_admin_page('index', 'Old search');
77
  }
78
 
79
  function export() {
82
  header('Content-Type: application/octet-stream');
83
  header('Content-Disposition: attachment; filename="newsletter-subscribers.csv"');
84
 
 
 
85
  // CSV header
86
  echo '"Email";"Name";"Surname";"Sex";"Status";"Date";"Token";';
87
 
97
 
98
  echo '"Feed by mail";"Follow up"';
99
 
 
 
 
 
 
100
  echo "\n";
101
 
102
  $page = 0;
125
  echo $recipients[$i]->feed . ';';
126
  echo $recipients[$i]->followup . ';';
127
 
 
 
 
 
 
 
 
 
 
 
 
 
128
  echo "\n";
129
  flush();
130
  }
131
+ if (count($recipients) < 500)
132
+ break;
133
  $page++;
134
  }
135
  die();
151
  * @param type $user
152
  * @return type
153
  */
154
+ function save_user($user, $return_format = OBJECT) {
155
  global $newsletter;
156
  return $newsletter->save_user($user, $return_format);
157
  }
175
  * @param type $format
176
  * @return boolean
177
  */
178
+ function get_user($id_or_email, $format = OBJECT) {
179
  global $wpdb, $newsletter;
180
  return $newsletter->get_user($id_or_email, $format);
181
  }
206
 
207
  }
208
 
209
+ NewsletterUsers::instance();
210
+
welcome.php DELETED
@@ -1,146 +0,0 @@
1
- <?php
2
- @include_once NEWSLETTER_INCLUDES_DIR . '/controls.php';
3
-
4
- $controls = new NewsletterControls();
5
-
6
- if ($controls->is_action('trigger')) {
7
- $newsletter->hook_newsletter();
8
- $controls->messages = 'Delivery engine triggered.';
9
- }
10
-
11
- if ($controls->is_action('trigger_followup')) {
12
- NewsletterFollowup::instance()->send();
13
- $controls->messages = 'Follow up delivery engine triggered.';
14
- }
15
-
16
- if ($controls->is_action('engine_on')) {
17
- wp_clear_scheduled_hook('newsletter');
18
- wp_schedule_event(time() + 30, 'newsletter', 'newsletter');
19
- $controls->messages = 'Delivery engine reactivated.';
20
- }
21
-
22
- if ($controls->is_action('upgrade')) {
23
- // TODO: Compact them in a call to Newsletter which should be able to manage the installed modules
24
- Newsletter::instance()->upgrade();
25
- NewsletterUsers::instance()->upgrade();
26
- NewsletterSubscription::instance()->upgrade();
27
- NewsletterEmails::instance()->upgrade();
28
- $controls->messages = 'Upgrade forced!';
29
- }
30
-
31
- if ($controls->is_action('delete_transient')) {
32
- delete_transient($_POST['btn']);
33
- $controls->messages = 'Deleted.';
34
- }
35
-
36
- $x = wp_next_scheduled('newsletter');
37
- if ($x === false) {
38
- $controls->errors = 'The delivery engine is off (it should never be off). See the System Check below to reactivate it.';
39
- }
40
- ?>
41
- <div class="wrap">
42
-
43
- <?php $help_url = 'http://www.satollo.net/plugins/newsletter'; ?>
44
- <?php include NEWSLETTER_DIR . '/header.php'; ?>
45
-
46
- <h2>Welcome and Support</h2>
47
-
48
- <?php $controls->show(); ?>
49
-
50
- <form method="post" action="">
51
- <?php $controls->init(); ?>
52
-
53
- <p>
54
- Thank you to use Newsletter plugin. Newsletter counts more than
55
- <a href="http://wordpress.org/extend/plugins/newsletter/stats/" target="_blank">400.000 downloads</a> and
56
- that number is a clear sign of how much useful it is to many bloggers. Or at least I hope that.
57
- </p>
58
-
59
- <p>
60
- <strong>Old 2.5.2.7 version is available <a href="http://www.satollo.net/wp-content/uploads/newsletter-2.5.2.7.zip">here</a>.</strong>
61
- </p>
62
-
63
- <h3>First steps</h3>
64
- <p>
65
- <strong>Newsletter works out of box</strong>. You don't need to create lists or configure it. Just use your WordPress
66
- appearance panel, enter the widgets panel and add the Newsletter widget to your sidebar.
67
- </p>
68
- <p>
69
- To get the most out of Newsletter, to translate messages and so on, it's important to understand the single configuration panels:
70
- </p>
71
- <ol>
72
- <li>
73
- <strong>Configuration</strong>: is where you find the main setting, like the SMTP, the sender address and name,
74
- the delivery engine speed and so on.
75
- </li>
76
- <li>
77
- <strong>Subscription</strong>: is where you configure the subscription process and it's one of the most important panel
78
- to explore and understand. Subscription is not limited to collect email addresses! There you define the fields of the
79
- subscription box, optionally a dedicated page for subscription and profile edit and so on.
80
- </li>
81
- <li>
82
- <strong>Newsletters</strong>: is where you create and send messages to your subscribers. You choose a theme,
83
- set some parameters, preview the message and finally compose it.
84
- </li>
85
- <li>
86
- <strong>Subscribers</strong>: is where you manage your subscribers like edit, create, export/import and so on.
87
- </li>
88
- <li>
89
- <strong>Statistics</strong>: is where you configure the statistic system; statistics of single email (open, clicks)
90
- are accessible directly from email lists.
91
- </li>
92
- </ol>
93
-
94
-
95
- <h3>Support</h3>
96
- <p>
97
- There are some options to find or ask for support. Users with Newsletter Pro or Newsletter Pro Extensions can
98
- use the <a href="http://www.satollo.net/support-form" target="_blank">support form</a> even if the resources below are the first option.
99
- </p>
100
- <ul>
101
- <li><a href="http://www.satollo.net/plugins/newsletter" target="_blank">The official Newsletter page</a> contains information and links extended documentationand FAQ</li>
102
- <li><a href="http://www.satollo.net/forums/forum/newsletter-plugin" target="_blank">The official Newsletter forum</a> where to find solutions or create new requests</li>
103
- <li><a href="http://www.satollo.net/tag/newsletter" target="_blank">Newsletter articles and comments</a> are a source of solutions</li>
104
- <li>Write directly to me at stefano@satollo.net</li>
105
- </ul>
106
-
107
- <h3>Collaboration</h3>
108
- <p>
109
- Any kind of collaboration for this free plugin is welcome (of course). I set up a
110
- <a href="http://www.satollo.net/plugins/newsletter/newsletter-collaboration" target="_blank">How to collaborate</a>
111
- page.
112
- </p>
113
-
114
- <h3>Documentation</h3>
115
- <p>
116
- Below are the pages on www.satollo.net which document Newsletter. Since the site evolves, more page can be available and
117
- the full list is always up-to-date on main Newsletter page.
118
- </p>
119
-
120
- <ul>
121
- <li><a href="http://www.satollo.net/plugins/newsletter" target="_blank">Official Newsletter page</a></li>
122
- <li><a href="http://www.satollo.net/plugins/newsletter/newsletter-configuration" target="_blank">Main configuration</a></li>
123
- <li><a href="http://www.satollo.net/plugins/newsletter/newsletter-diagnostic" target="_blank">Diagnostic</a></li>
124
- <li><a href="http://www.satollo.net/plugins/newsletter/newsletter-faq" target="_blank">FAQ</a></li>
125
- <li><a href="http://www.satollo.net/plugins/newsletter/newsletter-delivery-engine" target="_blank">Delivery Engine</a></li>
126
-
127
-
128
- <li><a href="http://www.satollo.net/plugins/newsletter/subscription-module" target="_blank">Subscription Module</a></li>
129
- <li><a href="http://www.satollo.net/plugins/newsletter/newsletter-forms" target="_blank">Subscription Forms</a></li>
130
- <li><a href="http://www.satollo.net/plugins/newsletter/newsletter-preferences" target="_blank">Subscriber's preferences</a></li>
131
-
132
- <li><a href="http://www.satollo.net/plugins/newsletter/newsletters-module" target="_blank">Newsletters Module</a></li>
133
- <li><a href="http://www.satollo.net/plugins/newsletter/newsletter-themes" target="_blank">Themes</a></li>
134
-
135
- <li><a href="http://www.satollo.net/plugins/newsletter/subscribers-module" target="_blank">Subscribers Module</a></li>
136
- <li><a href="http://www.satollo.net/plugins/newsletter/statistics-module" target="_blank">Statistics Module</a></li>
137
- <!--
138
- <li><a href="http://www.satollo.net/plugins/newsletter/feed-by-mail-module" target="_blank">Feed by Mail Module</a></li>
139
- <li><a href="http://www.satollo.net/plugins/newsletter/follow-up-module" target="_blank">Follow Up Module</a></li>
140
- -->
141
- </ul>
142
-
143
-
144
- </form>
145
-
146
- </div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
widget.php CHANGED
@@ -31,11 +31,9 @@ class NewsletterWidget extends WP_Widget {
31
  // Referrer
32
  $form .= '<input type="hidden" name="nr" value="widget"/>';
33
 
34
- if ($options_profile['name_status'] == 2)
35
- $form .= '<p><input class="newsletter-firstname" type="text" name="nn" value="' . $options_profile['name'] . '" onclick="if (this.defaultValue==this.value) this.value=\'\'" onblur="if (this.value==\'\') this.value=this.defaultValue"/></p>';
36
 
37
- if ($options_profile['surname_status'] == 2)
38
- $form .= '<p><input class="newsletter-lastname" type="text" name="ns" value="' . $options_profile['surname'] . '" onclick="if (this.defaultValue==this.value) this.value=\'\'" onblur="if (this.value==\'\') this.value=this.defaultValue"/></p>';
39
 
40
  $form .= '<p><input class="newsletter-email" type="email" required name="ne" value="' . $options_profile['email'] . '" onclick="if (this.defaultValue==this.value) this.value=\'\'" onblur="if (this.value==\'\') this.value=this.defaultValue"/></p>';
41
 
@@ -90,15 +88,27 @@ class NewsletterWidget extends WP_Widget {
90
  }
91
 
92
  $form .= '</form></div>';
93
- if (strpos($buffer, '{subscription_form}') !== false)
94
- $buffer = str_replace('{subscription_form}', $form, $buffer);
95
- else $buffer .= $form;
 
 
 
 
 
 
 
 
 
96
  }
97
  else {
98
  $buffer = str_ireplace('<form', '<form method="post" action="' . NEWSLETTER_SUBSCRIBE_URL . '" onsubmit="return newsletter_check(this)"', $buffer);
99
  $buffer = str_ireplace('</form>', '<input type="hidden" name="nr" value="widget"/></form>', $buffer);
100
  }
101
 
 
 
 
102
  echo $buffer;
103
  echo $after_widget;
104
  }
@@ -123,10 +133,7 @@ class NewsletterWidget extends WP_Widget {
123
  Introduction:
124
  <textarea class="widefat" rows="10" cols="20" id="<?php echo $this->get_field_id('text'); ?>" name="<?php echo $this->get_field_name('text'); ?>"><?php echo esc_html($instance['text']); ?></textarea>
125
  </label>
126
- The subscription form is created according the subscription panel configurations and appended at the end of the introduction text. If you
127
- want to place the form in the middle of introduction text above, use the {subscription_form} tag.<br />
128
- You can even create a full customized subscription on introduction text, it will be detected and the standard form not inserted.
129
- Just add a &lt;form&gt; tag with wanted newsletter fields (see documentation on custom form building).
130
  </p>
131
  <?php
132
  }
31
  // Referrer
32
  $form .= '<input type="hidden" name="nr" value="widget"/>';
33
 
34
+ if ($options_profile['name_status'] == 2) $form .= '<p><input class="newsletter-firstname" type="text" name="nn" value="' . $options_profile['name'] . '" onclick="if (this.defaultValue==this.value) this.value=\'\'" onblur="if (this.value==\'\') this.value=this.defaultValue"/></p>';
 
35
 
36
+ if ($options_profile['surname_status'] == 2) $form .= '<p><input class="newsletter-lastname" type="text" name="ns" value="' . $options_profile['surname'] . '" onclick="if (this.defaultValue==this.value) this.value=\'\'" onblur="if (this.value==\'\') this.value=this.defaultValue"/></p>';
 
37
 
38
  $form .= '<p><input class="newsletter-email" type="email" required name="ne" value="' . $options_profile['email'] . '" onclick="if (this.defaultValue==this.value) this.value=\'\'" onblur="if (this.value==\'\') this.value=this.defaultValue"/></p>';
39
 
88
  }
89
 
90
  $form .= '</form></div>';
91
+
92
+ // Canot user directly the replace, since the form is different on the widget...
93
+ if (strpos($buffer, '{subscription_form}') !== false) $buffer = str_replace('{subscription_form}', $form, $buffer);
94
+ else {
95
+ if (strpos($buffer, '{subscription_form_') !== false) {
96
+ // TODO: Optimize with a method to replace only the custom forms
97
+ $buffer = $newsletter->replace($buffer);
98
+ }
99
+ else {
100
+ $buffer .= $form;
101
+ }
102
+ }
103
  }
104
  else {
105
  $buffer = str_ireplace('<form', '<form method="post" action="' . NEWSLETTER_SUBSCRIBE_URL . '" onsubmit="return newsletter_check(this)"', $buffer);
106
  $buffer = str_ireplace('</form>', '<input type="hidden" name="nr" value="widget"/></form>', $buffer);
107
  }
108
 
109
+ // That replace all the remaining tags
110
+ $buffer = $newsletter->replace($buffer);
111
+
112
  echo $buffer;
113
  echo $after_widget;
114
  }
133
  Introduction:
134
  <textarea class="widefat" rows="10" cols="20" id="<?php echo $this->get_field_id('text'); ?>" name="<?php echo $this->get_field_name('text'); ?>"><?php echo esc_html($instance['text']); ?></textarea>
135
  </label>
136
+ <p>Use the tag {subscription_form} to place the subscription form within your personal text.
 
 
 
137
  </p>
138
  <?php
139
  }