Completed
Push — update/paid-block-frontend-upg... ( 4183a4...e9ae35 )
by Bernhard
79:30 queued 72:33
created

packages/sync/src/Actions.php (3 issues)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
/**
3
 * A class that defines syncable actions for Jetpack.
4
 *
5
 * @package automattic/jetpack-sync
6
 */
7
8
namespace Automattic\Jetpack\Sync;
9
10
use Automattic\Jetpack\Connection\Manager as Jetpack_Connection;
11
use Automattic\Jetpack\Constants;
12
use Automattic\Jetpack\Status;
13
14
/**
15
 * The role of this class is to hook the Sync subsystem into WordPress - when to listen for actions,
16
 * when to send, when to perform a full sync, etc.
17
 *
18
 * It also binds the action to send data to WPCOM to Jetpack's XMLRPC client object.
19
 */
20
class Actions {
21
	/**
22
	 * A variable to hold a sync sender object.
23
	 *
24
	 * @access public
25
	 * @static
26
	 *
27
	 * @var Automattic\Jetpack\Sync\Sender
28
	 */
29
	public static $sender = null;
30
31
	/**
32
	 * A variable to hold a sync listener object.
33
	 *
34
	 * @access public
35
	 * @static
36
	 *
37
	 * @var Automattic\Jetpack\Sync\Listener
38
	 */
39
	public static $listener = null;
40
41
	/**
42
	 * Name of the sync cron schedule.
43
	 *
44
	 * @access public
45
	 *
46
	 * @var string
47
	 */
48
	const DEFAULT_SYNC_CRON_INTERVAL_NAME = 'jetpack_sync_interval';
49
50
	/**
51
	 * Interval between the last and the next sync cron action.
52
	 *
53
	 * @access public
54
	 *
55
	 * @var int
56
	 */
57
	const DEFAULT_SYNC_CRON_INTERVAL_VALUE = 300; // 5 * MINUTE_IN_SECONDS;
58
59
	/**
60
	 * Initialize Sync for cron jobs, set up listeners for WordPress Actions,
61
	 * and set up a shut-down action for sending actions to WordPress.com
62
	 *
63
	 * @access public
64
	 * @static
65
	 */
66
	public static function init() {
67
		// Everything below this point should only happen if we're a valid sync site.
68
		if ( ! self::sync_allowed() ) {
69
			return;
70
		}
71
72
		if ( self::sync_via_cron_allowed() ) {
73
			self::init_sync_cron_jobs();
74
		} elseif ( wp_next_scheduled( 'jetpack_sync_cron' ) ) {
75
			self::clear_sync_cron_jobs();
76
		}
77
		// When importing via cron, do not sync.
78
		add_action( 'wp_cron_importer_hook', array( __CLASS__, 'set_is_importing_true' ), 1 );
79
80
		// Sync connected user role changes to WordPress.com.
81
		Users::init();
82
83
		// Publicize filter to prevent publicizing blacklisted post types.
84
		add_filter( 'publicize_should_publicize_published_post', array( __CLASS__, 'prevent_publicize_blacklisted_posts' ), 10, 2 );
85
86
		/**
87
		 * Fires on every request before default loading sync listener code.
88
		 * Return false to not load sync listener code that monitors common
89
		 * WP actions to be serialized.
90
		 *
91
		 * By default this returns true for cron jobs, non-GET-requests, or requests where the
92
		 * user is logged-in.
93
		 *
94
		 * @since 4.2.0
95
		 *
96
		 * @param bool should we load sync listener code for this request
97
		 */
98
		if ( apply_filters( 'jetpack_sync_listener_should_load', true ) ) {
99
			self::initialize_listener();
100
		}
101
102
		add_action( 'init', array( __CLASS__, 'add_sender_shutdown' ), 90 );
103
	}
104
105
	/**
106
	 * Prepares sync to send actions on shutdown for the current request.
107
	 *
108
	 * @access public
109
	 * @static
110
	 */
111
	public static function add_sender_shutdown() {
112
		/**
113
		 * Fires on every request before default loading sync sender code.
114
		 * Return false to not load sync sender code that serializes pending
115
		 * data and sends it to WPCOM for processing.
116
		 *
117
		 * By default this returns true for cron jobs, POST requests, admin requests, or requests
118
		 * by users who can manage_options.
119
		 *
120
		 * @since 4.2.0
121
		 *
122
		 * @param bool should we load sync sender code for this request
123
		 */
124
		if ( apply_filters(
125
			'jetpack_sync_sender_should_load',
126
			self::should_initialize_sender()
127
		) ) {
128
			self::initialize_sender();
129
			add_action( 'shutdown', array( self::$sender, 'do_sync' ) );
130
			add_action( 'shutdown', array( self::$sender, 'do_full_sync' ) );
131
		}
132
	}
133
134
	/**
135
	 * Decides if the sender should run on shutdown for this request.
136
	 *
137
	 * @access public
138
	 * @static
139
	 *
140
	 * @return bool
141
	 */
142
	public static function should_initialize_sender() {
143
		if ( Constants::is_true( 'DOING_CRON' ) ) {
144
			return self::sync_via_cron_allowed();
145
		}
146
147
		if ( isset( $_SERVER['REQUEST_METHOD'] ) && 'POST' === $_SERVER['REQUEST_METHOD'] ) {
148
			return true;
149
		}
150
151
		if ( current_user_can( 'manage_options' ) ) {
152
			return true;
153
		}
154
155
		if ( is_admin() ) {
156
			return true;
157
		}
158
159
		if ( defined( 'PHPUNIT_JETPACK_TESTSUITE' ) ) {
160
			return true;
161
		}
162
163
		return false;
164
	}
165
166
	/**
167
	 * Decides if sync should run at all during this request.
168
	 *
169
	 * @access public
170
	 * @static
171
	 *
172
	 * @return bool
173
	 */
174
	public static function sync_allowed() {
175
		if ( defined( 'PHPUNIT_JETPACK_TESTSUITE' ) ) {
176
			return true;
177
		}
178
179
		if ( ! Settings::is_sync_enabled() ) {
180
			return false;
181
		}
182
183
		$status = new Status();
184
		if ( $status->is_development_mode() ) {
185
			return false;
186
		}
187
188
		if ( \Jetpack::is_staging_site() ) {
189
			return false;
190
		}
191
192
		$connection = new Jetpack_Connection();
193
		if ( ! $connection->is_active() ) {
194
			if ( ! doing_action( 'jetpack_user_authorized' ) ) {
195
				return false;
196
			}
197
		}
198
199
		return true;
200
	}
201
202
	/**
203
	 * Determines if syncing during a cron job is allowed.
204
	 *
205
	 * @access public
206
	 * @static
207
	 *
208
	 * @return bool|int
209
	 */
210
	public static function sync_via_cron_allowed() {
211
		return ( Settings::get_setting( 'sync_via_cron' ) );
212
	}
213
214
	/**
215
	 * Decides if the given post should be Publicized based on its type.
216
	 *
217
	 * @access public
218
	 * @static
219
	 *
220
	 * @param bool     $should_publicize  Publicize status prior to this filter running.
221
	 * @param \WP_Post $post              The post to test for Publicizability.
222
	 * @return bool
223
	 */
224
	public static function prevent_publicize_blacklisted_posts( $should_publicize, $post ) {
225
		if ( in_array( $post->post_type, Settings::get_setting( 'post_types_blacklist' ), true ) ) {
226
			return false;
227
		}
228
229
		return $should_publicize;
230
	}
231
232
	/**
233
	 * Set an importing flag to `true` in sync settings.
234
	 *
235
	 * @access public
236
	 * @static
237
	 */
238
	public static function set_is_importing_true() {
239
		Settings::set_importing( true );
240
	}
241
242
	/**
243
	 * Sends data to WordPress.com via an XMLRPC request.
244
	 *
245
	 * @access public
246
	 * @static
247
	 *
248
	 * @param object $data                   Data relating to a sync action.
249
	 * @param string $codec_name             The name of the codec that encodes the data.
250
	 * @param float  $sent_timestamp         Current server time so we can compensate for clock differences.
251
	 * @param string $queue_id               The queue the action belongs to, sync or full_sync.
252
	 * @param float  $checkout_duration      Time spent retrieving queue items from the DB.
253
	 * @param float  $preprocess_duration    Time spent converting queue items into data to send.
254
	 * @return Jetpack_Error|mixed|WP_Error  The result of the sending request.
255
	 */
256
	public static function send_data( $data, $codec_name, $sent_timestamp, $queue_id, $checkout_duration, $preprocess_duration ) {
257
		\Jetpack::load_xml_rpc_client();
258
259
		$query_args = array(
260
			'sync'      => '1',             // Add an extra parameter to the URL so we can tell it's a sync action.
261
			'codec'     => $codec_name,
262
			'timestamp' => $sent_timestamp,
263
			'queue'     => $queue_id,
264
			'home'      => Functions::home_url(),  // Send home url option to check for Identity Crisis server-side.
265
			'siteurl'   => Functions::site_url(),  // Send siteurl option to check for Identity Crisis server-side.
266
			'cd'        => sprintf( '%.4f', $checkout_duration ),
267
			'pd'        => sprintf( '%.4f', $preprocess_duration ),
268
		);
269
270
		// Has the site opted in to IDC mitigation?
271
		if ( \Jetpack::sync_idc_optin() ) {
272
			$query_args['idc'] = true;
273
		}
274
275
		if ( \Jetpack_Options::get_option( 'migrate_for_idc', false ) ) {
276
			$query_args['migrate_for_idc'] = true;
277
		}
278
279
		$query_args['timeout'] = Settings::is_doing_cron() ? 30 : 15;
280
281
		/**
282
		 * Filters query parameters appended to the Sync request URL sent to WordPress.com.
283
		 *
284
		 * @since 4.7.0
285
		 *
286
		 * @param array $query_args associative array of query parameters.
287
		 */
288
		$query_args = apply_filters( 'jetpack_sync_send_data_query_args', $query_args );
289
290
		$url = add_query_arg( $query_args, \Jetpack::xmlrpc_api_url() );
291
292
		$rpc = new \Jetpack_IXR_Client(
293
			array(
294
				'url'     => $url,
295
				'user_id' => JETPACK_MASTER_USER,
296
				'timeout' => $query_args['timeout'],
297
			)
298
		);
299
300
		$result = $rpc->query( 'jetpack.syncActions', $data );
301
302
		if ( ! $result ) {
303
			return $rpc->get_jetpack_error();
304
		}
305
306
		$response = $rpc->getResponse();
307
308
		// Check if WordPress.com IDC mitigation blocked the sync request.
309
		if ( is_array( $response ) && isset( $response['error_code'] ) ) {
310
			$error_code              = $response['error_code'];
311
			$allowed_idc_error_codes = array(
312
				'jetpack_url_mismatch',
313
				'jetpack_home_url_mismatch',
314
				'jetpack_site_url_mismatch',
315
			);
316
317
			if ( in_array( $error_code, $allowed_idc_error_codes, true ) ) {
318
				\Jetpack_Options::update_option(
319
					'sync_error_idc',
320
					\Jetpack::get_sync_error_idc_option( $response )
321
				);
322
			}
323
324
			return new \WP_Error(
325
				'sync_error_idc',
326
				esc_html__( 'Sync has been blocked from WordPress.com because it would cause an identity crisis', 'jetpack' )
327
			);
328
		}
329
330
		return $response;
331
	}
332
333
	/**
334
	 * Kicks off the initial sync.
335
	 *
336
	 * @access public
337
	 * @static
338
	 *
339
	 * @return bool|null False if sync is not allowed.
340
	 */
341
	public static function do_initial_sync() {
342
		// Lets not sync if we are not suppose to.
343
		if ( ! self::sync_allowed() ) {
344
			return false;
345
		}
346
347
		$initial_sync_config = array(
348
			'options'   => true,
349
			'functions' => true,
350
			'constants' => true,
351
			'users'     => array( get_current_user_id() ),
352
		);
353
354
		if ( is_multisite() ) {
355
			$initial_sync_config['network_options'] = true;
356
		}
357
358
		self::do_full_sync( $initial_sync_config );
359
	}
360
361
	/**
362
	 * Kicks off a full sync.
363
	 *
364
	 * @access public
365
	 * @static
366
	 *
367
	 * @param array $modules  The sync modules should be included in this full sync. All will be included if null.
0 ignored issues
show
Should the type for parameter $modules not be array|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...
368
	 * @return bool           True if full sync was successfully started.
369
	 */
370
	public static function do_full_sync( $modules = null ) {
371
		if ( ! self::sync_allowed() ) {
372
			return false;
373
		}
374
375
		$full_sync_module = Modules::get_module( 'full-sync' );
376
377
		if ( ! $full_sync_module ) {
378
			return false;
379
		}
380
381
		self::initialize_listener();
382
383
		$full_sync_module->start( $modules );
384
385
		return true;
386
	}
387
388
	/**
389
	 * Adds a cron schedule for regular syncing via cron, unless the schedule already exists.
390
	 *
391
	 * @access public
392
	 * @static
393
	 *
394
	 * @param array $schedules  The list of WordPress cron schedules prior to this filter.
395
	 * @return array            A list of WordPress cron schedules with the Jetpack sync interval added.
396
	 */
397
	public static function jetpack_cron_schedule( $schedules ) {
398
		if ( ! isset( $schedules[ self::DEFAULT_SYNC_CRON_INTERVAL_NAME ] ) ) {
399
			$minutes = intval( self::DEFAULT_SYNC_CRON_INTERVAL_VALUE / 60 );
400
			$display = ( 1 === $minutes ) ?
401
				__( 'Every minute', 'jetpack' ) :
402
				/* translators: %d is an integer indicating the number of minutes. */
403
				sprintf( __( 'Every %d minutes', 'jetpack' ), $minutes );
404
			$schedules[ self::DEFAULT_SYNC_CRON_INTERVAL_NAME ] = array(
405
				'interval' => self::DEFAULT_SYNC_CRON_INTERVAL_VALUE,
406
				'display'  => $display,
407
			);
408
		}
409
		return $schedules;
410
	}
411
412
	/**
413
	 * Starts an incremental sync via cron.
414
	 *
415
	 * @access public
416
	 * @static
417
	 */
418
	public static function do_cron_sync() {
419
		self::do_cron_sync_by_type( 'sync' );
420
	}
421
422
	/**
423
	 * Starts a full sync via cron.
424
	 *
425
	 * @access public
426
	 * @static
427
	 */
428
	public static function do_cron_full_sync() {
429
		self::do_cron_sync_by_type( 'full_sync' );
430
	}
431
432
	/**
433
	 * Try to send actions until we run out of things to send,
434
	 * or have to wait more than 15s before sending again,
435
	 * or we hit a lock or some other sending issue
436
	 *
437
	 * @access public
438
	 * @static
439
	 *
440
	 * @param string $type Sync type. Can be `sync` or `full_sync`.
441
	 */
442
	public static function do_cron_sync_by_type( $type ) {
443
		if ( ! self::sync_allowed() || ( 'sync' !== $type && 'full_sync' !== $type ) ) {
444
			return;
445
		}
446
447
		self::initialize_sender();
448
449
		$time_limit = Settings::get_setting( 'cron_sync_time_limit' );
450
		$start_time = time();
451
452
		do {
453
			$next_sync_time = self::$sender->get_next_sync_time( $type );
454
455
			if ( $next_sync_time ) {
456
				$delay = $next_sync_time - time() + 1;
457
				if ( $delay > 15 ) {
458
					break;
459
				} elseif ( $delay > 0 ) {
460
					sleep( $delay );
461
				}
462
			}
463
464
			$result = 'full_sync' === $type ? self::$sender->do_full_sync() : self::$sender->do_sync();
465
		} while ( $result && ! is_wp_error( $result ) && ( $start_time + $time_limit ) > time() );
466
	}
467
468
	/**
469
	 * Initialize the sync listener.
470
	 *
471
	 * @access public
472
	 * @static
473
	 */
474
	public static function initialize_listener() {
475
		self::$listener = Listener::get_instance();
476
	}
477
478
	/**
479
	 * Initializes the sync sender.
480
	 *
481
	 * @access public
482
	 * @static
483
	 */
484
	public static function initialize_sender() {
485
		self::$sender = Sender::get_instance();
486
		add_filter( 'jetpack_sync_send_data', array( __CLASS__, 'send_data' ), 10, 6 );
487
	}
488
489
	/**
490
	 * Initializes sync for WooCommerce.
491
	 *
492
	 * @access public
493
	 * @static
494
	 */
495
	public static function initialize_woocommerce() {
496
		if ( false === class_exists( 'WooCommerce' ) ) {
497
			return;
498
		}
499
		add_filter( 'jetpack_sync_modules', array( __CLASS__, 'add_woocommerce_sync_module' ) );
500
	}
501
502
	/**
503
	 * Adds Woo's sync modules to existing modules for sending.
504
	 *
505
	 * @access public
506
	 * @static
507
	 *
508
	 * @param array $sync_modules The list of sync modules declared prior to this filter.
509
	 * @return array A list of sync modules that now includes Woo's modules.
510
	 */
511
	public static function add_woocommerce_sync_module( $sync_modules ) {
512
		$sync_modules[] = 'Automattic\\Jetpack\\Sync\\Modules\\WooCommerce';
513
		return $sync_modules;
514
	}
515
516
	/**
517
	 * Initializes sync for WP Super Cache.
518
	 *
519
	 * @access public
520
	 * @static
521
	 */
522
	public static function initialize_wp_super_cache() {
523
		if ( false === function_exists( 'wp_cache_is_enabled' ) ) {
524
			return;
525
		}
526
		add_filter( 'jetpack_sync_modules', array( __CLASS__, 'add_wp_super_cache_sync_module' ) );
527
	}
528
529
	/**
530
	 * Adds WP Super Cache's sync modules to existing modules for sending.
531
	 *
532
	 * @access public
533
	 * @static
534
	 *
535
	 * @param array $sync_modules The list of sync modules declared prior to this filer.
536
	 * @return array A list of sync modules that now includes WP Super Cache's modules.
537
	 */
538
	public static function add_wp_super_cache_sync_module( $sync_modules ) {
539
		$sync_modules[] = 'Automattic\\Jetpack\\Sync\\Modules\\WP_Super_Cache';
540
		return $sync_modules;
541
	}
542
543
	/**
544
	 * Sanitizes the name of sync's cron schedule.
545
	 *
546
	 * @access public
547
	 * @static
548
	 *
549
	 * @param string $schedule The name of a WordPress cron schedule.
550
	 * @return string The sanitized name of sync's cron schedule.
551
	 */
552
	public static function sanitize_filtered_sync_cron_schedule( $schedule ) {
553
		$schedule  = sanitize_key( $schedule );
554
		$schedules = wp_get_schedules();
555
556
		// Make sure that the schedule has actually been registered using the `cron_intervals` filter.
557
		if ( isset( $schedules[ $schedule ] ) ) {
558
			return $schedule;
559
		}
560
561
		return self::DEFAULT_SYNC_CRON_INTERVAL_NAME;
562
	}
563
564
	/**
565
	 * Allows offsetting of start times for sync cron jobs.
566
	 *
567
	 * @access public
568
	 * @static
569
	 *
570
	 * @param string $schedule The name of a cron schedule.
571
	 * @param string $hook     The hook that this method is responding to.
572
	 * @return int The offset for the sync cron schedule.
573
	 */
574
	public static function get_start_time_offset( $schedule = '', $hook = '' ) {
575
		$start_time_offset = is_multisite()
576
			? wp_rand( 0, ( 2 * self::DEFAULT_SYNC_CRON_INTERVAL_VALUE ) )
577
			: 0;
578
579
		/**
580
		 * Allows overriding the offset that the sync cron jobs will first run. This can be useful when scheduling
581
		 * cron jobs across multiple sites in a network.
582
		 *
583
		 * @since 4.5.0
584
		 *
585
		 * @param int    $start_time_offset
586
		 * @param string $hook
587
		 * @param string $schedule
588
		 */
589
		return intval(
590
			apply_filters(
591
				'jetpack_sync_cron_start_time_offset',
592
				$start_time_offset,
593
				$hook,
594
				$schedule
595
			)
596
		);
597
	}
598
599
	/**
600
	 * Decides if a sync cron should be scheduled.
601
	 *
602
	 * @access public
603
	 * @static
604
	 *
605
	 * @param string $schedule The name of a cron schedule.
606
	 * @param string $hook     The hook that this method is responding to.
607
	 */
608
	public static function maybe_schedule_sync_cron( $schedule, $hook ) {
609
		if ( ! $hook ) {
610
			return;
611
		}
612
		$schedule = self::sanitize_filtered_sync_cron_schedule( $schedule );
613
614
		$start_time = time() + self::get_start_time_offset( $schedule, $hook );
615
		if ( ! wp_next_scheduled( $hook ) ) {
616
			// Schedule a job to send pending queue items once a minute.
617
			wp_schedule_event( $start_time, $schedule, $hook );
618
		} elseif ( wp_get_schedule( $hook ) !== $schedule ) {
619
			// If the schedule has changed, update the schedule.
620
			wp_clear_scheduled_hook( $hook );
621
			wp_schedule_event( $start_time, $schedule, $hook );
622
		}
623
	}
624
625
	/**
626
	 * Clears Jetpack sync cron jobs.
627
	 *
628
	 * @access public
629
	 * @static
630
	 */
631
	public static function clear_sync_cron_jobs() {
632
		wp_clear_scheduled_hook( 'jetpack_sync_cron' );
633
		wp_clear_scheduled_hook( 'jetpack_sync_full_cron' );
634
	}
635
636
	/**
637
	 * Initializes Jetpack sync cron jobs.
638
	 *
639
	 * @access public
640
	 * @static
641
	 */
642
	public static function init_sync_cron_jobs() {
643
		add_filter( 'cron_schedules', array( __CLASS__, 'jetpack_cron_schedule' ) );
644
645
		add_action( 'jetpack_sync_cron', array( __CLASS__, 'do_cron_sync' ) );
646
		add_action( 'jetpack_sync_full_cron', array( __CLASS__, 'do_cron_full_sync' ) );
647
648
		/**
649
		 * Allows overriding of the default incremental sync cron schedule which defaults to once every 5 minutes.
650
		 *
651
		 * @since 4.3.2
652
		 *
653
		 * @param string self::DEFAULT_SYNC_CRON_INTERVAL_NAME
654
		 */
655
		$incremental_sync_cron_schedule = apply_filters( 'jetpack_sync_incremental_sync_interval', self::DEFAULT_SYNC_CRON_INTERVAL_NAME );
656
		self::maybe_schedule_sync_cron( $incremental_sync_cron_schedule, 'jetpack_sync_cron' );
657
658
		/**
659
		 * Allows overriding of the full sync cron schedule which defaults to once every 5 minutes.
660
		 *
661
		 * @since 4.3.2
662
		 *
663
		 * @param string self::DEFAULT_SYNC_CRON_INTERVAL_NAME
664
		 */
665
		$full_sync_cron_schedule = apply_filters( 'jetpack_sync_full_sync_interval', self::DEFAULT_SYNC_CRON_INTERVAL_NAME );
666
		self::maybe_schedule_sync_cron( $full_sync_cron_schedule, 'jetpack_sync_full_cron' );
667
	}
668
669
	/**
670
	 * Perform maintenance when a plugin upgrade occurs.
671
	 *
672
	 * @access public
673
	 * @static
674
	 *
675
	 * @param string $new_version New version of the plugin.
0 ignored issues
show
Should the type for parameter $new_version not be string|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...
676
	 * @param string $old_version Old version of the plugin.
0 ignored issues
show
Should the type for parameter $old_version not be string|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...
677
	 */
678
	public static function cleanup_on_upgrade( $new_version = null, $old_version = null ) {
679
		if ( wp_next_scheduled( 'jetpack_sync_send_db_checksum' ) ) {
680
			wp_clear_scheduled_hook( 'jetpack_sync_send_db_checksum' );
681
		}
682
683
		$is_new_sync_upgrade = version_compare( $old_version, '4.2', '>=' );
684
		if ( ! empty( $old_version ) && $is_new_sync_upgrade && version_compare( $old_version, '4.5', '<' ) ) {
685
			self::clear_sync_cron_jobs();
686
			Settings::update_settings(
687
				array(
688
					'render_filtered_content' => Defaults::$default_render_filtered_content,
689
				)
690
			);
691
		}
692
	}
693
694
	/**
695
	 * Get syncing status for the given fields.
696
	 *
697
	 * @access public
698
	 * @static
699
	 *
700
	 * @param string|null $fields A comma-separated string of the fields to include in the array from the JSON response.
701
	 * @return array An associative array with the status report.
702
	 */
703
	public static function get_sync_status( $fields = null ) {
704
		self::initialize_sender();
705
706
		$sync_module     = Modules::get_module( 'full-sync' );
707
		$queue           = self::$sender->get_sync_queue();
708
		$full_queue      = self::$sender->get_full_sync_queue();
709
		$cron_timestamps = array_keys( _get_cron_array() );
710
		$next_cron       = $cron_timestamps[0] - time();
711
712
		$checksums = array();
713
714
		if ( ! empty( $fields ) ) {
715
			$store         = new Replicastore();
716
			$fields_params = array_map( 'trim', explode( ',', $fields ) );
717
718
			if ( in_array( 'posts_checksum', $fields_params, true ) ) {
719
				$checksums['posts_checksum'] = $store->posts_checksum();
720
			}
721
			if ( in_array( 'comments_checksum', $fields_params, true ) ) {
722
				$checksums['comments_checksum'] = $store->comments_checksum();
723
			}
724
			if ( in_array( 'post_meta_checksum', $fields_params, true ) ) {
725
				$checksums['post_meta_checksum'] = $store->post_meta_checksum();
726
			}
727
			if ( in_array( 'comment_meta_checksum', $fields_params, true ) ) {
728
				$checksums['comment_meta_checksum'] = $store->comment_meta_checksum();
729
			}
730
		}
731
732
		$full_sync_status = ( $sync_module ) ? $sync_module->get_status() : array();
733
734
		return array_merge(
735
			$full_sync_status,
736
			$checksums,
737
			array(
738
				'cron_size'            => count( $cron_timestamps ),
739
				'next_cron'            => $next_cron,
740
				'queue_size'           => $queue->size(),
741
				'queue_lag'            => $queue->lag(),
742
				'queue_next_sync'      => ( self::$sender->get_next_sync_time( 'sync' ) - microtime( true ) ),
743
				'full_queue_size'      => $full_queue->size(),
744
				'full_queue_lag'       => $full_queue->lag(),
745
				'full_queue_next_sync' => ( self::$sender->get_next_sync_time( 'full_sync' ) - microtime( true ) ),
746
			)
747
		);
748
	}
749
}
750