wp_schedule_event()WP 2.1.0

Schedule a recurring event.

Schedules a hook which will be triggered by WordPress at the specified interval. The action will trigger when someone visits your WordPress site if the scheduled time has passed.

Valid values for the recurrence are 'hourly', 'twicedaily', 'daily', and 'weekly'. These can be extended using the cron_schedules filter in wp_get_schedules().

Use wp_next_scheduled() to prevent duplicate events.

Use wp_schedule_single_event() to schedule a non-recurring event.

Hooks from the function

Return

true|false|WP_Error. True if event successfully scheduled. False or WP_Error on failure.

Usage

wp_schedule_event( $timestamp, $recurrence, $hook, $args, $wp_error );
$timestamp(int) (required)
Unix timestamp (UTC) for when to next run the event.
$recurrence(string) (required)
How often the event should subsequently recur. See wp_get_schedules() for accepted values.
$hook(string) (required)
Action hook to execute when the event is run.
$args(array)
Array containing arguments to pass to the hook's callback function. Each value in the array is passed to the callback as an individual parameter. The array keys are ignored.
Default: empty array
$wp_error(true|false)
Whether to return a WP_Error on failure.
Default: false

Examples

1

#1 Adding a new interval

To add a new Cron interval in WordPress, use the filter cron_schedules.

Let's add a "5 minute" interval (do something every 5 minutes):

// add the 5-minute interval
add_filter( 'cron_schedules', 'cron_add_five_min' );

// register the event
add_action( 'wp', 'my_activation' );

// add a function to the specified hook
add_action( 'my_five_min_event', 'do_every_five_min' );

function cron_add_five_min( $schedules ) {

	$schedules['five_min'] = array(
		'interval' => 60 * 5,
		'display' => 'Once every 5 minutes'
	);

	return $schedules;
}

function my_activation() {

	if ( ! wp_next_scheduled( 'my_five_min_event' ) ) {
		wp_schedule_event( time(), 'five_min', 'my_five_min_event' );
	}
}

function do_every_five_min() {
	// do something every 5 minutes
}

WordPress constants that may come in handy when creating a cron interval:

  • HOUR_IN_SECONDS - hour in seconds - 60*60 = 3600
  • DAY_IN_SECONDS - day in seconds - 60*60*24 = 86400
  • WEEK_IN_SECONDS - week in seconds - 60*60*24*7 = 604800
0

#2 Create a cron task when a plugin is activated

Let's schedule an hourly action for the plugin. To do this, call wp_schedule_event() when the plugin is activated (if we do not do it when activated, we will get many scheduled events!).

// Add a cron job when the plugin is activated
register_activation_hook( __FILE__, 'my_activation' );

// Delete cron job when de-activating the plugin
register_deactivation_hook( __FILE__, 'my_deactivation');

// php function to be executed when a cron event occurs
add_action( 'my_hourly_event', 'do_this_hourly' );

function my_activation() {

	// delete all the same cron tasks just in case, so that
	// add new ones with a "clean slate" it may be necessary,
	// if the same task was connected incorrectly before (without checking if it already exists).
	wp_clear_scheduled_hook( 'my_hourly_event' );

	// check if there is already a task with the same hook
	// this item is not needed, because we deleted all tasks above...
	// if( ! wp_next_scheduled( 'my_hourly_event' ) )

	// add a new cron task
	wp_schedule_event( time(), 'hourly', 'my_hourly_event');
}

function do_this_hourly() {
	// do something every hour
}

function my_deactivation() {
	wp_clear_scheduled_hook( 'my_hourly_event' );
}
0

#3 Create a cron job if it does not already exist

This example does not rely on activating a plugin (via the plugins directory), instead it adds an event if it does not exist:

// add a planned hook
add_action( 'wp', 'add_my_cron_event' );

// add a cron-task function
add_action( 'my_hourly_event', 'do_this_hourly' );

function add_my_cron_event() {

	if( ! wp_next_scheduled( 'my_hourly_event' ) ) {
		wp_schedule_event( time(), 'hourly', 'my_hourly_event');
	}
}

function do_this_hourly() {
	// do something every hour
}
0

#4 Another example of creating a WP cron task (working example)

What the example does: gets the exchange rate of the ruble against the dollar and writes the result in the options. It is done only 2 times a day. Then, where necessary, the data can be quickly obtained from the option, where it was written.

Getting currency data works based on the [PHP Simple HTML DOM Parse] library (https://simplehtmldom.sourceforge.io/).

Note: But for today it's better to use modern lib to parse HTML: https://github.com/imangazaliev/didom

// Cron

// Register the schedule when the plugin is activated
register_activation_hook( __FILE__, 'activation_geting_dollar_rate' );

// Delete the schedule when the plugin is deactivated
register_deactivation_hook( __FILE__, 'deactivation_geting_dollar_rate' );

// Hook and function to be executed by Cron
add_action( 'geting_dollar_rate', 'get_real_dollar_rate' );

// Checking the existence of the schedule while the plugin is running, just in case
if( ! wp_next_scheduled( 'geting_dollar_rate' ) ){
	wp_schedule_event( time(), 'twicedaily', 'geting_dollar_rate' );
}

function activation_geting_dollar_rate() {
	wp_clear_scheduled_hook( 'geting_dollar_rate' );
	wp_schedule_event( time(), 'twicedaily', 'geting_dollar_rate' );
}

function deactivation_geting_dollar_rate() {
	wp_clear_scheduled_hook( 'geting_dollar_rate' );
}

function get_real_dollar_rate() {

	include 'inc/simple_html_dom.php';

	$html = file_get_html( 'https://news.yandex.ru/quotes/1.html' );

	$value = $html->find( '.quote_current_yes', 0 )->find( '.quote__value', 0 )->plaintext;
	$date = $html->find( '.quote_current_yes', 0 )->find( '.quote__date', 0 )->plaintext;

	$rate = [ 
		'dollar' => $value, 
		'date' => $date, 
		'check' => current_time( 'mysql', 1 ) 
	];

	update_option( 'i_price_dollar_rate', $rate, 'no' );
}

// returns dollar rate
function get_dollar_rate( $data = null ) {

	$rate = get_option( 'i_price_dollar_rate' );

	if( ! $data || $data === 'dollar' ){
		return $rate['dollar'];
	}

	if( $data === 'date' ){
		return $rate['date'];
	}

	if( $data === 'check' ){
		return $rate['check'];
	}
}
0

#5 Updating a task that has not yet been completed

Suppose we have a setting in the plugin for the interval of some cron-task. And we need to update the task interval depending on this setting.

The first thing to do is to delete the current task and add a new one. You should also consider changing the setting when you change the interval for the cron task.

This example shows how to do such operation with ACF plugin. When you update an option of which you need to update the cron task.

// function of cron task execution 'rs_cron_event'
add_action( 'rs_cron_event', 'rs_cron_rebuild_meta_products' );

// add our new interval for the crone
add_filter( 'cron_schedules', 'rs_cron_interval' );

// Field update function
add_filter( 'acf/update_value/name=rs_time_period', 'my_acf_update_value', 10, 3 );

function rs_cron_rebuild_meta_products() {

	// perform a cron job
	$headers = 'From: My Name <[email protected]>' . "\r\n";

	wp_mail( '[email protected]', 'Theme', 'Content', $headers );
}

function rs_cron_interval( $schedules, $value = '' ){

	// to be able to specify the value rigidly
	if( ! $value ) {
		$value = intval( get_option('options_rs_time_period') ?: 12 );
	}

	$schedules['rs_time_period'] = array(
		'interval' => $value * HOUR_IN_SECONDS ,
		'display' => 'Specified in the RS plugin settings'
	);

	return $schedules;
}

function my_acf_update_value( $new_period, $post_id, $field  ) {

	$old_period = get_option( 'options_rs_time_period' );

	// the option has changed, let's overwrite the cron job with the new setting!
	if( $new_period != $old_period ){

		// delete the existing cron task
		$timestamp = wp_next_scheduled( 'rs_cron_event' );
		wp_unschedule_event( $timestamp, 'rs_cron_event');

		// let's change the interval so that the task is added correctly...
		add_filter( 'cron_schedules', function( $schedules ) use ( $new_period ){

			// crank the interval hard
			return rs_cron_interval( $schedules, $new_period ); 
		} );

		// add the cron task again
		wp_reschedule_event( time(), 'rs_time_period', 'rs_cron_event' );
	}

	return $new_period;
}
0

#6 A simple class for conveniently adding WP CRON Events

See the article Kama_Cron.

0

#7 Schedule event with multiple arguments (Parameters)

Arguments must be passed as elements of an index array.

register_activation_hook( __FILE__, 'my_activation' );

function my_activation() {

	$args = [ $args_1, $args_2 ];

	if ( ! wp_next_scheduled ( 'my_hourly_event', $args ) ) {
		wp_schedule_event( time(), 'hourly', 'my_hourly_event', $args );
	}
}

Don't forget to specify how many arguments the function should get - the 4th parameter add_action().

add_action( 'my_hourly_event', 'do_this_hourly', 10, 2 );

function do_this_hourly( $args_1, $args_2 ) {
	// do something every hour
}

Don’t forget to clean the scheduler on deactivation:

register_deactivation_hook( __FILE__, 'my_deactivation' );

function my_deactivation() {

	// delete all events regardless of the arguments
	wp_unschedule_hook( 'my_hourly_event' );

	// OR remove single event by specifying it's parameters
	wp_clear_scheduled_hook( 'my_hourly_event', [ $args_1, $args_2 ] );
}
0

#8 Set WP CRON Trigger on Server side

It should be noted that depending on how resource-intensive your hook is, the default behavior of “Waiting until a user visits the site” may not be suitable. Of course you should try to make your code as efficient as possible – but if you have a specific case where it’s still resource intensive you do not want to keep the user sitting on a white screen while your hook does it’s work.

For specific situations you might want to consider disabling WP’s internal CRON by placing this line into the wp-config.php file:

define('DISABLE_WP_CRON', 'true');

Then create a CRON job on your server (using your hosting control panel or crontab -e command) to fetch the URL:

https://example.com/wp-cron.php?doing_wp_cron

OR execute:

/usr/bin/php -q /path-to-your-wp-installation/wp-cron.php

Changelog

Since 2.1.0 Introduced.
Since 5.1.0 Return value modified to boolean indicating success or failure, pre_schedule_event filter added to short-circuit the function.
Since 5.7.0 The $wp_error parameter was added.

wp_schedule_event() code WP 6.5.2

function wp_schedule_event( $timestamp, $recurrence, $hook, $args = array(), $wp_error = false ) {
	// Make sure timestamp is a positive integer.
	if ( ! is_numeric( $timestamp ) || $timestamp <= 0 ) {
		if ( $wp_error ) {
			return new WP_Error(
				'invalid_timestamp',
				__( 'Event timestamp must be a valid Unix timestamp.' )
			);
		}

		return false;
	}

	$schedules = wp_get_schedules();

	if ( ! isset( $schedules[ $recurrence ] ) ) {
		if ( $wp_error ) {
			return new WP_Error(
				'invalid_schedule',
				__( 'Event schedule does not exist.' )
			);
		}

		return false;
	}

	$event = (object) array(
		'hook'      => $hook,
		'timestamp' => $timestamp,
		'schedule'  => $recurrence,
		'args'      => $args,
		'interval'  => $schedules[ $recurrence ]['interval'],
	);

	/** This filter is documented in wp-includes/cron.php */
	$pre = apply_filters( 'pre_schedule_event', null, $event, $wp_error );

	if ( null !== $pre ) {
		if ( $wp_error && false === $pre ) {
			return new WP_Error(
				'pre_schedule_event_false',
				__( 'A plugin prevented the event from being scheduled.' )
			);
		}

		if ( ! $wp_error && is_wp_error( $pre ) ) {
			return false;
		}

		return $pre;
	}

	/** This filter is documented in wp-includes/cron.php */
	$event = apply_filters( 'schedule_event', $event );

	// A plugin disallowed this event.
	if ( ! $event ) {
		if ( $wp_error ) {
			return new WP_Error(
				'schedule_event_false',
				__( 'A plugin disallowed this event.' )
			);
		}

		return false;
	}

	$key = md5( serialize( $event->args ) );

	$crons = _get_cron_array();

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

	return _set_cron_array( $crons, $wp_error );
}