Skip to content
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
62 changes: 18 additions & 44 deletions src/event.php
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,26 @@ function run( $hookname, $sig ) {
$event = Event::create_immediate( $hookname, $data['args'] );

delete_transient( 'doing_cron' );
$scheduled = force_schedule_single_event( $hookname, $event->args ); // UTC
$scheduled = wp_schedule_single_event( 1, $hookname, $event->args, true ); // UTC

if ( is_wp_error( $scheduled ) ) {
return $scheduled;
if ( 'duplicate_event' !== $scheduled->get_error_code() ) {
return $scheduled;
}

// A duplicate_event error can be a false positive: Cavalcade's pre_schedule_event
// uses a 10-minute window centred on timestamp=1, so it flags the original near-future
// event as a duplicate without actually scheduling anything at timestamp=1.
// If no job exists at timestamp=1, unschedule the future one and retry.
$next = wp_next_scheduled( $hookname, $event->args );
if ( false !== $next && 1 !== $next ) {
wp_unschedule_event( $next, $hookname, $event->args );
$scheduled = wp_schedule_single_event( 1, $hookname, $event->args, true );
if ( is_wp_error( $scheduled ) ) {
return $scheduled;
}
}
// else: a job at timestamp=1 already exists, already queued to run immediately.
}

add_filter( 'cron_request', function ( array $cron_request_array ) {
Expand Down Expand Up @@ -67,48 +83,6 @@ function run( $hookname, $sig ) {
);
}

/**
* Forcibly schedules a single event for the purpose of manually running it.
*
* This is used instead of `wp_schedule_single_event()` to avoid the duplicate check that's otherwise performed.
*
* @param string $hook Action hook to execute when the event is run.
* @param mixed[] $args Optional. Array containing each separate argument to pass to the hook's callback function.
* @return true|WP_Error True if event successfully scheduled. WP_Error on failure.
*/
function force_schedule_single_event( $hook, $args = array() ) {
$event = (object) array(
'hook' => $hook,
'timestamp' => 1,
'schedule' => false,
'args' => $args,
);
$crons = get_core_cron_array();
$key = md5( serialize( $event->args ) );

$crons[ $event->timestamp ][ $event->hook ][ $key ] = array(
'schedule' => $event->schedule,
'args' => $event->args,
);
ksort( $crons );

$result = _set_cron_array( $crons );

// Not using the WP_Error from `_set_cron_array()` here so we can provide a more specific error message.
if ( false === $result ) {
return new WP_Error(
'could_not_add',
sprintf(
/* translators: %s: The name of the cron event. */
__( 'Failed to schedule the cron event %s.', 'wp-crontrol' ),
$hook
)
);
}

return true;
}

/**
* Adds a new cron event.
*
Expand Down
Loading