Completed
Push — update/jetpack_published_post_... ( bcfb1e...bb2bd8 )
by
unknown
07:38
created

maybe_send_subscription_email()   B

Complexity

Conditions 6
Paths 4

Size

Total Lines 12
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 6
eloc 6
nc 4
nop 3
dl 0
loc 12
rs 8.8571
c 0
b 0
f 0
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;
0 ignored issues
show
Coding Style Compatibility introduced by
The function jetpack_subscriptions_configuration_load() contains an exit expression.

An exit expression should only be used in rare cases. For example, if you write a short command line script.

In most cases however, using an exit expression makes the code untestable and often causes incompatibilities with other libraries. Thus, unless you are absolutely sure it is required here, we recommend to refactor your code to avoid its usage.

Loading history...
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();
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...
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...
0 ignored issues
show
Coding Style Best Practice introduced by
Comments for TODO tasks are often forgotten in the code; it might be better to use a dedicated issue tracker.
Loading history...
57
58
		// Add Configuration Page
59
		add_action( 'admin_init', array( $this, 'configure' ) );
60
61
		// Set up the subscription widget.
62
		add_action( 'widgets_init', array( $this, 'widget_init' ) );
63
64
		// Catch subscription widget submits
65
		if ( isset( $_REQUEST['jetpack_subscriptions_widget'] ) )
66
			add_action( 'template_redirect', array( $this, 'widget_submit' ) );
67
68
		// Set up the comment subscription checkboxes
69
		add_action( 'comment_form', array( $this, 'comment_subscribe_init' ) );
70
71
		// Catch comment posts and check for subscriptions.
72
		add_action( 'comment_post', array( $this, 'comment_subscribe_submit' ), 50, 2 );
73
74
		// Adds post meta checkbox in the post submit metabox
75
		add_action( 'post_submitbox_misc_actions', array( $this, 'subscription_post_page_metabox' ) );
76
77
		add_action( 'transition_post_status', array( $this, 'maybe_send_subscription_email' ), 10, 3 );
78
79
		add_filter( 'jetpack_published_post_flags', array( $this, 'set_post_flags' ), 10, 2 );
80
	}
81
82
	/**
83
	 * Jetpack_Subscriptions::xmlrpc_methods()
84
	 *
85
	 * Register subscriptions methods with the Jetpack XML-RPC server.
86
	 * @param array $methods
87
	 */
88
	function xmlrpc_methods( $methods ) {
89
		return array_merge(
90
			$methods,
91
			array(
92
				'jetpack.subscriptions.subscribe' => array( $this, 'subscribe' ),
93
			)
94
		);
95
	}
96
97
	/*
98
	 * Disable Subscribe on Single Post
99
	 * Register post meta
100
	 */
101
	function subscription_post_page_metabox() {
102
		if (
103
			/**
104
			 * Filter whether or not to show the per-post subscription option.
105
			 *
106
			 * @module subscriptions
107
			 *
108
			 * @since 3.7.0
109
			 *
110
			 * @param bool true = show checkbox option on all new posts | false = hide the option.
111
			 */
112
			 ! apply_filters( 'jetpack_allow_per_post_subscriptions', false ) )
113
		{
114
			return;
115
		}
116
117
		if ( has_filter( 'jetpack_subscriptions_exclude_these_categories' ) || has_filter( 'jetpack_subscriptions_include_only_these_categories' ) ) {
118
			return;
119
		}
120
121
		global $post;
122
		$disable_subscribe_value = get_post_meta( $post->ID, '_jetpack_dont_email_post_to_subs', true );
123
		// Nonce it
124
		wp_nonce_field( 'disable_subscribe', 'disable_subscribe_nonce' );
125
		// only show checkbox if post hasn't been published and is a 'post' post type.
126
		if ( get_post_status( $post->ID ) !== 'publish' && get_post_type( $post->ID ) == 'post' ) : ?>
127
			<div class="misc-pub-section">
128
				<label for="_jetpack_dont_email_post_to_subs"><?php _e( 'Jetpack Subscriptions:', 'jetpack' ); ?></label><br>
129
				<input type="checkbox" name="_jetpack_dont_email_post_to_subs" id="jetpack-per-post-subscribe" value="1" <?php checked( $disable_subscribe_value, 1, true ); ?> />
130
				<?php _e( 'Don&#8217;t send this to subscribers', 'jetpack' ); ?>
131
			</div>
132
		<?php endif;
133
	}
134
135
	/**
136
	 * Checks whether or not the post should be emailed to subscribers
137
	 *
138
	 * It checks for the following things in order:
139
	 * - Usage of filter jetpack_subscriptions_exclude_these_categories
140
	 * - Usage of filter jetpack_subscriptions_include_only_these_categories
141
	 * - Existence of the per-post checkbox option
142
	 *
143
	 * Only one of these can be used at any given time.
144
	 *
145
	 * @param $new_status string - the "new" post status of the transition when saved
146
	 * @param $old_status string - the "old" post status of the transition when saved
147
	 * @param $post obj - The post object
148
	 */
149
	function maybe_send_subscription_email( $new_status, $old_status, $post ) {
150
151
		if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) {
152
			return;
153
		}
154
155
		// Make sure that the checkbox is preseved
156
		if ( ! empty( $_POST['disable_subscribe_nonce'] ) && wp_verify_nonce( $_POST['disable_subscribe_nonce'], 'disable_subscribe' ) ) {
157
			$set_checkbox = isset( $_POST['_jetpack_dont_email_post_to_subs'] ) ? 1 : 0;
158
			update_post_meta( $post->ID, '_jetpack_dont_email_post_to_subs', $set_checkbox );
159
		}
160
	}
161
162
	public function should_email_post_to_subscribers( $post ) {
163
		$should_email = true;
164
		if ( get_post_meta( $post->ID, '_jetpack_dont_email_post_to_subs', true ) ) {
165
			return false;
166
		}
167
168
		/**
169
		 * Array of categories that will never trigger subscription emails.
170
		 *
171
		 * Will not send subscription emails from any post from within these categories.
172
		 *
173
		 * @module subscriptions
174
		 *
175
		 * @since 3.7.0
176
		 *
177
		 * @param array $args Array of category slugs or ID's.
178
		 */
179
		$excluded_categories = apply_filters( 'jetpack_subscriptions_exclude_these_categories', array() );
180
181
		// Never email posts from these categories
182
		if ( ! empty( $excluded_categories ) && in_category( $excluded_categories, $post->ID ) ) {
183
			$should_email = false;
184
		}
185
186
		/**
187
		 * ONLY send subscription emails for these categories
188
		 *
189
		 * Will ONLY send subscription emails to these categories.
190
		 *
191
		 * @module subscriptions
192
		 *
193
		 * @since 3.7.0
194
		 *
195
		 * @param array $args Array of category slugs or ID's.
196
		 */
197
		$only_these_categories = apply_filters( 'jetpack_subscriptions_exclude_all_categories_except', array() );
198
199
		// Only emails posts from these categories
200
		if ( ! empty( $only_these_categories ) && ! in_category( $only_these_categories, $post->ID ) ) {
201
			$should_email = false;
202
		}
203
204
205
		return $should_email;
206
	}
207
208
	function set_post_flags( $flags, $post ) {
209
		$flags['send_subscription'] = $this->should_email_post_to_subscribers( $post );
210
		return $flags;
211
	}
212
213
	/**
214
	 * Jetpack_Subscriptions::configure()
215
	 *
216
	 * Jetpack Subscriptions configuration screen.
217
	 */
218
	function configure() {
219
		// Create the section
220
		add_settings_section(
221
			'jetpack_subscriptions',
222
			__( 'Jetpack Subscriptions Settings', 'jetpack' ),
223
			array( $this, 'subscriptions_settings_section' ),
224
			'discussion'
225
		);
226
227
		/** Subscribe to Posts ***************************************************/
228
229
		add_settings_field(
230
			'jetpack_subscriptions_post_subscribe',
231
			__( 'Follow Blog', 'jetpack' ),
232
			array( $this, 'subscription_post_subscribe_setting' ),
233
			'discussion',
234
			'jetpack_subscriptions'
235
		);
236
237
		register_setting(
238
			'discussion',
239
			'stb_enabled'
240
		);
241
242
		/** Subscribe to Comments ******************************************************/
243
244
		add_settings_field(
245
			'jetpack_subscriptions_comment_subscribe',
246
			__( 'Follow Comments', 'jetpack' ),
247
			array( $this, 'subscription_comment_subscribe_setting' ),
248
			'discussion',
249
			'jetpack_subscriptions'
250
		);
251
252
		register_setting(
253
			'discussion',
254
			'stc_enabled'
255
		);
256
257
		/** Subscription Messaging Options ******************************************************/
258
259
		register_setting(
260
			'reading',
261
			'subscription_options',
262
			array( $this, 'validate_settings' )
263
		);
264
265
		add_settings_section(
266
			'email_settings',
267
			__( 'Follower Settings', 'jetpack' ),
268
			array( $this, 'reading_section' ),
269
			'reading'
270
		);
271
272
		add_settings_field(
273
			'invitation',
274
			__( 'Blog follow email text', 'jetpack' ),
275
			array( $this, 'setting_invitation' ),
276
			'reading',
277
			'email_settings'
278
		);
279
280
		add_settings_field(
281
			'comment-follow',
282
			__( 'Comment follow email text', 'jetpack' ),
283
			array( $this, 'setting_comment_follow' ),
284
			'reading',
285
			'email_settings'
286
		);
287
	}
288
289
	/**
290
	 * Discussions setting section blurb
291
	 *
292
	 */
293
	function subscriptions_settings_section() {
294
	?>
295
296
		<p id="jetpack-subscriptions-settings"><?php _e( 'Change whether your visitors can subscribe to your posts or comments or both.', 'jetpack' ); ?></p>
297
298
	<?php
299
	}
300
301
	/**
302
	 * Post Subscriptions Toggle
303
	 *
304
	 */
305 View Code Duplication
	function subscription_post_subscribe_setting() {
306
307
		$stb_enabled = get_option( 'stb_enabled', 1 ); ?>
308
309
		<p class="description">
310
			<input type="checkbox" name="stb_enabled" id="jetpack-post-subscribe" value="1" <?php checked( $stb_enabled, 1 ); ?> />
311
			<?php _e( "Show a <em>'follow blog'</em> option in the comment form", 'jetpack' ); ?>
312
		</p>
313
	<?php
314
	}
315
316
	/**
317
	 * Comments Subscriptions Toggle
318
	 *
319
	 */
320 View Code Duplication
	function subscription_comment_subscribe_setting() {
321
322
		$stc_enabled = get_option( 'stc_enabled', 1 ); ?>
323
324
		<p class="description">
325
			<input type="checkbox" name="stc_enabled" id="jetpack-comment-subscribe" value="1" <?php checked( $stc_enabled, 1 ); ?> />
326
			<?php _e( "Show a <em>'follow comments'</em> option in the comment form", 'jetpack' ); ?>
327
		</p>
328
329
	<?php
330
	}
331
332
	function validate_settings( $settings ) {
333
		global $allowedposttags;
334
335
		$default = $this->get_default_settings();
336
337
		// Blog Follow
338
		$settings['invitation'] = trim( wp_kses( $settings['invitation'], $allowedposttags ) );
339
		if ( empty( $settings['invitation'] ) )
340
			$settings['invitation'] = $default['invitation'];
341
342
		// Comments Follow (single post)
343
		$settings['comment_follow'] = trim( wp_kses( $settings['comment_follow'], $allowedposttags ) );
344
		if ( empty( $settings['comment_follow'] ) )
345
			$settings['comment_follow'] = $default['comment_follow'];
346
347
		return $settings;
348
	}
349
350
	public function reading_section() {
351
		echo '<p id="follower-settings">';
352
		_e( 'These settings change emails sent from your blog to followers.', 'jetpack' );
353
		echo '</p>';
354
	}
355
356
	public function setting_invitation() {
357
		$settings = $this->get_settings();
358
		echo '<textarea name="subscription_options[invitation]" class="large-text" cols="50" rows="5">' . esc_textarea( $settings['invitation'] ) . '</textarea>';
359
		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>';
360
	}
361
362
	public function setting_comment_follow() {
363
		$settings = $this->get_settings();
364
		echo '<textarea name="subscription_options[comment_follow]" class="large-text" cols="50" rows="5">' . esc_textarea( $settings['comment_follow'] ) . '</textarea>';
365
		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>';
366
	}
367
368
	function get_default_settings() {
369
		return array(
370
			'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' ),
371
			'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' )
372
		);
373
	}
374
375
	function get_settings() {
376
		return wp_parse_args( (array) get_option( 'subscription_options', array() ), $this->get_default_settings() );
377
	}
378
379
	/**
380
	 * Jetpack_Subscriptions::subscribe()
381
	 *
382
	 * Send a synchronous XML-RPC subscribe to blog posts or subscribe to post comments request.
383
	 *
384
	 * @param string $email
385
	 * @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...
386
	 * @param bool   $async    (optional) Should the subscription be performed asynchronously?  Defaults to true.
387
	 *
388
	 * @return true|Jetpack_Error true on success
389
	 *	invalid_email   : not a valid email address
390
	 *	invalid_post_id : not a valid post ID
391
	 *	unknown_post_id : unknown post
392
	 *	not_subscribed  : strange error.  Jetpack servers at WordPress.com could subscribe the email.
393
	 *	disabled        : Site owner has disabled subscriptions.
394
	 *	active          : Already subscribed.
395
	 *	unknown         : strange error.  Jetpack servers at WordPress.com returned something malformed.
396
	 *	unknown_status  : strange error.  Jetpack servers at WordPress.com returned something I didn't understand.
397
	 */
398
	function subscribe( $email, $post_ids = 0, $async = true, $extra_data = array() ) {
399
		if ( !is_email( $email ) ) {
400
			return new Jetpack_Error( 'invalid_email' );
401
		}
402
403
		if ( !$async ) {
404
			Jetpack::load_xml_rpc_client();
405
			$xml = new Jetpack_IXR_ClientMulticall();
406
		}
407
408
		foreach ( (array) $post_ids as $post_id ) {
409
			$post_id = (int) $post_id;
410
			if ( $post_id < 0 ) {
411
				return new Jetpack_Error( 'invalid_post_id' );
412
			} else if ( $post_id && !$post = get_post( $post_id ) ) {
413
				return new Jetpack_Error( 'unknown_post_id' );
414
			}
415
416
			if ( $async ) {
417
				Jetpack::xmlrpc_async_call( 'jetpack.subscribeToSite', $email, $post_id, serialize( $extra_data ) );
418
			} else {
419
				$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...
420
			}
421
		}
422
423
		if ( $async ) {
424
			return;
425
		}
426
427
		// Call
428
		$xml->query();
429
430
		if ( $xml->isError() ) {
431
			return $xml->get_jetpack_error();
432
		}
433
434
		$responses = $xml->getResponse();
435
436
		$r = array();
437
		foreach ( (array) $responses as $response ) {
438
			if ( isset( $response['faultCode'] ) || isset( $response['faultString'] ) ) {
439
				$r[] = $xml->get_jetpack_error( $response['faultCode'], $response['faultString'] );
440
				continue;
441
			}
442
443
			if ( !is_array( $response[0] ) || empty( $response[0]['status'] ) ) {
444
				$r[] = new Jetpack_Error( 'unknown' );
445
				continue;
446
			}
447
448
			switch ( $response[0]['status'] ) {
449
			case 'error' :
450
				$r[] = new Jetpack_Error( 'not_subscribed' );
451
				continue 2;
452
			case 'disabled' :
453
				$r[] = new Jetpack_Error( 'disabled' );
454
				continue 2;
455
			case 'active' :
456
				$r[] = new Jetpack_Error( 'active' );
457
				continue 2;
458
			case 'pending' :
459
				$r[] = true;
460
				continue 2;
461
			default :
0 ignored issues
show
Coding Style introduced by
There must be no space before the colon in a DEFAULT statement

As per the PSR-2 coding standard, there must not be a space in front of the colon in the default statement.

switch ($expr) {
    default : //wrong
        doSomething();
        break;
}

switch ($expr) {
    default: //right
        doSomething();
        break;
}

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

Loading history...
462
				$r[] = new Jetpack_Error( 'unknown_status', (string) $response[0]['status'] );
463
				continue 2;
464
			}
465
		}
466
467
		return $r;
468
	}
469
470
	/**
471
	 * Jetpack_Subscriptions::widget_init()
472
	 *
473
	 * Initialize and register the Jetpack Subscriptions widget.
474
	 */
475
	function widget_init() {
476
		register_widget( 'Jetpack_Subscriptions_Widget' );
477
	}
478
479
	/**
480
	 * Jetpack_Subscriptions::widget_submit()
481
	 *
482
	 * When a user submits their email via the blog subscription widget, check the details and call the subsribe() method.
483
	 */
484
	function widget_submit() {
485
		// Check the nonce.
486
		if ( is_user_logged_in() ) {
487
			check_admin_referer( 'blogsub_subscribe_' . get_current_blog_id() );
488
		}
489
490
		if ( empty( $_REQUEST['email'] ) )
491
			return false;
492
493
		$redirect_fragment = false;
494
		if ( isset( $_REQUEST['redirect_fragment'] ) ) {
495
			$redirect_fragment = preg_replace( '/[^a-z0-9_-]/i', '', $_REQUEST['redirect_fragment'] );
496
		}
497
		if ( !$redirect_fragment ) {
498
			$redirect_fragment = 'subscribe-blog';
499
		}
500
501
		$subscribe = Jetpack_Subscriptions::subscribe(
502
												$_REQUEST['email'],
503
												0,
504
												false,
505
												array(
506
													'source'         => 'widget',
507
													'widget-in-use'  => is_active_widget( false, false, 'blog_subscription', true ) ? 'yes' : 'no',
508
													'comment_status' => '',
509
													'server_data'    => $_SERVER,
510
												)
511
		);
512
513
		if ( is_wp_error( $subscribe ) ) {
514
			$error = $subscribe->get_error_code();
515
		} else {
516
			$error = false;
517
			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...
518
				if ( is_wp_error( $response ) ) {
519
					$error = $response->get_error_code();
520
					break;
521
				}
522
			}
523
		}
524
525
		switch ( $error ) {
526
			case false:
527
				$result = 'success';
528
				break;
529
			case 'invalid_email':
530
				$result = $error;
531
				break;
532
			case 'active':
533
			case 'blocked_email':
534
				$result = 'opted_out';
535
				break;
536
			case 'pending':
537
				$result = 'already';
538
				break;
539
			default:
540
				$result = 'error';
541
				break;
542
		}
543
544
		$redirect = add_query_arg( 'subscribe', $result );
545
546
		/**
547
		 * Fires on each subscription form submission.
548
		 *
549
		 * @module subscriptions
550
		 *
551
		 * @since 3.7.0
552
		 *
553
		 * @param string $result Result of form submission: success, invalid_email, already, error.
554
		 */
555
		do_action( 'jetpack_subscriptions_form_submission', $result );
556
557
		wp_safe_redirect( "$redirect#$redirect_fragment" );
558
		exit;
0 ignored issues
show
Coding Style Compatibility introduced by
The method widget_submit() contains an exit expression.

An exit expression should only be used in rare cases. For example, if you write a short command line script.

In most cases however, using an exit expression makes the code untestable and often causes incompatibilities with other libraries. Thus, unless you are absolutely sure it is required here, we recommend to refactor your code to avoid its usage.

Loading history...
559
	}
560
561
	/**
562
	 * Jetpack_Subscriptions::comment_subscribe_init()
563
	 *
564
	 * Set up and add the comment subscription checkbox to the comment form.
565
	 */
566
	function comment_subscribe_init() {
567
		global $post;
568
569
		$comments_checked = '';
570
		$blog_checked     = '';
571
572
		// Check for a comment / blog submission and set a cookie to retain the setting and check the boxes.
573
		if ( isset( $_COOKIE[ 'jetpack_comments_subscribe_' . self::$hash . '_' . $post->ID ] ) ) {
574
			$comments_checked = ' checked="checked"';
575
		}
576
577
		if ( isset( $_COOKIE[ 'jetpack_blog_subscribe_' . self::$hash ] ) ) {
578
			$blog_checked = ' checked="checked"';
579
		}
580
581
		// Some themes call this function, don't show the checkbox again
582
		remove_action( 'comment_form', 'subscription_comment_form' );
583
584
		// Check if Mark Jaquith's Subscribe to Comments plugin is active - if so, suppress Jetpack checkbox
585
586
		$str = '';
587
588
		if ( FALSE === has_filter( 'comment_form', 'show_subscription_checkbox' ) && 1 == get_option( 'stc_enabled', 1 ) && empty( $post->post_password ) && 'post' == get_post_type() ) {
589
			// Subscribe to comments checkbox
590
			$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 . ' /> ';
591
			$comment_sub_text = __( 'Notify me of follow-up comments by email.', 'jetpack' );
592
			$str .=	'<label class="subscribe-label" id="subscribe-label" for="subscribe_comments">' . esc_html(
593
				/**
594
				 * Filter the Subscribe to comments text appearing below the comment form.
595
				 *
596
				 * @module subscriptions
597
				 *
598
				 * @since 3.4.0
599
				 *
600
				 * @param string $comment_sub_text Subscribe to comments text.
601
				 */
602
				apply_filters( 'jetpack_subscribe_comment_label', $comment_sub_text )
603
			) . '</label>';
604
			$str .= '</p>';
605
		}
606
607
		if ( 1 == get_option( 'stb_enabled', 1 ) ) {
608
			// Subscribe to blog checkbox
609
			$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 . ' /> ';
610
			$blog_sub_text = __( 'Notify me of new posts by email.', 'jetpack' );
611
			$str .=	'<label class="subscribe-label" id="subscribe-blog-label" for="subscribe_blog">' . esc_html(
612
				/**
613
				 * Filter the Subscribe to blog text appearing below the comment form.
614
				 *
615
				 * @module subscriptions
616
				 *
617
				 * @since 3.4.0
618
				 *
619
				 * @param string $comment_sub_text Subscribe to blog text.
620
				 */
621
				apply_filters( 'jetpack_subscribe_blog_label', $blog_sub_text )
622
			) . '</label>';
623
			$str .= '</p>';
624
		}
625
626
		/**
627
		 * Filter the output of the subscription options appearing below the comment form.
628
		 *
629
		 * @module subscriptions
630
		 *
631
		 * @since 1.2.0
632
		 *
633
		 * @param string $str Comment Subscription form HTML output.
634
		 */
635
		echo apply_filters( 'jetpack_comment_subscription_form', $str );
636
	}
637
638
	/**
639
	 * Jetpack_Subscriptions::comment_subscribe_init()
640
	 *
641
	 * When a user checks the comment subscribe box and submits a comment, subscribe them to the comment thread.
642
	 */
643
	function comment_subscribe_submit( $comment_id, $approved ) {
644
		if ( 'spam' === $approved ) {
645
			return;
646
		}
647
648
		$comment = get_comment( $comment_id );
649
650
		// Set cookies for this post/comment
651
		$this->set_cookies( isset( $_REQUEST['subscribe_comments'] ), $comment->comment_post_ID, isset( $_REQUEST['subscribe_blog'] ) );
652
653
		if ( !isset( $_REQUEST['subscribe_comments'] ) && !isset( $_REQUEST['subscribe_blog'] ) )
654
			return;
655
656
		$post_ids = array();
657
658
		if ( isset( $_REQUEST['subscribe_comments'] ) )
659
			$post_ids[] = $comment->comment_post_ID;
660
661
		if ( isset( $_REQUEST['subscribe_blog'] ) )
662
			$post_ids[] = 0;
663
664
		Jetpack_Subscriptions::subscribe(
665
									$comment->comment_author_email,
666
									$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...
667
									true,
668
									array(
669
										'source'         => 'comment-form',
670
										'widget-in-use'  => is_active_widget( false, false, 'blog_subscription', true ) ? 'yes' : 'no',
671
										'comment_status' => $approved,
672
										'server_data'    => $_SERVER,
673
									)
674
		);
675
	}
676
677
	/**
678
	 * Jetpack_Subscriptions::set_cookies()
679
	 *
680
	 * Set a cookie to save state on the comment and post subscription checkboxes.
681
	 *
682
	 * @param bool $subscribe_to_post Whether the user chose to subscribe to subsequent comments on this post.
683
	 * @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...
684
	 * @param bool $subscribe_to_blog Whether the user chose to subscribe to all new posts on the blog.
685
	 */
686
	function set_cookies( $subscribe_to_post = false, $post_id = null, $subscribe_to_blog = false ) {
687
		$post_id = intval( $post_id );
688
689
		/** This filter is already documented in core/wp-includes/comment-functions.php */
690
		$cookie_lifetime = apply_filters( 'comment_cookie_lifetime',       30000000 );
691
692
		/**
693
		 * Filter the Jetpack Comment cookie path.
694
		 *
695
		 * @module subscriptions
696
		 *
697
		 * @since 2.5.0
698
		 *
699
		 * @param string COOKIEPATH Cookie path.
700
		 */
701
		$cookie_path     = apply_filters( 'jetpack_comment_cookie_path',   COOKIEPATH );
0 ignored issues
show
Coding Style introduced by
Equals sign not aligned correctly; expected 1 space but found 5 spaces

This check looks for improperly formatted assignments.

Every assignment must have exactly one space before and one space after the equals operator.

To illustrate:

$a = "a";
$ab = "ab";
$abc = "abc";

will have no issues, while

$a   = "a";
$ab  = "ab";
$abc = "abc";

will report issues in lines 1 and 2.

Loading history...
702
703
		/**
704
		 * Filter the Jetpack Comment cookie domain.
705
		 *
706
		 * @module subscriptions
707
		 *
708
		 * @since 2.5.0
709
		 *
710
		 * @param string COOKIE_DOMAIN Cookie domain.
711
		 */
712
		$cookie_domain   = apply_filters( 'jetpack_comment_cookie_domain', COOKIE_DOMAIN );
0 ignored issues
show
Coding Style introduced by
Equals sign not aligned correctly; expected 1 space but found 3 spaces

This check looks for improperly formatted assignments.

Every assignment must have exactly one space before and one space after the equals operator.

To illustrate:

$a = "a";
$ab = "ab";
$abc = "abc";

will have no issues, while

$a   = "a";
$ab  = "ab";
$abc = "abc";

will report issues in lines 1 and 2.

Loading history...
713
714
		if ( $subscribe_to_post && $post_id >= 0 ) {
715
			setcookie( 'jetpack_comments_subscribe_' . self::$hash . '_' . $post_id, 1, time() + $cookie_lifetime, $cookie_path, $cookie_domain );
716
		} else {
717
			setcookie( 'jetpack_comments_subscribe_' . self::$hash . '_' . $post_id, '', time() - 3600, $cookie_path, $cookie_domain );
718
		}
719
720
		if ( $subscribe_to_blog ) {
721
			setcookie( 'jetpack_blog_subscribe_' . self::$hash, 1, time() + $cookie_lifetime, $cookie_path, $cookie_domain );
722
		} else {
723
			setcookie( 'jetpack_blog_subscribe_' . self::$hash, '', time() - 3600, $cookie_path, $cookie_domain );
724
		}
725
	}
726
727
}
728
729
Jetpack_Subscriptions::init();
730
731
732
/***
733
 * Blog Subscription Widget
734
 */
735
736
class Jetpack_Subscriptions_Widget extends WP_Widget {
0 ignored issues
show
Coding Style Compatibility introduced by
PSR1 recommends that each class should be in its own file to aid autoloaders.

Having each class in a dedicated file usually plays nice with PSR autoloaders and is therefore a well established practice. If you use other autoloaders, you might not want to follow this rule.

Loading history...
737 View Code Duplication
	function __construct() {
738
		$widget_ops  = array(
0 ignored issues
show
Coding Style introduced by
Equals sign not aligned correctly; expected 1 space but found 2 spaces

This check looks for improperly formatted assignments.

Every assignment must have exactly one space before and one space after the equals operator.

To illustrate:

$a = "a";
$ab = "ab";
$abc = "abc";

will have no issues, while

$a   = "a";
$ab  = "ab";
$abc = "abc";

will report issues in lines 1 and 2.

Loading history...
739
			'classname' => 'jetpack_subscription_widget',
740
			'description' => esc_html__( 'Add an email signup form to allow people to subscribe to your blog.', 'jetpack' ),
741
			'customize_selective_refresh' => true,
742
		);
743
744
		parent::__construct(
745
			'blog_subscription',
746
			/** This filter is documented in modules/widgets/facebook-likebox.php */
747
			apply_filters( 'jetpack_widget_name', __( 'Blog Subscriptions', 'jetpack' ) ),
748
			$widget_ops
749
		);
750
751
		if ( is_active_widget( false, false, $this->id_base ) || is_active_widget( false, false, 'monster' ) || is_customize_preview() ) {
752
			add_action( 'wp_enqueue_scripts', array( $this, 'enqueue_style' ) );
753
		}
754
	}
755
756
	/**
757
	 * Enqueue the form's CSS.
758
	 *
759
	 * @since 4.5.0
760
	 */
761
	function enqueue_style() {
762
		wp_register_style( 'jetpack-subscriptions', plugins_url( 'subscriptions/subscriptions.css', __FILE__ ) );
763
		wp_enqueue_style( 'jetpack-subscriptions' );
764
	}
765
766
	function widget( $args, $instance ) {
767
		if (
768
			( ! defined( 'IS_WPCOM' ) || ! IS_WPCOM ) &&
769
			/** This filter is already documented in modules/contact-form/grunion-contact-form.php */
770
			false === apply_filters( 'jetpack_auto_fill_logged_in_user', false )
771
		) {
772
			$subscribe_email = '';
773
		} else {
774
			$current_user = wp_get_current_user();
775
			if ( ! empty( $current_user->user_email ) ) {
776
				$subscribe_email = esc_attr( $current_user->user_email );
777
			} else {
778
				$subscribe_email = '';
779
			}
780
		}
781
782
		/** This action is already documented in modules/widgets/gravatar-profile.php */
783
		do_action( 'jetpack_stats_extra', 'widget_view', 'jetpack_subscriptions' );
784
785
		$source                 = 'widget';
786
		$instance            	= wp_parse_args( (array) $instance, $this->defaults() );
787
		$subscribe_text      	= isset( $instance['subscribe_text'] )        ? stripslashes( $instance['subscribe_text'] )        : '';
788
		$subscribe_placeholder 	= isset( $instance['subscribe_placeholder'] ) ? stripslashes( $instance['subscribe_placeholder'] ) : '';
789
		$subscribe_button    	= isset( $instance['subscribe_button'] )      ? stripslashes( $instance['subscribe_button'] )      : '';
790
		$success_message    	= isset( $instance['success_message'] )       ? stripslashes( $instance['success_message'] )      : '';
791
		$widget_id              = esc_attr( !empty( $args['widget_id'] )      ? esc_attr( $args['widget_id'] ) : mt_rand( 450, 550 ) );
792
793
		$show_subscribers_total = (bool) $instance['show_subscribers_total'];
794
		$subscribers_total      = $this->fetch_subscriber_count(); // Only used for the shortcode [total-subscribers]
795
796
		// Give the input element a unique ID
797
		/**
798
		 * Filter the subscription form's ID prefix.
799
		 *
800
		 * @module subscriptions
801
		 *
802
		 * @since 2.7.0
803
		 *
804
		 * @param string subscribe-field Subscription form field prefix.
805
		 * @param int $widget_id Widget ID.
806
		 */
807
		$subscribe_field_id = apply_filters( 'subscribe_field_id', 'subscribe-field', $widget_id );
808
809
		// Display the subscription form
810
		echo $args['before_widget'];
811
812
		// Only show the title if there actually is a title
813 View Code Duplication
		if( ! empty( $instance['title'] ) ) {
814
			echo $args['before_title'] . esc_attr( $instance['title'] ) . $args['after_title'] . "\n";
815
		}
816
817
		$referer = set_url_scheme( 'http://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'] );
818
819
		// Display any errors
820
		if ( isset( $_GET['subscribe'] ) ) :
821
			switch ( $_GET['subscribe'] ) :
822
				case 'invalid_email' : ?>
0 ignored issues
show
Coding Style introduced by
The case body in a switch statement must start on the line following the statement.

According to the PSR-2, the body of a case statement must start on the line immediately following the case statement.

switch ($expr) {
case "A":
    doSomething(); //right
    break;
case "B":

    doSomethingElse(); //wrong
    break;

}

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

Loading history...
823
					<p class="error"><?php esc_html_e( 'The email you entered was invalid. Please check and try again.', 'jetpack' ); ?></p>
824
				<?php break;
0 ignored issues
show
Coding Style introduced by
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...
825
				case 'opted_out' : ?>
0 ignored issues
show
Coding Style introduced by
The case body in a switch statement must start on the line following the statement.

According to the PSR-2, the body of a case statement must start on the line immediately following the case statement.

switch ($expr) {
case "A":
    doSomething(); //right
    break;
case "B":

    doSomethingElse(); //wrong
    break;

}

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

Loading history...
826
					<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' ),
827
							'https://subscribe.wordpress.com/',
828
							__( 'Manage your email preferences.', 'jetpack' )
829
						); ?>
830
				<?php break;
0 ignored issues
show
Coding Style introduced by
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...
831
				case 'already' : ?>
0 ignored issues
show
Coding Style introduced by
The case body in a switch statement must start on the line following the statement.

According to the PSR-2, the body of a case statement must start on the line immediately following the case statement.

switch ($expr) {
case "A":
    doSomething(); //right
    break;
case "B":

    doSomethingElse(); //wrong
    break;

}

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

Loading history...
832
					<p class="error"><?php esc_html_e( 'You have already subscribed to this site. Please check your inbox.', 'jetpack' ); ?></p>
833
				<?php break;
0 ignored issues
show
Coding Style introduced by
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...
834
				case 'success' : ?>
0 ignored issues
show
Coding Style introduced by
The case body in a switch statement must start on the line following the statement.

According to the PSR-2, the body of a case statement must start on the line immediately following the case statement.

switch ($expr) {
case "A":
    doSomething(); //right
    break;
case "B":

    doSomethingElse(); //wrong
    break;

}

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

Loading history...
835
					<div class="success"><?php echo wpautop( str_replace( '[total-subscribers]', number_format_i18n( $subscribers_total['value'] ), $success_message ) ); ?></div>
836
					<?php break;
0 ignored issues
show
Coding Style introduced by
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...
837
				default : ?>
0 ignored issues
show
Coding Style introduced by
There must be no space before the colon in a DEFAULT statement

As per the PSR-2 coding standard, there must not be a space in front of the colon in the default statement.

switch ($expr) {
    default : //wrong
        doSomething();
        break;
}

switch ($expr) {
    default: //right
        doSomething();
        break;
}

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

Loading history...
Coding Style introduced by
The default body in a switch statement must start on the line following the statement.

According to the PSR-2, the body of a default statement must start on the line immediately following the statement.

switch ($expr) {
    default:
        doSomething(); //right
        break;
}


switch ($expr) {
    default:

        doSomething(); //wrong
        break;
}

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

Loading history...
838
					<p class="error"><?php esc_html_e( 'There was an error when subscribing. Please try again.', 'jetpack' ); ?></p>
839
				<?php break;
0 ignored issues
show
Coding Style introduced by
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...
840
			endswitch;
841
		endif;
842
843
		// Display a subscribe form
844
		if ( isset( $_GET['subscribe'] ) && 'success' == $_GET['subscribe'] ) { ?>
845
			<?php
846
		} else { ?>
847
			<form action="#" method="post" accept-charset="utf-8" id="subscribe-blog-<?php echo $widget_id; ?>">
848
				<?php
849
				if ( ! isset ( $_GET['subscribe'] ) || 'success' != $_GET['subscribe'] ) {
850
					?><div id="subscribe-text"><?php echo wpautop( str_replace( '[total-subscribers]', number_format_i18n( $subscribers_total['value'] ), $subscribe_text ) ); ?></div><?php
851
				}
852
853
				if ( $show_subscribers_total && 0 < $subscribers_total['value'] ) {
854
					echo wpautop( sprintf( _n( 'Join %s other subscriber', 'Join %s other subscribers', $subscribers_total['value'], 'jetpack' ), number_format_i18n( $subscribers_total['value'] ) ) );
855
				}
856
				if ( ! isset ( $_GET['subscribe'] ) || 'success' != $_GET['subscribe'] ) { ?>
857
					<p id="subscribe-email">
858
						<label id="jetpack-subscribe-label" for="<?php echo esc_attr( $subscribe_field_id ) . '-' . esc_attr( $widget_id ); ?>">
859
							<?php echo !empty( $subscribe_placeholder ) ? esc_html( $subscribe_placeholder ) : esc_html__( 'Email Address:', 'jetpack' ); ?>
860
						</label>
861
						<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 ); ?>" />
862
					</p>
863
864
					<p id="subscribe-submit">
865
						<input type="hidden" name="action" value="subscribe" />
866
						<input type="hidden" name="source" value="<?php echo esc_url( $referer ); ?>" />
867
						<input type="hidden" name="sub-type" value="<?php echo esc_attr( $source ); ?>" />
868
						<input type="hidden" name="redirect_fragment" value="<?php echo $widget_id; ?>" />
869
						<?php
870
							if ( is_user_logged_in() ) {
871
								wp_nonce_field( 'blogsub_subscribe_'. get_current_blog_id(), '_wpnonce', false );
872
							}
873
						?>
874
						<input type="submit" value="<?php echo esc_attr( $subscribe_button ); ?>" name="jetpack_subscriptions_widget" />
875
					</p>
876
				<?php }?>
877
			</form>
878
879
			<script>
880
			/*
881
			Custom functionality for safari and IE
882
			 */
883
			(function( d ) {
884
				// In case the placeholder functionality is available we remove labels
885
				if ( ( 'placeholder' in d.createElement( 'input' ) ) ) {
886
					var label = d.querySelector( 'label[for=subscribe-field-<?php echo $widget_id; ?>]' );
887
						label.style.clip 	 = 'rect(1px, 1px, 1px, 1px)';
888
						label.style.position = 'absolute';
889
						label.style.height   = '1px';
890
						label.style.width    = '1px';
891
						label.style.overflow = 'hidden';
892
				}
893
894
				// Make sure the email value is filled in before allowing submit
895
				var form = d.getElementById('subscribe-blog-<?php echo $widget_id; ?>'),
896
					input = d.getElementById('<?php echo esc_attr( $subscribe_field_id ) . '-' . esc_attr( $widget_id ); ?>'),
897
					handler = function( event ) {
898
						if ( '' === input.value ) {
899
							input.focus();
900
901
							if ( event.preventDefault ){
902
								event.preventDefault();
903
							}
904
905
							return false;
906
						}
907
					};
908
909
				if ( window.addEventListener ) {
910
					form.addEventListener( 'submit', handler, false );
911
				} else {
912
					form.attachEvent( 'onsubmit', handler );
913
				}
914
			})( document );
915
			</script>
916
		<?php } ?>
917
		<?php
918
919
		echo "\n" . $args['after_widget'];
920
	}
921
922
	function increment_subscriber_count( $current_subs_array = array() ) {
923
		$current_subs_array['value']++;
924
925
		set_transient( 'wpcom_subscribers_total', $current_subs_array, 3600 ); // try to cache the result for at least 1 hour
926
927
		return $current_subs_array;
928
	}
929
930
	function fetch_subscriber_count() {
931
		$subs_count = get_transient( 'wpcom_subscribers_total' );
932
933
		if ( FALSE === $subs_count || 'failed' == $subs_count['status'] ) {
934
			Jetpack:: load_xml_rpc_client();
0 ignored issues
show
Coding Style introduced by
Expected 0 spaces after double colon; 1 found

This check looks for references to static members where there are spaces between the name of the type and the actual member.

An example:

Certificate:: TRIPLEDES_CBC

will actually work, but is not very readable.

Loading history...
935
936
			$xml = new Jetpack_IXR_Client( array( 'user_id' => JETPACK_MASTER_USER, ) );
937
938
			$xml->query( 'jetpack.fetchSubscriberCount' );
939
940
			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
941
				$subs_count = array(
942
					'status'  => 'failed',
943
					'code'    => $xml->getErrorCode(),
944
					'message' => $xml->getErrorMessage(),
945
					'value'	  => ( isset( $subs_count['value'] ) ) ? $subs_count['value'] : 0,
946
				);
947
			} else {
948
				$subs_count = array(
949
					'status' => 'success',
950
					'value'  => $xml->getResponse(),
951
				);
952
			}
953
954
			set_transient( 'wpcom_subscribers_total', $subs_count, 3600 ); // try to cache the result for at least 1 hour
955
		}
956
957
		return $subs_count;
958
	}
959
960
	function update( $new_instance, $old_instance ) {
961
		$instance = $old_instance;
962
963
		$instance['title']					= wp_kses( stripslashes( $new_instance['title'] ), array() );
964
		$instance['subscribe_text']			= wp_filter_post_kses( stripslashes( $new_instance['subscribe_text'] ) );
965
		$instance['subscribe_placeholder']	= wp_kses( stripslashes( $new_instance['subscribe_placeholder'] ), array() );
966
		$instance['subscribe_button']		= wp_kses( stripslashes( $new_instance['subscribe_button'] ), array() );
967
		$instance['success_message']		= wp_kses( stripslashes( $new_instance['success_message'] ), array() );
968
		$instance['show_subscribers_total']	= isset( $new_instance['show_subscribers_total'] ) && $new_instance['show_subscribers_total'];
969
970
		return $instance;
971
	}
972
973
	public static function defaults() {
974
		return array(
975
			'title'               	 => esc_html__( 'Subscribe to Blog via Email', 'jetpack' ),
976
			'subscribe_text'      	 => esc_html__( 'Enter your email address to subscribe to this blog and receive notifications of new posts by email.', 'jetpack' ),
977
			'subscribe_placeholder'	 => esc_html__( 'Email Address', 'jetpack' ),
978
			'subscribe_button'    	 => esc_html__( 'Subscribe', 'jetpack' ),
979
			'success_message'    	 => esc_html__( "Success! An email was just sent to confirm your subscription. Please find the email now and click 'Confirm Follow' to start subscribing.", 'jetpack' ),
980
			'show_subscribers_total' => true,
981
		);
982
	}
983
984
	function form( $instance ) {
985
		$instance = wp_parse_args( (array) $instance, $this->defaults() );
986
987
		$title               	= stripslashes( $instance['title'] );
988
		$subscribe_text      	= stripslashes( $instance['subscribe_text'] );
989
		$subscribe_placeholder 	= stripslashes( $instance['subscribe_placeholder'] );
990
		$subscribe_button    	= stripslashes( $instance['subscribe_button'] );
991
		$success_message		= stripslashes( $instance['success_message']);
992
		$show_subscribers_total = checked( $instance['show_subscribers_total'], true, false );
993
994
		$subs_fetch = $this->fetch_subscriber_count();
995
996
		if ( 'failed' == $subs_fetch['status'] ) {
997
			printf( '<div class="error inline"><p>' . __( '%s: %s', 'jetpack' ) . '</p></div>', esc_html( $subs_fetch['code'] ), esc_html( $subs_fetch['message'] ) );
998
		}
999
		$subscribers_total = number_format_i18n( $subs_fetch['value'] );
1000
?>
1001
<p>
1002
	<label for="<?php echo $this->get_field_id( 'title' ); ?>">
1003
		<?php _e( 'Widget title:', 'jetpack' ); ?>
1004
		<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 ); ?>" />
1005
	</label>
1006
</p>
1007
<p>
1008
	<label for="<?php echo $this->get_field_id( 'subscribe_text' ); ?>">
1009
		<?php _e( 'Optional text to display to your readers:', 'jetpack' ); ?>
1010
		<textarea class="widefat" id="<?php echo $this->get_field_id( 'subscribe_text' ); ?>" name="<?php echo $this->get_field_name( 'subscribe_text' ); ?>" rows="3"><?php echo esc_html( $subscribe_text ); ?></textarea>
1011
	</label>
1012
</p>
1013
<p>
1014
	<label for="<?php echo $this->get_field_id( 'subscribe_placeholder' ); ?>">
1015
		<?php esc_html_e( 'Subscribe Placeholder:', 'jetpack' ); ?>
1016
		<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 ); ?>" />
1017
	</label>
1018
</p>
1019
<p>
1020
	<label for="<?php echo $this->get_field_id( 'subscribe_button' ); ?>">
1021
		<?php _e( 'Subscribe Button:', 'jetpack' ); ?>
1022
		<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 ); ?>" />
1023
	</label>
1024
</p>
1025
<p>
1026
	<label for="<?php echo $this->get_field_id( 'success_message' ); ?>">
1027
		<?php _e( 'Success Message Text:', 'jetpack' ); ?>
1028
		<textarea class="widefat" id="<?php echo $this->get_field_id( 'success_message' ); ?>" name="<?php echo $this->get_field_name( 'success_message' ); ?>" rows="5"><?php echo esc_html( $success_message ); ?></textarea>
1029
	</label>
1030
</p>
1031
<p>
1032
	<label for="<?php echo $this->get_field_id( 'show_subscribers_total' ); ?>">
1033
		<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; ?> />
1034
		<?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 ) ); ?>
1035
	</label>
1036
</p>
1037
<?php
1038
	}
1039
}
1040
1041
add_shortcode( 'jetpack_subscription_form', 'jetpack_do_subscription_form' );
1042
add_shortcode( 'blog_subscription_form', 'jetpack_do_subscription_form' );
1043
1044
function jetpack_do_subscription_form( $instance ) {
1045
	$instance['show_subscribers_total'] = empty( $instance['show_subscribers_total'] ) ? false : true;
1046
	$instance = shortcode_atts( Jetpack_Subscriptions_Widget::defaults(), $instance, 'jetpack_subscription_form' );
1047
	$args = array(
1048
		'before_widget' => sprintf( '<div class="%s">', 'jetpack_subscription_widget' ),
1049
	);
1050
	ob_start();
1051
	the_widget( 'Jetpack_Subscriptions_Widget', $instance, $args );
1052
	$output = ob_get_clean();
1053
	return $output;
1054
}
1055