From 7a652a7c43d9f53dc7890beca74f864c3e6b2bfe Mon Sep 17 00:00:00 2001 From: Raam Dev Date: Sun, 6 Dec 2015 21:43:12 -0500 Subject: [PATCH] Improve WP Cron setup and validation of schedules See websharks/zencache#613 --- src/includes/classes/Plugin.php | 21 ++------- src/includes/closures/Plugin/CronUtils.php | 46 ++++++++++++++++++- src/includes/closures/Plugin/InstallUtils.php | 4 +- 3 files changed, 51 insertions(+), 20 deletions(-) diff --git a/src/includes/classes/Plugin.php b/src/includes/classes/Plugin.php index 96b914b1..4def7633 100644 --- a/src/includes/classes/Plugin.php +++ b/src/includes/classes/Plugin.php @@ -255,8 +255,11 @@ public function setup() /* Core/systematic plugin options. */ 'version' => VERSION, - 'crons_setup' => '0', // `0` or timestamp. 'welcomed' => '0', // `0|1` welcomed yet? + 'crons_setup' => '0', // A timestamp when last set up. + 'crons_setup_on_namespace' => '', // The namespace on which they were set up. + 'crons_setup_with_cache_cleanup_schedule' => '', // The cleanup schedule selected by site owner during last setup. + 'crons_setup_on_wp_with_schedules' => '', // A sha1 hash of `wp_get_schedules()` /* Primary switch; enable? */ @@ -428,6 +431,7 @@ public function setup() add_action('init', array($this, 'checkAdvancedCache')); add_action('init', array($this, 'checkBlogPaths')); + add_action('init', array($this, 'checkCronSetup'), PHP_INT_MAX); add_action('wp_loaded', array($this, 'actions')); add_action('admin_init', array($this, 'checkVersion')); @@ -543,21 +547,6 @@ public function setup() if (!is_multisite() || is_main_site()) { // Main site only. add_filter('cron_schedules', array($this, 'extendCronSchedules')); - - if ($_schedules = wp_get_schedules() && !isset($_schedules[$this->options['cache_cleanup_schedule']])) { // Schedule no longer exists; reset to default - $this->updateOptions(array('cache_cleanup_schedule' => $this->default_options['cache_cleanup_schedule'], 'crons_setup' => '0')); - unset($_schedules); - } - if ((integer) $this->options['crons_setup'] < 1449411081 || substr($this->options['crons_setup'], 10) !== '-'.__NAMESPACE__.'-'.$this->options['cache_cleanup_schedule']) { - wp_clear_scheduled_hook('_cron_'.GLOBAL_NS.'_cleanup'); - wp_schedule_event(time() + 60, $this->options['cache_cleanup_schedule'], '_cron_'.GLOBAL_NS.'_cleanup'); - - /*[pro strip-from="lite"]*/ // Auto-cache engine. - wp_clear_scheduled_hook('_cron_'.GLOBAL_NS.'_auto_cache'); - wp_schedule_event(time() + 60, 'every15m', '_cron_'.GLOBAL_NS.'_auto_cache'); - /*[/pro]*/ - $this->updateOptions(array('crons_setup' => time().'-'.__NAMESPACE__.'-'.$this->options['cache_cleanup_schedule'])); - } add_action('_cron_'.GLOBAL_NS.'_cleanup', array($this, 'cleanupCache')); /*[pro strip-from="lite"]*/ // Auto-cache engine. diff --git a/src/includes/closures/Plugin/CronUtils.php b/src/includes/closures/Plugin/CronUtils.php index c14e8f04..f9810f92 100644 --- a/src/includes/closures/Plugin/CronUtils.php +++ b/src/includes/closures/Plugin/CronUtils.php @@ -20,6 +20,41 @@ return $schedules; }; +/* + * Checks Cron setup, validates schedules, and reschedules events if necessary. + * + * @attaches-to `init` hook. + * + * @since 15xxxx Improving WP Cron setup and validation of schedules + */ +$self->checkCronSetup = function () use ($self) { + if ($self->options['crons_setup'] < 1439005906 + || $self->options['crons_setup_on_namespace'] !== __NAMESPACE__ + || $self->options['crons_setup_with_cache_cleanup_schedule'] !== $self->options['cache_cleanup_schedule'] + || $self->options['crons_setup_on_wp_with_schedules'] !== sha1(serialize(wp_get_schedules())) + || !wp_next_scheduled('_cron_'.GLOBAL_NS.'_cleanup') + || !wp_next_scheduled('_cron_'.GLOBAL_NS.'_auto_cache') + ) { + + wp_clear_scheduled_hook('_cron_'.GLOBAL_NS.'_cleanup'); + wp_schedule_event(time() + 60, $self->options['cache_cleanup_schedule'], '_cron_'.GLOBAL_NS.'_cleanup'); + + /*[pro strip-from="lite"]*/ // Auto-cache engine. + wp_clear_scheduled_hook('_cron_'.GLOBAL_NS.'_auto_cache'); + wp_schedule_event(time() + 60, 'every15m', '_cron_'.GLOBAL_NS.'_auto_cache'); + /*[/pro]*/ + + $self->updateOptions( + array( + 'crons_setup' => time(), + 'crons_setup_on_namespace' => __NAMESPACE__, + 'crons_setup_with_cache_cleanup_schedule' => $self->options['cache_cleanup_schedule'], + 'crons_setup_on_wp_with_schedules' => sha1(serialize(wp_get_schedules())) + ) + ); + } +}; + /* * Resets `crons_setup` and clears WP-Cron schedules. * @@ -27,7 +62,7 @@ * * @note This MUST happen upon uninstall and deactivation due to buggy WP_Cron behavior. Events with a custom schedule will disappear when plugin is not active (see http://bit.ly/1lGdr78). */ -$self->resetCronsSetup = function ( ) use ($self) { +$self->resetCronSetup = function ( ) use ($self) { if (is_multisite()) { // Main site CRON jobs. switch_to_blog(get_current_site()->blog_id); wp_clear_scheduled_hook('_cron_'.GLOBAL_NS.'_auto_cache'); @@ -37,5 +72,12 @@ wp_clear_scheduled_hook('_cron_'.GLOBAL_NS.'_auto_cache'); wp_clear_scheduled_hook('_cron_'.GLOBAL_NS.'_cleanup'); } - $self->updateOptions(array('crons_setup' => '0')); // Reset so that crons are rescheduled upon next activation + $self->updateOptions( + array( // Reset so that crons are rescheduled upon next activation + 'crons_setup' => $self->default_options['crons_setup'], + 'crons_setup_on_namespace' => $self->default_options['crons_setup_on_namespace'], + 'crons_setup_with_cache_cleanup_schedule' => $self->default_options['crons_setup_with_cache_cleanup_schedule'], + 'crons_setup_on_wp_with_schedules' => $self->default_options['crons_setup_on_wp_with_schedules'] + ) + ); }; diff --git a/src/includes/closures/Plugin/InstallUtils.php b/src/includes/closures/Plugin/InstallUtils.php index 9dd664ed..f789048b 100644 --- a/src/includes/closures/Plugin/InstallUtils.php +++ b/src/includes/closures/Plugin/InstallUtils.php @@ -69,7 +69,7 @@ $self->removeWpHtaccess(); $self->removeAdvancedCache(); $self->clearCache(); - $self->resetCronsSetup(); + $self->resetCronSetup(); }; /* @@ -93,7 +93,7 @@ $self->removeWpHtaccess(); $self->removeAdvancedCache(); $self->wipeCache(); - $self->resetCronsSetup(); + $self->resetCronSetup(); if (!$self->options['uninstall_on_deletion']) { return; // Nothing to do here.