Newsletter - Version 5.3.4

Version Description

  • GDPR ready
  • Maintenance option to add all subscriber without a list to a specified list
  • Dismissed the tabled subscription form
  • Fixed privacy checkbox label for field shortcode
  • Logs of lists change
  • Last activity tracking
  • Retargeting/deletion of inactive subscribers
  • Privacy checkbox without the checkbox (option)
  • Personal data export
  • Improved subscriber deletion with cleanup of log tables
Download this release

Release Info

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

Code changes from version 5.3.3 to 5.3.4

includes/module.php CHANGED
@@ -162,8 +162,9 @@ class NewsletterModule {
162
  */
163
  function get_options($sub = '') {
164
  $options = get_option($this->get_prefix($sub), array());
165
- if (!is_array($options))
166
  return array();
 
167
  return $options;
168
  }
169
 
@@ -668,7 +669,12 @@ class NewsletterModule {
668
  }
669
 
670
  function delete_email($id) {
671
- return $this->store->delete(NEWSLETTER_EMAILS_TABLE, $id);
 
 
 
 
 
672
  }
673
 
674
  function get_email_field($id, $field_name) {
@@ -891,8 +897,39 @@ class NewsletterModule {
891
  $r = $this->store->delete(NEWSLETTER_USERS_TABLE, $id);
892
  if ($r !== false) {
893
  $wpdb->delete(NEWSLETTER_STATS_TABLE, array('user_id' => $id));
 
894
  }
895
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
896
 
897
  /**
898
  *
@@ -1118,6 +1155,8 @@ class NewsletterModule {
1118
  function replace_url($text, $tag, $url) {
1119
  $home = trailingslashit(home_url());
1120
  $tag_lower = strtolower($tag);
 
 
1121
  $text = str_replace($home . '{' . $tag_lower . '}', $url, $text);
1122
  $text = str_replace($home . '%7B' . $tag_lower . '%7D', $url, $text);
1123
  $text = str_replace('{' . $tag_lower . '}', $url, $text);
162
  */
163
  function get_options($sub = '') {
164
  $options = get_option($this->get_prefix($sub), array());
165
+ if (!is_array($options)) {
166
  return array();
167
+ }
168
  return $options;
169
  }
170
 
669
  }
670
 
671
  function delete_email($id) {
672
+ $r = $this->store->delete(NEWSLETTER_EMAILS_TABLE, $id);
673
+ if ($r !== false) {
674
+ $wpdb->delete(NEWSLETTER_STATS_TABLE, array('email_id' => $id));
675
+ $wpdb->delete(NEWSLETTER_SENT_TABLE, array('email_id' => $id));
676
+ }
677
+ return $r;
678
  }
679
 
680
  function get_email_field($id, $field_name) {
897
  $r = $this->store->delete(NEWSLETTER_USERS_TABLE, $id);
898
  if ($r !== false) {
899
  $wpdb->delete(NEWSLETTER_STATS_TABLE, array('user_id' => $id));
900
+ $wpdb->delete(NEWSLETTER_SENT_TABLE, array('user_id' => $id));
901
  }
902
  }
903
+
904
+ function anonymize_ip($ip) {
905
+ if (empty($ip)) return $ip;
906
+ $parts = explode('.', $ip);
907
+ array_pop($parts);
908
+ return implode('.', $parts);
909
+ }
910
+
911
+ function anonymize_user($id) {
912
+ global $wpdb;
913
+ $user = $this->get_user($id);
914
+ if (!$user) return null;
915
+
916
+ $user->name = '';
917
+ $user->surname = '';
918
+ $user->ip = $this->anonymize_ip($user->ip);
919
+
920
+ for ($i=1; $i<=NEWSLETTER_PROFILE_MAX; $i++) {
921
+ $field = 'profile_' . $i;
922
+ $user->$field = '';
923
+ }
924
+
925
+ // [TODO] Status?
926
+ $user->status = 'U';
927
+ $user->email = $user->id . '@anonymi.zed';
928
+
929
+ $user = $this->save_user($user);
930
+
931
+ return $user;
932
+ }
933
 
934
  /**
935
  *
1155
  function replace_url($text, $tag, $url) {
1156
  $home = trailingslashit(home_url());
1157
  $tag_lower = strtolower($tag);
1158
+ $text = str_replace('http://{' . $tag_lower . '}', $url, $text);
1159
+ $text = str_replace('https://{' . $tag_lower . '}', $url, $text);
1160
  $text = str_replace($home . '{' . $tag_lower . '}', $url, $text);
1161
  $text = str_replace($home . '%7B' . $tag_lower . '%7D', $url, $text);
1162
  $text = str_replace('{' . $tag_lower . '}', $url, $text);
plugin.php CHANGED
@@ -4,7 +4,7 @@
4
  Plugin Name: Newsletter
5
  Plugin URI: https://www.thenewsletterplugin.com/plugins/newsletter
6
  Description: Newsletter is a cool plugin to create your own subscriber list, to send newsletters, to build your business. <strong>Before update give a look to <a href="https://www.thenewsletterplugin.com/category/release">this page</a> to know what's changed.</strong>
7
- Version: 5.3.3
8
  Author: Stefano Lissa & The Newsletter Team
9
  Author URI: https://www.thenewsletterplugin.com
10
  Disclaimer: Use at your own risk. No warranty expressed or implied is provided.
@@ -14,7 +14,7 @@
14
  */
15
 
16
  // Used as dummy parameter on css and js links
17
- define('NEWSLETTER_VERSION', '5.3.3');
18
 
19
  global $wpdb, $newsletter;
20
 
@@ -1214,6 +1214,7 @@ class Newsletter extends NewsletterModule {
1214
  $newsletter = Newsletter::instance();
1215
 
1216
  require_once NEWSLETTER_DIR . '/subscription/subscription.php';
 
1217
  require_once NEWSLETTER_DIR . '/emails/emails.php';
1218
  require_once NEWSLETTER_DIR . '/users/users.php';
1219
  require_once NEWSLETTER_DIR . '/statistics/statistics.php';
4
  Plugin Name: Newsletter
5
  Plugin URI: https://www.thenewsletterplugin.com/plugins/newsletter
6
  Description: Newsletter is a cool plugin to create your own subscriber list, to send newsletters, to build your business. <strong>Before update give a look to <a href="https://www.thenewsletterplugin.com/category/release">this page</a> to know what's changed.</strong>
7
+ Version: 5.3.4
8
  Author: Stefano Lissa & The Newsletter Team
9
  Author URI: https://www.thenewsletterplugin.com
10
  Disclaimer: Use at your own risk. No warranty expressed or implied is provided.
14
  */
15
 
16
  // Used as dummy parameter on css and js links
17
+ define('NEWSLETTER_VERSION', '5.3.4');
18
 
19
  global $wpdb, $newsletter;
20
 
1214
  $newsletter = Newsletter::instance();
1215
 
1216
  require_once NEWSLETTER_DIR . '/subscription/subscription.php';
1217
+ require_once NEWSLETTER_DIR . '/profile/profile.php';
1218
  require_once NEWSLETTER_DIR . '/emails/emails.php';
1219
  require_once NEWSLETTER_DIR . '/users/users.php';
1220
  require_once NEWSLETTER_DIR . '/statistics/statistics.php';
profile/index.php ADDED
@@ -0,0 +1,32 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ defined('ABSPATH') || exit;
3
+
4
+ require_once NEWSLETTER_INCLUDES_DIR . '/controls.php';
5
+
6
+ $controls = new NewsletterControls();
7
+ $module = NewsletterProfile::instance();
8
+
9
+ ?>
10
+
11
+ <div class="wrap tnp-profile tnp-profile-index" id="tnp-wrap">
12
+
13
+ <?php include NEWSLETTER_DIR . '/tnp-header.php'; ?>
14
+
15
+ <div id="tnp-heading">
16
+
17
+ <h2><?php _e('Profile editing', 'newsletter') ?></h2>
18
+
19
+ </div>
20
+
21
+ <div id="tnp-body">
22
+
23
+ <form id="channel" method="post" action="">
24
+ <?php $controls->init(); ?>
25
+
26
+
27
+ </form>
28
+ </div>
29
+
30
+ <?php include NEWSLETTER_DIR . '/tnp-footer.php'; ?>
31
+
32
+ </div>
profile/profile.php ADDED
@@ -0,0 +1,184 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ defined('ABSPATH') || exit;
4
+
5
+ require_once NEWSLETTER_INCLUDES_DIR . '/module.php';
6
+
7
+ class NewsletterProfile extends NewsletterModule {
8
+
9
+ static $instance;
10
+ var $home_url;
11
+
12
+ /**
13
+ * @return NewsletterProfile
14
+ */
15
+ static function instance() {
16
+ if (self::$instance == null) {
17
+ self::$instance = new NewsletterProfile();
18
+ }
19
+ return self::$instance;
20
+ }
21
+
22
+ function __construct() {
23
+ parent::__construct('profile', '1.0.0');
24
+ add_action('init', array($this, 'hook_init'));
25
+ add_action('wp_loaded', array($this, 'hook_wp_loaded'));
26
+ add_shortcode('newsletter_profile', array($this, 'shortcode_newsletter_profile'));
27
+ }
28
+
29
+ function hook_init() {
30
+ if (is_admin()) {
31
+ add_action('wp_ajax_newsletter_users_export', array($this, 'hook_wp_ajax_newsletter_users_export'));
32
+ }
33
+ add_filter('newsletter_replace', array($this, 'hook_newsletter_replace'), 10, 3);
34
+ }
35
+
36
+ function hook_wp_loaded() {
37
+ global $wpdb;
38
+
39
+ $this->home_url = home_url('/');
40
+
41
+ switch (Newsletter::instance()->action) {
42
+ case 'profile_export':
43
+ $user = $this->get_user_from_request(true);
44
+ header('Content-Type: application/json;chartse=UTF-8');
45
+ echo $this->to_json($user);
46
+ die();
47
+ }
48
+ }
49
+
50
+ /**
51
+ *
52
+ * @param stdClass $user
53
+ */
54
+ function get_profile_export_url($user) {
55
+ return $this->home_url . '?na=profile_export&nk=' . $user->id . '-' . $user->token;
56
+ }
57
+
58
+ /**
59
+ *
60
+ * @param stdClass $user
61
+ */
62
+ function get_profile_url($user) {
63
+ $options_profile = get_option('newsletter_profile');
64
+
65
+ if (empty($options_profile['profile_url'])) {
66
+ $profile_url = $this->home_url . '?na=profile&nk=' . $user->id . '-' . $user->token;
67
+ } else {
68
+ $profile_url = self::add_qs($options_profile['profile_url'], 'nk=' . $user->id . '-' . $user->token);
69
+ }
70
+
71
+ $profile_url = apply_filters('newsletter_profile_url', $profile_url, $user);
72
+ return $profile_url;
73
+ }
74
+
75
+ function hook_newsletter_replace($text, $user, $email) {
76
+ $profile_options = NewsletterSubscription::instance()->get_options('profile');
77
+
78
+ // Profile edit page URL and link
79
+ $url = $this->get_profile_url($user);
80
+ $text = $this->replace_url($text, 'PROFILE_URL', $url);
81
+ $text = str_replace('{profile_link}', '<a class="tnp-profile-link" href="' . $url . '">' . $profile_options['profile_edit'] . '</a>', $text);
82
+
83
+ // Profile export URL and link
84
+ $url = $this->get_profile_export_url($user);
85
+ $text = $this->replace_url($text, 'PROFILE_EXPORT_URL', $url);
86
+ $text = str_replace('{profile_export_link}', '<a class="tnp-profile-export-link" href="' . $url . '">' . $profile_options['profile_export'] . '</a>', $text);
87
+
88
+ return $text;
89
+ }
90
+
91
+ function shortcode_newsletter_profile($attrs, $content) {
92
+ $user = $this->check_user();
93
+
94
+ if (empty($user)) {
95
+ if (empty($content)) {
96
+ return __('Subscriber profile not found.', 'newsletter');
97
+ } else {
98
+ return $content;
99
+ }
100
+ }
101
+
102
+ if (isset($attrs['layout']) && $attrs['layout'] == 'table') {
103
+ return NewsletterSubscription::instance()->get_profile_form($user);
104
+ } else {
105
+ return NewsletterSubscription::instance()->get_profile_form_html5($user);
106
+ }
107
+ }
108
+
109
+ function to_json($user) {
110
+ global $wpdb;
111
+
112
+ $user = (array) $user;
113
+ $fields = array('id', 'name', 'surname', 'sex', 'created', 'ip');
114
+ $data = array();
115
+ $options_profile = get_option('newsletter_profile', array());
116
+ $lists = array();
117
+ $profiles = array();
118
+ foreach ($user as $key => $value) {
119
+ if (strpos($key, 'list_') === 0) {
120
+ if (empty($value)) continue;
121
+ if ($options_profile[$key . '_status'] != 1 && $options_profile[$key . '_status'] != 2) {
122
+ continue;
123
+ }
124
+ $lists[] = $options_profile[$key];
125
+ }
126
+
127
+ // Check if disabled
128
+ if (strpos($key, 'profile_') === 0) {
129
+ if (empty($value)) continue;
130
+ if ($options_profile[$key . '_status'] == 0) {
131
+ continue;
132
+ }
133
+ $profiles[$key] = array('name' => $options_profile[$key], 'value' => $value);
134
+ }
135
+
136
+
137
+ if (in_array($key, $fields))
138
+ $data[$key] = $value;
139
+ }
140
+
141
+ $data['lists'] = $lists;
142
+ $data['profiles'] = $profiles;
143
+
144
+
145
+ // Newsletters
146
+ $sent = $wpdb->get_results($wpdb->prepare("select * from {$wpdb->prefix}newsletter_sent where user_id=%d order by email_id asc", $user['id']));
147
+ $newsletters = array();
148
+ foreach ($sent as $item) {
149
+ $action = 'none';
150
+ if ($item->open == 1)
151
+ $action = 'read';
152
+ else if ($item->open == 2)
153
+ $action = 'click';
154
+
155
+ $email = $this->get_email($item->email_id);
156
+ if (!$email)
157
+ continue;
158
+ // 'id'=>$item->email_id,
159
+ $newsletters[] = array('subject' => $email->subject, 'action' => $action, 'sent' => date('Y-m-d h:i:s', $email->send_on));
160
+ }
161
+
162
+ $data['newsletters'] = $newsletters;
163
+
164
+ $extra = apply_filters('newsletter_profile_export_extra', array());
165
+
166
+ $data = array_merge($extra, $data);
167
+
168
+ return json_encode($data, JSON_PRETTY_PRINT);
169
+ }
170
+
171
+ function upgrade() {
172
+ global $wpdb, $charset_collate;
173
+
174
+ parent::upgrade();
175
+ }
176
+
177
+ function admin_menu() {
178
+ //$this->add_menu_page('index', 'Subscribers');
179
+ //$this->add_admin_page('index', 'Profile');
180
+ }
181
+
182
+ }
183
+
184
+ NewsletterProfile::instance();
readme.txt CHANGED
@@ -2,7 +2,7 @@
2
  Tags: newsletter,email,subscription,mass mail,list build,email marketing,direct mailing,automation,automated
3
  Requires at least: 3.4.0
4
  Tested up to: 4.9.5
5
- Stable tag: 5.3.3
6
  Contributors: satollo,webagile,michael-travan
7
 
8
  Add a real newsletter system to your blog. For free. With unlimited newsletters and subscribers.
@@ -15,6 +15,7 @@ send and track e-mails, headache-free. It just works out of box!
15
  = Main Features =
16
 
17
  * Subscription spam check with domain/ip black lists, Akismet, captcha
 
18
  * **Responsive email Drag & Drop composer**
19
  * **Unlimited subscribers** with statistics
20
  * **Unlimited newsletter** with tracking
@@ -89,6 +90,19 @@ Thank you, The Newsletter Team
89
 
90
  == Changelog ==
91
 
 
 
 
 
 
 
 
 
 
 
 
 
 
92
  = 5.3.3 =
93
 
94
  * Added GIPHY composer block
2
  Tags: newsletter,email,subscription,mass mail,list build,email marketing,direct mailing,automation,automated
3
  Requires at least: 3.4.0
4
  Tested up to: 4.9.5
5
+ Stable tag: 5.3.4
6
  Contributors: satollo,webagile,michael-travan
7
 
8
  Add a real newsletter system to your blog. For free. With unlimited newsletters and subscribers.
15
  = Main Features =
16
 
17
  * Subscription spam check with domain/ip black lists, Akismet, captcha
18
+ * GDPR ready
19
  * **Responsive email Drag & Drop composer**
20
  * **Unlimited subscribers** with statistics
21
  * **Unlimited newsletter** with tracking
90
 
91
  == Changelog ==
92
 
93
+ = 5.3.4 =
94
+
95
+ * GDPR ready
96
+ * Maintenance option to add all subscriber without a list to a specified list
97
+ * Dismissed the tabled subscription form
98
+ * Fixed privacy checkbox label for field shortcode
99
+ * Logs of lists change
100
+ * Last activity tracking
101
+ * Retargeting/deletion of inactive subscribers
102
+ * Privacy checkbox without the checkbox (option)
103
+ * Personal data export
104
+ * Improved subscriber deletion with cleanup of log tables
105
+
106
  = 5.3.3 =
107
 
108
  * Added GIPHY composer block
statistics/statistics.php CHANGED
@@ -52,11 +52,6 @@ class NewsletterStatistics extends NewsletterModule {
52
  // The remaining elements are the url splitted when it contains
53
  $url = implode(';', $parts);
54
 
55
- //list($email_id, $user_id, $url, $anchor, $signature) = explode(';', base64_decode($_GET['nltr']), 5);
56
- //$url = esc_url_raw($url);
57
- //$user_id = (int) $user_id;
58
- //$email_id = (int) $email_id;
59
-
60
  if (empty($user_id) || empty($url)) {
61
  header("HTTP/1.0 404 Not Found");
62
  die('Invalid data');
@@ -64,10 +59,7 @@ class NewsletterStatistics extends NewsletterModule {
64
 
65
  $parts = parse_url($url);
66
 
67
- //$verified = $parts['host'] == $_SERVER['HTTP_HOST'];
68
- //if (!$verified) {
69
- $verified = $signature == md5($email_id . ';' . $user_id . ';' . $url . ';' . $anchor . $this->options['key']);
70
- //}
71
 
72
  if (!$verified) {
73
  header("HTTP/1.0 404 Not Found");
@@ -96,28 +88,21 @@ class NewsletterStatistics extends NewsletterModule {
96
 
97
  $is_action = strpos($url, '?na=');
98
 
99
- $ip = $this->get_remote_ip();
100
-
101
  if (!$is_action) {
102
- $wpdb->insert(NEWSLETTER_STATS_TABLE, array(
 
103
  'email_id' => $email_id,
104
  'user_id' => $user_id,
105
  'url' => $url,
106
  'ip' => $ip
107
  )
108
  );
 
109
  } else {
110
- $this->logger->debug('Is an action');
111
- // Uhm...
112
- // if (!strpos($url, 'nk=')) {
113
- // $url = $this->add_qs($url, 'nk=' . $user->id . '-' . $user->token, false);
114
- // }
115
- // if (!strpos($url, 'nek=')) {
116
- // $url = $this->add_qs($url, 'nek=' . $email->id . '-' . $email->token, false);
117
- // }
118
  }
119
 
120
- $wpdb->query($wpdb->prepare("update " . NEWSLETTER_SENT_TABLE . " set open=2, ip=%s where email_id=%d and user_id=%d limit 1", $ip, $email_id, $user_id));
121
 
122
  header('Location: ' . apply_filters('newsletter_redirect_url', $url, $email, $user));
123
  die();
@@ -154,27 +139,28 @@ class NewsletterStatistics extends NewsletterModule {
154
 
155
  $ip = $this->get_remote_ip();
156
 
157
- $row = $wpdb->get_row($wpdb->prepare("select * from " . NEWSLETTER_STATS_TABLE . " where email_id=%d and user_id=%d and url='' limit 1", $email->id, $user->id));
158
- if ($row) {
159
- $this->logger->info('Open already registered');
160
- // MAybe an update for some fields?
161
- } else {
162
- $wpdb->query($wpdb->prepare("update " . NEWSLETTER_SENT_TABLE . " set open=1, ip=%s where email_id=%d and user_id=%d limit 1", $ip, $email_id, $user_id));
163
- $res = $wpdb->insert(NEWSLETTER_STATS_TABLE, array(
164
- 'email_id' => (int) $email_id,
165
- 'user_id' => (int) $user_id,
166
- 'ip' => $ip)
167
- );
168
- if (!$res) {
169
- $this->logger->fatal($wpdb->last_error);
170
- }
171
  }
 
 
172
 
173
  header('Content-Type: image/gif');
174
  echo base64_decode('_R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7');
175
  die();
176
  }
177
  }
 
 
 
 
 
178
 
179
  function upgrade() {
180
  global $wpdb, $charset_collate;
@@ -185,7 +171,6 @@ class NewsletterStatistics extends NewsletterModule {
185
  `id` int(11) NOT NULL AUTO_INCREMENT,
186
  `created` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
187
  `url` varchar(255) NOT NULL DEFAULT '',
188
- `newsletter` varchar(50) NOT NULL DEFAULT '',
189
  `anchor` varchar(200) NOT NULL DEFAULT '',
190
  `user_id` int(11) NOT NULL DEFAULT '0',
191
  `email_id` varchar(10) NOT NULL DEFAULT '0',
52
  // The remaining elements are the url splitted when it contains
53
  $url = implode(';', $parts);
54
 
 
 
 
 
 
55
  if (empty($user_id) || empty($url)) {
56
  header("HTTP/1.0 404 Not Found");
57
  die('Invalid data');
59
 
60
  $parts = parse_url($url);
61
 
62
+ $verified = $signature == md5($email_id . ';' . $user_id . ';' . $url . ';' . $anchor . $this->options['key']);
 
 
 
63
 
64
  if (!$verified) {
65
  header("HTTP/1.0 404 Not Found");
88
 
89
  $is_action = strpos($url, '?na=');
90
 
 
 
91
  if (!$is_action) {
92
+
93
+ $res = $wpdb->insert(NEWSLETTER_STATS_TABLE, array(
94
  'email_id' => $email_id,
95
  'user_id' => $user_id,
96
  'url' => $url,
97
  'ip' => $ip
98
  )
99
  );
100
+ $wpdb->query($wpdb->prepare("update " . NEWSLETTER_SENT_TABLE . " set open=2, ip=%s where email_id=%d and user_id=%d limit 1", $ip, $email_id, $user_id));
101
  } else {
102
+ $wpdb->query($wpdb->prepare("update " . NEWSLETTER_SENT_TABLE . " set open=1, ip=%s where email_id=%d and user_id=%d where open=0 limit 1", $ip, $email_id, $user_id));
 
 
 
 
 
 
 
103
  }
104
 
105
+ $this->update_last_activity($user);
106
 
107
  header('Location: ' . apply_filters('newsletter_redirect_url', $url, $email, $user));
108
  die();
139
 
140
  $ip = $this->get_remote_ip();
141
 
142
+ $wpdb->query($wpdb->prepare("update " . NEWSLETTER_SENT_TABLE . " set open=1, ip=%s where email_id=%d and user_id=%d where open=0 limit 1", $ip, $email_id, $user_id));
143
+ $res = $wpdb->insert(NEWSLETTER_STATS_TABLE, array(
144
+ 'email_id' => (int) $email_id,
145
+ 'user_id' => (int) $user_id,
146
+ 'ip' => $ip)
147
+ );
148
+ if (!$res) {
149
+ $this->logger->fatal($wpdb->last_error);
 
 
 
 
 
 
150
  }
151
+
152
+ $this->update_last_activity($user);
153
 
154
  header('Content-Type: image/gif');
155
  echo base64_decode('_R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7');
156
  die();
157
  }
158
  }
159
+
160
+ function update_last_activity($user) {
161
+ global $wpdb;
162
+ $wpdb->query($wpdb->prepare("update " . NEWSLETTER_USERS_TABLE . " set last_activity=%d where id=%d limit 1", time(), $user->id));
163
+ }
164
 
165
  function upgrade() {
166
  global $wpdb, $charset_collate;
171
  `id` int(11) NOT NULL AUTO_INCREMENT,
172
  `created` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
173
  `url` varchar(255) NOT NULL DEFAULT '',
 
174
  `anchor` varchar(200) NOT NULL DEFAULT '',
175
  `user_id` int(11) NOT NULL DEFAULT '0',
176
  `email_id` varchar(10) NOT NULL DEFAULT '0',
subscription/languages/en_US.php CHANGED
@@ -12,7 +12,7 @@
12
 
13
  $options = array();
14
 
15
- $options['noconfirmation'] = 0;
16
  $options['antiflood'] = 10;
17
  $options['ip_blacklist'] = array();
18
  $options['address_blacklist'] = array();
12
 
13
  $options = array();
14
 
15
+ $options['noconfirmation'] = 1;
16
  $options['antiflood'] = 10;
17
  $options['ip_blacklist'] = array();
18
  $options['address_blacklist'] = array();
subscription/languages/profile-en_US.php CHANGED
@@ -22,6 +22,8 @@ $options['privacy_url'] = '';
22
 
23
  $options['subscribe'] = 'Subscribe';
24
  $options['save'] = 'Save';
 
 
25
 
26
  $options['title_female'] = 'Mrs.';
27
  $options['title_male'] = 'Mr.';
22
 
23
  $options['subscribe'] = 'Subscribe';
24
  $options['save'] = 'Save';
25
+ $options['profile_export'] = 'Export your data';
26
+ $options['profile_edit'] = 'Change your profile';
27
 
28
  $options['title_female'] = 'Mrs.';
29
  $options['title_male'] = 'Mr.';
subscription/options.php CHANGED
@@ -184,8 +184,8 @@ if (empty($controls->data['page'])) {
184
  <ul>
185
  <li><a href="#tabs-general"><?php _e('General', 'newsletter') ?></a></li>
186
  <li><a href="#tabs-2"><?php _e('Subscription', 'newsletter') ?></a></li>
187
- <li><a href="#tabs-3"><?php _e('Activation', 'newsletter') ?></a></li>
188
  <li><a href="#tabs-4"><?php _e('Welcome', 'newsletter') ?></a></li>
 
189
  <li><a href="#tabs-9"><?php _e('Profile', 'newsletter') ?></a></li>
190
  </ul>
191
 
184
  <ul>
185
  <li><a href="#tabs-general"><?php _e('General', 'newsletter') ?></a></li>
186
  <li><a href="#tabs-2"><?php _e('Subscription', 'newsletter') ?></a></li>
 
187
  <li><a href="#tabs-4"><?php _e('Welcome', 'newsletter') ?></a></li>
188
+ <li><a href="#tabs-3"><?php _e('Activation', 'newsletter') ?></a></li>
189
  <li><a href="#tabs-9"><?php _e('Profile', 'newsletter') ?></a></li>
190
  </ul>
191
 
subscription/profile.php CHANGED
@@ -129,6 +129,8 @@ $rules = array(0 => 'Optional', 1 => 'Required');
129
  <table class="newsletter-option-grid">
130
  <tr><th>Subscribe button</th><td><?php $controls->text('subscribe'); ?></td></tr>
131
  <tr><th>Save button</th><td><?php $controls->text('save'); ?> (on profile page)</td></tr>
 
 
132
  </table>
133
  <p class="description">
134
  For "subscribe" insert an URL to an image (http://...) to use it as a graphical button.
@@ -137,10 +139,10 @@ $rules = array(0 => 'Optional', 1 => 'Required');
137
  </tr>
138
 
139
  <tr>
140
- <th>Privacy check box</th>
141
  <td>
142
  <table class="newsletter-option-grid">
143
- <tr><th>Enabled?</th><td><?php $controls->yesno('privacy_status'); ?></td></tr>
144
  <tr><th>Label</th><td><?php $controls->text('privacy', 50); ?></td></tr>
145
  <tr><th>Privacy URL</th><td><?php $controls->text('privacy_url', 50); ?></td></tr>
146
  <tr><th>Error message</th><td><?php $controls->text('privacy_error', 50); ?></td></tr>
129
  <table class="newsletter-option-grid">
130
  <tr><th>Subscribe button</th><td><?php $controls->text('subscribe'); ?></td></tr>
131
  <tr><th>Save button</th><td><?php $controls->text('save'); ?> (on profile page)</td></tr>
132
+ <tr><th>Export button/link</th><td><?php $controls->text('profile_export'); ?></td></tr>
133
+ <tr><th>Profile editing link</th><td><?php $controls->text('profile_edit'); ?></td></tr>
134
  </table>
135
  <p class="description">
136
  For "subscribe" insert an URL to an image (http://...) to use it as a graphical button.
139
  </tr>
140
 
141
  <tr>
142
+ <th>Privacy checkbox/notice</th>
143
  <td>
144
  <table class="newsletter-option-grid">
145
+ <tr><th>Enabled?</th><td><?php $controls->select('privacy_status', array(0=>'No', 1=>'Yes', 2=>'Only the notice')); ?></td></tr>
146
  <tr><th>Label</th><td><?php $controls->text('privacy', 50); ?></td></tr>
147
  <tr><th>Privacy URL</th><td><?php $controls->text('privacy_url', 50); ?></td></tr>
148
  <tr><th>Error message</th><td><?php $controls->text('privacy_error', 50); ?></td></tr>
subscription/subscription.php CHANGED
@@ -23,7 +23,7 @@ class NewsletterSubscription extends NewsletterModule {
23
 
24
  function __construct() {
25
 
26
- parent::__construct('subscription', '2.0.4');
27
 
28
  // Must be called after the Newsletter::hook_init, since some constants are defined
29
  // there.
@@ -38,7 +38,7 @@ class NewsletterSubscription extends NewsletterModule {
38
  add_action('wp_enqueue_scripts', array($this, 'hook_wp_enqueue_scripts'));
39
  add_shortcode('newsletter', array($this, 'shortcode_newsletter'));
40
  add_shortcode('newsletter_form', array($this, 'shortcode_newsletter_form'));
41
- add_shortcode('newsletter_profile', array($this, 'shortcode_newsletter_profile'));
42
  add_shortcode('newsletter_field', array($this, 'shortcode_newsletter_field'));
43
  }
44
  }
@@ -304,6 +304,7 @@ class NewsletterSubscription extends NewsletterModule {
304
  }
305
  die();
306
  break;
 
307
  case 'p':
308
  case 'pe':
309
  $user = $this->check_user();
@@ -398,6 +399,22 @@ class NewsletterSubscription extends NewsletterModule {
398
  }
399
 
400
  $this->init_options('template', false);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
401
 
402
  return true;
403
  }
@@ -811,8 +828,14 @@ class NewsletterSubscription extends NewsletterModule {
811
  $this->notify_admin($user, 'Newsletter unsubscription');
812
  }
813
 
 
 
 
 
 
814
  function save_profile() {
815
-
 
816
  $user = $this->get_user_from_request(true);
817
 
818
  $options_profile = get_option('newsletter_profile', array());
@@ -854,11 +877,19 @@ class NewsletterSubscription extends NewsletterModule {
854
  }
855
 
856
  // For each preference which an be edited (and so is present on profile form)...
 
 
857
  for ($i = 1; $i <= NEWSLETTER_LIST_MAX; $i++) {
858
  if ($options_profile['list_' . $i . '_status'] == 0) {
859
  continue;
860
  }
861
- $data['list_' . $i] = in_array($i, $nl) ? 1 : 0;
 
 
 
 
 
 
862
  }
863
 
864
  // Profile
@@ -873,6 +904,11 @@ class NewsletterSubscription extends NewsletterModule {
873
 
874
  // Feed by Mail service is saved here
875
  $data = apply_filters('newsletter_profile_save', $data);
 
 
 
 
 
876
 
877
  $user = $this->save_user($data);
878
 
@@ -1264,7 +1300,7 @@ class NewsletterSubscription extends NewsletterModule {
1264
  }
1265
 
1266
  if (!isset($attrs['label'])) {
1267
- $attrs['label'] = $options_profile['list_' . $i];
1268
  }
1269
 
1270
  $buffer .= '<div class="tnp-field tnp-field-checkbox tnp-field-privacy">';
@@ -1291,151 +1327,7 @@ class NewsletterSubscription extends NewsletterModule {
1291
  * @return string The html code of the subscription form
1292
  */
1293
  function get_subscription_form($referrer = null, $action = null, $attrs = array()) {
1294
- if (isset($attrs['action'])) {
1295
- $action = $attrs['action'];
1296
- }
1297
- if (isset($attrs['referrer'])) {
1298
- $referrer = $attrs['referrer'];
1299
- }
1300
-
1301
- if (empty($action)) {
1302
- $action = esc_attr(home_url('/') . '?na=s');
1303
- }
1304
-
1305
- $options_profile = get_option('newsletter_profile');
1306
- $options = get_option('newsletter');
1307
-
1308
- $buffer = $this->get_form_javascript();
1309
-
1310
- $buffer .= '<div class="tnp tnp-subscription">' . "\n";
1311
- $buffer .= '<form method="post" action="' . $action . '" onsubmit="return newsletter_check(this)">' . "\n\n";
1312
-
1313
- if (isset($attrs['confirmation_url'])) {
1314
- $buffer .= "<input type='hidden' name='ncu' value='" . esc_attr($attrs['confirmation_url']) . "'>\n";
1315
- }
1316
- if (!empty($referrer)) {
1317
- $buffer .= "<input type='hidden' name='nr' value='$referrer'>\n";
1318
- }
1319
-
1320
- if (isset($attrs['list'])) {
1321
- $arr = explode(',', $attrs['list']);
1322
- foreach ($arr as $a) {
1323
- $buffer .= "<input type='hidden' name='nl[]' value='" . esc_attr(trim($a)) . "'>\n";
1324
- }
1325
- }
1326
-
1327
- $buffer .= '<table cellspacing="0" cellpadding="3" border="0">' . "\n\n";
1328
- if ($options_profile['name_status'] == 2) {
1329
- $buffer .= "<!-- first name -->\n";
1330
- $buffer .= "<tr>\n\t" . '<th>' . $options_profile['name'] . '</th>' . "\n\t" . '<td><input class="tnp-firstname" type="text" name="nn" size="30"' . ($options_profile['name_rules'] == 1 ? 'required' : '') . '></td>' . "\n" . '</tr>' . "\n\n";
1331
- }
1332
-
1333
- if ($options_profile['surname_status'] == 2) {
1334
- $buffer .= "<!-- last name -->\n";
1335
- $buffer .= "<tr>\n\t" . '<th>' . $options_profile['surname'] . '</th>' . "\n\t" . '<td><input class="tnp-lastname" type="text" name="ns" size="30"' . ($options_profile['surname_rules'] == 1 ? 'required' : '') . '></td>' . "\n" . '</tr>' . "\n\n";
1336
- }
1337
-
1338
- $buffer .= "<!-- email -->\n";
1339
- $buffer .= "<tr>\n\t" . '<th>' . $options_profile['email'] . '</th>' . "\n\t" . '<td align="left"><input class="tnp-email" type="email" name="ne" size="30" required></td>' . "\n" . '</tr>' . "\n\n";
1340
-
1341
- if ($options_profile['sex_status'] == 2) {
1342
- $buffer .= "<!-- sex -->\n";
1343
- $buffer .= "<tr>\n\t<th>" . $options_profile['sex'] . "</th>\n";
1344
- $buffer .= "\t<td>\n\t" . '<select name="nx" class="tnp-gender">' . "\n";
1345
- $buffer .= "\t\t" . '<option value="m">' . $options_profile['sex_male'] . '</option>' . "\n";
1346
- $buffer .= "\t\t" . '<option value="f">' . $options_profile['sex_female'] . '</option>' . "\n";
1347
- $buffer .= "\t</select>\n\t</td></tr>\n";
1348
- }
1349
-
1350
- if (isset($attrs['preferences'])) {
1351
- $preferences = explode(',', str_replace(' ', '', $attrs['preferences']));
1352
- foreach ($preferences as $preference) {
1353
- $buffer .= '<input type="hidden" name="nl[]" value="' . $preference . '">';
1354
- }
1355
- }
1356
-
1357
- $lists = '';
1358
- for ($i = 1; $i <= NEWSLETTER_LIST_MAX; $i++) {
1359
- if ($options_profile['list_' . $i . '_status'] != 2) {
1360
- continue;
1361
- }
1362
-
1363
- // Already added above
1364
- if (isset($preferences) && array_search($i, $preferences) !== false) {
1365
- continue;
1366
- }
1367
-
1368
- $lists .= "\t\t" . '<input type="checkbox" name="nl[]" value="' . $i . '"';
1369
- if ($options_profile['list_' . $i . '_checked'] == 1)
1370
- $lists .= ' checked';
1371
- $lists .= '/>&nbsp;' . $options_profile['list_' . $i] . '<br />' . "\n";
1372
- }
1373
- if (!empty($lists))
1374
- $buffer .= "<!-- preferences -->\n<tr>\n\t<th>&nbsp;</th>\n\t<td>\n" . $lists . "\t</td>\n</tr>\n\n";
1375
-
1376
- // Extra profile fields
1377
- for ($i = 1; $i <= NEWSLETTER_PROFILE_MAX; $i++) {
1378
- // Not for subscription form
1379
- if ($options_profile['profile_' . $i . '_status'] != 2)
1380
- continue;
1381
-
1382
- // Text field
1383
- if ($options_profile['profile_' . $i . '_type'] == 'text') {
1384
- $buffer .= "<tr>\n\t<th>" . $options_profile['profile_' . $i] . "</th>\n\t<td>\n\t\t";
1385
- $buffer .= '<input class="tnp-profile tnp-profile-' . $i . '" type="text" size="30" name="np' . $i . '"';
1386
- $buffer .= ' placeholder="' . esc_attr($options_profile['profile_' . $i . '_placeholder']) . '"';
1387
- if (!empty($options_profile['profile_' . $i . '_rules'])) {
1388
- $buffer .= ' required';
1389
- }
1390
- $buffer .= '/>' . "\n\t</td>\n</tr>\n\n";
1391
- }
1392
-
1393
- // Select field
1394
- if ($options_profile['profile_' . $i . '_type'] == 'select') {
1395
- $buffer .= "<tr>\n\t<th>" . $options_profile['profile_' . $i] . "</th>\n\t<td>\n\t\t" . '<select class="tnp-profile tnp-profile-' . $i . '" name="np' . $i . '"';
1396
- if (!empty($options_profile['profile_' . $i . '_rules'])) {
1397
- $buffer .= ' required';
1398
- }
1399
- $buffer .= '>' . "\n";
1400
- $opts = explode(',', $options_profile['profile_' . $i . '_options']);
1401
- for ($j = 0; $j < count($opts); $j++) {
1402
- $buffer .= "\t\t\t<option>" . trim($opts[$j]) . "</option>\n";
1403
- }
1404
- $buffer .= "\t\t</select>\n\t</td>\n</tr>\n\n";
1405
- }
1406
- }
1407
-
1408
- $extra = apply_filters('newsletter_subscription_extra', array());
1409
- foreach ($extra as &$x) {
1410
- $label = $x['label'];
1411
- if (empty($label))
1412
- $label = '&nbsp;';
1413
- $buffer .= "<tr>\n\t<th>" . $label . "</th>\n\t<td>\n\t\t";
1414
- $buffer .= $x['field'] . "\n\t</td>\n</tr>\n\n";
1415
- }
1416
-
1417
- if ($options_profile['privacy_status'] == 1) {
1418
- $buffer .= "<tr>\n\t" . '<td colspan="2" class="tnp-td-privacy">' . "\n";
1419
- $buffer .= "\t\t" . '<input type="checkbox" name="ny" required>&nbsp;';
1420
- if (!empty($options_profile['privacy_url'])) {
1421
- $buffer .= '<a target="_blank" href="' . $options_profile['privacy_url'] . '">';
1422
- $buffer .= $options_profile['privacy'] . '</a>';
1423
- } else {
1424
- $buffer .= $options_profile['privacy'];
1425
- }
1426
- $buffer .= "\n\t</td>\n</tr>\n\n";
1427
- }
1428
-
1429
- $buffer .= "<tr>\n\t" . '<td colspan="2" class="tnp-td-submit">' . "\n";
1430
-
1431
- if (strpos($options_profile['subscribe'], 'http://') !== false) {
1432
- $buffer .= "\t\t" . '<input class="tnp-submit-image" type="image" src="' . $options_profile['subscribe'] . '"/>' . "\n\t</td>\n</tr>\n\n";
1433
- } else {
1434
- $buffer .= "\t\t" . '<input class="tnp-submit" type="submit" value="' . $options_profile['subscribe'] . '"/>' . "\n\t</td>\n</tr>\n\n";
1435
- }
1436
-
1437
- $buffer .= "</table>\n</form>\n</div>";
1438
- return $buffer;
1439
  }
1440
 
1441
  /**
@@ -1600,10 +1492,15 @@ class NewsletterSubscription extends NewsletterModule {
1600
  $buffer .= '<div class="tnp-field tnp-field-' . $name . '"><label>' . $label . "</label>";
1601
  $buffer .= $x['field'] . "</div>\n";
1602
  }
 
 
1603
 
1604
- if ($options_profile['privacy_status'] == 1) {
1605
  $buffer .= '<div class="tnp-field tnp-field-privacy">';
1606
- $buffer .= '<label><input type="checkbox" name="ny" required class="tnp-privacy">&nbsp;';
 
 
 
1607
  if (!empty($options_profile['privacy_url'])) {
1608
  $buffer .= '<a target="_blank" href="' . esc_attr($options_profile['privacy_url']) . '">';
1609
  $buffer .= esc_attr($options_profile['privacy']) . '</a>';
@@ -1612,7 +1509,7 @@ class NewsletterSubscription extends NewsletterModule {
1612
  }
1613
 
1614
  $buffer .= "</label></div>\n";
1615
- }
1616
 
1617
  $buffer .= '<div class="tnp-field tnp-field-button">';
1618
 
@@ -1629,24 +1526,6 @@ class NewsletterSubscription extends NewsletterModule {
1629
  return $buffer;
1630
  }
1631
 
1632
- function shortcode_newsletter_profile($attrs, $content) {
1633
- $user = $this->check_user();
1634
-
1635
- if (empty($user)) {
1636
- if (empty($content)) {
1637
- return __('Subscriber profile not found.', 'newsletter');
1638
- } else {
1639
- return $content;
1640
- }
1641
- }
1642
-
1643
- if (isset($attrs['layout']) && $attrs['layout'] == 'table') {
1644
- return $this->get_profile_form($user);
1645
- } else {
1646
- return $this->get_profile_form_html5($user);
1647
- }
1648
- }
1649
-
1650
  /**
1651
  * Generate the profile editing form.
1652
  */
@@ -2029,6 +1908,8 @@ class NewsletterSubscription extends NewsletterModule {
2029
  $email = NewsletterSubscription::instance()->get_email_from_request();
2030
 
2031
  $message = $newsletter->replace($message, $user, $email, 'page');
 
 
2032
 
2033
  if (isset($_REQUEST['alert'])) {
2034
  // slashes are already added by wordpress!
23
 
24
  function __construct() {
25
 
26
+ parent::__construct('subscription', '2.0.5');
27
 
28
  // Must be called after the Newsletter::hook_init, since some constants are defined
29
  // there.
38
  add_action('wp_enqueue_scripts', array($this, 'hook_wp_enqueue_scripts'));
39
  add_shortcode('newsletter', array($this, 'shortcode_newsletter'));
40
  add_shortcode('newsletter_form', array($this, 'shortcode_newsletter_form'));
41
+ //add_shortcode('newsletter_profile', array($this, 'shortcode_newsletter_profile'));
42
  add_shortcode('newsletter_field', array($this, 'shortcode_newsletter_field'));
43
  }
44
  }
304
  }
305
  die();
306
  break;
307
+ case 'profile':
308
  case 'p':
309
  case 'pe':
310
  $user = $this->check_user();
399
  }
400
 
401
  $this->init_options('template', false);
402
+
403
+ global $wpdb, $charset_collate;
404
+
405
+ require_once(ABSPATH . 'wp-admin/includes/upgrade.php');
406
+
407
+
408
+
409
+ $sql = "CREATE TABLE `" . $wpdb->prefix . "newsletter_user_logs` (
410
+ `id` int(11) NOT NULL AUTO_INCREMENT,
411
+ `user_id` int(11) NOT NULL DEFAULT 0,
412
+ `data` longtext,
413
+ `created` int(11) NOT NULL DEFAULT 0,
414
+ PRIMARY KEY (`id`)
415
+ ) $charset_collate;";
416
+
417
+ dbDelta($sql);
418
 
419
  return true;
420
  }
828
  $this->notify_admin($user, 'Newsletter unsubscription');
829
  }
830
 
831
+ /**
832
+ * Saves the subscriber data.
833
+ *
834
+ * @return type
835
+ */
836
  function save_profile() {
837
+ global $wpdb;
838
+ // Get the current subscriber
839
  $user = $this->get_user_from_request(true);
840
 
841
  $options_profile = get_option('newsletter_profile', array());
877
  }
878
 
879
  // For each preference which an be edited (and so is present on profile form)...
880
+ $lists_changed = false;
881
+ $changed = array('old'=>array(), 'new'=>array());
882
  for ($i = 1; $i <= NEWSLETTER_LIST_MAX; $i++) {
883
  if ($options_profile['list_' . $i . '_status'] == 0) {
884
  continue;
885
  }
886
+ $field_name = 'list_' . $i;
887
+ $data[$field_name] = in_array($i, $nl) ? 1 : 0;
888
+ if ($data[$field_name] != $user->$field_name) {
889
+ $lists_changed = true;
890
+ $changed['old'][$field_name] = $user->$field_name;
891
+ $changed['new'][$field_name] = $data[$field_name];
892
+ }
893
  }
894
 
895
  // Profile
904
 
905
  // Feed by Mail service is saved here
906
  $data = apply_filters('newsletter_profile_save', $data);
907
+
908
+ // Log the previous user data as a for of consensus if he changed the lists
909
+ if ($lists_changed) {
910
+ $this->store->save($wpdb->prefix . 'newsletter_user_logs', array('user_id'=>$user->id, 'created'=>time(), 'data'=> json_encode($changed)));
911
+ }
912
 
913
  $user = $this->save_user($data);
914
 
1300
  }
1301
 
1302
  if (!isset($attrs['label'])) {
1303
+ $attrs['label'] = $options_profile['privacy_label'];
1304
  }
1305
 
1306
  $buffer .= '<div class="tnp-field tnp-field-checkbox tnp-field-privacy">';
1327
  * @return string The html code of the subscription form
1328
  */
1329
  function get_subscription_form($referrer = null, $action = null, $attrs = array()) {
1330
+ return $this->get_subscription_form_html5($referrer, $action, $attrs);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1331
  }
1332
 
1333
  /**
1492
  $buffer .= '<div class="tnp-field tnp-field-' . $name . '"><label>' . $label . "</label>";
1493
  $buffer .= $x['field'] . "</div>\n";
1494
  }
1495
+
1496
+ $privacy_status = (int)$options_profile['privacy_status'];
1497
 
1498
+ if ($privacy_status === 1 || $privacy_status === 2) {
1499
  $buffer .= '<div class="tnp-field tnp-field-privacy">';
1500
+ $buffer .= '<label>';
1501
+ if ($privacy_status === 1) {
1502
+ $buffer .= '<input type="checkbox" name="ny" required class="tnp-privacy">&nbsp;';
1503
+ }
1504
  if (!empty($options_profile['privacy_url'])) {
1505
  $buffer .= '<a target="_blank" href="' . esc_attr($options_profile['privacy_url']) . '">';
1506
  $buffer .= esc_attr($options_profile['privacy']) . '</a>';
1509
  }
1510
 
1511
  $buffer .= "</label></div>\n";
1512
+ }
1513
 
1514
  $buffer .= '<div class="tnp-field tnp-field-button">';
1515
 
1526
  return $buffer;
1527
  }
1528
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1529
  /**
1530
  * Generate the profile editing form.
1531
  */
1908
  $email = NewsletterSubscription::instance()->get_email_from_request();
1909
 
1910
  $message = $newsletter->replace($message, $user, $email, 'page');
1911
+
1912
+ $message = do_shortcode($message);
1913
 
1914
  if (isset($_REQUEST['alert'])) {
1915
  // slashes are already added by wordpress!
users/edit.php CHANGED
@@ -107,6 +107,7 @@ function percentValue($value, $total) {
107
  <li><a href="#tabs-profile">Profile</a></li>
108
  <li><a href="#tabs-other">Other</a></li>
109
  <li><a href="#tabs-newsletters">Newsletters</a></li>
 
110
 
111
  </ul>
112
 
@@ -213,7 +214,13 @@ function percentValue($value, $total) {
213
  <tr>
214
  <th><?php _e('Created', 'newsletter') ?></th>
215
  <td>
216
- <?php $controls->value('created'); ?>
 
 
 
 
 
 
217
  </td>
218
  </tr>
219
  <tr>
@@ -257,6 +264,51 @@ function percentValue($value, $total) {
257
  }
258
  ?>
259
  </div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
260
 
261
  <?php
262
  if (isset($panels['user_edit'])) {
107
  <li><a href="#tabs-profile">Profile</a></li>
108
  <li><a href="#tabs-other">Other</a></li>
109
  <li><a href="#tabs-newsletters">Newsletters</a></li>
110
+ <li><a href="#tabs-history">History</a></li>
111
 
112
  </ul>
113
 
214
  <tr>
215
  <th><?php _e('Created', 'newsletter') ?></th>
216
  <td>
217
+ <?php echo $controls->print_date(strtotime($controls->data['created'])); ?>
218
+ </td>
219
+ </tr>
220
+ <tr>
221
+ <th><?php _e('Last activity', 'newsletter') ?></th>
222
+ <td>
223
+ <?php echo $controls->print_date($controls->data['last_activity']); ?>
224
  </td>
225
  </tr>
226
  <tr>
264
  }
265
  ?>
266
  </div>
267
+
268
+ <div id="tabs-history" class="tnp-tab">
269
+ <?php
270
+ $logs = $wpdb->get_results($wpdb->prepare("select * from {$wpdb->prefix}newsletter_user_logs where user_id=%d order by id desc", $id));
271
+ ?>
272
+ <?php if (empty($logs)) { ?>
273
+ <p>No logs available</p>;
274
+ <?php } else { ?>
275
+ <table class="widefat" style="width: auto">
276
+ <thead>
277
+ <tr>
278
+ <th>Date</th>
279
+ <th>Old data</th>
280
+ <th>New data</th>
281
+ </tr>
282
+
283
+ <tbody>
284
+ <?php foreach ($logs as $log) { ?>
285
+ <?php
286
+ $data = json_decode($log->data, ARRAY_A);
287
+ ?>
288
+ <tr>
289
+ <td><?php echo $controls->print_date($log->created)?></td>
290
+ <td>
291
+ <?php
292
+ foreach ($data['old'] as $key=>$value) {
293
+ echo esc_html(str_replace('_', ' ', $key)), ': ', esc_html($value) . '<br>';
294
+ }
295
+ ?>
296
+ </td>
297
+ <td><?php
298
+ foreach ($data['new'] as $key=>$value) {
299
+ echo esc_html(str_replace('_', ' ', $key)), ': ', esc_html($value) . '<br>';
300
+ }
301
+ ?>
302
+ </td>
303
+ </tr>
304
+ <?php } ?>
305
+ </tbody>
306
+
307
+ </table>
308
+ <?php } ?>
309
+
310
+
311
+ </div>
312
 
313
  <?php
314
  if (isset($panels['user_edit'])) {
users/massive.php CHANGED
@@ -1,6 +1,7 @@
1
  <?php
2
- if (!defined('ABSPATH'))
3
- exit;
 
4
 
5
  @include_once NEWSLETTER_INCLUDES_DIR . '/controls.php';
6
 
@@ -57,7 +58,10 @@ if ($controls->is_action('list_remove')) {
57
  }
58
 
59
  if ($controls->is_action('list_delete')) {
60
- $wpdb->query("delete from " . NEWSLETTER_USERS_TABLE . " where list_" . ((int) $controls->data['list']) . "<>0");
 
 
 
61
  }
62
 
63
  if ($controls->is_action('list_manage')) {
@@ -72,6 +76,30 @@ if ($controls->is_action('list_manage')) {
72
  }
73
  }
74
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
75
  if ($controls->is_action('bounces')) {
76
  $lines = explode("\n", $controls->data['bounced_emails']);
77
  $total = 0;
@@ -157,7 +185,7 @@ if ($controls->is_action('bounces')) {
157
  </ul>
158
 
159
  <div id="tabs-1">
160
- <table class="widefat">
161
  <thead>
162
  <tr>
163
  <th><?php _e('Status', 'newsletter') ?></th>
@@ -215,9 +243,35 @@ if ($controls->is_action('bounces')) {
215
  <?php $controls->button_confirm('remove_bounced', __('Delete all bounced', 'newsletter'), __('Are you sure?', 'newsletter')); ?>
216
  </td>
217
  </tr>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
218
  </table>
219
 
220
-
221
  </div>
222
 
223
 
@@ -227,13 +281,13 @@ if ($controls->is_action('bounces')) {
227
  <th>&nbsp;</th>
228
  <td>
229
  <?php $controls->select('list', $lists) ?>:
230
- <?php $controls->button_confirm('list_add', 'Add it to every user', __('Are you sure?', 'newsletter')); ?>
231
- <?php $controls->button_confirm('list_remove', 'Remove it from every user', __('Are you sure?', 'newsletter')); ?>
232
- <?php $controls->button_confirm('list_delete', 'Delete subscribers of it', __('Are you sure?', 'newsletter')); ?>
233
  <br><br>
234
  <?php $controls->select('list_action', array('move' => 'Change', 'add' => 'Add')); ?>
235
- <?php _e('all subscribers in', 'newsletter')?> <?php $controls->select('list_1', $lists); ?>
236
- <?php _e('to', 'newsletter')?> <?php $controls->select('list_2', $lists); ?>
237
  <?php $controls->button_confirm('list_manage', 'Go!', 'Are you sure?'); ?>
238
  <p class="description">
239
  If you choose to <strong>delete</strong> users in a list, they will be
@@ -241,6 +295,14 @@ if ($controls->is_action('bounces')) {
241
  </p>
242
  </td>
243
  </tr>
 
 
 
 
 
 
 
 
244
  </table>
245
  </div>
246
 
1
  <?php
2
+ /* @var $wpdb wpdb */
3
+
4
+ defined('ABSPATH') || exit;
5
 
6
  @include_once NEWSLETTER_INCLUDES_DIR . '/controls.php';
7
 
58
  }
59
 
60
  if ($controls->is_action('list_delete')) {
61
+ $count = $wpdb->query("delete from " . NEWSLETTER_USERS_TABLE . " where list_" . ((int) $controls->data['list']) . "<>0");
62
+ $wpdb->query("delete s from `{$wpdb->prefix}newsletter_sent` s left join `{$wpdb->prefix}newsletter` u on s.user_id=u.id where u.id is null");
63
+ $wpdb->query("delete s from `{$wpdb->prefix}newsletter_stats` s left join `{$wpdb->prefix}newsletter` u on s.user_id=u.id where u.id is null");
64
+ $controls->messages = $count . ' ' . __('deleted', 'newsletter');
65
  }
66
 
67
  if ($controls->is_action('list_manage')) {
76
  }
77
  }
78
 
79
+ if ($controls->is_action('list_none')) {
80
+ $where = '1=1';
81
+
82
+ for ($i = 1; $i <= NEWSLETTER_LIST_MAX; $i++) {
83
+ $where .= ' and list_' . $i . '=0';
84
+ }
85
+
86
+ $count = $wpdb->query("update " . NEWSLETTER_USERS_TABLE . ' set list_' . ((int) $controls->data['list_3']) . '=1' .
87
+ ' where ' . $where);
88
+ $controls->messages = $count . ' subscribers updated';
89
+ }
90
+
91
+ if ($controls->is_action('update_inactive')) {
92
+ $wpdb->query("update `{$wpdb->prefix}newsletter` n join (select user_id, max(s.time) as max_time from `{$wpdb->prefix}newsletter_sent` s where s.open>0 group by user_id) as ss
93
+ on n.id=ss.user_id set last_activity=ss.max_time");
94
+
95
+ $inactive_time = (int) $controls->data['inactive_time'];
96
+
97
+ $where = 'last_activity > 0 and last_activity<' . (time() - $inactive_time * 30 * 24 * 3600);
98
+
99
+ $count = $wpdb->query("update " . NEWSLETTER_USERS_TABLE . ' set list_' . ((int) $controls->data['list_inactive']) . '=1 where ' . $where);
100
+ $controls->messages = $count . ' subscribers updated';
101
+ }
102
+
103
  if ($controls->is_action('bounces')) {
104
  $lines = explode("\n", $controls->data['bounced_emails']);
105
  $total = 0;
185
  </ul>
186
 
187
  <div id="tabs-1">
188
+ <table class="widefat" style="width: auto">
189
  <thead>
190
  <tr>
191
  <th><?php _e('Status', 'newsletter') ?></th>
243
  <?php $controls->button_confirm('remove_bounced', __('Delete all bounced', 'newsletter'), __('Are you sure?', 'newsletter')); ?>
244
  </td>
245
  </tr>
246
+ <tr>
247
+ <td><?php _e('Inactive since', 'newsletter') ?></td>
248
+ <td>
249
+ <?php
250
+ $controls->select('inactive_time', array(
251
+ '6' => '6 ' . __('months', 'newsletter'),
252
+ '12' => '1 ' . __('year', 'newsletter'),
253
+ '24' => '2 ' . __('years', 'newsletter'),
254
+ '36' => '3 ' . __('years', 'newsletter'),
255
+ '48' => '4 ' . __('years', 'newsletter'),
256
+ '60' => '5 ' . __('years', 'newsletter'),
257
+ '72' => '6 ' . __('years', 'newsletter'),
258
+ '84' => '7 ' . __('years', 'newsletter'),
259
+ '96' => '8 ' . __('years', 'newsletter'),
260
+ '108' => '9 ' . __('years', 'newsletter'),
261
+ '120' => '10 ' . __('years', 'newsletter')
262
+ ))
263
+ ?>
264
+ to
265
+ <?php $controls->select('list_inactive', $lists); ?>
266
+
267
+ </td>
268
+ <td>
269
+ <?php $controls->button_confirm('update_inactive', __('Update', 'newsletter'), __('Are you sure?', 'newsletter')); ?>
270
+ </td>
271
+ </tr>
272
  </table>
273
 
274
+
275
  </div>
276
 
277
 
281
  <th>&nbsp;</th>
282
  <td>
283
  <?php $controls->select('list', $lists) ?>:
284
+ <?php $controls->button_confirm('list_add', 'Activate for everyone', __('Are you sure?', 'newsletter')); ?>
285
+ <?php $controls->button_confirm('list_remove', 'Deactivate for everyone', __('Are you sure?', 'newsletter')); ?>
286
+ <?php $controls->button_confirm('list_delete', 'Delete everyone in that list', __('Are you sure?', 'newsletter')); ?>
287
  <br><br>
288
  <?php $controls->select('list_action', array('move' => 'Change', 'add' => 'Add')); ?>
289
+ <?php _e('all subscribers in', 'newsletter') ?> <?php $controls->select('list_1', $lists); ?>
290
+ <?php _e('to', 'newsletter') ?> <?php $controls->select('list_2', $lists); ?>
291
  <?php $controls->button_confirm('list_manage', 'Go!', 'Are you sure?'); ?>
292
  <p class="description">
293
  If you choose to <strong>delete</strong> users in a list, they will be
295
  </p>
296
  </td>
297
  </tr>
298
+ <tr>
299
+ <th>&nbsp;</th>
300
+ <td>
301
+ <?php _e('Add to list', 'newsletter') ?>
302
+ <?php $controls->select('list_3', $lists) ?> <?php _e('subscribers without a list', 'newsletter') ?> <?php $controls->button_confirm('list_none', '&raquo;', __('Are you sure?', 'newsletter')); ?>
303
+ </td>
304
+ </tr>
305
+
306
  </table>
307
  </div>
308
 
users/users.php CHANGED
@@ -20,7 +20,7 @@ class NewsletterUsers extends NewsletterModule {
20
  }
21
 
22
  function __construct() {
23
- parent::__construct('users', '1.1.4');
24
  add_action('init', array($this, 'hook_init'));
25
  }
26
 
@@ -59,6 +59,7 @@ class NewsletterUsers extends NewsletterModule {
59
  `profile` mediumtext,
60
  `created` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
61
  `updated` int(11) NOT NULL DEFAULT '0',
 
62
  `followup_step` tinyint(4) NOT NULL DEFAULT '0',
63
  `followup_time` bigint(20) NOT NULL DEFAULT '0',
64
  `followup` tinyint(4) NOT NULL DEFAULT '0',
@@ -90,7 +91,8 @@ class NewsletterUsers extends NewsletterModule {
90
  $sql .= "PRIMARY KEY (`id`),\nUNIQUE KEY `email` (`email`),\nKEY `wp_user_id` (`wp_user_id`)\n) $charset_collate;";
91
 
92
  dbDelta($sql);
93
-
 
94
  }
95
 
96
  function admin_menu() {
20
  }
21
 
22
  function __construct() {
23
+ parent::__construct('users', '1.1.5');
24
  add_action('init', array($this, 'hook_init'));
25
  }
26
 
59
  `profile` mediumtext,
60
  `created` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
61
  `updated` int(11) NOT NULL DEFAULT '0',
62
+ `last_activity` int(11) NOT NULL DEFAULT '0',
63
  `followup_step` tinyint(4) NOT NULL DEFAULT '0',
64
  `followup_time` bigint(20) NOT NULL DEFAULT '0',
65
  `followup` tinyint(4) NOT NULL DEFAULT '0',
91
  $sql .= "PRIMARY KEY (`id`),\nUNIQUE KEY `email` (`email`),\nKEY `wp_user_id` (`wp_user_id`)\n) $charset_collate;";
92
 
93
  dbDelta($sql);
94
+ $this->upgrade_query("alter table " . NEWSLETTER_USERS_TABLE . " convert to character set $charset_collate");
95
+
96
  }
97
 
98
  function admin_menu() {