to existing modules for sending. * * @access public * @static * * @param array $sync_modules The list of sync modules declared prior to this filer. * @return array A list of sync modules that now includes WP Super Cache's modules. */ public static function add_wp_super_cache_sync_module( $sync_modules ) { $sync_modules[] = 'Automattic\\Jetpack\\Sync\\Modules\\WP_Super_Cache'; return $sync_modules; } /** * Sanitizes the name of sync's cron schedule. * * @access public * @static * * @param string $schedule The name of a WordPress cron schedule. * @return string The sanitized name of sync's cron schedule. */ public static function sanitize_filtered_sync_cron_schedule( $schedule ) { $schedule = sanitize_key( $schedule ); $schedules = wp_get_schedules(); // Make sure that the schedule has actually been registered using the `cron_intervals` filter. if ( isset( $schedules[ $schedule ] ) ) { return $schedule; } return self::DEFAULT_SYNC_CRON_INTERVAL_NAME; } /** * Allows offsetting of start times for sync cron jobs. * * @access public * @static * * @param string $schedule The name of a cron schedule. * @param string $hook The hook that this method is responding to. * @return int The offset for the sync cron schedule. */ public static function get_start_time_offset( $schedule = '', $hook = '' ) { $start_time_offset = is_multisite() ? wp_rand( 0, ( 2 * self::DEFAULT_SYNC_CRON_INTERVAL_VALUE ) ) : 0; /** * Allows overriding the offset that the sync cron jobs will first run. This can be useful when scheduling * cron jobs across multiple sites in a network. * * @since 1.6.3 * @since-jetpack 4.5.0 * * @param int $start_time_offset * @param string $hook * @param string $schedule */ return (int) apply_filters( 'jetpack_sync_cron_start_time_offset', $start_time_offset, $hook, $schedule ); } /** * Decides if a sync cron should be scheduled. * * @access public * @static * * @param string $schedule The name of a cron schedule. * @param string $hook The hook that this method is responding to. */ public static function maybe_schedule_sync_cron( $schedule, $hook ) { if ( ! $hook ) { return; } $schedule = self::sanitize_filtered_sync_cron_schedule( $schedule ); $start_time = time() + self::get_start_time_offset( $schedule, $hook ); if ( ! wp_next_scheduled( $hook ) ) { // Schedule a job to send pending queue items once a minute. wp_schedule_event( $start_time, $schedule, $hook ); } elseif ( wp_get_schedule( $hook ) !== $schedule ) { // If the schedule has changed, update the schedule. wp_clear_scheduled_hook( $hook ); wp_schedule_event( $start_time, $schedule, $hook ); } } /** * Clears Jetpack sync cron jobs. * * @access public * @static */ public static function clear_sync_cron_jobs() { wp_clear_scheduled_hook( 'jetpack_sync_cron' ); wp_clear_scheduled_hook( 'jetpack_sync_full_cron' ); } /** * Initializes Jetpack sync cron jobs. * * @access public * @static */ public static function init_sync_cron_jobs() { add_filter( 'cron_schedules', array( __CLASS__, 'jetpack_cron_schedule' ) ); // phpcs:ignore WordPress.WP.CronInterval.ChangeDetected add_action( 'jetpack_sync_cron', array( __CLASS__, 'do_cron_sync' ) ); add_action( 'jetpack_sync_full_cron', array( __CLASS__, 'do_cron_full_sync' ) ); /** * Allows overriding of the default incremental sync cron schedule which defaults to once every 5 minutes. * * @since 1.6.3 * @since-jetpack 4.3.2 * * @param string self::DEFAULT_SYNC_CRON_INTERVAL_NAME */ $incremental_sync_cron_schedule = apply_filters( 'jetpack_sync_incremental_sync_interval', self::DEFAULT_SYNC_CRON_INTERVAL_NAME ); self::maybe_schedule_sync_cron( $incremental_sync_cron_schedule, 'jetpack_sync_cron' ); /** * Allows overriding of the full sync cron schedule which defaults to once every 5 minutes. * * @since 1.6.3 * @since-jetpack 4.3.2 * * @param string self::DEFAULT_SYNC_CRON_INTERVAL_NAME */ $full_sync_cron_schedule = apply_filters( 'jetpack_sync_full_sync_interval', self::DEFAULT_SYNC_CRON_INTERVAL_NAME ); self::maybe_schedule_sync_cron( $full_sync_cron_schedule, 'jetpack_sync_full_cron' ); } /** * Perform maintenance when a plugin upgrade occurs. * * @access public * @static * * @param string $new_version New version of the plugin. * @param string $old_version Old version of the plugin. */ public static function cleanup_on_upgrade( $new_version = '', $old_version = '' ) { if ( wp_next_scheduled( 'jetpack_sync_send_db_checksum' ) ) { wp_clear_scheduled_hook( 'jetpack_sync_send_db_checksum' ); } $is_new_sync_upgrade = version_compare( $old_version, '4.2', '>=' ); if ( ! empty( $old_version ) && $is_new_sync_upgrade && version_compare( $old_version, '4.5', '<' ) ) { self::clear_sync_cron_jobs(); Settings::update_settings( array( 'render_filtered_content' => Defaults::$default_render_filtered_content, ) ); } Health::on_jetpack_upgraded(); } /** * Get syncing status for the given fields. * * @access public * @static * * @param string|null $fields A comma-separated string of the fields to include in the array from the JSON response. * @return array An associative array with the status report. */ public static function get_sync_status( $fields = null ) { self::initialize_sender(); $sync_module = Modules::get_module( 'full-sync' ); $queue = self::$sender->get_sync_queue(); // _get_cron_array can be false $cron_timestamps = ( _get_cron_array() ) ? array_keys( _get_cron_array() ) : array(); $next_cron = ( ! empty( $cron_timestamps ) ) ? $cron_timestamps[0] - time() : ''; $checksums = array(); $debug = array(); if ( ! empty( $fields ) ) { $store = new Replicastore(); $fields_params = array_map( 'trim', explode( ',', $fields ) ); if ( in_array( 'posts_checksum', $fields_params, true ) ) { $checksums['posts_checksum'] = $store->posts_checksum(); } if ( in_array( 'comments_checksum', $fields_params, true ) ) { $checksums['comments_checksum'] = $store->comments_checksum(); } if ( in_array( 'post_meta_checksum', $fields_params, true ) ) { $checksums['post_meta_checksum'] = $store->post_meta_checksum(); } if ( in_array( 'comment_meta_checksum', $fields_params, true ) ) { $checksums['comment_meta_checksum'] = $store->comment_meta_checksum(); } if ( in_array( 'debug_details', $fields_params, true ) ) { $debug = self::get_debug_details(); } } $full_sync_status = ( $sync_module ) ? $sync_module->get_status() : array(); $full_queue = self::$sender->get_full_sync_queue(); $result = array_merge( $full_sync_status, $checksums, $debug, array( 'cron_size' => count( $cron_timestamps ), 'next_cron' => $next_cron, 'queue_size' => $queue->size(), 'queue_lag' => $queue->lag(), 'queue_next_sync' => ( self::$sender->get_next_sync_time( 'sync' ) - microtime( true ) ), 'full_queue_next_sync' => ( self::$sender->get_next_sync_time( 'full_sync' ) - microtime( true ) ), ) ); // Verify $sync_module is not false. if ( ( $sync_module ) && ! str_contains( get_class( $sync_module ), 'Full_Sync_Immediately' ) ) { $result['full_queue_size'] = $full_queue->size(); $result['full_queue_lag'] = $full_queue->lag(); } return $result; } /** * Reset Sync locks. * * @access public * @static * @since 1.43.0 * * @param bool $unlock_queues Whether to unlock Sync queues. Defaults to true. */ public static function reset_sync_locks( $unlock_queues = true ) { // Next sync locks. delete_option( Sender::NEXT_SYNC_TIME_OPTION_NAME . '_sync' ); delete_option( Sender::NEXT_SYNC_TIME_OPTION_NAME . '_full_sync' ); delete_option( Sender::NEXT_SYNC_TIME_OPTION_NAME . '_full-sync-enqueue' ); // Retry after locks. delete_option( self::RETRY_AFTER_PREFIX . 'sync' ); delete_option( self::RETRY_AFTER_PREFIX . 'full_sync' ); // Dedicated sync locks. \Jetpack_Options::delete_raw_option( Dedicated_Sender::DEDICATED_SYNC_REQUEST_LOCK_OPTION_NAME ); delete_transient( Dedicated_Sender::DEDICATED_SYNC_TEMPORARY_DISABLE_FLAG ); // Queue locks. // Note that we are just unlocking the queues here, not reseting them. if ( $unlock_queues ) { $sync_queue = new Queue( 'sync' ); $sync_queue->unlock(); $full_sync_queue = new Queue( 'full_sync' ); $full_sync_queue->unlock(); } } }