Completed
Push — feature/videopress-uploader ( 58b703...e9e1f9 )
by
unknown
104:20 queued 95:05
created

modules/subscriptions.php (2 issues)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

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
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 View Code Duplication
		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 View Code Duplication
		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 View Code Duplication
	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 View Code Duplication
	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 View Code Duplication
		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 View Code Duplication
		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 View Code Duplication
	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 View Code Duplication
		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;
0 ignored issues
show
Terminating statement must be on a line by itself

As per the PSR-2 coding standard, the break (or other terminating) statement must be on a line of its own.

switch ($expr) {
     case "A":
         doSomething();
         break; //wrong
     case "B":
         doSomething();
         break; //right
     case "C:":
         doSomething();
         return true; //right
 }

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
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;
0 ignored issues
show
Terminating statement must be on a line by itself

As per the PSR-2 coding standard, the break (or other terminating) statement must be on a line of its own.

switch ($expr) {
     case "A":
         doSomething();
         break; //wrong
     case "B":
         doSomething();
         break; //right
     case "C:":
         doSomething();
         return true; //right
 }

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
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