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