Completed
Push — update/security-widget-languag... ( 75ac2c...0fa1b8 )
by
unknown
126:04 queued 116:11
created

subscriptions.php ➔ jetpack_subscriptions_cherry_pick_server_data()   B

Complexity

Conditions 6
Paths 4

Size

Total Lines 15
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Importance

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