Add specific time scheduling to Preload#1026
Conversation
0fc64ea to
ba16f73
Compare
There was a problem hiding this comment.
Pull request overview
Adds a scheduler to WP Super Cache’s Preload feature so admins can run preloading either on a repeating timer or at a specific clock time (similar to the Garbage Collection scheduler).
Changes:
- Introduces new Preload scheduling settings (
intervalvstime, scheduled time, cron interval). - Updates
wpsc_preload_settings()andwp_cron_preload_cache()to schedule either single events (timer) or recurring cron events (clock). - Adds Preload UI controls for selecting Timer/Clock mode and configuring time + interval.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 5 comments.
| File | Description |
|---|---|
wp-cache.php |
Implements new schedule settings persistence and cron scheduling behavior for interval/time modes. |
wp-cache-config-sample.php |
Adds sample defaults for the new preload scheduling variables. |
partials/preload.php |
Adds the Scheduler UI (Timer/Clock) to the Preload settings tab. |
Comments suppressed due to low confidence (1)
wp-cache.php:3720
- In time-based scheduling mode,
$cache_max_timeis still derived from$wp_cache_preload_interval(minutes). If the user switches to Clock mode but leaves the timer value at a small/default value, the cleanup step may delete cached files much sooner than the next scheduled preload run. Consider deriving$cache_max_timefrom the Clock interval (e.g., the selected cron schedule duration) when$preload_schedule_type === 'time'.
global $file_prefix, $cache_max_time;
if ( $wp_cache_preload_interval > 0 ) {
$cache_max_time = (int)$wp_cache_preload_interval * 60; // fool the GC into expiring really old files
} else {
$cache_max_time = 86400; // fool the GC into expiring really old files
}
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| if ( $preload_schedule_type === 'interval' ) { | ||
| // Interval-based: schedule single event X minutes from now | ||
| wp_schedule_single_event( time() + ( $wp_cache_preload_interval * 60 ), 'wp_cache_full_preload_hook' ); | ||
| } else { | ||
| // Time-based: schedule recurring event at specific time | ||
| if ( ! isset( $preload_scheduled_time ) ) { | ||
| $preload_scheduled_time = '00:00'; | ||
| } |
There was a problem hiding this comment.
Time-based scheduling uses wp_schedule_event( strtotime( $preload_scheduled_time ), ...), but strtotime('HH:MM') is interpreted in the server/PHP timezone and can resolve to a timestamp in the past (causing the event to run immediately rather than at the next intended time). Since the UI says “UTC”, it would be safer to compute the next future UTC timestamp explicitly (e.g., based on current_time()/wp_timezone() and advancing to tomorrow when needed).
| if ( $preload_schedule_type === 'interval' ) { | |
| // Interval-based: schedule single event X minutes from now | |
| wp_schedule_single_event( time() + ( $wp_cache_preload_interval * 60 ), 'wp_cache_full_preload_hook' ); | |
| } else { | |
| // Time-based: schedule recurring event at specific time | |
| if ( ! isset( $preload_scheduled_time ) ) { | |
| $preload_scheduled_time = '00:00'; | |
| } | |
| // Time-based: schedule recurring event at a specific UTC time. | |
| if ( ! isset( $preload_scheduled_time ) ) { | |
| $preload_scheduled_time = '00:00'; | |
| } | |
| if ( ! isset( $preload_schedule_interval ) ) { | |
| $preload_schedule_interval = 'daily'; | |
| } | |
| $preload_time_parts = explode( ':', $preload_scheduled_time, 2 ); | |
| $preload_hour = isset( $preload_time_parts[0] ) ? (int) $preload_time_parts[0] : 0; | |
| $preload_minute = isset( $preload_time_parts[1] ) ? (int) $preload_time_parts[1] : 0; | |
| if ( $preload_hour < 0 || $preload_hour > 23 ) { | |
| $preload_hour = 0; | |
| } | |
| if ( $preload_minute < 0 || $preload_minute > 59 ) { | |
| $preload_minute = 0; | |
| } | |
| $preload_utc_now = new DateTime( 'now', new DateTimeZone( 'UTC' ) ); | |
| $preload_utc_next = new DateTime( 'now', new DateTimeZone( 'UTC' ) ); | |
| $preload_utc_next->setTime( $preload_hour, $preload_minute, 0 ); | |
| if ( $preload_utc_next->getTimestamp() <= $preload_utc_now->getTimestamp() ) { | |
| $preload_utc_next->modify( '+1 day' ); | |
| } | |
| wp_schedule_event( $preload_utc_next->getTimestamp(), $preload_schedule_interval, 'wp_cache_full_preload_hook' ); |
| if ( ! isset( $preload_schedule_interval ) ) { | ||
| $preload_schedule_interval = 'daily'; | ||
| } | ||
| $schedules = wp_get_schedules(); | ||
| $interval_display = isset( $schedules[ $preload_schedule_interval ]['display'] ) ? $schedules[ $preload_schedule_interval ]['display'] : $preload_schedule_interval; | ||
| if ( $wp_cache_preload_email_me ) | ||
| /* translators: 1: scheduled time, 2: schedule interval display name */ | ||
| $msg = sprintf( __( 'Scheduling next preload at %1$s (%2$s).', 'wp-super-cache' ), $preload_scheduled_time, $interval_display ); | ||
| wp_cache_debug( "wp_cron_preload_cache: no more posts. scheduling next preload at $preload_scheduled_time ($preload_schedule_interval).", 5 ); | ||
| wp_schedule_event( strtotime( $preload_scheduled_time ), $preload_schedule_interval, 'wp_cache_full_preload_hook' ); |
There was a problem hiding this comment.
When rescheduling in time mode, $preload_schedule_interval is used directly in wp_schedule_event(...) without verifying it still exists in wp_get_schedules(). If a custom schedule was removed after the setting was saved, scheduling will fail and preloading may stop. Consider falling back to a known interval (e.g., daily) when the configured interval is missing.
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
- Display input time in the site's configured timezone instead of UTC. - Convert the entered HH:MM to the next UTC timestamp via a shared helper, advancing to the next day when the chosen time has already passed today. - Fix a stray/malformed preg_match line left over from the previous commit and tighten HH:MM validation to reject out-of-range values.
Reviewed the scheduling state machine, since converting ContextTwo cron hooks both fire Blocker
wp_unschedule_event( $next_full_preload, 'wp_cache_full_preload_hook' );
wp_clear_scheduled_hook( 'wp_cache_full_preload_hook' ); // handles single + recurringThe Cleanup (not a blocker)End-of-run reschedule block in "time" mode is dead code — in Warnings
Not issuesTimezone handling in SuggestionThe root cause is that "convert to recurring" wasn't applied uniformly across the schedule / cancel / enable paths. Consider centralizing into a single |
Summary
wp_cron_preload_cache()andwpsc_preload_settings()to handle both interval and time-based schedulingThis allows server administrators to schedule resource-intensive preloading during off-peak hours (e.g., 03:00 AM) to minimize impact on site performance.
Originally proposed by @zeus2611 in Automattic/jetpack#47018.
Fixes #1017
Test plan
wp_cache_preload_hookis scheduled at the correct time (e.g., via WP Crontrol)