Completed
Push — add/site-importer-ui ( 829ce4...ff4189 )
by
unknown
07:07
created

subscriptions.php ➔ jetpack_do_subscription_form()   A

Complexity

Conditions 4
Paths 4

Size

Total Lines 19

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 4
nc 4
nop 1
dl 0
loc 19
rs 9.6333
c 0
b 0
f 0
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: 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
/**
29
 * Cherry picks keys from `$_SERVER` array.
30
 *
31
 * @since 6.0.0
32
 *
33
 * @return array An array of server data.
34
 */
35
function jetpack_subscriptions_cherry_pick_server_data() {
36
	$data = array();
37
38
	foreach ( $_SERVER as $key => $value ) {
39
		if ( ! is_string( $value ) || 0 === strpos( $key, 'HTTP_COOKIE' ) ) {
40
			continue;
41
		}
42
43
		if ( 0 === strpos( $key, 'HTTP_' ) || in_array( $key, array( 'REMOTE_ADDR', 'REQUEST_URI', 'DOCUMENT_URI' ), true ) ) {
44
			$data[ $key ] = $value;
45
		}
46
	}
47
48
	return $data;
49
}
50
51
class Jetpack_Subscriptions {
52
	public $jetpack = false;
53
54
	public static $hash;
55
56
	/**
57
	 * Singleton
58
	 * @static
59
	 */
60
	static function init() {
61
		static $instance = false;
62
63
		if ( !$instance ) {
64
			$instance = new Jetpack_Subscriptions;
65
		}
66
67
		return $instance;
68
	}
69
70
	function __construct() {
71
		$this->jetpack = Jetpack::init();
0 ignored issues
show
Documentation Bug introduced by
It seems like \Jetpack::init() of type object<Jetpack> is incompatible with the declared type boolean of property $jetpack.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
72
73
		// Don't use COOKIEHASH as it could be shared across installs && is non-unique in multisite.
74
		// @see: https://twitter.com/nacin/status/378246957451333632
75
		self::$hash = md5( get_option( 'siteurl' ) );
76
77
		add_filter( 'jetpack_xmlrpc_methods', array( $this, 'xmlrpc_methods' ) );
78
79
		// @todo remove sync from subscriptions and move elsewhere...
80
81
		// Add Configuration Page
82
		add_action( 'admin_init', array( $this, 'configure' ) );
83
84
		// Catch subscription widget submits
85
		if ( isset( $_REQUEST['jetpack_subscriptions_widget'] ) )
86
			add_action( 'template_redirect', array( $this, 'widget_submit' ) );
87
88
		// Set up the comment subscription checkboxes
89
		add_action( 'comment_form_after_fields', array( $this, 'comment_subscribe_init' ) );
90
91
		// Catch comment posts and check for subscriptions.
92
		add_action( 'comment_post', array( $this, 'comment_subscribe_submit' ), 50, 2 );
93
94
		// Adds post meta checkbox in the post submit metabox
95
		add_action( 'post_submitbox_misc_actions', array( $this, 'subscription_post_page_metabox' ) );
96
97
		add_action( 'transition_post_status', array( $this, 'maybe_send_subscription_email' ), 10, 3 );
98
99
		add_filter( 'jetpack_published_post_flags', array( $this, 'set_post_flags' ), 10, 2 );
100
101
		add_filter( 'post_updated_messages', array( $this, 'update_published_message' ), 18, 1 );
102
	}
103
104
	/**
105
	 * Jetpack_Subscriptions::xmlrpc_methods()
106
	 *
107
	 * Register subscriptions methods with the Jetpack XML-RPC server.
108
	 * @param array $methods
109
	 */
110
	function xmlrpc_methods( $methods ) {
111
		return array_merge(
112
			$methods,
113
			array(
114
				'jetpack.subscriptions.subscribe' => array( $this, 'subscribe' ),
115
			)
116
		);
117
	}
118
119
	/*
120
	 * Disable Subscribe on Single Post
121
	 * Register post meta
122
	 */
123
	function subscription_post_page_metabox() {
124
		if (
125
			/**
126
			 * Filter whether or not to show the per-post subscription option.
127
			 *
128
			 * @module subscriptions
129
			 *
130
			 * @since 3.7.0
131
			 *
132
			 * @param bool true = show checkbox option on all new posts | false = hide the option.
133
			 */
134
			 ! apply_filters( 'jetpack_allow_per_post_subscriptions', false ) )
135
		{
136
			return;
137
		}
138
139
		if ( has_filter( 'jetpack_subscriptions_exclude_these_categories' ) || has_filter( 'jetpack_subscriptions_include_only_these_categories' ) ) {
140
			return;
141
		}
142
143
		global $post;
144
		$disable_subscribe_value = get_post_meta( $post->ID, '_jetpack_dont_email_post_to_subs', true );
145
		// only show checkbox if post hasn't been published and is a 'post' post type.
146
		if ( get_post_status( $post->ID ) !== 'publish' && get_post_type( $post->ID ) == 'post' ) :
147
			// Nonce it
148
			wp_nonce_field( 'disable_subscribe', 'disable_subscribe_nonce' );
149
			?>
150
			<div class="misc-pub-section">
151
				<label for="_jetpack_dont_email_post_to_subs"><?php _e( 'Jetpack Subscriptions:', 'jetpack' ); ?></label><br>
152
				<input type="checkbox" name="_jetpack_dont_email_post_to_subs" id="jetpack-per-post-subscribe" value="1" <?php checked( $disable_subscribe_value, 1, true ); ?> />
153
				<?php _e( 'Don&#8217;t send this to subscribers', 'jetpack' ); ?>
154
			</div>
155
		<?php endif;
156
	}
157
158
	/**
159
	 * Checks whether or not the post should be emailed to subscribers
160
	 *
161
	 * It checks for the following things in order:
162
	 * - Usage of filter jetpack_subscriptions_exclude_these_categories
163
	 * - Usage of filter jetpack_subscriptions_include_only_these_categories
164
	 * - Existence of the per-post checkbox option
165
	 *
166
	 * Only one of these can be used at any given time.
167
	 *
168
	 * @param $new_status string - the "new" post status of the transition when saved
169
	 * @param $old_status string - the "old" post status of the transition when saved
170
	 * @param $post obj - The post object
171
	 */
172
	function maybe_send_subscription_email( $new_status, $old_status, $post ) {
173
174
		if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) {
175
			return;
176
		}
177
178
		// Make sure that the checkbox is preseved
179
		if ( ! empty( $_POST['disable_subscribe_nonce'] ) && wp_verify_nonce( $_POST['disable_subscribe_nonce'], 'disable_subscribe' ) ) {
180
			$set_checkbox = isset( $_POST['_jetpack_dont_email_post_to_subs'] ) ? 1 : 0;
181
			update_post_meta( $post->ID, '_jetpack_dont_email_post_to_subs', $set_checkbox );
182
		}
183
	}
184
185
	function update_published_message( $messages ) {
186
		global $post;
187
		if ( ! $this->should_email_post_to_subscribers( $post ) ) {
188
			return $messages;
189
		}
190
191
		$view_post_link_html = sprintf( ' <a href="%1$s">%2$s</a>',
192
			esc_url( get_permalink( $post ) ),
193
			__( 'View post', 'jetpack' )
194
		);
195
196
		$messages['post'][6] = sprintf(
197
			/* translators: Message shown after a post is published */
198
			esc_html__( 'Post published and sending emails to subscribers.', 'jetpack' )
199
			) . $view_post_link_html;
200
		return $messages;
201
	}
202
203
	public function should_email_post_to_subscribers( $post ) {
204
		$should_email = true;
205
		if ( get_post_meta( $post->ID, '_jetpack_dont_email_post_to_subs', true ) ) {
206
			return false;
207
		}
208
209
		// Only posts are currently supported
210
		if ( $post->post_type !== 'post' ) {
211
			return false;
212
		}
213
214
		/**
215
		 * Array of categories that will never trigger subscription emails.
216
		 *
217
		 * Will not send subscription emails from any post from within these categories.
218
		 *
219
		 * @module subscriptions
220
		 *
221
		 * @since 3.7.0
222
		 *
223
		 * @param array $args Array of category slugs or ID's.
224
		 */
225
		$excluded_categories = apply_filters( 'jetpack_subscriptions_exclude_these_categories', array() );
226
227
		// Never email posts from these categories
228
		if ( ! empty( $excluded_categories ) && in_category( $excluded_categories, $post->ID ) ) {
229
			$should_email = false;
230
		}
231
232
		/**
233
		 * ONLY send subscription emails for these categories
234
		 *
235
		 * Will ONLY send subscription emails to these categories.
236
		 *
237
		 * @module subscriptions
238
		 *
239
		 * @since 3.7.0
240
		 *
241
		 * @param array $args Array of category slugs or ID's.
242
		 */
243
		$only_these_categories = apply_filters( 'jetpack_subscriptions_exclude_all_categories_except', array() );
244
245
		// Only emails posts from these categories
246
		if ( ! empty( $only_these_categories ) && ! in_category( $only_these_categories, $post->ID ) ) {
247
			$should_email = false;
248
		}
249
250
		return $should_email;
251
	}
252
253
	function set_post_flags( $flags, $post ) {
254
		$flags['send_subscription'] = $this->should_email_post_to_subscribers( $post );
255
		return $flags;
256
	}
257
258
	/**
259
	 * Jetpack_Subscriptions::configure()
260
	 *
261
	 * Jetpack Subscriptions configuration screen.
262
	 */
263
	function configure() {
264
		// Create the section
265
		add_settings_section(
266
			'jetpack_subscriptions',
267
			__( 'Jetpack Subscriptions Settings', 'jetpack' ),
268
			array( $this, 'subscriptions_settings_section' ),
269
			'discussion'
270
		);
271
272
		/** Subscribe to Posts ***************************************************/
273
274
		add_settings_field(
275
			'jetpack_subscriptions_post_subscribe',
276
			__( 'Follow Blog', 'jetpack' ),
277
			array( $this, 'subscription_post_subscribe_setting' ),
278
			'discussion',
279
			'jetpack_subscriptions'
280
		);
281
282
		register_setting(
283
			'discussion',
284
			'stb_enabled'
285
		);
286
287
		/** Subscribe to Comments ******************************************************/
288
289
		add_settings_field(
290
			'jetpack_subscriptions_comment_subscribe',
291
			__( 'Follow Comments', 'jetpack' ),
292
			array( $this, 'subscription_comment_subscribe_setting' ),
293
			'discussion',
294
			'jetpack_subscriptions'
295
		);
296
297
		register_setting(
298
			'discussion',
299
			'stc_enabled'
300
		);
301
302
		/** Subscription Messaging Options ******************************************************/
303
304
		register_setting(
305
			'reading',
306
			'subscription_options',
307
			array( $this, 'validate_settings' )
308
		);
309
310
		add_settings_section(
311
			'email_settings',
312
			__( 'Follower Settings', 'jetpack' ),
313
			array( $this, 'reading_section' ),
314
			'reading'
315
		);
316
317
		add_settings_field(
318
			'invitation',
319
			__( 'Blog follow email text', 'jetpack' ),
320
			array( $this, 'setting_invitation' ),
321
			'reading',
322
			'email_settings'
323
		);
324
325
		add_settings_field(
326
			'comment-follow',
327
			__( 'Comment follow email text', 'jetpack' ),
328
			array( $this, 'setting_comment_follow' ),
329
			'reading',
330
			'email_settings'
331
		);
332
	}
333
334
	/**
335
	 * Discussions setting section blurb
336
	 *
337
	 */
338
	function subscriptions_settings_section() {
339
	?>
340
		<p id="jetpack-subscriptions-settings"><?php _e( 'Change whether your visitors can subscribe to your posts or comments or both.', 'jetpack' ); ?></p>
341
342
	<?php
343
	}
344
345
	/**
346
	 * Post Subscriptions Toggle
347
	 *
348
	 */
349 View Code Duplication
	function subscription_post_subscribe_setting() {
350
351
		$stb_enabled = get_option( 'stb_enabled', 1 ); ?>
352
353
		<p class="description">
354
			<input type="checkbox" name="stb_enabled" id="jetpack-post-subscribe" value="1" <?php checked( $stb_enabled, 1 ); ?> />
355
			<?php _e( "Show a <em>'follow blog'</em> option in the comment form", 'jetpack' ); ?>
356
		</p>
357
	<?php
358
	}
359
360
	/**
361
	 * Comments Subscriptions Toggle
362
	 *
363
	 */
364 View Code Duplication
	function subscription_comment_subscribe_setting() {
365
366
		$stc_enabled = get_option( 'stc_enabled', 1 ); ?>
367
368
		<p class="description">
369
			<input type="checkbox" name="stc_enabled" id="jetpack-comment-subscribe" value="1" <?php checked( $stc_enabled, 1 ); ?> />
370
			<?php _e( "Show a <em>'follow comments'</em> option in the comment form", 'jetpack' ); ?>
371
		</p>
372
373
	<?php
374
	}
375
376
	function validate_settings( $settings ) {
377
		global $allowedposttags;
378
379
		$default = $this->get_default_settings();
380
381
		// Blog Follow
382
		$settings['invitation'] = trim( wp_kses( $settings['invitation'], $allowedposttags ) );
383
		if ( empty( $settings['invitation'] ) )
384
			$settings['invitation'] = $default['invitation'];
385
386
		// Comments Follow (single post)
387
		$settings['comment_follow'] = trim( wp_kses( $settings['comment_follow'], $allowedposttags ) );
388
		if ( empty( $settings['comment_follow'] ) )
389
			$settings['comment_follow'] = $default['comment_follow'];
390
391
		return $settings;
392
	}
393
394
	public function reading_section() {
395
		echo '<p id="follower-settings">';
396
		_e( 'These settings change emails sent from your blog to followers.', 'jetpack' );
397
		echo '</p>';
398
	}
399
400
	public function setting_invitation() {
401
		$settings = $this->get_settings();
402
		echo '<textarea name="subscription_options[invitation]" class="large-text" cols="50" rows="5">' . esc_textarea( $settings['invitation'] ) . '</textarea>';
403
		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>';
404
	}
405
406
	public function setting_comment_follow() {
407
		$settings = $this->get_settings();
408
		echo '<textarea name="subscription_options[comment_follow]" class="large-text" cols="50" rows="5">' . esc_textarea( $settings['comment_follow'] ) . '</textarea>';
409
		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>';
410
	}
411
412
	function get_default_settings() {
413
		return array(
414
			'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' ),
415
			'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' )
416
		);
417
	}
418
419
	function get_settings() {
420
		return wp_parse_args( (array) get_option( 'subscription_options', array() ), $this->get_default_settings() );
421
	}
422
423
	/**
424
	 * Jetpack_Subscriptions::subscribe()
425
	 *
426
	 * Send a synchronous XML-RPC subscribe to blog posts or subscribe to post comments request.
427
	 *
428
	 * @param string $email
429
	 * @param array  $post_ids (optional) defaults to 0 for blog posts only: array of post IDs to subscribe to blog's posts
0 ignored issues
show
Documentation introduced by
Should the type for parameter $post_ids not be integer?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
430
	 * @param bool   $async    (optional) Should the subscription be performed asynchronously?  Defaults to true.
431
	 *
432
	 * @return true|Jetpack_Error true on success
433
	 *	invalid_email   : not a valid email address
434
	 *	invalid_post_id : not a valid post ID
435
	 *	unknown_post_id : unknown post
436
	 *	not_subscribed  : strange error.  Jetpack servers at WordPress.com could subscribe the email.
437
	 *	disabled        : Site owner has disabled subscriptions.
438
	 *	active          : Already subscribed.
439
	 *	unknown         : strange error.  Jetpack servers at WordPress.com returned something malformed.
440
	 *	unknown_status  : strange error.  Jetpack servers at WordPress.com returned something I didn't understand.
441
	 */
442
	function subscribe( $email, $post_ids = 0, $async = true, $extra_data = array() ) {
443
		if ( !is_email( $email ) ) {
444
			return new Jetpack_Error( 'invalid_email' );
445
		}
446
447
		if ( !$async ) {
448
			Jetpack::load_xml_rpc_client();
449
			$xml = new Jetpack_IXR_ClientMulticall();
450
		}
451
452
		foreach ( (array) $post_ids as $post_id ) {
453
			$post_id = (int) $post_id;
454
			if ( $post_id < 0 ) {
455
				return new Jetpack_Error( 'invalid_post_id' );
456
			} else if ( $post_id && !$post = get_post( $post_id ) ) {
457
				return new Jetpack_Error( 'unknown_post_id' );
458
			}
459
460
			if ( $async ) {
461
				Jetpack::xmlrpc_async_call( 'jetpack.subscribeToSite', $email, $post_id, serialize( $extra_data ) );
462
			} else {
463
				$xml->addCall( 'jetpack.subscribeToSite', $email, $post_id, serialize( $extra_data ) );
0 ignored issues
show
Bug introduced by
The variable $xml does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
464
			}
465
		}
466
467
		if ( $async ) {
468
			return;
469
		}
470
471
		// Call
472
		$xml->query();
473
474
		if ( $xml->isError() ) {
475
			return $xml->get_jetpack_error();
476
		}
477
478
		$responses = $xml->getResponse();
479
480
		$r = array();
481
		foreach ( (array) $responses as $response ) {
482
			if ( isset( $response['faultCode'] ) || isset( $response['faultString'] ) ) {
483
				$r[] = $xml->get_jetpack_error( $response['faultCode'], $response['faultString'] );
484
				continue;
485
			}
486
487
			if ( !is_array( $response[0] ) || empty( $response[0]['status'] ) ) {
488
				$r[] = new Jetpack_Error( 'unknown' );
489
				continue;
490
			}
491
492
			switch ( $response[0]['status'] ) {
493
			case 'error' :
494
				$r[] = new Jetpack_Error( 'not_subscribed' );
495
				continue 2;
496
			case 'disabled' :
497
				$r[] = new Jetpack_Error( 'disabled' );
498
				continue 2;
499
			case 'active' :
500
				$r[] = new Jetpack_Error( 'active' );
501
				continue 2;
502
			case 'pending' :
503
				$r[] = true;
504
				continue 2;
505
			default :
506
				$r[] = new Jetpack_Error( 'unknown_status', (string) $response[0]['status'] );
507
				continue 2;
508
			}
509
		}
510
511
		return $r;
512
	}
513
514
	/**
515
	 * Jetpack_Subscriptions::widget_submit()
516
	 *
517
	 * When a user submits their email via the blog subscription widget, check the details and call the subsribe() method.
518
	 */
519
	function widget_submit() {
520
		// Check the nonce.
521
		if ( is_user_logged_in() ) {
522
			check_admin_referer( 'blogsub_subscribe_' . get_current_blog_id() );
523
		}
524
525
		if ( empty( $_REQUEST['email'] ) )
526
			return false;
527
528
		$redirect_fragment = false;
529
		if ( isset( $_REQUEST['redirect_fragment'] ) ) {
530
			$redirect_fragment = preg_replace( '/[^a-z0-9_-]/i', '', $_REQUEST['redirect_fragment'] );
531
		}
532
		if ( !$redirect_fragment ) {
533
			$redirect_fragment = 'subscribe-blog';
534
		}
535
536
		$subscribe = Jetpack_Subscriptions::subscribe(
537
												$_REQUEST['email'],
538
												0,
539
												false,
540
												array(
541
													'source'         => 'widget',
542
													'widget-in-use'  => is_active_widget( false, false, 'blog_subscription', true ) ? 'yes' : 'no',
543
													'comment_status' => '',
544
													'server_data'    => jetpack_subscriptions_cherry_pick_server_data(),
545
												)
546
		);
547
548
		if ( is_wp_error( $subscribe ) ) {
549
			$error = $subscribe->get_error_code();
550
		} else {
551
			$error = false;
552
			foreach ( $subscribe as $response ) {
0 ignored issues
show
Bug introduced by
The expression $subscribe of type object<Jetpack_Error>|null|array is not guaranteed to be traversable. How about adding an additional type check?

There are different options of fixing this problem.

  1. If you want to be on the safe side, you can add an additional type-check:

    $collection = json_decode($data, true);
    if ( ! is_array($collection)) {
        throw new \RuntimeException('$collection must be an array.');
    }
    
    foreach ($collection as $item) { /** ... */ }
    
  2. If you are sure that the expression is traversable, you might want to add a doc comment cast to improve IDE auto-completion and static analysis:

    /** @var array $collection */
    $collection = json_decode($data, true);
    
    foreach ($collection as $item) { /** .. */ }
    
  3. Mark the issue as a false-positive: Just hover the remove button, in the top-right corner of this issue for more options.

Loading history...
553
				if ( is_wp_error( $response ) ) {
554
					$error = $response->get_error_code();
555
					break;
556
				}
557
			}
558
		}
559
560
		switch ( $error ) {
561
			case false:
562
				$result = 'success';
563
				break;
564
			case 'invalid_email':
565
				$result = $error;
566
				break;
567
			case 'blocked_email':
568
				$result = 'opted_out';
569
				break;
570
			case 'active':
571
			case 'pending':
572
				$result = 'already';
573
				break;
574
			default:
575
				$result = 'error';
576
				break;
577
		}
578
579
		$redirect = add_query_arg( 'subscribe', $result );
580
581
		/**
582
		 * Fires on each subscription form submission.
583
		 *
584
		 * @module subscriptions
585
		 *
586
		 * @since 3.7.0
587
		 *
588
		 * @param string $result Result of form submission: success, invalid_email, already, error.
589
		 */
590
		do_action( 'jetpack_subscriptions_form_submission', $result );
591
592
		wp_safe_redirect( "$redirect#$redirect_fragment" );
593
		exit;
594
	}
595
596
	/**
597
	 * Jetpack_Subscriptions::comment_subscribe_init()
598
	 *
599
	 * Set up and add the comment subscription checkbox to the comment form.
600
	 */
601
	function comment_subscribe_init() {
602
		global $post;
603
604
		$comments_checked = '';
605
		$blog_checked     = '';
606
607
		// Check for a comment / blog submission and set a cookie to retain the setting and check the boxes.
608
		if ( isset( $_COOKIE[ 'jetpack_comments_subscribe_' . self::$hash . '_' . $post->ID ] ) ) {
609
			$comments_checked = ' checked="checked"';
610
		}
611
612
		if ( isset( $_COOKIE[ 'jetpack_blog_subscribe_' . self::$hash ] ) ) {
613
			$blog_checked = ' checked="checked"';
614
		}
615
616
		// Some themes call this function, don't show the checkbox again
617
		remove_action( 'comment_form', 'subscription_comment_form' );
618
619
		// Check if Mark Jaquith's Subscribe to Comments plugin is active - if so, suppress Jetpack checkbox
620
621
		$str = '';
622
623
		if ( FALSE === has_filter( 'comment_form', 'show_subscription_checkbox' ) && 1 == get_option( 'stc_enabled', 1 ) && empty( $post->post_password ) && 'post' == get_post_type() ) {
624
			// Subscribe to comments checkbox
625
			$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 . ' /> ';
626
			$comment_sub_text = __( 'Notify me of follow-up comments by email.', 'jetpack' );
627
			$str .=	'<label class="subscribe-label" id="subscribe-label" for="subscribe_comments">' . esc_html(
628
				/**
629
				 * Filter the Subscribe to comments text appearing below the comment form.
630
				 *
631
				 * @module subscriptions
632
				 *
633
				 * @since 3.4.0
634
				 *
635
				 * @param string $comment_sub_text Subscribe to comments text.
636
				 */
637
				apply_filters( 'jetpack_subscribe_comment_label', $comment_sub_text )
638
			) . '</label>';
639
			$str .= '</p>';
640
		}
641
642
		if ( 1 == get_option( 'stb_enabled', 1 ) ) {
643
			// Subscribe to blog checkbox
644
			$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 . ' /> ';
645
			$blog_sub_text = __( 'Notify me of new posts by email.', 'jetpack' );
646
			$str .=	'<label class="subscribe-label" id="subscribe-blog-label" for="subscribe_blog">' . esc_html(
647
				/**
648
				 * Filter the Subscribe to blog text appearing below the comment form.
649
				 *
650
				 * @module subscriptions
651
				 *
652
				 * @since 3.4.0
653
				 *
654
				 * @param string $comment_sub_text Subscribe to blog text.
655
				 */
656
				apply_filters( 'jetpack_subscribe_blog_label', $blog_sub_text )
657
			) . '</label>';
658
			$str .= '</p>';
659
		}
660
661
		/**
662
		 * Filter the output of the subscription options appearing below the comment form.
663
		 *
664
		 * @module subscriptions
665
		 *
666
		 * @since 1.2.0
667
		 *
668
		 * @param string $str Comment Subscription form HTML output.
669
		 */
670
		echo apply_filters( 'jetpack_comment_subscription_form', $str );
671
	}
672
673
	/**
674
	 * Jetpack_Subscriptions::comment_subscribe_init()
675
	 *
676
	 * When a user checks the comment subscribe box and submits a comment, subscribe them to the comment thread.
677
	 */
678
	function comment_subscribe_submit( $comment_id, $approved ) {
679
		if ( 'spam' === $approved ) {
680
			return;
681
		}
682
683
		$comment = get_comment( $comment_id );
684
685
		// Set cookies for this post/comment
686
		$this->set_cookies( isset( $_REQUEST['subscribe_comments'] ), $comment->comment_post_ID, isset( $_REQUEST['subscribe_blog'] ) );
687
688
		if ( !isset( $_REQUEST['subscribe_comments'] ) && !isset( $_REQUEST['subscribe_blog'] ) )
689
			return;
690
691
		$post_ids = array();
692
693
		if ( isset( $_REQUEST['subscribe_comments'] ) )
694
			$post_ids[] = $comment->comment_post_ID;
695
696
		if ( isset( $_REQUEST['subscribe_blog'] ) )
697
			$post_ids[] = 0;
698
699
		$result = Jetpack_Subscriptions::subscribe(
700
									$comment->comment_author_email,
701
									$post_ids,
0 ignored issues
show
Documentation introduced by
$post_ids is of type array, but the function expects a integer.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
702
									true,
703
									array(
704
										'source'         => 'comment-form',
705
										'widget-in-use'  => is_active_widget( false, false, 'blog_subscription', true ) ? 'yes' : 'no',
706
										'comment_status' => $approved,
707
										'server_data'    => jetpack_subscriptions_cherry_pick_server_data(),
708
									)
709
		);
710
711
		/**
712
		 * Fires on each comment subscription form submission.
713
		 *
714
		 * @module subscriptions
715
		 *
716
		 * @since 5.5.0
717
		 *
718
		 * @param NULL|WP_Error $result Result of form submission: NULL on success, WP_Error otherwise.
719
		 * @param Array $post_ids An array of post IDs that the user subscribed to, 0 means blog subscription.
720
		 */
721
		do_action( 'jetpack_subscriptions_comment_form_submission', $result, $post_ids );
722
	}
723
724
	/**
725
	 * Jetpack_Subscriptions::set_cookies()
726
	 *
727
	 * Set a cookie to save state on the comment and post subscription checkboxes.
728
	 *
729
	 * @param bool $subscribe_to_post Whether the user chose to subscribe to subsequent comments on this post.
730
	 * @param int $post_id If $subscribe_to_post is true, the post ID they've subscribed to.
0 ignored issues
show
Documentation introduced by
Should the type for parameter $post_id not be integer|null?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
731
	 * @param bool $subscribe_to_blog Whether the user chose to subscribe to all new posts on the blog.
732
	 */
733
	function set_cookies( $subscribe_to_post = false, $post_id = null, $subscribe_to_blog = false ) {
734
		$post_id = intval( $post_id );
735
736
		/** This filter is already documented in core/wp-includes/comment-functions.php */
737
		$cookie_lifetime = apply_filters( 'comment_cookie_lifetime',       30000000 );
738
739
		/**
740
		 * Filter the Jetpack Comment cookie path.
741
		 *
742
		 * @module subscriptions
743
		 *
744
		 * @since 2.5.0
745
		 *
746
		 * @param string COOKIEPATH Cookie path.
747
		 */
748
		$cookie_path     = apply_filters( 'jetpack_comment_cookie_path',   COOKIEPATH );
749
750
		/**
751
		 * Filter the Jetpack Comment cookie domain.
752
		 *
753
		 * @module subscriptions
754
		 *
755
		 * @since 2.5.0
756
		 *
757
		 * @param string COOKIE_DOMAIN Cookie domain.
758
		 */
759
		$cookie_domain   = apply_filters( 'jetpack_comment_cookie_domain', COOKIE_DOMAIN );
760
761
		if ( $subscribe_to_post && $post_id >= 0 ) {
762
			setcookie( 'jetpack_comments_subscribe_' . self::$hash . '_' . $post_id, 1, time() + $cookie_lifetime, $cookie_path, $cookie_domain );
763
		} else {
764
			setcookie( 'jetpack_comments_subscribe_' . self::$hash . '_' . $post_id, '', time() - 3600, $cookie_path, $cookie_domain );
765
		}
766
767
		if ( $subscribe_to_blog ) {
768
			setcookie( 'jetpack_blog_subscribe_' . self::$hash, 1, time() + $cookie_lifetime, $cookie_path, $cookie_domain );
769
		} else {
770
			setcookie( 'jetpack_blog_subscribe_' . self::$hash, '', time() - 3600, $cookie_path, $cookie_domain );
771
		}
772
	}
773
774
}
775
776
Jetpack_Subscriptions::init();
777
778
include dirname( __FILE__ ) . '/subscriptions/views.php';
779