PluginProbe
Jetpack – WP Security, Backup, Speed, & Growth / 4.2.5
Jetpack – WP Security, Backup, Speed, & Growth v4.2.5
16.2-beta 12.0.3 12.1.3 12.2.3 12.3.2 12.4.2 12.5.2 12.6.4 12.7.3 12.8.3 12.9.5 13.0.2 13.1.5 13.2.4 13.3.3 13.4.5 13.5.2 13.6.2 13.7.2 13.8.3 13.9.2 14.0.1 14.1.1 14.2.2 14.3.1 All 501 releases
← All changes | modules/subscriptions.php +544 -560 14.2.24.2.5 View file →
@@ -1,104 +1,55 @@
1 -<?php // phpcs:ignore WordPress.Files.FileName.InvalidClassFileName)
1 +<?php
2 2 /**
3 - * Module Name: Newsletter
4 - * Module Description: Let visitors subscribe to new posts and comments via email
3 + * Module Name: Subscriptions
4 + * Module Description: Allow users to subscribe to your posts and comments and receive notifications via email.
5 + * Jumpstart Description: Give visitors two easy subscription options — while commenting, or via a separate email subscription widget you can display.
5 6 * Sort Order: 9
6 7 * Recommendation Order: 8
7 8 * First Introduced: 1.2
8 9 * Requires Connection: Yes
9 - * Requires User Connection: Yes
10 - * Auto Activate: No
10 + * Auto Activate: Yes
11 11 * Module Tags: Social
12 - * Feature: Engagement
13 - * Additional Search Queries: subscriptions, subscription, email, follow, followers, subscribers, signup, newsletter, creator
12 + * Feature: Jumpstart
13 + * Additional Search Queries: subscriptions, subscription, email, follow, followers, subscribers, signup
14 14 */
15 15
16 -// phpcs:disable Universal.Files.SeparateFunctionsFromOO.Mixed -- TODO: Move classes to appropriately-named class files.
17 -
18 -use Automattic\Jetpack\Admin_UI\Admin_Menu;
19 -use Automattic\Jetpack\Connection\Manager as Connection_Manager;
20 -use Automattic\Jetpack\Connection\XMLRPC_Async_Call;
21 -use Automattic\Jetpack\Redirect;
22 -use Automattic\Jetpack\Status;
23 -use Automattic\Jetpack\Status\Host;
24 -
25 16 add_action( 'jetpack_modules_loaded', 'jetpack_subscriptions_load' );
26 17
27 -// Loads the User Content Link Redirection feature.
28 -require_once __DIR__ . '/subscriptions/jetpack-user-content-link-redirection.php';
29 -
30 -/**
31 - * Loads the Subscriptions module.
32 - */
33 18 function jetpack_subscriptions_load() {
34 19 Jetpack::enable_module_configurable( __FILE__ );
20 + Jetpack::module_configuration_load( __FILE__, 'jetpack_subscriptions_configuration_load' );
35 21 }
36 22
37 -/**
38 - * Cherry picks keys from `$_SERVER` array.
39 - *
40 - * @since 6.0.0
41 - *
42 - * @return array An array of server data.
43 - */
44 -function jetpack_subscriptions_cherry_pick_server_data() {
45 - $data = array();
46 -
47 - foreach ( $_SERVER as $key => $value ) {
48 - if ( ! is_string( $value ) || str_starts_with( $key, 'HTTP_COOKIE' ) ) {
49 - continue;
50 - }
51 -
52 - if ( str_starts_with( $key, 'HTTP_' ) || in_array( $key, array( 'REMOTE_ADDR', 'REQUEST_URI', 'DOCUMENT_URI' ), true ) ) {
53 - $data[ $key ] = $value;
54 - }
55 - }
56 -
57 - return $data;
23 +function jetpack_subscriptions_configuration_load() {
24 + wp_safe_redirect( admin_url( 'options-discussion.php#jetpack-subscriptions-settings' ) );
25 + exit;
58 26 }
59 27
60 -/**
61 - * Main class file for the Subscriptions module.
62 - */
63 28 class Jetpack_Subscriptions {
64 - /**
65 - * Whether Jetpack has been instantiated or not.
66 - *
67 - * @var bool
68 - */
69 29 public $jetpack = false;
70 30
71 - /**
72 - * Hash of the siteurl option.
73 - *
74 - * @var string
75 - */
76 31 public static $hash;
77 32
78 33 /**
79 34 * Singleton
80 - *
81 35 * @static
82 36 */
83 - public static function init() {
37 + static function init() {
84 38 static $instance = false;
85 39
86 - if ( ! $instance ) {
87 - $instance = new Jetpack_Subscriptions();
40 + if ( !$instance ) {
41 + $instance = new Jetpack_Subscriptions;
88 42 }
89 43
90 44 return $instance;
91 45 }
92 46
93 - /**
94 - * Jetpack_Subscriptions constructor.
95 - */
96 - public function __construct() {
47 + function __construct() {
97 48 $this->jetpack = Jetpack::init();
98 49
99 50 // Don't use COOKIEHASH as it could be shared across installs && is non-unique in multisite.
100 - // @see: https://twitter.com/nacin/status/378246957451333632 .
51 + // @see: https://twitter.com/nacin/status/378246957451333632
101 52 self::$hash = md5( get_option( 'siteurl' ) );
102 53
103 54 add_filter( 'jetpack_xmlrpc_methods', array( $this, 'xmlrpc_methods' ) );
104 55
@@ -103,51 +54,47 @@
103 54 add_filter( 'jetpack_xmlrpc_methods', array( $this, 'xmlrpc_methods' ) );
104 55
105 56 // @todo remove sync from subscriptions and move elsewhere...
106 57
107 - // Add Configuration Page.
58 + // Add Configuration Page
108 59 add_action( 'admin_init', array( $this, 'configure' ) );
109 60
110 - // Catch subscription widget submits.
111 - if ( isset( $_REQUEST['jetpack_subscriptions_widget'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Nonce checked in widget_submit() for logged in users.
61 + // Set up the subscription widget.
62 + add_action( 'widgets_init', array( $this, 'widget_init' ) );
63 +
64 + // Catch subscription widget submits
65 + if ( isset( $_REQUEST['jetpack_subscriptions_widget'] ) )
112 66 add_action( 'template_redirect', array( $this, 'widget_submit' ) );
113 - }
114 67
115 - // Set up the comment subscription checkboxes.
116 - add_filter( 'comment_form_submit_field', array( $this, 'comment_subscribe_init' ), 10, 2 );
68 + // Set up the comment subscription checkboxes
69 + add_action( 'comment_form', array( $this, 'comment_subscribe_init' ) );
117 70
118 71 // Catch comment posts and check for subscriptions.
119 72 add_action( 'comment_post', array( $this, 'comment_subscribe_submit' ), 50, 2 );
120 73
121 - // Adds post meta checkbox in the post submit metabox.
74 + // Adds post meta checkbox in the post submit metabox
122 75 add_action( 'post_submitbox_misc_actions', array( $this, 'subscription_post_page_metabox' ) );
123 76
124 77 add_action( 'transition_post_status', array( $this, 'maybe_send_subscription_email' ), 10, 3 );
78 + }
125 79
126 - add_filter( 'jetpack_published_post_flags', array( $this, 'set_post_flags' ), 10, 2 );
80 + function post_is_public( $the_post ) {
81 + if ( !$post = get_post( $the_post ) ) {
82 + return false;
83 + }
127 84
128 - add_filter( 'post_updated_messages', array( $this, 'update_published_message' ), 18, 1 );
129 -
130 - // Set "social_notifications_subscribe" option during the first-time activation.
131 - add_action( 'jetpack_activate_module_subscriptions', array( $this, 'set_social_notifications_subscribe' ) );
132 -
133 - // Hide subscription messaging in Publish panel for posts that were published in the past
134 - add_action( 'init', array( $this, 'register_post_meta' ), 20 );
135 - add_action( 'transition_post_status', array( $this, 'maybe_set_first_published_status' ), 10, 3 );
136 -
137 - // Add Subscribers menu to Jetpack navigation.
138 - add_action( 'jetpack_admin_menu', array( $this, 'add_subscribers_menu' ) );
139 -
140 - // Customize the configuration URL to lead to the Subscriptions settings.
141 - add_filter(
142 - 'jetpack_module_configuration_url_subscriptions',
143 - function () {
144 - return Jetpack::admin_url( array( 'page' => 'jetpack#/newsletter' ) );
145 - }
146 - );
147 -
148 - // Track categories created through the category editor page
149 - add_action( 'wp_ajax_add-tag', array( $this, 'track_newsletter_category_creation' ), 1 );
85 + if ( 'publish' === $post->post_status && strlen( (string) $post->post_password ) < 1 ) {
86 + /**
87 + * Filter whether posts can be emailed to subscribers.
88 + *
89 + * @module subscriptions
90 + *
91 + * @since 2.4.0
92 + *
93 + * @param bool true Can the post be emailed to Subscribers. Default to true.
94 + */
95 + return apply_filters( 'jetpack_is_post_mailable', true );
96 + }
150 97 }
151 98
152 99 /**
153 100 * Jetpack_Subscriptions::xmlrpc_methods()
@@ -152,12 +99,11 @@
152 99 /**
153 100 * Jetpack_Subscriptions::xmlrpc_methods()
154 101 *
155 102 * Register subscriptions methods with the Jetpack XML-RPC server.
156 - *
157 - * @param array $methods Methods being registered.
103 + * @param array $methods
158 104 */
159 - public function xmlrpc_methods( $methods ) {
105 + function xmlrpc_methods( $methods ) {
160 106 return array_merge(
161 107 $methods,
162 108 array(
163 109 'jetpack.subscriptions.subscribe' => array( $this, 'subscribe' ),
@@ -164,13 +110,13 @@
164 110 )
165 111 );
166 112 }
167 113
168 - /**
114 + /*
169 115 * Disable Subscribe on Single Post
170 116 * Register post meta
171 117 */
172 - public function subscription_post_page_metabox() {
118 + function subscription_post_page_metabox() {
173 119 if (
174 120 /**
175 121 * Filter whether or not to show the per-post subscription option.
176 122 *
@@ -179,9 +125,10 @@
179 125 * @since 3.7.0
180 126 *
181 127 * @param bool true = show checkbox option on all new posts | false = hide the option.
182 128 */
183 - ! apply_filters( 'jetpack_allow_per_post_subscriptions', false ) ) {
129 + ! apply_filters( 'jetpack_allow_per_post_subscriptions', false ) )
130 + {
184 131 return;
185 132 }
186 133
187 134 if ( has_filter( 'jetpack_subscriptions_exclude_these_categories' ) || has_filter( 'jetpack_subscriptions_include_only_these_categories' ) ) {
@@ -189,20 +136,18 @@
189 136 }
190 137
191 138 global $post;
192 139 $disable_subscribe_value = get_post_meta( $post->ID, '_jetpack_dont_email_post_to_subs', true );
140 + // Nonce it
141 + wp_nonce_field( 'disable_subscribe', 'disable_subscribe_nonce' );
193 142 // only show checkbox if post hasn't been published and is a 'post' post type.
194 - if ( get_post_status( $post->ID ) !== 'publish' && get_post_type( $post->ID ) === 'post' ) :
195 - // Nonce it.
196 - wp_nonce_field( 'disable_subscribe', 'disable_subscribe_nonce' );
197 - ?>
143 + if ( get_post_status( $post->ID ) !== 'publish' && get_post_type( $post->ID ) == 'post' ) : ?>
198 144 <div class="misc-pub-section">
199 - <label for="_jetpack_dont_email_post_to_subs"><?php esc_html_e( 'Jetpack Subscriptions:', 'jetpack' ); ?></label><br>
145 + <label for="_jetpack_dont_email_post_to_subs"><?php _e( 'Jetpack Subscriptions:', 'jetpack' ); ?></label><br>
200 146 <input type="checkbox" name="_jetpack_dont_email_post_to_subs" id="jetpack-per-post-subscribe" value="1" <?php checked( $disable_subscribe_value, 1, true ); ?> />
201 - <?php esc_html_e( 'Don&#8217;t send this to subscribers', 'jetpack' ); ?>
147 + <?php _e( 'Don&#8217;t send this to subscribers', 'jetpack' ); ?>
202 148 </div>
203 - <?php
204 - endif;
149 + <?php endif;
205 150 }
206 151
207 152 /**
208 153 * Checks whether or not the post should be emailed to subscribers
@@ -213,70 +158,21 @@
213 158 * - Existence of the per-post checkbox option
214 159 *
215 160 * Only one of these can be used at any given time.
216 161 *
217 - * @param string $new_status Tthe "new" post status of the transition when saved.
218 - * @param string $old_status The "old" post status of the transition when saved.
219 - * @param object $post obj The post object.
162 + * @param $new_status string - the "new" post status of the transition when saved
163 + * @param $old_status string - the "old" post status of the transition when saved
164 + * @param $post obj - The post object
220 165 */
221 - public function maybe_send_subscription_email( $new_status, $old_status, $post ) {
222 -
166 + function maybe_send_subscription_email( $new_status, $old_status, $post ) {
167 + // Only do things on publish
168 + if ( 'publish' !== $new_status ) {
169 + return;
170 + }
223 171 if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) {
224 172 return;
225 173 }
226 174
227 - // Make sure that the checkbox is preseved.
228 - if ( ! empty( $_POST['disable_subscribe_nonce'] ) && wp_verify_nonce( $_POST['disable_subscribe_nonce'], 'disable_subscribe' ) ) { // phpcs:ignore WordPress.Security.ValidatedSanitizedInput -- WP Core doesn't unslash or sanitize nonces either.
229 - $set_checkbox = isset( $_POST['_jetpack_dont_email_post_to_subs'] ) ? 1 : 0;
230 - update_post_meta( $post->ID, '_jetpack_dont_email_post_to_subs', $set_checkbox );
231 - }
232 - }
233 -
234 - /**
235 - * Message used when publishing a post.
236 - *
237 - * @param array $messages Message array for a post.
238 - */
239 - public function update_published_message( $messages ) {
240 - global $post;
241 - if ( ! $this->should_email_post_to_subscribers( $post ) ) {
242 - return $messages;
243 - }
244 -
245 - $view_post_link_html = sprintf(
246 - ' <a href="%1$s">%2$s</a>',
247 - esc_url( get_permalink( $post ) ),
248 - __( 'View post', 'jetpack' )
249 - );
250 -
251 - $messages['post'][6] = sprintf(
252 - /* translators: Message shown after a post is published */
253 - esc_html__( 'Post published and sending emails to subscribers.', 'jetpack' )
254 - ) . $view_post_link_html;
255 - return $messages;
256 - }
257 -
258 - /**
259 - * Determine if a post should notifiy subscribers via email.
260 - *
261 - * @param object $post The post.
262 - */
263 - public function should_email_post_to_subscribers( $post ) {
264 - $should_email = true;
265 - if ( get_post_meta( $post->ID, '_jetpack_dont_email_post_to_subs', true ) ) {
266 - return false;
267 - }
268 -
269 - // Only posts are currently supported.
270 - if ( 'post' !== $post->post_type ) {
271 - return false;
272 - }
273 -
274 - // Private posts are not sent to subscribers.
275 - if ( 'private' === $post->post_status ) {
276 - return false;
277 - }
278 -
279 175 /**
280 176 * Array of categories that will never trigger subscription emails.
281 177 *
282 178 * Will not send subscription emails from any post from within these categories.
@@ -288,11 +184,11 @@
288 184 * @param array $args Array of category slugs or ID's.
289 185 */
290 186 $excluded_categories = apply_filters( 'jetpack_subscriptions_exclude_these_categories', array() );
291 187
292 - // Never email posts from these categories.
188 + // Never email posts from these categories
293 189 if ( ! empty( $excluded_categories ) && in_category( $excluded_categories, $post->ID ) ) {
294 - $should_email = false;
190 + update_post_meta( $post->ID, '_jetpack_dont_email_post_to_subs', 1 );
295 191 }
296 192
297 193 /**
298 194 * ONLY send subscription emails for these categories
@@ -306,34 +202,28 @@
306 202 * @param array $args Array of category slugs or ID's.
307 203 */
308 204 $only_these_categories = apply_filters( 'jetpack_subscriptions_exclude_all_categories_except', array() );
309 205
310 - // Only emails posts from these categories.
206 + // Only emails posts from these categories
311 207 if ( ! empty( $only_these_categories ) && ! in_category( $only_these_categories, $post->ID ) ) {
312 - $should_email = false;
208 + update_post_meta( $post->ID, '_jetpack_dont_email_post_to_subs', 1 );
313 209 }
314 210
315 - return $should_email;
211 + // Email the post, depending on the checkbox option
212 + if ( ! empty( $_POST['disable_subscribe_nonce'] ) && wp_verify_nonce( $_POST['disable_subscribe_nonce'], 'disable_subscribe' ) ) {
213 + if ( isset( $_POST['_jetpack_dont_email_post_to_subs'] ) ) {
214 + update_post_meta( $post->ID, '_jetpack_dont_email_post_to_subs', $_POST['_jetpack_dont_email_post_to_subs'] );
215 + }
216 + }
316 217 }
317 218
318 219 /**
319 - * Retrieve which flags should be added to a particular post.
320 - *
321 - * @param array $flags Flags to be added.
322 - * @param object $post A post object.
323 - */
324 - public function set_post_flags( $flags, $post ) {
325 - $flags['send_subscription'] = $this->should_email_post_to_subscribers( $post );
326 - return $flags;
327 - }
328 -
329 - /**
330 220 * Jetpack_Subscriptions::configure()
331 221 *
332 222 * Jetpack Subscriptions configuration screen.
333 223 */
334 - public function configure() {
335 - // Create the section.
224 + function configure() {
225 + // Create the section
336 226 add_settings_section(
337 227 'jetpack_subscriptions',
338 228 __( 'Jetpack Subscriptions Settings', 'jetpack' ),
339 229 array( $this, 'subscriptions_settings_section' ),
@@ -339,9 +229,9 @@
339 229 array( $this, 'subscriptions_settings_section' ),
340 230 'discussion'
341 231 );
342 232
343 - /** Subscribe to Posts */
233 + /** Subscribe to Posts ***************************************************/
344 234
345 235 add_settings_field(
346 236 'jetpack_subscriptions_post_subscribe',
347 237 __( 'Follow Blog', 'jetpack' ),
@@ -354,9 +244,9 @@
354 244 'discussion',
355 245 'stb_enabled'
356 246 );
357 247
358 - /** Subscribe to Comments */
248 + /** Subscribe to Comments ******************************************************/
359 249
360 250 add_settings_field(
361 251 'jetpack_subscriptions_comment_subscribe',
362 252 __( 'Follow Comments', 'jetpack' ),
@@ -369,180 +259,156 @@
369 259 'discussion',
370 260 'stc_enabled'
371 261 );
372 262
373 - /** Email me whenever: Someone subscribes to my blog */
374 - /* @since 8.1 */
263 + /** Subscription Messaging Options ******************************************************/
375 264
265 + register_setting(
266 + 'reading',
267 + 'subscription_options',
268 + array( $this, 'validate_settings' )
269 + );
270 +
376 271 add_settings_section(
377 - 'notifications_section',
378 - __( 'Someone subscribes to my blog', 'jetpack' ),
379 - array( $this, 'social_notifications_subscribe_section' ),
380 - 'discussion'
272 + 'email_settings',
273 + __( 'Follower Settings', 'jetpack' ),
274 + array( $this, 'reading_section' ),
275 + 'reading'
381 276 );
382 277
383 278 add_settings_field(
384 - 'jetpack_subscriptions_social_notifications_subscribe',
385 - __( 'Email me whenever', 'jetpack' ),
386 - array( $this, 'social_notifications_subscribe_field' ),
387 - 'discussion',
388 - 'notifications_section'
279 + 'invitation',
280 + __( 'Blog follow email text', 'jetpack' ),
281 + array( $this, 'setting_invitation' ),
282 + 'reading',
283 + 'email_settings'
389 284 );
390 285
391 - register_setting(
392 - 'discussion',
393 - 'social_notifications_subscribe',
394 - array( $this, 'social_notifications_subscribe_validate' )
286 + add_settings_field(
287 + 'comment-follow',
288 + __( 'Comment follow email text', 'jetpack' ),
289 + array( $this, 'setting_comment_follow' ),
290 + 'reading',
291 + 'email_settings'
395 292 );
396 293 }
397 294
398 295 /**
399 - * Discussions setting section blurb.
296 + * Discussions setting section blurb
297 + *
400 298 */
401 - public function subscriptions_settings_section() {
402 - ?>
403 - <p id="jetpack-subscriptions-settings"><?php esc_html_e( 'Change whether your visitors can subscribe to your posts or comments or both.', 'jetpack' ); ?></p>
299 + function subscriptions_settings_section() {
300 + ?>
404 301
405 - <?php
302 + <p id="jetpack-subscriptions-settings"><?php _e( 'Change whether your visitors can subscribe to your posts or comments or both.', 'jetpack' ); ?></p>
303 +
304 + <?php
406 305 }
407 306
408 307 /**
409 - * Post Subscriptions Toggle.
308 + * Post Subscriptions Toggle
309 + *
410 310 */
411 - public function subscription_post_subscribe_setting() {
311 + function subscription_post_subscribe_setting() {
412 312
413 - $stb_enabled = get_option( 'stb_enabled', 1 );
414 - ?>
313 + $stb_enabled = get_option( 'stb_enabled', 1 ); ?>
415 314
416 315 <p class="description">
417 316 <input type="checkbox" name="stb_enabled" id="jetpack-post-subscribe" value="1" <?php checked( $stb_enabled, 1 ); ?> />
418 - <?php
419 - echo wp_kses(
420 - __(
421 - "Show a <em>'follow blog'</em> option in the comment form",
422 - 'jetpack'
423 - ),
424 - array( 'em' => array() )
425 - );
426 - ?>
317 + <?php _e( "Show a <em>'follow blog'</em> option in the comment form", 'jetpack' ); ?>
427 318 </p>
428 - <?php
319 + <?php
429 320 }
430 321
431 322 /**
432 - * Comments Subscriptions Toggle.
323 + * Comments Subscriptions Toggle
324 + *
433 325 */
434 - public function subscription_comment_subscribe_setting() {
326 + function subscription_comment_subscribe_setting() {
435 327
436 - $stc_enabled = get_option( 'stc_enabled', 1 );
437 - ?>
328 + $stc_enabled = get_option( 'stc_enabled', 1 ); ?>
438 329
439 330 <p class="description">
440 331 <input type="checkbox" name="stc_enabled" id="jetpack-comment-subscribe" value="1" <?php checked( $stc_enabled, 1 ); ?> />
441 - <?php
442 - echo wp_kses(
443 - __(
444 - "Show a <em>'follow comments'</em> option in the comment form",
445 - 'jetpack'
446 - ),
447 - array( 'em' => array() )
448 - );
449 - ?>
332 + <?php _e( "Show a <em>'follow comments'</em> option in the comment form", 'jetpack' ); ?>
450 333 </p>
451 334
452 - <?php
335 + <?php
453 336 }
454 337
455 - /**
456 - * Someone subscribes to my blog section
457 - *
458 - * @since 8.1
459 - */
460 - public function social_notifications_subscribe_section() {
461 - // Atypical usage here. We emit jquery to move subscribe notification checkbox to be with the rest of the email notification settings.
462 - ?>
463 - <script type="text/javascript">
464 - jQuery( function( $ ) {
465 - var table = $( '#social_notifications_subscribe' ).parents( 'table:first' ),
466 - header = table.prevAll( 'h2:first' ),
467 - newParent = $( '#moderation_notify' ).parent( 'label' ).parent();
338 + function validate_settings( $settings ) {
339 + global $allowedposttags;
468 340
469 - if ( ! table.length || ! header.length || ! newParent.length ) {
470 - return;
471 - }
341 + $default = $this->get_default_settings();
472 342
473 - newParent.append( '<br/>' ).append( table.end().parent( 'label' ).siblings().andSelf() );
474 - header.remove();
475 - table.remove();
476 - } );
477 - </script>
478 - <?php
343 + // Blog Follow
344 + $settings['invitation'] = trim( wp_kses( $settings['invitation'], $allowedposttags ) );
345 + if ( empty( $settings['invitation'] ) )
346 + $settings['invitation'] = $default['invitation'];
347 +
348 + // Comments Follow (single post)
349 + $settings['comment_follow'] = trim( wp_kses( $settings['comment_follow'], $allowedposttags ) );
350 + if ( empty( $settings['comment_follow'] ) )
351 + $settings['comment_follow'] = $default['comment_follow'];
352 +
353 + return $settings;
479 354 }
480 355
481 - /**
482 - * Someone subscribes to my blog Toggle
483 - *
484 - * @since 8.1
485 - */
486 - public function social_notifications_subscribe_field() {
487 - $checked = (int) ( 'on' === get_option( 'social_notifications_subscribe', 'on' ) );
488 - ?>
356 + public function reading_section() {
357 + echo '<p id="follower-settings">';
358 + _e( 'These settings change emails sent from your blog to followers.', 'jetpack' );
359 + echo '</p>';
360 + }
489 361
490 - <label>
491 - <input type="checkbox" name="social_notifications_subscribe" id="social_notifications_subscribe" value="1" <?php checked( $checked ); ?> />
492 - <?php
493 - /* translators: this is a label for a setting that starts with "Email me whenever" */
494 - esc_html_e( 'Someone subscribes to my blog', 'jetpack' );
495 - ?>
496 - </label>
497 - <?php
362 + public function setting_invitation() {
363 + $settings = $this->get_settings();
364 + echo '<textarea name="subscription_options[invitation]" class="large-text" cols="50" rows="5">' . esc_textarea( $settings['invitation'] ) . '</textarea>';
365 + echo '<p><span class="description">'.__( 'Introduction text sent when someone follows your blog. (Site and confirmation details will be automatically added for you.)', 'jetpack' ).'</span></p>';
498 366 }
499 367
500 - /**
501 - * Validate "Someone subscribes to my blog" option
502 - *
503 - * @since 8.1
504 - *
505 - * @param String $input the input string to be validated.
506 - * @return string on|off
507 - */
508 - public function social_notifications_subscribe_validate( $input ) {
509 - // If it's not set (was unchecked during form submission) or was set to off (during option update), return 'off'.
510 - if ( ! $input || 'off' === $input ) {
511 - return 'off';
512 - }
368 + public function setting_comment_follow() {
369 + $settings = $this->get_settings();
370 + echo '<textarea name="subscription_options[comment_follow]" class="large-text" cols="50" rows="5">' . esc_textarea( $settings['comment_follow'] ) . '</textarea>';
371 + echo '<p><span class="description">'.__( 'Introduction text sent when someone follows a post on your blog. (Site and confirmation details will be automatically added for you.)', 'jetpack' ).'</span></p>';
372 + }
513 373
514 - // Otherwise we return 'on'.
515 - return 'on';
374 + function get_default_settings() {
375 + return array(
376 + 'invitation' => __( "Howdy.\n\nYou recently followed this blog's posts. This means you will receive each new post by email.\n\nTo activate, click confirm below. If you believe this is an error, ignore this message and we'll never bother you again.", 'jetpack' ),
377 + 'comment_follow' => __( "Howdy.\n\nYou recently followed one of my posts. This means you will receive an email when new comments are posted.\n\nTo activate, click confirm below. If you believe this is an error, ignore this message and we'll never bother you again.", 'jetpack' )
378 + );
516 379 }
517 380
381 + function get_settings() {
382 + return wp_parse_args( (array) get_option( 'subscription_options', array() ), $this->get_default_settings() );
383 + }
384 +
518 385 /**
519 386 * Jetpack_Subscriptions::subscribe()
520 387 *
521 388 * Send a synchronous XML-RPC subscribe to blog posts or subscribe to post comments request.
522 389 *
523 - * @param string $email being subscribed.
524 - * @param array $post_ids (optional) defaults to 0 for blog posts only: array of post IDs to subscribe to blog's posts.
390 + * @param string $email
391 + * @param array $post_ids (optional) defaults to 0 for blog posts only: array of post IDs to subscribe to blog's posts
525 392 * @param bool $async (optional) Should the subscription be performed asynchronously? Defaults to true.
526 - * @param array $extra_data Additional data passed to the `jetpack.subscribeToSite` call.
527 393 *
528 - * @return true|WP_Error true on success
529 - * invalid_email : not a valid email address
530 - * invalid_post_id : not a valid post ID
531 - * unknown_post_id : unknown post
532 - * not_subscribed : strange error. Jetpack servers at WordPress.com could subscribe the email.
533 - * disabled : Site owner has disabled subscriptions.
534 - * active : Already subscribed.
535 - * pending : Tried to subscribe before but the confirmation link is never clicked. No confirmation email is sent.
536 - * unknown : strange error. Jetpack servers at WordPress.com returned something malformed.
537 - * unknown_status : strange error. Jetpack servers at WordPress.com returned something I didn't understand.
394 + * @return true|Jetpack_Error true on success
395 + * invalid_email : not a valid email address
396 + * invalid_post_id : not a valid post ID
397 + * unknown_post_id : unknown post
398 + * not_subscribed : strange error. Jetpack servers at WordPress.com could subscribe the email.
399 + * disabled : Site owner has disabled subscriptions.
400 + * active : Already subscribed.
401 + * unknown : strange error. Jetpack servers at WordPress.com returned something malformed.
402 + * unknown_status : strange error. Jetpack servers at WordPress.com returned something I didn't understand.
538 403 */
539 - public function subscribe( $email, $post_ids = 0, $async = true, $extra_data = array() ) {
540 - if ( ! is_email( $email ) ) {
541 - return new WP_Error( 'invalid_email' );
404 + function subscribe( $email, $post_ids = 0, $async = true, $extra_data = array() ) {
405 + if ( !is_email( $email ) ) {
406 + return new Jetpack_Error( 'invalid_email' );
542 407 }
543 408
544 - if ( ! $async ) {
409 + if ( !$async ) {
410 + Jetpack::load_xml_rpc_client();
545 411 $xml = new Jetpack_IXR_ClientMulticall();
546 412 }
547 413
548 414 foreach ( (array) $post_ids as $post_id ) {
@@ -547,17 +413,17 @@
547 413
548 414 foreach ( (array) $post_ids as $post_id ) {
549 415 $post_id = (int) $post_id;
550 416 if ( $post_id < 0 ) {
551 - return new WP_Error( 'invalid_post_id' );
552 - } elseif ( $post_id && ! get_post( $post_id ) ) {
553 - return new WP_Error( 'unknown_post_id' );
417 + return new Jetpack_Error( 'invalid_post_id' );
418 + } else if ( $post_id && !$post = get_post( $post_id ) ) {
419 + return new Jetpack_Error( 'unknown_post_id' );
554 420 }
555 421
556 422 if ( $async ) {
557 - XMLRPC_Async_Call::add_call( 'jetpack.subscribeToSite', 0, $email, $post_id, serialize( $extra_data ) ); //phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.serialize_serialize
423 + Jetpack::xmlrpc_async_call( 'jetpack.subscribeToSite', $email, $post_id, serialize( $extra_data ) );
558 424 } else {
559 - $xml->addCall( 'jetpack.subscribeToSite', $email, $post_id, serialize( $extra_data ) ); //phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.serialize_serialize
425 + $xml->addCall( 'jetpack.subscribeToSite', $email, $post_id, serialize( $extra_data ) );
560 426 }
561 427 }
562 428
563 429 if ( $async ) {
@@ -563,9 +429,9 @@
563 429 if ( $async ) {
564 430 return;
565 431 }
566 432
567 - // Call.
433 + // Call
568 434 $xml->query();
569 435
570 436 if ( $xml->isError() ) {
571 437 return $xml->get_jetpack_error();
@@ -579,32 +445,29 @@
579 445 $r[] = $xml->get_jetpack_error( $response['faultCode'], $response['faultString'] );
580 446 continue;
581 447 }
582 448
583 - if ( ! is_array( $response[0] ) || empty( $response[0]['status'] ) ) {
584 - $r[] = new WP_Error( 'unknown' );
449 + if ( !is_array( $response[0] ) || empty( $response[0]['status'] ) ) {
450 + $r[] = new Jetpack_Error( 'unknown' );
585 451 continue;
586 452 }
587 453
588 454 switch ( $response[0]['status'] ) {
589 - case 'error':
590 - $r[] = new WP_Error( 'not_subscribed' );
591 - continue 2;
592 - case 'disabled':
593 - $r[] = new WP_Error( 'disabled' );
594 - continue 2;
595 - case 'active':
596 - $r[] = new WP_Error( 'active' );
597 - continue 2;
598 - case 'confirming':
599 - $r[] = true;
600 - continue 2;
601 - case 'pending':
602 - $r[] = new WP_Error( 'pending' );
603 - continue 2;
604 - default:
605 - $r[] = new WP_Error( 'unknown_status', (string) $response[0]['status'] );
606 - continue 2;
455 + case 'error' :
456 + $r[] = new Jetpack_Error( 'not_subscribed' );
457 + continue 2;
458 + case 'disabled' :
459 + $r[] = new Jetpack_Error( 'disabled' );
460 + continue 2;
461 + case 'active' :
462 + $r[] = new Jetpack_Error( 'active' );
463 + continue 2;
464 + case 'pending' :
465 + $r[] = true;
466 + continue 2;
467 + default :
468 + $r[] = new Jetpack_Error( 'unknown_status', (string) $response[0]['status'] );
469 + continue 2;
607 470 }
608 471 }
609 472
610 473 return $r;
@@ -610,40 +473,48 @@
610 473 return $r;
611 474 }
612 475
613 476 /**
477 + * Jetpack_Subscriptions::widget_init()
478 + *
479 + * Initialize and register the Jetpack Subscriptions widget.
480 + */
481 + function widget_init() {
482 + register_widget( 'Jetpack_Subscriptions_Widget' );
483 + }
484 +
485 + /**
614 486 * Jetpack_Subscriptions::widget_submit()
615 487 *
616 488 * When a user submits their email via the blog subscription widget, check the details and call the subsribe() method.
617 489 */
618 - public function widget_submit() {
490 + function widget_submit() {
619 491 // Check the nonce.
620 - if ( ! wp_verify_nonce( isset( $_REQUEST['_wpnonce'] ) ? sanitize_key( $_REQUEST['_wpnonce'] ) : '', 'blogsub_subscribe_' . \Jetpack_Options::get_option( 'id' ) ) ) {
621 - return false;
492 + if ( is_user_logged_in() ) {
493 + check_admin_referer( 'blogsub_subscribe_' . get_current_blog_id() );
622 494 }
623 495
624 - if ( empty( $_REQUEST['email'] ) || ! is_string( $_REQUEST['email'] ) ) {
496 + if ( empty( $_REQUEST['email'] ) )
625 497 return false;
626 - }
627 498
628 499 $redirect_fragment = false;
629 500 if ( isset( $_REQUEST['redirect_fragment'] ) ) {
630 - $redirect_fragment = preg_replace( '/[^a-z0-9_-]/i', '', $_REQUEST['redirect_fragment'] ); // phpcs:ignore WordPress.Security.ValidatedSanitizedInput -- This is manually unslashing and sanitizing.
501 + $redirect_fragment = preg_replace( '/[^a-z0-9_-]/i', '', $_REQUEST['redirect_fragment'] );
631 502 }
632 - if ( ! $redirect_fragment || ! is_string( $redirect_fragment ) ) {
503 + if ( !$redirect_fragment ) {
633 504 $redirect_fragment = 'subscribe-blog';
634 505 }
635 506
636 - $subscribe = self::subscribe(
637 - isset( $_REQUEST['email'] ) ? wp_unslash( $_REQUEST['email'] ) : null, // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- Validated inside self::subscribe().
638 - 0,
639 - false,
640 - array(
641 - 'source' => 'widget',
642 - 'widget-in-use' => is_active_widget( false, false, 'blog_subscription', true ) ? 'yes' : 'no',
643 - 'comment_status' => '',
644 - 'server_data' => jetpack_subscriptions_cherry_pick_server_data(),
645 - )
507 + $subscribe = Jetpack_Subscriptions::subscribe(
508 + $_REQUEST['email'],
509 + 0,
510 + false,
511 + array(
512 + 'source' => 'widget',
513 + 'widget-in-use' => is_active_widget( false, false, 'blog_subscription', true ) ? 'yes' : 'no',
514 + 'comment_status' => '',
515 + 'server_data' => $_SERVER,
516 + )
646 517 );
647 518
648 519 if ( is_wp_error( $subscribe ) ) {
649 520 $error = $subscribe->get_error_code();
@@ -663,20 +534,15 @@
663 534 break;
664 535 case 'invalid_email':
665 536 $result = $error;
666 537 break;
538 + case 'active':
667 539 case 'blocked_email':
668 540 $result = 'opted_out';
669 541 break;
670 - case 'active':
542 + case 'pending':
671 543 $result = 'already';
672 544 break;
673 - case 'flooded_email':
674 - $result = 'many_pending_subs';
675 - break;
676 - case 'pending':
677 - $result = 'pending';
678 - break;
679 545 default:
680 546 $result = 'error';
681 547 break;
682 548 }
@@ -701,43 +567,34 @@
701 567 /**
702 568 * Jetpack_Subscriptions::comment_subscribe_init()
703 569 *
704 570 * Set up and add the comment subscription checkbox to the comment form.
705 - *
706 - * @param string $submit_button HTML markup for the submit field.
707 571 */
708 - public function comment_subscribe_init( $submit_button ) {
572 + function comment_subscribe_init() {
709 573 global $post;
710 574
711 - // Subscriptions are only available for posts so far.
712 - if ( ! $post || 'post' !== $post->post_type ) {
713 - return $submit_button;
714 - }
715 -
716 575 $comments_checked = '';
717 576 $blog_checked = '';
718 577
719 578 // Check for a comment / blog submission and set a cookie to retain the setting and check the boxes.
720 - if ( isset( $_COOKIE[ 'jetpack_comments_subscribe_' . self::$hash . '_' . $post->ID ] ) ) {
579 + if ( isset( $_COOKIE[ 'jetpack_comments_subscribe_' . self::$hash ] ) && $_COOKIE[ 'jetpack_comments_subscribe_' . self::$hash ] == $post->ID )
721 580 $comments_checked = ' checked="checked"';
722 - }
723 581
724 - if ( isset( $_COOKIE[ 'jetpack_blog_subscribe_' . self::$hash ] ) ) {
582 + if ( isset( $_COOKIE[ 'jetpack_blog_subscribe_' . self::$hash ] ) )
725 583 $blog_checked = ' checked="checked"';
726 - }
727 584
728 - // Some themes call this function, don't show the checkbox again.
585 + // Some themes call this function, don't show the checkbox again
729 586 remove_action( 'comment_form', 'subscription_comment_form' );
730 587
731 - // Check if Mark Jaquith's Subscribe to Comments plugin is active - if so, suppress Jetpack checkbox.
588 + // Check if Mark Jaquith's Subscribe to Comments plugin is active - if so, suppress Jetpack checkbox
732 589
733 590 $str = '';
734 591
735 - if ( false === has_filter( 'comment_form', 'show_subscription_checkbox' ) && 1 === (int) get_option( 'stc_enabled', 1 ) && empty( $post->post_password ) && 'post' === get_post_type() ) {
736 - // Subscribe to comments checkbox.
737 - $str .= '<p class="comment-subscription-form"><input type="checkbox" name="subscribe_comments" id="subscribe_comments" value="subscribe" style="width: auto; -moz-appearance: checkbox; -webkit-appearance: checkbox;"' . $comments_checked . ' /> ';
592 + if ( FALSE === has_filter( 'comment_form', 'show_subscription_checkbox' ) && 1 == get_option( 'stc_enabled', 1 ) && empty( $post->post_password ) && 'post' == get_post_type() ) {
593 + // Subscribe to comments checkbox
594 + $str .= '<p class="comment-subscription-form"><input type="checkbox" name="subscribe_comments" id="subscribe_comments" value="subscribe" style="width: auto; -moz-appearance: checkbox; -webkit-appearance: checkbox;"' . $comments_checked . ' /> ';
738 595 $comment_sub_text = __( 'Notify me of follow-up comments by email.', 'jetpack' );
739 - $str .= '<label class="subscribe-label" id="subscribe-label" for="subscribe_comments">' . esc_html(
596 + $str .= '<label class="subscribe-label" id="subscribe-label" for="subscribe_comments">' . esc_html(
740 597 /**
741 598 * Filter the Subscribe to comments text appearing below the comment form.
742 599 *
743 600 * @module subscriptions
@@ -750,13 +607,13 @@
750 607 ) . '</label>';
751 608 $str .= '</p>';
752 609 }
753 610
754 - if ( 1 === (int) get_option( 'stb_enabled', 1 ) ) {
755 - // Subscribe to blog checkbox.
756 - $str .= '<p class="comment-subscription-form"><input type="checkbox" name="subscribe_blog" id="subscribe_blog" value="subscribe" style="width: auto; -moz-appearance: checkbox; -webkit-appearance: checkbox;"' . $blog_checked . ' /> ';
611 + if ( 1 == get_option( 'stb_enabled', 1 ) ) {
612 + // Subscribe to blog checkbox
613 + $str .= '<p class="comment-subscription-form"><input type="checkbox" name="subscribe_blog" id="subscribe_blog" value="subscribe" style="width: auto; -moz-appearance: checkbox; -webkit-appearance: checkbox;"' . $blog_checked . ' /> ';
757 614 $blog_sub_text = __( 'Notify me of new posts by email.', 'jetpack' );
758 - $str .= '<label class="subscribe-label" id="subscribe-blog-label" for="subscribe_blog">' . esc_html(
615 + $str .= '<label class="subscribe-label" id="subscribe-blog-label" for="subscribe_blog">' . esc_html(
759 616 /**
760 617 * Filter the Subscribe to blog text appearing below the comment form.
761 618 *
762 619 * @module subscriptions
@@ -778,11 +635,9 @@
778 635 * @since 1.2.0
779 636 *
780 637 * @param string $str Comment Subscription form HTML output.
781 638 */
782 - $str = apply_filters( 'jetpack_comment_subscription_form', $str );
783 -
784 - return $str . $submit_button;
639 + echo apply_filters( 'jetpack_comment_subscription_form', $str );
785 640 }
786 641
787 642 /**
788 643 * Jetpack_Subscriptions::comment_subscribe_init()
@@ -787,62 +642,40 @@
787 642 /**
788 643 * Jetpack_Subscriptions::comment_subscribe_init()
789 644 *
790 645 * When a user checks the comment subscribe box and submits a comment, subscribe them to the comment thread.
791 - *
792 - * @param int|string $comment_id Comment thread being subscribed to.
793 - * @param string $approved Comment status.
794 646 */
795 - public function comment_subscribe_submit( $comment_id, $approved ) {
647 + function comment_subscribe_submit( $comment_id, $approved ) {
796 648 if ( 'spam' === $approved ) {
797 649 return;
798 650 }
799 651
800 - $comment = get_comment( $comment_id );
801 - if ( ! $comment ) {
802 - return;
803 - }
652 + // Set cookies for this post/comment
653 + $this->set_cookies( isset( $_REQUEST['subscribe_comments'] ), isset( $_REQUEST['subscribe_blog'] ) );
804 654
805 - // Set cookies for this post/comment.
806 - $this->set_cookies( isset( $_REQUEST['subscribe_comments'] ), $comment->comment_post_ID, isset( $_REQUEST['subscribe_blog'] ) ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended
807 -
808 - if ( ! isset( $_REQUEST['subscribe_comments'] ) && ! isset( $_REQUEST['subscribe_blog'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
655 + if ( !isset( $_REQUEST['subscribe_comments'] ) && !isset( $_REQUEST['subscribe_blog'] ) )
809 656 return;
810 - }
811 657
658 + $comment = get_comment( $comment_id );
812 659 $post_ids = array();
813 660
814 - if ( isset( $_REQUEST['subscribe_comments'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
661 + if ( isset( $_REQUEST['subscribe_comments'] ) )
815 662 $post_ids[] = $comment->comment_post_ID;
816 - }
817 663
818 - if ( isset( $_REQUEST['subscribe_blog'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
664 + if ( isset( $_REQUEST['subscribe_blog'] ) )
819 665 $post_ids[] = 0;
820 - }
821 666
822 - $result = self::subscribe(
823 - $comment->comment_author_email,
824 - $post_ids,
825 - true,
826 - array(
827 - 'source' => 'comment-form',
828 - 'widget-in-use' => is_active_widget( false, false, 'blog_subscription', true ) ? 'yes' : 'no',
829 - 'comment_status' => $approved,
830 - 'server_data' => jetpack_subscriptions_cherry_pick_server_data(),
831 - )
667 + Jetpack_Subscriptions::subscribe(
668 + $comment->comment_author_email,
669 + $post_ids,
670 + true,
671 + array(
672 + 'source' => 'comment-form',
673 + 'widget-in-use' => is_active_widget( false, false, 'blog_subscription', true ) ? 'yes' : 'no',
674 + 'comment_status' => $approved,
675 + 'server_data' => $_SERVER,
676 + )
832 677 );
833 -
834 - /**
835 - * Fires on each comment subscription form submission.
836 - *
837 - * @module subscriptions
838 - *
839 - * @since 5.5.0
840 - *
841 - * @param NULL|WP_Error $result Result of form submission: NULL on success, WP_Error otherwise.
842 - * @param array $post_ids An array of post IDs that the user subscribed to, 0 means blog subscription.
843 - */
844 - do_action( 'jetpack_subscriptions_comment_form_submission', $result, $post_ids );
845 678 }
846 679
847 680 /**
848 681 * Jetpack_Subscriptions::set_cookies()
@@ -847,19 +680,14 @@
847 680 /**
848 681 * Jetpack_Subscriptions::set_cookies()
849 682 *
850 683 * Set a cookie to save state on the comment and post subscription checkboxes.
851 - *
852 - * @param bool $subscribe_to_post Whether the user chose to subscribe to subsequent comments on this post.
853 - * @param int $post_id If $subscribe_to_post is true, the post ID they've subscribed to.
854 - * @param bool $subscribe_to_blog Whether the user chose to subscribe to all new posts on the blog.
855 684 */
856 - public function set_cookies( $subscribe_to_post = false, $post_id = null, $subscribe_to_blog = false ) {
857 - $post_id = (int) $post_id;
685 + function set_cookies( $comments = true, $posts = true ) {
686 + global $post;
858 687
859 688 /** This filter is already documented in core/wp-includes/comment-functions.php */
860 - $cookie_lifetime = apply_filters( 'comment_cookie_lifetime', 30000000 );
861 -
689 + $cookie_lifetime = apply_filters( 'comment_cookie_lifetime', 30000000 );
862 690 /**
863 691 * Filter the Jetpack Comment cookie path.
864 692 *
865 693 * @module subscriptions
@@ -867,10 +695,9 @@
867 695 * @since 2.5.0
868 696 *
869 697 * @param string COOKIEPATH Cookie path.
870 698 */
871 - $cookie_path = apply_filters( 'jetpack_comment_cookie_path', COOKIEPATH );
872 -
699 + $cookie_path = apply_filters( 'jetpack_comment_cookie_path', COOKIEPATH );
873 700 /**
874 701 * Filter the Jetpack Comment cookie domain.
875 702 *
876 703 * @module subscriptions
@@ -878,173 +705,330 @@
878 705 * @since 2.5.0
879 706 *
880 707 * @param string COOKIE_DOMAIN Cookie domain.
881 708 */
882 - $cookie_domain = apply_filters( 'jetpack_comment_cookie_domain', COOKIE_DOMAIN );
709 + $cookie_domain = apply_filters( 'jetpack_comment_cookie_domain', COOKIE_DOMAIN );
883 710
884 - if ( $subscribe_to_post && $post_id >= 0 ) {
885 - setcookie( 'jetpack_comments_subscribe_' . self::$hash . '_' . $post_id, 1, time() + $cookie_lifetime, $cookie_path, $cookie_domain, is_ssl(), true );
886 - } else {
887 - setcookie( 'jetpack_comments_subscribe_' . self::$hash . '_' . $post_id, '', time() - 3600, $cookie_path, $cookie_domain, is_ssl(), true );
888 - }
711 + if ( $comments )
712 + setcookie( 'jetpack_comments_subscribe_' . self::$hash, $post->ID, time() + $cookie_lifetime, $cookie_path, $cookie_domain );
713 + else
714 + setcookie( 'jetpack_comments_subscribe_' . self::$hash, '', time() - 3600, $cookie_path, $cookie_domain );
889 715
890 - if ( $subscribe_to_blog ) {
891 - setcookie( 'jetpack_blog_subscribe_' . self::$hash, 1, time() + $cookie_lifetime, $cookie_path, $cookie_domain, is_ssl(), true );
892 - } else {
893 - setcookie( 'jetpack_blog_subscribe_' . self::$hash, '', time() - 3600, $cookie_path, $cookie_domain, is_ssl(), true );
894 - }
716 + if ( $posts )
717 + setcookie( 'jetpack_blog_subscribe_' . self::$hash, 1, time() + $cookie_lifetime, $cookie_path, $cookie_domain );
718 + else
719 + setcookie( 'jetpack_blog_subscribe_' . self::$hash, '', time() - 3600, $cookie_path, $cookie_domain );
895 720 }
721 +}
896 722
897 - /**
898 - * Set the social_notifications_subscribe option to `off` when the Subscriptions module is activated in the first time.
899 - *
900 - * @since 8.1
901 - *
902 - * @return void
903 - */
904 - public function set_social_notifications_subscribe() {
905 - if ( false === get_option( 'social_notifications_subscribe' ) ) {
906 - add_option( 'social_notifications_subscribe', 'off' );
907 - }
723 +Jetpack_Subscriptions::init();
724 +
725 +
726 +/***
727 + * Blog Subscription Widget
728 + */
729 +
730 +class Jetpack_Subscriptions_Widget extends WP_Widget {
731 + function __construct() {
732 + $widget_ops = array( 'classname' => 'jetpack_subscription_widget', 'description' => __( 'Add an email signup form to allow people to subscribe to your blog.', 'jetpack' ) );
733 + $control_ops = array( 'width' => 300 );
734 +
735 + parent::__construct(
736 + 'blog_subscription',
737 + /** This filter is documented in modules/widgets/facebook-likebox.php */
738 + apply_filters( 'jetpack_widget_name', __( 'Blog Subscriptions', 'jetpack' ) ),
739 + $widget_ops,
740 + $control_ops
741 + );
908 742 }
909 743
910 - /**
911 - * Save a flag when a post was ever published.
912 - *
913 - * It saves the post meta when the post was published and becomes a draft.
914 - * Then this meta is used to hide subscription messaging in Publish panel.
915 - *
916 - * @param string $new_status Tthe "new" post status of the transition when saved.
917 - * @param string $old_status The "old" post status of the transition when saved.
918 - * @param object $post obj The post object.
919 - */
920 - public function maybe_set_first_published_status( $new_status, $old_status, $post ) {
921 - $was_post_ever_published = get_post_meta( $post->ID, '_jetpack_post_was_ever_published', true );
922 - if ( ! $was_post_ever_published && 'publish' === $old_status && 'draft' === $new_status ) {
923 - update_post_meta( $post->ID, '_jetpack_post_was_ever_published', true );
744 + function widget( $args, $instance ) {
745 + if (
746 + ( ! defined( 'IS_WPCOM' ) || ! IS_WPCOM ) &&
747 + /** This filter is already documented in modules/contact-form/grunion-contact-form.php */
748 + false === apply_filters( 'jetpack_auto_fill_logged_in_user', false )
749 + ) {
750 + $subscribe_email = '';
751 + } else {
752 + global $current_user;
753 + if ( ! empty( $current_user->user_email ) ) {
754 + $subscribe_email = esc_attr( $current_user->user_email );
755 + } else {
756 + $subscribe_email = '';
757 + }
924 758 }
925 - }
926 759
927 - /**
928 - * Checks if the current user can publish posts.
929 - *
930 - * @return bool
931 - */
932 - public function first_published_status_meta_auth_callback() {
760 +
761 +
762 + $source = 'widget';
763 + $instance = wp_parse_args( (array) $instance, $this->defaults() );
764 + $subscribe_text = isset( $instance['subscribe_text'] ) ? stripslashes( $instance['subscribe_text'] ) : '';
765 + $subscribe_placeholder = isset( $instance['subscribe_placeholder'] ) ? stripslashes( $instance['subscribe_placeholder'] ) : '';
766 + $subscribe_button = isset( $instance['subscribe_button'] ) ? stripslashes( $instance['subscribe_button'] ) : '';
767 + $success_message = isset( $instance['success_message'] ) ? stripslashes( $instance['success_message'] ) : '';
768 + $widget_id = esc_attr( !empty( $args['widget_id'] ) ? esc_attr( $args['widget_id'] ) : mt_rand( 450, 550 ) );
769 +
770 + $show_subscribers_total = (bool) $instance['show_subscribers_total'];
771 + $subscribers_total = $this->fetch_subscriber_count(); // Only used for the shortcode [total-subscribers]
772 +
773 + // Give the input element a unique ID
933 774 /**
934 - * Filter the capability to view if a post was ever published in the Subscription Module.
775 + * Filter the subscription form's ID prefix.
935 776 *
936 777 * @module subscriptions
937 778 *
938 - * @since 13.4
779 + * @since 2.7.0
939 780 *
940 - * @param string $capability User capability needed to view if a post was ever published. Default to publish_posts.
781 + * @param string subscribe-field Subscription form field prefix.
782 + * @param int $widget_id Widget ID.
941 783 */
942 - $capability = apply_filters( 'jetpack_subscriptions_post_was_ever_published_capability', 'publish_posts' );
943 - if ( current_user_can( $capability ) ) {
944 - return true;
784 + $subscribe_field_id = apply_filters( 'subscribe_field_id', 'subscribe-field', $widget_id );
785 +
786 + // Enqueue the form's CSS
787 + wp_register_style( 'jetpack-subscriptions', plugins_url( 'subscriptions/subscriptions.css', __FILE__ ) );
788 + wp_enqueue_style( 'jetpack-subscriptions' );
789 +
790 + // Display the subscription form
791 + echo $args['before_widget'];
792 +
793 + // Only show the title if there actually is a title
794 + if( ! empty( $instance['title'] ) ) {
795 + echo $args['before_title'] . esc_attr( $instance['title'] ) . $args['after_title'] . "\n";
945 796 }
946 - return false;
797 +
798 + $referer = set_url_scheme( 'http://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'] );
799 +
800 + // Display any errors
801 + if ( isset( $_GET['subscribe'] ) ) :
802 + switch ( $_GET['subscribe'] ) :
803 + case 'invalid_email' : ?>
804 + <p class="error"><?php esc_html_e( 'The email you entered was invalid. Please check and try again.', 'jetpack' ); ?></p>
805 + <?php break;
806 + case 'opted_out' : ?>
807 + <p class="error"><?php printf( __( 'The email address has opted out of subscription emails. <br /> You can manage your preferences at <a href="%1$s" title="%2$s" target="_blank">subscribe.wordpress.com</a>', 'jetpack' ),
808 + 'https://subscribe.wordpress.com/',
809 + __( 'Manage your email preferences.', 'jetpack' )
810 + ); ?>
811 + <?php break;
812 + case 'already' : ?>
813 + <p class="error"><?php esc_html_e( 'You have already subscribed to this site. Please check your inbox.', 'jetpack' ); ?></p>
814 + <?php break;
815 + case 'success' : ?>
816 + <div class="success"><?php echo wpautop( str_replace( '[total-subscribers]', number_format_i18n( $subscribers_total['value'] ), $success_message ) ); ?></div>
817 + <?php break;
818 + default : ?>
819 + <p class="error"><?php esc_html_e( 'There was an error when subscribing. Please try again.', 'jetpack' ); ?></p>
820 + <?php break;
821 + endswitch;
822 + endif;
823 +
824 + // Display a subscribe form
825 + if ( isset( $_GET['subscribe'] ) && 'success' == $_GET['subscribe'] ) { ?>
826 + <?php
827 + } else { ?>
828 + <form action="#" method="post" accept-charset="utf-8" id="subscribe-blog-<?php echo $widget_id; ?>">
829 + <?php
830 + if ( ! isset ( $_GET['subscribe'] ) || 'success' != $_GET['subscribe'] ) {
831 + ?><div id="subscribe-text"><?php echo wpautop( str_replace( '[total-subscribers]', number_format_i18n( $subscribers_total['value'] ), $subscribe_text ) ); ?></div><?php
832 + }
833 +
834 + if ( $show_subscribers_total && 0 < $subscribers_total['value'] ) {
835 + echo wpautop( sprintf( _n( 'Join %s other subscriber', 'Join %s other subscribers', $subscribers_total['value'], 'jetpack' ), number_format_i18n( $subscribers_total['value'] ) ) );
836 + }
837 + if ( ! isset ( $_GET['subscribe'] ) || 'success' != $_GET['subscribe'] ) { ?>
838 + <p id="subscribe-email">
839 + <label id="jetpack-subscribe-label" for="<?php echo esc_attr( $subscribe_field_id ) . '-' . esc_attr( $widget_id ); ?>">
840 + <?php echo !empty( $subscribe_placeholder ) ? esc_html( $subscribe_placeholder ) : esc_html__( 'Email Address:', 'jetpack' ); ?>
841 + </label>
842 + <input type="email" name="email" required="required" class="required" value="<?php echo esc_attr( $subscribe_email ); ?>" id="<?php echo esc_attr( $subscribe_field_id ) . '-' . esc_attr( $widget_id ); ?>" placeholder="<?php echo esc_attr( $subscribe_placeholder ); ?>" />
843 + </p>
844 +
845 + <p id="subscribe-submit">
846 + <input type="hidden" name="action" value="subscribe" />
847 + <input type="hidden" name="source" value="<?php echo esc_url( $referer ); ?>" />
848 + <input type="hidden" name="sub-type" value="<?php echo esc_attr( $source ); ?>" />
849 + <input type="hidden" name="redirect_fragment" value="<?php echo $widget_id; ?>" />
850 + <?php
851 + if ( is_user_logged_in() ) {
852 + wp_nonce_field( 'blogsub_subscribe_'. get_current_blog_id(), '_wpnonce', false );
853 + }
854 + ?>
855 + <input type="submit" value="<?php echo esc_attr( $subscribe_button ); ?>" name="jetpack_subscriptions_widget" />
856 + </p>
857 + <?php }?>
858 + </form>
859 +
860 + <script>
861 + /*
862 + Custom functionality for safari and IE
863 + */
864 + (function( d ) {
865 + // In case the placeholder functionality is available we remove labels
866 + if ( ( 'placeholder' in d.createElement( 'input' ) ) ) {
867 + var label = d.querySelector( 'label[for=subscribe-field-<?php echo $widget_id; ?>]' );
868 + label.style.clip = 'rect(1px, 1px, 1px, 1px)';
869 + label.style.position = 'absolute';
870 + label.style.height = '1px';
871 + label.style.width = '1px';
872 + label.style.overflow = 'hidden';
873 + }
874 +
875 + // Make sure the email value is filled in before allowing submit
876 + var form = d.getElementById('subscribe-blog-<?php echo $widget_id; ?>'),
877 + input = d.getElementById('<?php echo esc_attr( $subscribe_field_id ) . '-' . esc_attr( $widget_id ); ?>'),
878 + handler = function( event ) {
879 + if ( '' === input.value ) {
880 + input.focus();
881 +
882 + if ( event.preventDefault ){
883 + event.preventDefault();
884 + }
885 +
886 + return false;
887 + }
888 + };
889 +
890 + if ( window.addEventListener ) {
891 + form.addEventListener( 'submit', handler, false );
892 + } else {
893 + form.attachEvent( 'onsubmit', handler );
894 + }
895 + })( document );
896 + </script>
897 + <?php } ?>
898 + <?php
899 +
900 + echo "\n" . $args['after_widget'];
947 901 }
948 902
949 - /**
950 - * Registers the 'post_was_ever_published' post meta for use in the REST API.
951 - */
952 - public function register_post_meta() {
953 - $jetpack_post_was_ever_published = array(
954 - 'type' => 'boolean',
955 - 'description' => __( 'Whether the post was ever published.', 'jetpack' ),
956 - 'single' => true,
957 - 'default' => false,
958 - 'show_in_rest' => array(
959 - 'name' => 'jetpack_post_was_ever_published',
960 - ),
961 - 'auth_callback' => array( $this, 'first_published_status_meta_auth_callback' ),
962 - );
903 + function increment_subscriber_count( $current_subs_array = array() ) {
904 + $current_subs_array['value']++;
963 905
964 - register_meta( 'post', '_jetpack_post_was_ever_published', $jetpack_post_was_ever_published );
906 + set_transient( 'wpcom_subscribers_total', $current_subs_array, 3600 ); // try to cache the result for at least 1 hour
907 +
908 + return $current_subs_array;
965 909 }
966 910
967 - /**
968 - * Create a Subscribers menu displayed on self-hosted sites.
969 - *
970 - * - It is not displayed on WordPress.com sites.
971 - * - It directs you to Calypso to the existing Subscribers page.
972 - *
973 - * @return void
974 - */
975 - public function add_subscribers_menu() {
976 - /*
977 - * Do not display any menu on WoA and WordPress.com Simple sites (unless Classic wp-admin is enabled).
978 - * They already get a menu item under Users via nav-unification.
979 - */
980 - if ( ( new Host() )->is_wpcom_platform() && get_option( 'wpcom_admin_interface' ) !== 'wp-admin' ) {
981 - return;
911 + function fetch_subscriber_count() {
912 + $subs_count = get_transient( 'wpcom_subscribers_total' );
913 +
914 + if ( FALSE === $subs_count || 'failed' == $subs_count['status'] ) {
915 + Jetpack:: load_xml_rpc_client();
916 +
917 + $xml = new Jetpack_IXR_Client( array( 'user_id' => JETPACK_MASTER_USER, ) );
918 +
919 + $xml->query( 'jetpack.fetchSubscriberCount' );
920 +
921 + if ( $xml->isError() ) { // if we get an error from .com, set the status to failed so that we will try again next time the data is requested
922 + $subs_count = array(
923 + 'status' => 'failed',
924 + 'code' => $xml->getErrorCode(),
925 + 'message' => $xml->getErrorMessage(),
926 + 'value' => ( isset( $subs_count['value'] ) ) ? $subs_count['value'] : 0,
927 + );
928 + } else {
929 + $subs_count = array(
930 + 'status' => 'success',
931 + 'value' => $xml->getResponse(),
932 + );
933 + }
934 +
935 + set_transient( 'wpcom_subscribers_total', $subs_count, 3600 ); // try to cache the result for at least 1 hour
982 936 }
983 937
984 - $status = new Status();
938 + return $subs_count;
939 + }
985 940
986 - /*
987 - * Do not display if we're in Offline mode,
988 - * or if the user is not connected.
989 - */
990 - if (
991 - $status->is_offline_mode()
992 - || ! ( new Connection_Manager( 'jetpack' ) )->is_user_connected()
993 - ) {
994 - return;
995 - }
941 + function update( $new_instance, $old_instance ) {
942 + $instance = $old_instance;
996 943
997 - $blog_id = Connection_Manager::get_site_id( true );
944 + $instance['title'] = wp_kses( stripslashes( $new_instance['title'] ), array() );
945 + $instance['subscribe_text'] = wp_filter_post_kses( stripslashes( $new_instance['subscribe_text'] ) );
946 + $instance['subscribe_placeholder'] = wp_kses( stripslashes( $new_instance['subscribe_placeholder'] ), array() );
947 + $instance['subscribe_button'] = wp_kses( stripslashes( $new_instance['subscribe_button'] ), array() );
948 + $instance['success_message'] = wp_kses( stripslashes( $new_instance['success_message'] ), array() );
949 + $instance['show_subscribers_total'] = isset( $new_instance['show_subscribers_total'] ) && $new_instance['show_subscribers_total'];
998 950
999 - $link = Redirect::get_url(
1000 - 'jetpack-menu-jetpack-manage-subscribers',
1001 - array( 'site' => $blog_id ? $blog_id : $status->get_site_suffix() )
1002 - );
951 + return $instance;
952 + }
1003 953
1004 - Admin_Menu::add_menu(
1005 - __( 'Subscribers', 'jetpack' ),
1006 - __( 'Subscribers', 'jetpack' ) . ' <span class="dashicons dashicons-external"></span>',
1007 - 'manage_options',
1008 - esc_url( $link ),
1009 - null,
1010 - 11
954 + public static function defaults() {
955 + return array(
956 + 'title' => esc_html__( 'Subscribe to Blog via Email', 'jetpack' ),
957 + 'subscribe_text' => esc_html__( 'Enter your email address to subscribe to this blog and receive notifications of new posts by email.', 'jetpack' ),
958 + 'subscribe_placeholder' => esc_html__( 'Email Address', 'jetpack' ),
959 + 'subscribe_button' => esc_html__( 'Subscribe', 'jetpack' ),
960 + 'success_message' => esc_html__( 'Success! An email was just sent to confirm your subscription. Please find the email now and click activate to start subscribing.', 'jetpack' ),
961 + 'show_subscribers_total' => true,
1011 962 );
1012 963 }
1013 964
1014 - /**
1015 - * Record tracks event if categories is created when user enters
1016 - * the edit category page through the newsletter settings page.
1017 - *
1018 - * @return void
1019 - */
1020 - public function track_newsletter_category_creation() {
965 + function form( $instance ) {
966 + $instance = wp_parse_args( (array) $instance, $this->defaults() );
1021 967
1022 - // phpcs:disable WordPress.Security.NonceVerification.Missing
1023 - if ( empty( $_POST['_wp_http_referer'] ) ) {
1024 - return;
1025 - }
968 + $title = stripslashes( $instance['title'] );
969 + $subscribe_text = stripslashes( $instance['subscribe_text'] );
970 + $subscribe_placeholder = stripslashes( $instance['subscribe_placeholder'] );
971 + $subscribe_button = stripslashes( $instance['subscribe_button'] );
972 + $success_message = stripslashes( $instance['success_message']);
973 + $show_subscribers_total = checked( $instance['show_subscribers_total'], true, false );
1026 974
1027 - if ( strpos( sanitize_url( wp_unslash( $_POST['_wp_http_referer'] ) ), 'referer=newsletter-categories' ) > -1 ) {
975 + $subs_fetch = $this->fetch_subscriber_count();
1028 976
1029 - $parent = filter_var( empty( $_POST['parent'] ) ? 0 : wp_unslash( $_POST['parent'] ), FILTER_SANITIZE_NUMBER_INT );
1030 -
1031 - $is_child_category = $parent > 0;
1032 -
1033 - $tracking = new Automattic\Jetpack\Tracking();
1034 - $tracking->tracks_record_event(
1035 - wp_get_current_user(),
1036 - 'jetpack_newsletter_add_category',
1037 - array(
1038 - 'is_child_category' => $is_child_category,
1039 - )
1040 - );
977 + if ( 'failed' == $subs_fetch['status'] ) {
978 + printf( '<div class="error inline"><p>' . __( '%s: %s', 'jetpack' ) . '</p></div>', esc_html( $subs_fetch['code'] ), esc_html( $subs_fetch['message'] ) );
1041 979 }
980 + $subscribers_total = number_format_i18n( $subs_fetch['value'] );
981 +?>
982 +<p>
983 + <label for="<?php echo $this->get_field_id( 'title' ); ?>">
984 + <?php _e( 'Widget title:', 'jetpack' ); ?>
985 + <input class="widefat" id="<?php echo $this->get_field_id( 'title' ); ?>" name="<?php echo $this->get_field_name( 'title' ); ?>" type="text" value="<?php echo esc_attr( $title ); ?>" />
986 + </label>
987 +</p>
988 +<p>
989 + <label for="<?php echo $this->get_field_id( 'subscribe_text' ); ?>">
990 + <?php _e( 'Optional text to display to your readers:', 'jetpack' ); ?>
991 + <textarea style="width: 95%" id="<?php echo $this->get_field_id( 'subscribe_text' ); ?>" name="<?php echo $this->get_field_name( 'subscribe_text' ); ?>" type="text"><?php echo esc_html( $subscribe_text ); ?></textarea>
992 + </label>
993 +</p>
994 +<p>
995 + <label for="<?php echo $this->get_field_id( 'subscribe_placeholder' ); ?>">
996 + <?php esc_html_e( 'Subscribe Placeholder:', 'jetpack' ); ?>
997 + <input class="widefat" id="<?php echo $this->get_field_id( 'subscribe_placeholder' ); ?>" name="<?php echo $this->get_field_name( 'subscribe_placeholder' ); ?>" type="text" value="<?php echo esc_attr( $subscribe_placeholder ); ?>" />
998 + </label>
999 +</p>
1000 +<p>
1001 + <label for="<?php echo $this->get_field_id( 'subscribe_button' ); ?>">
1002 + <?php _e( 'Subscribe Button:', 'jetpack' ); ?>
1003 + <input class="widefat" id="<?php echo $this->get_field_id( 'subscribe_button' ); ?>" name="<?php echo $this->get_field_name( 'subscribe_button' ); ?>" type="text" value="<?php echo esc_attr( $subscribe_button ); ?>" />
1004 + </label>
1005 +</p>
1006 +<p>
1007 + <label for="<?php echo $this->get_field_id( 'success_message' ); ?>">
1008 + <?php _e( 'Success Message Text:', 'jetpack' ); ?>
1009 + <textarea style="width: 95%" id="<?php echo $this->get_field_id( 'success_message' ); ?>" name="<?php echo $this->get_field_name( 'success_message' ); ?>" type="text"><?php echo esc_html( $success_message ); ?></textarea>
1010 + </label>
1011 +</p>
1012 +<p>
1013 + <label for="<?php echo $this->get_field_id( 'show_subscribers_total' ); ?>">
1014 + <input type="checkbox" id="<?php echo $this->get_field_id( 'show_subscribers_total' ); ?>" name="<?php echo $this->get_field_name( 'show_subscribers_total' ); ?>" value="1"<?php echo $show_subscribers_total; ?> />
1015 + <?php echo esc_html( sprintf( _n( 'Show total number of subscribers? (%s subscriber)', 'Show total number of subscribers? (%s subscribers)', $subscribers_total, 'jetpack' ), $subscribers_total ) ); ?>
1016 + </label>
1017 +</p>
1018 +<?php
1042 1019 }
1043 1020 }
1044 1021
1045 -Jetpack_Subscriptions::init();
1022 +add_shortcode( 'jetpack_subscription_form', 'jetpack_do_subscription_form' );
1046 1023
1047 -require __DIR__ . '/subscriptions/views.php';
1048 -require __DIR__ . '/subscriptions/subscribe-modal/class-jetpack-subscribe-modal.php';
1049 -require __DIR__ . '/subscriptions/subscribe-overlay/class-jetpack-subscribe-overlay.php';
1050 -require __DIR__ . '/subscriptions/subscribe-floating-button/class-jetpack-subscribe-floating-button.php';
1024 +function jetpack_do_subscription_form( $instance ) {
1025 + $instance['show_subscribers_total'] = empty( $instance['show_subscribers_total'] ) ? false : true;
1026 + $instance = shortcode_atts( Jetpack_Subscriptions_Widget::defaults(), $instance, 'jetpack_subscription_form' );
1027 + $args = array(
1028 + 'before_widget' => sprintf( '<div class="%s">', 'jetpack_subscription_widget' ),
1029 + );
1030 + ob_start();
1031 + the_widget( 'Jetpack_Subscriptions_Widget', $instance, $args );
1032 + $output = ob_get_clean();
1033 + return $output;
1034 +}