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

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

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