PluginProbe
Jetpack – WP Security, Backup, Speed, & Growth / 10.8.2
Jetpack – WP Security, Backup, Speed, & Growth v10.8.2
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
jetpack / modules / subscriptions.php

subscriptions.php in Jetpack – WP Security, Backup, Speed, & Growth 10.8.2, at modules/subscriptions.php

982 lines 29.3 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php // phpcs:ignore WordPress.Files.FileName.InvalidClassFileName)
2 /**
3 * Module Name: Subscriptions
4 * Module Description: Let visitors subscribe to new posts and comments via email
5 * Sort Order: 9
6 * Recommendation Order: 8
7 * First Introduced: 1.2
8 * Requires Connection: Yes
9 * Requires User Connection: Yes
10 * Auto Activate: No
11 * Module Tags: Social
12 * Feature: Engagement
13 * Additional Search Queries: subscriptions, subscription, email, follow, followers, subscribers, signup
14 */
15
16 use Automattic\Jetpack\Connection\XMLRPC_Async_Call;
17
18 add_action( 'jetpack_modules_loaded', 'jetpack_subscriptions_load' );
19
20 /**
21 * Loads the Subscriptions module.
22 */
23 function jetpack_subscriptions_load() {
24 Jetpack::enable_module_configurable( __FILE__ );
25 }
26
27 /**
28 * Cherry picks keys from `$_SERVER` array.
29 *
30 * @since 6.0.0
31 *
32 * @return array An array of server data.
33 */
34 function jetpack_subscriptions_cherry_pick_server_data() {
35 $data = array();
36
37 foreach ( $_SERVER as $key => $value ) {
38 if ( ! is_string( $value ) || 0 === strpos( $key, 'HTTP_COOKIE' ) ) {
39 continue;
40 }
41
42 if ( 0 === strpos( $key, 'HTTP_' ) || in_array( $key, array( 'REMOTE_ADDR', 'REQUEST_URI', 'DOCUMENT_URI' ), true ) ) {
43 $data[ $key ] = $value;
44 }
45 }
46
47 return $data;
48 }
49
50 /**
51 * Main class file for the Subscriptions module.
52 */
53 class Jetpack_Subscriptions {
54 /**
55 * Whether Jetpack has been instantiated or not.
56 *
57 * @var bool
58 */
59 public $jetpack = false;
60
61 /**
62 * Hash of the siteurl option.
63 *
64 * @var string
65 */
66 public static $hash;
67
68 /**
69 * Singleton
70 *
71 * @static
72 */
73 public static function init() {
74 static $instance = false;
75
76 if ( ! $instance ) {
77 $instance = new Jetpack_Subscriptions();
78 }
79
80 return $instance;
81 }
82
83 /**
84 * Jetpack_Subscriptions constructor.
85 */
86 public function __construct() {
87 $this->jetpack = Jetpack::init();
88
89 // Don't use COOKIEHASH as it could be shared across installs && is non-unique in multisite.
90 // @see: https://twitter.com/nacin/status/378246957451333632 .
91 self::$hash = md5( get_option( 'siteurl' ) );
92
93 add_filter( 'jetpack_xmlrpc_methods', array( $this, 'xmlrpc_methods' ) );
94
95 // @todo remove sync from subscriptions and move elsewhere...
96
97 // Add Configuration Page.
98 add_action( 'admin_init', array( $this, 'configure' ) );
99
100 // Catch subscription widget submits.
101 if ( isset( $_REQUEST['jetpack_subscriptions_widget'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Nonce checked in widget_submit() for logged in users.
102 add_action( 'template_redirect', array( $this, 'widget_submit' ) );
103 }
104
105 // Set up the comment subscription checkboxes.
106 add_filter( 'comment_form_submit_field', array( $this, 'comment_subscribe_init' ), 10, 2 );
107
108 // Catch comment posts and check for subscriptions.
109 add_action( 'comment_post', array( $this, 'comment_subscribe_submit' ), 50, 2 );
110
111 // Adds post meta checkbox in the post submit metabox.
112 add_action( 'post_submitbox_misc_actions', array( $this, 'subscription_post_page_metabox' ) );
113
114 add_action( 'transition_post_status', array( $this, 'maybe_send_subscription_email' ), 10, 3 );
115
116 add_filter( 'jetpack_published_post_flags', array( $this, 'set_post_flags' ), 10, 2 );
117
118 add_filter( 'post_updated_messages', array( $this, 'update_published_message' ), 18, 1 );
119
120 // Set "social_notifications_subscribe" option during the first-time activation.
121 add_action( 'jetpack_activate_module_subscriptions', array( $this, 'set_social_notifications_subscribe' ) );
122 }
123
124 /**
125 * Jetpack_Subscriptions::xmlrpc_methods()
126 *
127 * Register subscriptions methods with the Jetpack XML-RPC server.
128 *
129 * @param array $methods Methods being registered.
130 */
131 public function xmlrpc_methods( $methods ) {
132 return array_merge(
133 $methods,
134 array(
135 'jetpack.subscriptions.subscribe' => array( $this, 'subscribe' ),
136 )
137 );
138 }
139
140 /**
141 * Disable Subscribe on Single Post
142 * Register post meta
143 */
144 public function subscription_post_page_metabox() {
145 if (
146 /**
147 * Filter whether or not to show the per-post subscription option.
148 *
149 * @module subscriptions
150 *
151 * @since 3.7.0
152 *
153 * @param bool true = show checkbox option on all new posts | false = hide the option.
154 */
155 ! apply_filters( 'jetpack_allow_per_post_subscriptions', false ) ) {
156 return;
157 }
158
159 if ( has_filter( 'jetpack_subscriptions_exclude_these_categories' ) || has_filter( 'jetpack_subscriptions_include_only_these_categories' ) ) {
160 return;
161 }
162
163 global $post;
164 $disable_subscribe_value = get_post_meta( $post->ID, '_jetpack_dont_email_post_to_subs', true );
165 // only show checkbox if post hasn't been published and is a 'post' post type.
166 if ( get_post_status( $post->ID ) !== 'publish' && get_post_type( $post->ID ) === 'post' ) :
167 // Nonce it.
168 wp_nonce_field( 'disable_subscribe', 'disable_subscribe_nonce' );
169 ?>
170 <div class="misc-pub-section">
171 <label for="_jetpack_dont_email_post_to_subs"><?php esc_html_e( 'Jetpack Subscriptions:', 'jetpack' ); ?></label><br>
172 <input type="checkbox" name="_jetpack_dont_email_post_to_subs" id="jetpack-per-post-subscribe" value="1" <?php checked( $disable_subscribe_value, 1, true ); ?> />
173 <?php esc_html_e( 'Don&#8217;t send this to subscribers', 'jetpack' ); ?>
174 </div>
175 <?php
176 endif;
177 }
178
179 /**
180 * Checks whether or not the post should be emailed to subscribers
181 *
182 * It checks for the following things in order:
183 * - Usage of filter jetpack_subscriptions_exclude_these_categories
184 * - Usage of filter jetpack_subscriptions_include_only_these_categories
185 * - Existence of the per-post checkbox option
186 *
187 * Only one of these can be used at any given time.
188 *
189 * @param string $new_status Tthe "new" post status of the transition when saved.
190 * @param string $old_status The "old" post status of the transition when saved.
191 * @param object $post obj The post object.
192 */
193 public function maybe_send_subscription_email( $new_status, $old_status, $post ) {
194
195 if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) {
196 return;
197 }
198
199 // Make sure that the checkbox is preseved.
200 if ( ! empty( $_POST['disable_subscribe_nonce'] ) && wp_verify_nonce( $_POST['disable_subscribe_nonce'], 'disable_subscribe' ) ) {
201 $set_checkbox = isset( $_POST['_jetpack_dont_email_post_to_subs'] ) ? 1 : 0;
202 update_post_meta( $post->ID, '_jetpack_dont_email_post_to_subs', $set_checkbox );
203 }
204 }
205
206 /**
207 * Message used when publishing a post.
208 *
209 * @param array $messages Message array for a post.
210 */
211 public function update_published_message( $messages ) {
212 global $post;
213 if ( ! $this->should_email_post_to_subscribers( $post ) ) {
214 return $messages;
215 }
216
217 $view_post_link_html = sprintf(
218 ' <a href="%1$s">%2$s</a>',
219 esc_url( get_permalink( $post ) ),
220 __( 'View post', 'jetpack' )
221 );
222
223 $messages['post'][6] = sprintf(
224 /* translators: Message shown after a post is published */
225 esc_html__( 'Post published and sending emails to subscribers.', 'jetpack' )
226 ) . $view_post_link_html;
227 return $messages;
228 }
229
230 /**
231 * Determine if a post should notifiy subscribers via email.
232 *
233 * @param object $post The post.
234 */
235 public function should_email_post_to_subscribers( $post ) {
236 $should_email = true;
237 if ( get_post_meta( $post->ID, '_jetpack_dont_email_post_to_subs', true ) ) {
238 return false;
239 }
240
241 // Only posts are currently supported.
242 if ( 'post' !== $post->post_type ) {
243 return false;
244 }
245
246 // Private posts are not sent to subscribers.
247 if ( 'private' === $post->post_status ) {
248 return false;
249 }
250
251 /**
252 * Array of categories that will never trigger subscription emails.
253 *
254 * Will not send subscription emails from any post from within these categories.
255 *
256 * @module subscriptions
257 *
258 * @since 3.7.0
259 *
260 * @param array $args Array of category slugs or ID's.
261 */
262 $excluded_categories = apply_filters( 'jetpack_subscriptions_exclude_these_categories', array() );
263
264 // Never email posts from these categories.
265 if ( ! empty( $excluded_categories ) && in_category( $excluded_categories, $post->ID ) ) {
266 $should_email = false;
267 }
268
269 /**
270 * ONLY send subscription emails for these categories
271 *
272 * Will ONLY send subscription emails to these categories.
273 *
274 * @module subscriptions
275 *
276 * @since 3.7.0
277 *
278 * @param array $args Array of category slugs or ID's.
279 */
280 $only_these_categories = apply_filters( 'jetpack_subscriptions_exclude_all_categories_except', array() );
281
282 // Only emails posts from these categories.
283 if ( ! empty( $only_these_categories ) && ! in_category( $only_these_categories, $post->ID ) ) {
284 $should_email = false;
285 }
286
287 return $should_email;
288 }
289
290 /**
291 * Retrieve which flags should be added to a particular post.
292 *
293 * @param array $flags Flags to be added.
294 * @param object $post A post object.
295 */
296 public function set_post_flags( $flags, $post ) {
297 $flags['send_subscription'] = $this->should_email_post_to_subscribers( $post );
298 return $flags;
299 }
300
301 /**
302 * Jetpack_Subscriptions::configure()
303 *
304 * Jetpack Subscriptions configuration screen.
305 */
306 public function configure() {
307 // Create the section.
308 add_settings_section(
309 'jetpack_subscriptions',
310 __( 'Jetpack Subscriptions Settings', 'jetpack' ),
311 array( $this, 'subscriptions_settings_section' ),
312 'discussion'
313 );
314
315 /** Subscribe to Posts */
316
317 add_settings_field(
318 'jetpack_subscriptions_post_subscribe',
319 __( 'Follow Blog', 'jetpack' ),
320 array( $this, 'subscription_post_subscribe_setting' ),
321 'discussion',
322 'jetpack_subscriptions'
323 );
324
325 register_setting(
326 'discussion',
327 'stb_enabled'
328 );
329
330 /** Subscribe to Comments */
331
332 add_settings_field(
333 'jetpack_subscriptions_comment_subscribe',
334 __( 'Follow Comments', 'jetpack' ),
335 array( $this, 'subscription_comment_subscribe_setting' ),
336 'discussion',
337 'jetpack_subscriptions'
338 );
339
340 register_setting(
341 'discussion',
342 'stc_enabled'
343 );
344
345 /** Email me whenever: Someone follows my blog */
346 /* @since 8.1 */
347
348 add_settings_section(
349 'notifications_section',
350 __( 'Someone follows my blog', 'jetpack' ),
351 array( $this, 'social_notifications_subscribe_section' ),
352 'discussion'
353 );
354
355 add_settings_field(
356 'jetpack_subscriptions_social_notifications_subscribe',
357 __( 'Email me whenever', 'jetpack' ),
358 array( $this, 'social_notifications_subscribe_field' ),
359 'discussion',
360 'notifications_section'
361 );
362
363 register_setting(
364 'discussion',
365 'social_notifications_subscribe',
366 array( $this, 'social_notifications_subscribe_validate' )
367 );
368
369 /** Subscription Messaging Options */
370
371 register_setting(
372 'reading',
373 'subscription_options',
374 array( $this, 'validate_settings' )
375 );
376
377 add_settings_section(
378 'email_settings',
379 __( 'Follower Settings', 'jetpack' ),
380 array( $this, 'reading_section' ),
381 'reading'
382 );
383
384 add_settings_field(
385 'invitation',
386 __( 'Blog follow email text', 'jetpack' ),
387 array( $this, 'setting_invitation' ),
388 'reading',
389 'email_settings'
390 );
391
392 add_settings_field(
393 'comment-follow',
394 __( 'Comment follow email text', 'jetpack' ),
395 array( $this, 'setting_comment_follow' ),
396 'reading',
397 'email_settings'
398 );
399 }
400
401 /**
402 * Discussions setting section blurb.
403 */
404 public function subscriptions_settings_section() {
405 ?>
406 <p id="jetpack-subscriptions-settings"><?php esc_html_e( 'Change whether your visitors can subscribe to your posts or comments or both.', 'jetpack' ); ?></p>
407
408 <?php
409 }
410
411 /**
412 * Post Subscriptions Toggle.
413 */
414 public function subscription_post_subscribe_setting() {
415
416 $stb_enabled = get_option( 'stb_enabled', 1 );
417 ?>
418
419 <p class="description">
420 <input type="checkbox" name="stb_enabled" id="jetpack-post-subscribe" value="1" <?php checked( $stb_enabled, 1 ); ?> />
421 <?php
422 echo wp_kses(
423 __(
424 "Show a <em>'follow blog'</em> option in the comment form",
425 'jetpack'
426 ),
427 array( 'em' => array() )
428 );
429 ?>
430 </p>
431 <?php
432 }
433
434 /**
435 * Comments Subscriptions Toggle.
436 */
437 public function subscription_comment_subscribe_setting() {
438
439 $stc_enabled = get_option( 'stc_enabled', 1 );
440 ?>
441
442 <p class="description">
443 <input type="checkbox" name="stc_enabled" id="jetpack-comment-subscribe" value="1" <?php checked( $stc_enabled, 1 ); ?> />
444 <?php
445 echo wp_kses(
446 __(
447 "Show a <em>'follow comments'</em> option in the comment form",
448 'jetpack'
449 ),
450 array( 'em' => array() )
451 );
452 ?>
453 </p>
454
455 <?php
456 }
457
458 /**
459 * Someone follows my blog section
460 *
461 * @since 8.1
462 */
463 public function social_notifications_subscribe_section() {
464 // Atypical usage here. We emit jquery to move subscribe notification checkbox to be with the rest of the email notification settings.
465 ?>
466 <script type="text/javascript">
467 jQuery( function( $ ) {
468 var table = $( '#social_notifications_subscribe' ).parents( 'table:first' ),
469 header = table.prevAll( 'h2:first' ),
470 newParent = $( '#moderation_notify' ).parent( 'label' ).parent();
471
472 if ( ! table.length || ! header.length || ! newParent.length ) {
473 return;
474 }
475
476 newParent.append( '<br/>' ).append( table.end().parent( 'label' ).siblings().andSelf() );
477 header.remove();
478 table.remove();
479 } );
480 </script>
481 <?php
482 }
483
484 /**
485 * Someone follows my blog Toggle
486 *
487 * @since 8.1
488 */
489 public function social_notifications_subscribe_field() {
490 $checked = (int) ( 'on' === get_option( 'social_notifications_subscribe', 'on' ) );
491 ?>
492
493 <label>
494 <input type="checkbox" name="social_notifications_subscribe" id="social_notifications_subscribe" value="1" <?php checked( $checked ); ?> />
495 <?php
496 /* translators: this is a label for a setting that starts with "Email me whenever" */
497 esc_html_e( 'Someone follows my blog', 'jetpack' );
498 ?>
499 </label>
500 <?php
501 }
502
503 /**
504 * Validate "Someone follows my blog" option
505 *
506 * @since 8.1
507 *
508 * @param String $input the input string to be validated.
509 * @return string on|off
510 */
511 public function social_notifications_subscribe_validate( $input ) {
512 // If it's not set (was unchecked during form submission) or was set to off (during option update), return 'off'.
513 if ( ! $input || 'off' === $input ) {
514 return 'off';
515 }
516
517 // Otherwise we return 'on'.
518 return 'on';
519 }
520
521 /**
522 * Validate settings for the Subscriptions module.
523 *
524 * @param array $settings Settings to be validated.
525 */
526 public function validate_settings( $settings ) {
527 global $allowedposttags;
528
529 $default = $this->get_default_settings();
530
531 // Blog Follow.
532 $settings['invitation'] = trim( wp_kses( $settings['invitation'], $allowedposttags ) );
533 if ( empty( $settings['invitation'] ) ) {
534 $settings['invitation'] = $default['invitation'];
535 }
536
537 // Comments Follow (single post).
538 $settings['comment_follow'] = trim( wp_kses( $settings['comment_follow'], $allowedposttags ) );
539 if ( empty( $settings['comment_follow'] ) ) {
540 $settings['comment_follow'] = $default['comment_follow'];
541 }
542
543 return $settings;
544 }
545
546 /**
547 * HTML output helper for Reading section.
548 */
549 public function reading_section() {
550 echo '<p id="follower-settings">';
551 esc_html_e( 'These settings change emails sent from your blog to followers.', 'jetpack' );
552 echo '</p>';
553 }
554
555 /**
556 * HTML output helper for Invitation section.
557 */
558 public function setting_invitation() {
559 $settings = $this->get_settings();
560 echo '<textarea name="subscription_options[invitation]" class="large-text" cols="50" rows="5">' . esc_textarea( $settings['invitation'] ) . '</textarea>';
561 echo '<p><span class="description">' . esc_html__( 'Introduction text sent when someone follows your blog. (Site and confirmation details will be automatically added for you.)', 'jetpack' ) . '</span></p>';
562 }
563
564 /**
565 * HTML output helper for Comment Follow section.
566 */
567 public function setting_comment_follow() {
568 $settings = $this->get_settings();
569 echo '<textarea name="subscription_options[comment_follow]" class="large-text" cols="50" rows="5">' . esc_textarea( $settings['comment_follow'] ) . '</textarea>';
570 echo '<p><span class="description">' . esc_html__( 'Introduction text sent when someone follows a post on your blog. (Site and confirmation details will be automatically added for you.)', 'jetpack' ) . '</span></p>';
571 }
572
573 /**
574 * Get default settings for the Subscriptions module.
575 */
576 public function get_default_settings() {
577 return array(
578 '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' ),
579 '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' ),
580 );
581 }
582
583 /**
584 * Reeturn merged `subscription_options` option with module default settings.
585 */
586 public function get_settings() {
587 return wp_parse_args( (array) get_option( 'subscription_options', array() ), $this->get_default_settings() );
588 }
589
590 /**
591 * Jetpack_Subscriptions::subscribe()
592 *
593 * Send a synchronous XML-RPC subscribe to blog posts or subscribe to post comments request.
594 *
595 * @param string $email being subscribed.
596 * @param array $post_ids (optional) defaults to 0 for blog posts only: array of post IDs to subscribe to blog's posts.
597 * @param bool $async (optional) Should the subscription be performed asynchronously? Defaults to true.
598 * @param array $extra_data Additional data passed to the `jetpack.subscribeToSite` call.
599 *
600 * @return true|WP_Error true on success
601 * invalid_email : not a valid email address
602 * invalid_post_id : not a valid post ID
603 * unknown_post_id : unknown post
604 * not_subscribed : strange error. Jetpack servers at WordPress.com could subscribe the email.
605 * disabled : Site owner has disabled subscriptions.
606 * active : Already subscribed.
607 * pending : Tried to subscribe before but the confirmation link is never clicked. No confirmation email is sent.
608 * unknown : strange error. Jetpack servers at WordPress.com returned something malformed.
609 * unknown_status : strange error. Jetpack servers at WordPress.com returned something I didn't understand.
610 */
611 public function subscribe( $email, $post_ids = 0, $async = true, $extra_data = array() ) {
612 if ( ! is_email( $email ) ) {
613 return new WP_Error( 'invalid_email' );
614 }
615
616 if ( ! $async ) {
617 $xml = new Jetpack_IXR_ClientMulticall();
618 }
619
620 foreach ( (array) $post_ids as $post_id ) {
621 $post_id = (int) $post_id;
622 if ( $post_id < 0 ) {
623 return new WP_Error( 'invalid_post_id' );
624 } elseif ( $post_id && ! get_post( $post_id ) ) {
625 return new WP_Error( 'unknown_post_id' );
626 }
627
628 if ( $async ) {
629 XMLRPC_Async_Call::add_call( 'jetpack.subscribeToSite', 0, $email, $post_id, serialize( $extra_data ) ); //phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.serialize_serialize
630 } else {
631 $xml->addCall( 'jetpack.subscribeToSite', $email, $post_id, serialize( $extra_data ) ); //phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.serialize_serialize
632 }
633 }
634
635 if ( $async ) {
636 return;
637 }
638
639 // Call.
640 $xml->query();
641
642 if ( $xml->isError() ) {
643 return $xml->get_jetpack_error();
644 }
645
646 $responses = $xml->getResponse();
647
648 $r = array();
649 foreach ( (array) $responses as $response ) {
650 if ( isset( $response['faultCode'] ) || isset( $response['faultString'] ) ) {
651 $r[] = $xml->get_jetpack_error( $response['faultCode'], $response['faultString'] );
652 continue;
653 }
654
655 if ( ! is_array( $response[0] ) || empty( $response[0]['status'] ) ) {
656 $r[] = new WP_Error( 'unknown' );
657 continue;
658 }
659
660 switch ( $response[0]['status'] ) {
661 case 'error':
662 $r[] = new WP_Error( 'not_subscribed' );
663 continue 2;
664 case 'disabled':
665 $r[] = new WP_Error( 'disabled' );
666 continue 2;
667 case 'active':
668 $r[] = new WP_Error( 'active' );
669 continue 2;
670 case 'confirming':
671 $r[] = true;
672 continue 2;
673 case 'pending':
674 $r[] = new WP_Error( 'pending' );
675 continue 2;
676 default:
677 $r[] = new WP_Error( 'unknown_status', (string) $response[0]['status'] );
678 continue 2;
679 }
680 }
681
682 return $r;
683 }
684
685 /**
686 * Jetpack_Subscriptions::widget_submit()
687 *
688 * When a user submits their email via the blog subscription widget, check the details and call the subsribe() method.
689 */
690 public function widget_submit() {
691 // Check the nonce.
692 if ( is_user_logged_in() ) {
693 check_admin_referer( 'blogsub_subscribe_' . get_current_blog_id() );
694 }
695
696 if ( empty( $_REQUEST['email'] ) || ! is_string( $_REQUEST['email'] ) ) {
697 return false;
698 }
699
700 $redirect_fragment = false;
701 if ( isset( $_REQUEST['redirect_fragment'] ) ) {
702 $redirect_fragment = preg_replace( '/[^a-z0-9_-]/i', '', $_REQUEST['redirect_fragment'] );
703 }
704 if ( ! $redirect_fragment || ! is_string( $redirect_fragment ) ) {
705 $redirect_fragment = 'subscribe-blog';
706 }
707
708 $subscribe = self::subscribe(
709 $_REQUEST['email'],
710 0,
711 false,
712 array(
713 'source' => 'widget',
714 'widget-in-use' => is_active_widget( false, false, 'blog_subscription', true ) ? 'yes' : 'no',
715 'comment_status' => '',
716 'server_data' => jetpack_subscriptions_cherry_pick_server_data(),
717 )
718 );
719
720 if ( is_wp_error( $subscribe ) ) {
721 $error = $subscribe->get_error_code();
722 } else {
723 $error = false;
724 foreach ( $subscribe as $response ) {
725 if ( is_wp_error( $response ) ) {
726 $error = $response->get_error_code();
727 break;
728 }
729 }
730 }
731
732 switch ( $error ) {
733 case false:
734 $result = 'success';
735 break;
736 case 'invalid_email':
737 $result = $error;
738 break;
739 case 'blocked_email':
740 $result = 'opted_out';
741 break;
742 case 'active':
743 $result = 'already';
744 break;
745 case 'flooded_email':
746 $result = 'many_pending_subs';
747 break;
748 case 'pending':
749 $result = 'pending';
750 break;
751 default:
752 $result = 'error';
753 break;
754 }
755
756 $redirect = add_query_arg( 'subscribe', $result );
757
758 /**
759 * Fires on each subscription form submission.
760 *
761 * @module subscriptions
762 *
763 * @since 3.7.0
764 *
765 * @param string $result Result of form submission: success, invalid_email, already, error.
766 */
767 do_action( 'jetpack_subscriptions_form_submission', $result );
768
769 wp_safe_redirect( "$redirect#$redirect_fragment" );
770 exit;
771 }
772
773 /**
774 * Jetpack_Subscriptions::comment_subscribe_init()
775 *
776 * Set up and add the comment subscription checkbox to the comment form.
777 *
778 * @param string $submit_button HTML markup for the submit field.
779 */
780 public function comment_subscribe_init( $submit_button ) {
781 global $post;
782
783 $comments_checked = '';
784 $blog_checked = '';
785
786 // Check for a comment / blog submission and set a cookie to retain the setting and check the boxes.
787 if ( isset( $_COOKIE[ 'jetpack_comments_subscribe_' . self::$hash . '_' . $post->ID ] ) ) {
788 $comments_checked = ' checked="checked"';
789 }
790
791 if ( isset( $_COOKIE[ 'jetpack_blog_subscribe_' . self::$hash ] ) ) {
792 $blog_checked = ' checked="checked"';
793 }
794
795 // Some themes call this function, don't show the checkbox again.
796 remove_action( 'comment_form', 'subscription_comment_form' );
797
798 // Check if Mark Jaquith's Subscribe to Comments plugin is active - if so, suppress Jetpack checkbox.
799
800 $str = '';
801
802 if ( false === has_filter( 'comment_form', 'show_subscription_checkbox' ) && 1 === (int) get_option( 'stc_enabled', 1 ) && empty( $post->post_password ) && 'post' === get_post_type() ) {
803 // Subscribe to comments checkbox.
804 $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 . ' /> ';
805 $comment_sub_text = __( 'Notify me of follow-up comments by email.', 'jetpack' );
806 $str .= '<label class="subscribe-label" id="subscribe-label" for="subscribe_comments">' . esc_html(
807 /**
808 * Filter the Subscribe to comments text appearing below the comment form.
809 *
810 * @module subscriptions
811 *
812 * @since 3.4.0
813 *
814 * @param string $comment_sub_text Subscribe to comments text.
815 */
816 apply_filters( 'jetpack_subscribe_comment_label', $comment_sub_text )
817 ) . '</label>';
818 $str .= '</p>';
819 }
820
821 if ( 1 === (int) get_option( 'stb_enabled', 1 ) ) {
822 // Subscribe to blog checkbox.
823 $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 . ' /> ';
824 $blog_sub_text = __( 'Notify me of new posts by email.', 'jetpack' );
825 $str .= '<label class="subscribe-label" id="subscribe-blog-label" for="subscribe_blog">' . esc_html(
826 /**
827 * Filter the Subscribe to blog text appearing below the comment form.
828 *
829 * @module subscriptions
830 *
831 * @since 3.4.0
832 *
833 * @param string $comment_sub_text Subscribe to blog text.
834 */
835 apply_filters( 'jetpack_subscribe_blog_label', $blog_sub_text )
836 ) . '</label>';
837 $str .= '</p>';
838 }
839
840 /**
841 * Filter the output of the subscription options appearing below the comment form.
842 *
843 * @module subscriptions
844 *
845 * @since 1.2.0
846 *
847 * @param string $str Comment Subscription form HTML output.
848 */
849 $str = apply_filters( 'jetpack_comment_subscription_form', $str );
850
851 return $str . $submit_button;
852 }
853
854 /**
855 * Jetpack_Subscriptions::comment_subscribe_init()
856 *
857 * When a user checks the comment subscribe box and submits a comment, subscribe them to the comment thread.
858 *
859 * @param int|string $comment_id Comment thread being subscribed to.
860 * @param string $approved Comment status.
861 */
862 public function comment_subscribe_submit( $comment_id, $approved ) {
863 if ( 'spam' === $approved ) {
864 return;
865 }
866
867 $comment = get_comment( $comment_id );
868 if ( ! $comment ) {
869 return;
870 }
871
872 // Set cookies for this post/comment.
873 $this->set_cookies( isset( $_REQUEST['subscribe_comments'] ), $comment->comment_post_ID, isset( $_REQUEST['subscribe_blog'] ) ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended
874
875 if ( ! isset( $_REQUEST['subscribe_comments'] ) && ! isset( $_REQUEST['subscribe_blog'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
876 return;
877 }
878
879 $post_ids = array();
880
881 if ( isset( $_REQUEST['subscribe_comments'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
882 $post_ids[] = $comment->comment_post_ID;
883 }
884
885 if ( isset( $_REQUEST['subscribe_blog'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
886 $post_ids[] = 0;
887 }
888
889 $result = self::subscribe(
890 $comment->comment_author_email,
891 $post_ids,
892 true,
893 array(
894 'source' => 'comment-form',
895 'widget-in-use' => is_active_widget( false, false, 'blog_subscription', true ) ? 'yes' : 'no',
896 'comment_status' => $approved,
897 'server_data' => jetpack_subscriptions_cherry_pick_server_data(),
898 )
899 );
900
901 /**
902 * Fires on each comment subscription form submission.
903 *
904 * @module subscriptions
905 *
906 * @since 5.5.0
907 *
908 * @param NULL|WP_Error $result Result of form submission: NULL on success, WP_Error otherwise.
909 * @param array $post_ids An array of post IDs that the user subscribed to, 0 means blog subscription.
910 */
911 do_action( 'jetpack_subscriptions_comment_form_submission', $result, $post_ids );
912 }
913
914 /**
915 * Jetpack_Subscriptions::set_cookies()
916 *
917 * Set a cookie to save state on the comment and post subscription checkboxes.
918 *
919 * @param bool $subscribe_to_post Whether the user chose to subscribe to subsequent comments on this post.
920 * @param int $post_id If $subscribe_to_post is true, the post ID they've subscribed to.
921 * @param bool $subscribe_to_blog Whether the user chose to subscribe to all new posts on the blog.
922 */
923 public function set_cookies( $subscribe_to_post = false, $post_id = null, $subscribe_to_blog = false ) {
924 $post_id = (int) $post_id;
925
926 /** This filter is already documented in core/wp-includes/comment-functions.php */
927 $cookie_lifetime = apply_filters( 'comment_cookie_lifetime', 30000000 );
928
929 /**
930 * Filter the Jetpack Comment cookie path.
931 *
932 * @module subscriptions
933 *
934 * @since 2.5.0
935 *
936 * @param string COOKIEPATH Cookie path.
937 */
938 $cookie_path = apply_filters( 'jetpack_comment_cookie_path', COOKIEPATH );
939
940 /**
941 * Filter the Jetpack Comment cookie domain.
942 *
943 * @module subscriptions
944 *
945 * @since 2.5.0
946 *
947 * @param string COOKIE_DOMAIN Cookie domain.
948 */
949 $cookie_domain = apply_filters( 'jetpack_comment_cookie_domain', COOKIE_DOMAIN );
950
951 if ( $subscribe_to_post && $post_id >= 0 ) {
952 setcookie( 'jetpack_comments_subscribe_' . self::$hash . '_' . $post_id, 1, time() + $cookie_lifetime, $cookie_path, $cookie_domain );
953 } else {
954 setcookie( 'jetpack_comments_subscribe_' . self::$hash . '_' . $post_id, '', time() - 3600, $cookie_path, $cookie_domain );
955 }
956
957 if ( $subscribe_to_blog ) {
958 setcookie( 'jetpack_blog_subscribe_' . self::$hash, 1, time() + $cookie_lifetime, $cookie_path, $cookie_domain );
959 } else {
960 setcookie( 'jetpack_blog_subscribe_' . self::$hash, '', time() - 3600, $cookie_path, $cookie_domain );
961 }
962 }
963
964 /**
965 * Set the social_notifications_subscribe option to `off` when the Subscriptions module is activated in the first time.
966 *
967 * @since 8.1
968 *
969 * @return void
970 */
971 public function set_social_notifications_subscribe() {
972 if ( false === get_option( 'social_notifications_subscribe' ) ) {
973 add_option( 'social_notifications_subscribe', 'off' );
974 }
975 }
976
977 }
978
979 Jetpack_Subscriptions::init();
980
981 require __DIR__ . '/subscriptions/views.php';
982