PluginProbe
Jetpack – WP Security, Backup, Speed, & Growth / 4.4.5
Jetpack – WP Security, Backup, Speed, & Growth v4.4.5
16.2-beta 12.0.3 12.1.3 12.2.3 12.3.2 12.4.2 12.5.2 12.6.4 12.7.3 12.8.3 12.9.5 13.0.2 13.1.5 13.2.4 13.3.3 13.4.5 13.5.2 13.6.2 13.7.2 13.8.3 13.9.2 14.0.1 14.1.1 14.2.2 14.3.1 All 501 releases
jetpack / modules / subscriptions.php

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

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