Completed
Push — branch-8.7-built ( 50de0f...7a10d7 )
by Jeremy
32:57 queued 24:29
created

Jetpack_Cxn_Tests::test__check_if_connected()   B

Complexity

Conditions 4
Paths 4

Size

Total Lines 56

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 4
nc 4
nop 0
dl 0
loc 56
rs 8.9599
c 0
b 0
f 0

How to fix   Long Method   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
/**
3
 * Collection of tests to run on the Jetpack connection locally.
4
 *
5
 * @package Jetpack
6
 */
7
8
use Automattic\Jetpack\Connection\Client;
9
use Automattic\Jetpack\Status;
10
use Automattic\Jetpack\Connection\Utils as Connection_Utils;
11
use Automattic\Jetpack\Sync\Modules;
12
use Automattic\Jetpack\Sync\Settings as Sync_Settings;
13
use Automattic\Jetpack\Sync\Health as Sync_Health;
14
use Automattic\Jetpack\Sync\Sender as Sync_Sender;
15
use Automattic\Jetpack\Redirect;
16
17
/**
18
 * Class Jetpack_Cxn_Tests contains all of the actual tests.
19
 */
20
class Jetpack_Cxn_Tests extends Jetpack_Cxn_Test_Base {
21
22
	/**
23
	 * Jetpack_Cxn_Tests constructor.
24
	 */
25
	public function __construct() {
26
		parent::__construct();
27
28
		$methods = get_class_methods( 'Jetpack_Cxn_Tests' );
29
30
		foreach ( $methods as $method ) {
31
			if ( false === strpos( $method, 'test__' ) ) {
32
				continue;
33
			}
34
			$this->add_test( array( $this, $method ), $method, 'direct' );
35
		}
36
37
		/**
38
		 * Fires after loading default Jetpack Connection tests.
39
		 *
40
		 * @since 7.1.0
41
		 * @since 8.3.0 Passes the Jetpack_Cxn_Tests instance.
42
		 */
43
		do_action( 'jetpack_connection_tests_loaded', $this );
44
45
		/**
46
		 * Determines if the WP.com testing suite should be included.
47
		 *
48
		 * @since 7.1.0
49
		 * @since 8.1.0 Default false.
50
		 *
51
		 * @param bool $run_test To run the WP.com testing suite. Default false.
52
		 */
53
		if ( apply_filters( 'jetpack_debugger_run_self_test', false ) ) {
54
			/**
55
			 * Intentionally added last as it checks for an existing failure state before attempting.
56
			 * Generally, any failed location condition would result in the WP.com check to fail too, so
57
			 * we will skip it to avoid confusing error messages.
58
			 *
59
			 * Note: This really should be an 'async' test.
60
			 */
61
			$this->add_test( array( $this, 'last__wpcom_self_test' ), 'test__wpcom_self_test', 'direct' );
62
		}
63
	}
64
65
	/**
66
	 * Helper function to look up the expected master user and return the local WP_User.
67
	 *
68
	 * @return WP_User Jetpack's expected master user.
69
	 */
70
	protected function helper_retrieve_local_master_user() {
71
		$master_user = Jetpack_Options::get_option( 'master_user' );
72
		return new WP_User( $master_user );
73
	}
74
75
	/**
76
	 * Is Jetpack even connected and supposed to be talking to WP.com?
77
	 */
78
	protected function helper_is_jetpack_connected() {
79
		return Jetpack::is_active() && ! ( new Status() )->is_development_mode();
80
	}
81
82
	/**
83
	 * Retrieve the `blog_token` if it exists.
84
	 *
85
	 * @return object|false
86
	 */
87
	protected function helper_get_blog_token() {
88
		return Jetpack::connection()->get_access_token();
89
	}
90
91
	/**
92
	 * Returns a support url based on development mode.
93
	 */
94
	protected function helper_get_support_url() {
95
		return Jetpack::is_development_version()
96
			? Redirect::get_url( 'jetpack-contact-support-beta-group' )
97
			: Redirect::get_url( 'jetpack-contact-support' );
98
	}
99
100
	/**
101
	 * Gets translated support text.
102
	 */
103
	protected function helper_get_support_text() {
104
		return __( 'Please contact Jetpack support.', 'jetpack' );
105
	}
106
107
	/**
108
	 * Gets translated text to enable outbound requests.
109
	 *
110
	 * @param string $protocol Either 'HTTP' or 'HTTPS'.
111
	 *
112
	 * @return string The translated text.
113
	 */
114
	protected function helper_enable_outbound_requests( $protocol ) {
115
		return sprintf(
116
			/* translators: %1$s - request protocol, either http or https */
117
			__(
118
				'Your server did not successfully connect to the Jetpack server using %1$s
119
				Please ask your hosting provider to confirm your server can make outbound requests to jetpack.com.',
120
				'jetpack'
121
			),
122
			$protocol
123
		);
124
	}
125
126
	/**
127
	 * Returns 30 for use with a filter.
128
	 *
129
	 * To allow time for WP.com to run upstream testing, this function exists to increase the http_request_timeout value
130
	 * to 30.
131
	 *
132
	 * @return int 30
133
	 */
134
	public static function increase_timeout() {
135
		return 30; // seconds.
136
	}
137
138
	/**
139
	 * The test verifies the blog token exists.
140
	 *
141
	 * @return array
142
	 */
143
	protected function test__blog_token_if_exists() {
144
		$blog_token = $this->helper_get_blog_token();
145
146 View Code Duplication
		if ( $blog_token ) {
147
			$result = self::passing_test( array( 'name' => __FUNCTION__ ) );
148
		} else {
149
			$result = self::failing_test(
150
				array(
151
					'name'              => __FUNCTION__,
152
					'short_description' => __( 'Blog token is missing.', 'jetpack' ),
153
					'action'            => admin_url( 'admin.php?page=jetpack#/dashboard' ),
154
					'action_label'      => __( 'Disconnect your site from WordPress.com, and connect it again.', 'jetpack' ),
155
				)
156
			);
157
		}
158
159
		return $result;
160
	}
161
162
	/**
163
	 * Test if Jetpack is connected.
164
	 */
165
	protected function test__check_if_connected() {
166
		$name = __FUNCTION__;
167
168
		if ( ! $this->helper_get_blog_token() ) {
169
			return self::skipped_test(
170
				array(
171
					'name'              => $name,
172
					'short_description' => __( 'Blog token is missing.', 'jetpack' ),
173
				)
174
			);
175
		}
176
177
		if ( $this->helper_is_jetpack_connected() ) {
178
			$result = self::passing_test(
179
				array(
180
					'name'             => $name,
181
					'label'            => __( 'Your site is connected to Jetpack', 'jetpack' ),
182
					'long_description' => sprintf(
183
						'<p>%1$s</p>' .
184
						'<p><span class="dashicons pass"><span class="screen-reader-text">%2$s</span></span> %3$s</p>',
185
						__( 'A healthy connection ensures Jetpack essential services are provided to your WordPress site, such as Stats and Site Security.', 'jetpack' ),
186
						/* translators: Screen reader text indicating a test has passed */
187
						__( 'Passed', 'jetpack' ),
188
						__( 'Your site is connected to Jetpack.', 'jetpack' )
189
					),
190
				)
191
			);
192
		} elseif ( ( new Status() )->is_development_mode() ) {
193
			$result = self::skipped_test(
194
				array(
195
					'name'              => $name,
196
					'short_description' => __( 'Jetpack is in Development Mode:', 'jetpack' ) . ' ' . Jetpack::development_mode_trigger_text(),
197
				)
198
			);
199
		} else {
200
			$result = self::failing_test(
201
				array(
202
					'name'             => $name,
203
					'label'            => __( 'Your site is not connected to Jetpack', 'jetpack' ),
204
					'action'           => admin_url( 'admin.php?page=jetpack#/dashboard' ),
205
					'action_label'     => __( 'Reconnect your site now', 'jetpack' ),
206
					'long_description' => sprintf(
207
						'<p>%1$s</p>' .
208
						'<p><span class="dashicons fail"><span class="screen-reader-text">%2$s</span></span> %3$s<strong> %4$s</strong></p>',
209
						__( 'A healthy connection ensures Jetpack essential services are provided to your WordPress site, such as Stats and Site Security.', 'jetpack' ),
210
						/* translators: screen reader text indicating a test failed */
211
						__( 'Error', 'jetpack' ),
212
						__( 'Your site is not connected to Jetpack.', 'jetpack' ),
213
						__( 'We recommend reconnecting Jetpack.', 'jetpack' )
214
					),
215
				)
216
			);
217
		}
218
219
		return $result;
220
	}
221
222
	/**
223
	 * Test that the master user still exists on this site.
224
	 *
225
	 * @return array Test results.
226
	 */
227
	protected function test__master_user_exists_on_site() {
228
		$name = __FUNCTION__;
229 View Code Duplication
		if ( ! $this->helper_is_jetpack_connected() ) {
230
			return self::skipped_test(
231
				array(
232
					'name'              => $name,
233
					'short_description' => __( 'Jetpack is not connected. No master user to check.', 'jetpack' ),
234
				)
235
			);
236
		}
237
		$local_user = $this->helper_retrieve_local_master_user();
238
239
		if ( $local_user->exists() ) {
240
			$result = self::passing_test( array( 'name' => $name ) );
241
		} else {
242
			$result = self::failing_test(
243
				array(
244
					'name'              => $name,
245
					'short_description' => __( 'The user who setup the Jetpack connection no longer exists on this site.', 'jetpack' ),
246
					'action_label'      => __( 'Please disconnect and reconnect Jetpack.', 'jetpack' ),
247
					'action'            => Redirect::get_url( 'jetpack-support-reconnecting-reinstalling-jetpack' ),
248
				)
249
			);
250
		}
251
252
		return $result;
253
	}
254
255
	/**
256
	 * Test that the master user has the manage options capability (e.g. is an admin).
257
	 *
258
	 * Generic calls from WP.com execute on Jetpack as the master user. If it isn't an admin, random things will fail.
259
	 *
260
	 * @return array Test results.
261
	 */
262
	protected function test__master_user_can_manage_options() {
263
		$name = __FUNCTION__;
264 View Code Duplication
		if ( ! $this->helper_is_jetpack_connected() ) {
265
			return self::skipped_test(
266
				array(
267
					'name'              => $name,
268
					'short_description' => __( 'Jetpack is not connected.', 'jetpack' ),
269
				)
270
			);
271
		}
272
		$master_user = $this->helper_retrieve_local_master_user();
273
274
		if ( user_can( $master_user, 'manage_options' ) ) {
275
			$result = self::passing_test( array( 'name' => $name ) );
276
		} else {
277
			$result = self::failing_test(
278
				array(
279
					'name'              => $name,
280
					/* translators: a WordPress username */
281
					'short_description' => sprintf( __( 'The user (%s) who setup the Jetpack connection is not an administrator.', 'jetpack' ), $master_user->user_login ),
282
					'action_label'      => __( 'Either upgrade the user or disconnect and reconnect Jetpack.', 'jetpack' ),
283
					'action'            => Redirect::get_url( 'jetpack-support-reconnecting-reinstalling-jetpack' ),
284
				)
285
			);
286
		}
287
288
		return $result;
289
	}
290
291
	/**
292
	 * Test that the PHP's XML library is installed.
293
	 *
294
	 * While it should be installed by default, increasingly in PHP 7, some OSes require an additional php-xml package.
295
	 *
296
	 * @return array Test results.
297
	 */
298
	protected function test__xml_parser_available() {
299
		$name = __FUNCTION__;
300
		if ( function_exists( 'xml_parser_create' ) ) {
301
			$result = self::passing_test( array( 'name' => $name ) );
302 View Code Duplication
		} else {
303
			$result = self::failing_test(
304
				array(
305
					'name'              => $name,
306
					'label'             => __( 'PHP XML manipulation libraries are not available.', 'jetpack' ),
307
					'short_description' => __( 'Please ask your hosting provider to refer to our server requirements and enable PHP\'s XML module.', 'jetpack' ),
308
					'action_label'      => __( 'View our server requirements', 'jetpack' ),
309
					'action'            => Redirect::get_url( 'jetpack-support-server-requirements' ),
310
				)
311
			);
312
		}
313
		return $result;
314
	}
315
316
	/**
317
	 * Test that the server is able to send an outbound http communication.
318
	 *
319
	 * @return array Test results.
320
	 */
321 View Code Duplication
	protected function test__outbound_http() {
322
		$name    = __FUNCTION__;
323
		$request = wp_remote_get( preg_replace( '/^https:/', 'http:', JETPACK__API_BASE ) . 'test/1/' );
324
		$code    = wp_remote_retrieve_response_code( $request );
325
326
		if ( 200 === intval( $code ) ) {
327
			$result = self::passing_test( array( 'name' => $name ) );
328
		} else {
329
			$result = self::failing_test(
330
				array(
331
					'name'              => $name,
332
					'short_description' => $this->helper_enable_outbound_requests( 'HTTP' ),
333
				)
334
			);
335
		}
336
337
		return $result;
338
	}
339
340
	/**
341
	 * Test that the server is able to send an outbound https communication.
342
	 *
343
	 * @return array Test results.
344
	 */
345 View Code Duplication
	protected function test__outbound_https() {
346
		$name    = __FUNCTION__;
347
		$request = wp_remote_get( preg_replace( '/^http:/', 'https:', JETPACK__API_BASE ) . 'test/1/' );
348
		$code    = wp_remote_retrieve_response_code( $request );
349
350
		if ( 200 === intval( $code ) ) {
351
			$result = self::passing_test( array( 'name' => $name ) );
352
		} else {
353
			$result = self::failing_test(
354
				array(
355
					'name'              => $name,
356
					'short_description' => $this->helper_enable_outbound_requests( 'HTTPS' ),
357
				)
358
			);
359
		}
360
361
		return $result;
362
	}
363
364
	/**
365
	 * Check for an IDC.
366
	 *
367
	 * @return array Test results.
368
	 */
369
	protected function test__identity_crisis() {
370
		$name = __FUNCTION__;
371 View Code Duplication
		if ( ! $this->helper_is_jetpack_connected() ) {
372
			return self::skipped_test(
373
				array(
374
					'name'              => $name,
375
					'short_description' => __( 'Jetpack is not connected.', 'jetpack' ),
376
				)
377
			);
378
		}
379
		$identity_crisis = Jetpack::check_identity_crisis();
380
381
		if ( ! $identity_crisis ) {
382
			$result = self::passing_test( array( 'name' => $name ) );
383
		} else {
384
			$result = self::failing_test(
385
				array(
386
					'name'              => $name,
387
					'short_description' => sprintf(
388
						/* translators: Two URLs. The first is the locally-recorded value, the second is the value as recorded on WP.com. */
389
						__( 'Your url is set as `%1$s`, but your WordPress.com connection lists it as `%2$s`!', 'jetpack' ),
390
						$identity_crisis['home'],
391
						$identity_crisis['wpcom_home']
392
					),
393
					'action_label'      => $this->helper_get_support_text(),
394
					'action'            => $this->helper_get_support_url(),
395
				)
396
			);
397
		}
398
		return $result;
399
	}
400
401
	/**
402
	 * Tests connection status against wp.com's test-connection endpoint.
403
	 *
404
	 * @todo: Compare with the wpcom_self_test. We only need one of these.
405
	 *
406
	 * @return array Test results.
407
	 */
408
	protected function test__wpcom_connection_test() {
409
		$name = __FUNCTION__;
410
411
		$status = new Status();
412 View Code Duplication
		if ( ! Jetpack::is_active() || $status->is_development_mode() || $status->is_staging_site() || ! $this->pass ) {
413
			return self::skipped_test( array( 'name' => $name ) );
414
		}
415
416
		add_filter( 'http_request_timeout', array( 'Jetpack_Cxn_Tests', 'increase_timeout' ) );
417
		$response = Client::wpcom_json_api_request_as_blog(
418
			sprintf( '/jetpack-blogs/%d/test-connection', Jetpack_Options::get_option( 'id' ) ),
419
			Client::WPCOM_JSON_API_VERSION
420
		);
421
		remove_filter( 'http_request_timeout', array( 'Jetpack_Cxn_Tests', 'increase_timeout' ) );
422
423 View Code Duplication
		if ( is_wp_error( $response ) ) {
424
			return self::failing_test(
425
				array(
426
					'name'              => $name,
427
					/* translators: %1$s is the error code, %2$s is the error message */
428
					'short_description' => sprintf( __( 'Connection test failed (#%1$s: %2$s)', 'jetpack' ), $response->get_error_code(), $response->get_error_message() ),
429
					'action_label'      => $this->helper_get_support_text(),
430
					'action'            => $this->helper_get_support_url(),
431
				)
432
			);
433
		}
434
435
		$body = wp_remote_retrieve_body( $response );
436 View Code Duplication
		if ( ! $body ) {
437
			return self::failing_test(
438
				array(
439
					'name'              => $name,
440
					'short_description' => __( 'Connection test failed (empty response body)', 'jetpack' ) . wp_remote_retrieve_response_code( $response ),
441
					'action_label'      => $this->helper_get_support_text(),
442
					'action'            => $this->helper_get_support_url(),
443
				)
444
			);
445
		}
446
447 View Code Duplication
		if ( 404 === wp_remote_retrieve_response_code( $response ) ) {
448
			return self::skipped_test(
449
				array(
450
					'name'              => $name,
451
					'short_description' => __( 'The WordPress.com API returned a 404 error.', 'jetpack' ),
452
				)
453
			);
454
		}
455
456
		$result       = json_decode( $body );
457
		$is_connected = ! empty( $result->connected );
458
		$message      = $result->message . ': ' . wp_remote_retrieve_response_code( $response );
459
460
		if ( $is_connected ) {
461
			return self::passing_test( array( 'name' => $name ) );
462
		} else {
463
			return self::failing_test(
464
				array(
465
					'name'              => $name,
466
					'short_description' => $message,
467
					'action_label'      => $this->helper_get_support_text(),
468
					'action'            => $this->helper_get_support_url(),
469
				)
470
			);
471
		}
472
	}
473
474
	/**
475
	 * Tests the port number to ensure it is an expected value.
476
	 *
477
	 * We expect that sites on be on one of:
478
	 * port 80,
479
	 * port 443 (https sites only),
480
	 * the value of JETPACK_SIGNATURE__HTTP_PORT,
481
	 * unless the site is intentionally on a different port (e.g. example.com:8080 is the site's URL).
482
	 *
483
	 * If the value isn't one of those and the site's URL doesn't include a port, then the signature verification will fail.
484
	 *
485
	 * This happens most commonly on sites with reverse proxies, so the edge (e.g. Varnish) is running on 80/443, but nginx
486
	 * or Apache is responding internally on a different port (e.g. 81).
487
	 *
488
	 * @return array Test results
489
	 */
490
	protected function test__server_port_value() {
491
		$name = __FUNCTION__;
492
		if ( ! isset( $_SERVER['HTTP_X_FORWARDED_PORT'] ) && ! isset( $_SERVER['SERVER_PORT'] ) ) {
493
			return self::skipped_test(
494
				array(
495
					'name'              => $name,
496
					'short_description' => __( 'The server port values are not defined. This is most common when running PHP via a CLI.', 'jetpack' ),
497
				)
498
			);
499
		}
500
		$site_port   = wp_parse_url( home_url(), PHP_URL_PORT );
501
		$server_port = isset( $_SERVER['HTTP_X_FORWARDED_PORT'] ) ? (int) $_SERVER['HTTP_X_FORWARDED_PORT'] : (int) $_SERVER['SERVER_PORT'];
502
		$http_ports  = array( 80 );
503
		$https_ports = array( 80, 443 );
504
505
		if ( defined( 'JETPACK_SIGNATURE__HTTP_PORT' ) ) {
506
			$http_ports[] = JETPACK_SIGNATURE__HTTP_PORT;
507
		}
508
509
		if ( defined( 'JETPACK_SIGNATURE__HTTPS_PORT' ) ) {
510
			$https_ports[] = JETPACK_SIGNATURE__HTTPS_PORT;
511
		}
512
513
		if ( $site_port ) {
514
			return self::skipped_test( array( 'name' => $name ) ); // Not currently testing for this situation.
515
		}
516
517
		if ( is_ssl() && in_array( $server_port, $https_ports, true ) ) {
518
			return self::passing_test( array( 'name' => $name ) );
519
		} elseif ( in_array( $server_port, $http_ports, true ) ) {
520
			return self::passing_test( array( 'name' => $name ) );
521
		} else {
522
			if ( is_ssl() ) {
523
				$needed_constant = 'JETPACK_SIGNATURE__HTTPS_PORT';
524
			} else {
525
				$needed_constant = 'JETPACK_SIGNATURE__HTTP_PORT';
526
			}
527
			return self::failing_test(
528
				array(
529
					'name'              => $name,
530
					'short_description' => sprintf(
531
						/* translators: %1$s - a PHP code snippet */
532
						__(
533
							'The server port value is unexpected.
534
						Try adding the following to your wp-config.php file: %1$s',
535
							'jetpack'
536
						),
537
						"define( '$needed_constant', $server_port )"
538
					),
539
				)
540
			);
541
		}
542
	}
543
544
	/**
545
	 * Full Sync Health Test.
546
	 *
547
	 * Sync Disabled: Results in a skipped test
548
	 * Not In Progress : Results in a skipped test
549
	 * In Progress: Results in skipped test w/ status in CLI
550
	 */
551
	protected function test__full_sync_health() {
552
553
		$name = __FUNCTION__;
554
555
		if ( ! $this->helper_is_jetpack_connected() ) {
556
			// If the site is not connected, there is no point in testing Sync health.
557
			return self::skipped_test(
558
				array(
559
					'name'                => $name,
560
					'show_in_site_health' => false,
561
				)
562
			);
563
		}
564
565
		// Sync is enabled.
566
		if ( Sync_Settings::is_sync_enabled() ) {
567
568
			// Get Full Sync Progress.
569
			$full_sync_module = Modules::get_module( 'full-sync' );
570
			$progress_percent = $full_sync_module ? $full_sync_module->get_sync_progress_percentage() : null;
571
572
			// Full Sync in Progress.
573
			if ( $progress_percent ) {
574
575
				return self::informational_test(
576
					array(
577
						'name'              => $name,
578
						'label'             => __( 'Jetpack is performing a full sync of your site', 'jetpack' ),
579
						'severity'          => 'recommended',
580
						/* translators: placeholder is a percentage number. */
581
						'short_description' => sprintf( __( 'Jetpack is performing a full sync of your site. Current Progress: %1$d %%', 'jetpack' ), $progress_percent ),
582
						'long_description'  => sprintf(
583
							'<p>%1$s</p><p><span class="dashicons dashicons-update"><span class="screen-reader-text">%2$s</span></span> %3$s</p><div class="jetpack-sync-progress-ui"><div class="jetpack-sync-progress-label"></div><div class="jetpack-sync-progress-bar"></div></div>',
584
							__( 'The information synced by Jetpack ensures that Jetpack Search, Related Posts and other features are aligned with your site’s current content.', 'jetpack' ), /* translators: screen reader text indicating data is updating. */
585
							__( 'Updating', 'jetpack' ),
586
							__( 'Jetpack is currently performing a full sync of your site data.', 'jetpack' )
587
						),
588
					)
589
				);
590
591
			} else {
592
593
				// no Full Sync in Progress.
594
				return self::skipped_test(
595
					array(
596
						'name'                => $name,
597
						'show_in_site_health' => false,
598
					)
599
				);
600
601
			}
602
		} else {
603
604
			// If sync is not enabled no Full Sync can occur.
605
			return self::skipped_test(
606
				array(
607
					'name'                => $name,
608
					'show_in_site_health' => false,
609
				)
610
			);
611
612
		}
613
614
	}
615
616
	/**
617
	 * Sync Health Tests.
618
	 *
619
	 * Disabled: Results in a failing test (recommended)
620
	 * Delayed: Results in failing test (recommended)
621
	 * Error: Results in failing test (critical)
622
	 */
623
	protected function test__sync_health() {
624
625
		$name = __FUNCTION__;
626
627
		if ( ! $this->helper_is_jetpack_connected() ) {
628
			// If the site is not connected, there is no point in testing Sync health.
629
			return self::skipped_test(
630
				array(
631
					'name'                => $name,
632
					'show_in_site_health' => false,
633
				)
634
			);
635
		}
636
637
		// Sync is enabled.
638
		if ( Sync_Settings::is_sync_enabled() ) {
639
640
			if ( Sync_Health::get_status() === Sync_Health::STATUS_OUT_OF_SYNC ) {
641
				/*
642
				 * Sync has experienced Data Loss.
643
				 */
644
				$description  = '<p>';
645
				$description .= esc_html__( 'The information synced by Jetpack ensures that Jetpack Search, Related Posts and other features are aligned with your site’s current content.', 'jetpack' );
646
				$description .= '</p>';
647
				$description .= '<p>';
648
				$description .= sprintf(
649
					'<span class="dashicons fail"><span class="screen-reader-text">%1$s</span></span> ',
650
					esc_html__( 'Error', 'jetpack' )
651
				);
652
				$description .= wp_kses(
653
					__( 'Jetpack has detected an error while syncing your site. <strong>We recommend <a id="full_sync_request_link" href="#">a full sync</a> to align Jetpack with your site data.</strong>', 'jetpack' ),
654
					array(
655
						'a'      => array(
656
							'id'   => array(),
657
							'href' => array(),
658
						),
659
						'strong' => array(),
660
					)
661
				);
662
				$description .= '</p>';
663
664
				return self::failing_test(
665
					array(
666
						'name'              => $name,
667
						'label'             => __( 'Jetpack has detected an error syncing your site.', 'jetpack' ),
668
						'severity'          => 'critical',
669
						'action'            => Redirect::get_url( 'jetpack-contact-support' ),
670
						'action_label'      => __( 'Contact Jetpack Support', 'jetpack' ),
671
						'short_description' => __( 'Jetpack has detected an error while syncing your site. We recommend a full sync to align Jetpack with your site data.', 'jetpack' ),
672
						'long_description'  => $description,
673
					)
674
				);
675
676
			} else {
677
				// Get the Sync Queue.
678
				$sender     = Sync_Sender::get_instance();
679
				$sync_queue = $sender->get_sync_queue();
680
681
				// lag exceeds 5 minutes.
682
				if ( $sync_queue->lag() > 5 * MINUTE_IN_SECONDS ) {
683
684
					$description  = '<p>';
685
					$description .= esc_html__( 'The information synced by Jetpack ensures that Jetpack Search, Related Posts and other features are aligned with your site’s current content.', 'jetpack' );
686
					$description .= '</p>';
687
					$description .= '<p>';
688
					$description .= sprintf(
689
						'<span class="dashicons dashicons-clock" style="color: orange;"><span class="screen-reader-text">%1$s</span></span> ',
690
						/* translators: name, used to describe a clock icon. */
691
						esc_html__( 'Clock', 'jetpack' )
692
					);
693
					$description .= wp_kses(
694
						sprintf(
695
							/* translators: placeholder is a number of minutes. */
696
							_n(
697
								'Jetpack has identified a delay while syncing individual content updates. Certain features might be slower than usual, but this is only temporary while sync catches up with recent changes to your site. <strong>We’re seeing a current delay of %1$d minute.</strong>',
698
								'Jetpack has identified a delay while syncing individual content updates. Certain features might be slower than usual, but this is only temporary while sync catches up with recent changes to your site. <strong>We’re seeing a current delay of %1$d minutes.</strong>',
699
								intval( $sync_queue->lag() / MINUTE_IN_SECONDS ),
700
								'jetpack'
701
							),
702
							number_format_i18n( $sync_queue->lag() / MINUTE_IN_SECONDS )
703
						),
704
						array( 'strong' => array() )
705
					);
706
					$description .= '</p>';
707
708
					return self::informational_test(
709
						array(
710
							'name'              => $name,
711
							'label'             => __( 'Jetpack is experiencing a delay syncing your site.', 'jetpack' ),
712
							'severity'          => 'recommended',
713
							'action'            => null,
714
							'action_label'      => null,
715
							'short_description' => __( 'Jetpack is experiencing a delay syncing your site.', 'jetpack' ),
716
							'long_description'  => $description,
717
						)
718
					);
719
720
				} else {
721
722
					// Sync is Healthy.
723
					return self::passing_test( array( 'name' => $name ) );
724
725
				}
726
			}
727
		} else {
728
			/*
729
			 * Sync is disabled.
730
			 */
731
732
			$description  = '<p>';
733
			$description .= esc_html__( 'The information synced by Jetpack ensures that Jetpack Search, Related Posts and other features are aligned with your site’s current content.', 'jetpack' );
734
			$description .= '</p>';
735
			$description .= '<p>';
736
			$description .= __( 'Developers may enable / disable syncing using the Sync Settings API.', 'jetpack' );
737
			$description .= '</p>';
738
			$description .= '<p>';
739
			$description .= sprintf(
740
				'<span class="dashicons fail"><span class="screen-reader-text">%1$s</span></span> ',
741
				esc_html__( 'Error', 'jetpack' )
742
			);
743
			$description .= wp_kses(
744
				__( 'Jetpack Sync has been disabled on your site. Without it, certain Jetpack features will not work. <strong>We recommend enabling Sync.</strong>', 'jetpack' ),
745
				array( 'strong' => array() )
746
			);
747
			$description .= '</p>';
748
749
			return self::failing_test(
750
				array(
751
					'name'              => $name,
752
					'label'             => __( 'Jetpack Sync has been disabled on your site.', 'jetpack' ),
753
					'severity'          => 'recommended',
754
					'action'            => 'https://github.com/Automattic/jetpack/blob/master/packages/sync/src/class-settings.php',
755
					'action_label'      => __( 'See Github for more on Sync Settings', 'jetpack' ),
756
					'short_description' => __( 'Jetpack Sync has been disabled on your site.', 'jetpack' ),
757
					'long_description'  => $description,
758
				)
759
			);
760
761
		}
762
763
	}
764
765
	/**
766
	 * Calls to WP.com to run the connection diagnostic testing suite.
767
	 *
768
	 * Intentionally added last as it will be skipped if any local failed conditions exist.
769
	 *
770
	 * @since 7.1.0
771
	 * @since 7.9.0 Timeout waiting for a WP.com response no longer fails the test. Test is marked skipped instead.
772
	 *
773
	 * @return array Test results.
774
	 */
775
	protected function last__wpcom_self_test() {
776
		$name = 'test__wpcom_self_test';
777
778
		$status = new Status();
779 View Code Duplication
		if ( ! Jetpack::is_active() || $status->is_development_mode() || $status->is_staging_site() || ! $this->pass ) {
780
			return self::skipped_test( array( 'name' => $name ) );
781
		}
782
783
		$self_xml_rpc_url = site_url( 'xmlrpc.php' );
784
785
		$testsite_url = Connection_Utils::fix_url_for_bad_hosts( JETPACK__API_BASE . 'testsite/1/?url=' );
786
787
		// Using PHP_INT_MAX - 1 so that there is still a way to override this if needed and since it only impacts this one call.
788
		add_filter( 'http_request_timeout', array( 'Jetpack_Cxn_Tests', 'increase_timeout' ), PHP_INT_MAX - 1 );
789
790
		$response = wp_remote_get( $testsite_url . $self_xml_rpc_url );
791
792
		remove_filter( 'http_request_timeout', array( 'Jetpack_Cxn_Tests', 'increase_timeout' ), PHP_INT_MAX - 1 );
793
794
		if ( 200 === wp_remote_retrieve_response_code( $response ) ) {
795
			return self::passing_test( array( 'name' => $name ) );
796
		} elseif ( is_wp_error( $response ) && false !== strpos( $response->get_error_message(), 'cURL error 28' ) ) { // Timeout.
797
			return self::skipped_test(
798
				array(
799
					'name'              => $name,
800
					'short_description' => __( 'The test timed out which may sometimes indicate a failure or may be a false failure.', 'jetpack' ),
801
				)
802
			);
803
		} else {
804
			return self::failing_test(
805
				array(
806
					'name'              => $name,
807
					'short_description' => sprintf(
808
						/* translators: %1$s - A debugging url */
809
						__( 'Jetpack.com detected an error on the WP.com Self Test. Visit the Jetpack Debug page for more info: %1$s, or contact support.', 'jetpack' ),
810
						Redirect::get_url( 'jetpack-support-debug', array( 'query' => 'url=' . rawurlencode( site_url() ) ) )
811
					),
812
					'action_label'      => $this->helper_get_support_text(),
813
					'action'            => $this->helper_get_support_url(),
814
				)
815
			);
816
		}
817
	}
818
}
819