Completed
Push — fix/5151-add-in-progress-notic... ( 7efd6d...b3b4d3 )
by
unknown
13:37
created

subscription_post_subscribe_setting()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 10
Code Lines 7

Duplication

Lines 10
Ratio 100 %

Importance

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