WordPress Tutorial: Cron Jobs and Scheduled Tasks

WordPress provides a simple way to add periodic tasks via cronjobs that initiate custom functions. There are various situations where you will want to run custom PHP code such as updating post statuses or emailing registered users links to new site content.

Whatever your requirement, the WordPress scheduling system is easy to use and extend.

The following code is a basic example of creating an action (hook) that is initiated on a daily basis.

if (!wp_next_scheduled('my_task_hook')) {
wp_schedule_event( time(), 'daily', 'my_task_hook' );
}
add_action ( 'my_task_hook', 'my_task_function' );
function my_task_function() {
echo 'I am a WordPress task. I will be called again tomorrow';
} 

As you can see this is a very basic example that simply outputs the text: 'I am a WordPress task. I will be called again tomorrow'.

Looking more closely at this example the core WordPress function for creating a scheduled event is: wp_schedule_event( $timestamp, $recurrence, $hook, $args ). By default, WordPress offers two recurrence types: hourly and daily. This is great for most sites uses, however there are times when you require more intervals so using the following code you can extend the default intervals to suit your needs.

function extra_reccurences() {
return array(
'weekly' => array('interval' => 604800, 'display' => 'Once Weekly'),
'fortnightly' => array('interval' => 1209600, 'display' => 'Once Fortnightly'),
);
}
add_filter('cron_schedules', 'extra_reccurences'); 

Wrapping it all up

if (!wp_next_scheduled('my_task_hook')) {
wp_schedule_event( time(), 'weekly', 'my_task_hook' );
}
add_action ( 'my_task_hook', 'my_task_function' );
function my_task_function() {
echo 'I have been called to action. I will do the same next week';
} 

This example uses our new interval named 'weekly' to initiate the function named my_task_function on a weekly basis.

In this final example we use a custom interval for scheduled tasks by adding a filter using cron_schedules:

function my_cron_schedules($schedules){
    if(!isset($schedules["5min"])){
        $schedules["5min"] = array(
            'interval' => 5*60,
            'display' => __('Once every 5 minutes'));
    }
    if(!isset($schedules["30min"])){
        $schedules["30min"] = array(
            'interval' => 30*60,
            'display' => __('Once every 30 minutes'));
    }
    return $schedules;
}
add_filter('cron_schedules','my_cron_schedules');

if (!wp_next_scheduled('my_task_hook')) {
	wp_schedule_event( time(), '5min', 'my_task_hook' );
}
add_action ( 'my_task_hook', 'my_task_function' );

function my_task_function() {
	echo 'I have been called to action. I will do the same next week';
}

This allows events to be scheduled every 5 or 30 minutes using the custom cron schedules interval of either 5min or 30min.

Please note: The WordPress cron system is activated automatically based on a page view / init action but this can lead to issues with scheduled posts not being publish - you will most likely see the message 'missed schedule'. Therefore it is best to set up a cronjob to call the wp-cron.php file in the root of your WordPress install every 5 minutes, otherwise your scheduled tasks may not run correctly. This is especially important if you are using a caching mechanisms such as Varnish that completely bypass the WordPress bootstrap / initiation process.

The following is an example cron job that calls the Wordpress wp-cron.php file every 15 minutes.

*/15 * * * * wget -q -O - http://example.com/wp-cron.php?doing_wp_cron >/dev/null 2>&1

You can also use Curl to the call the script.

*/15 * * * * curl http://example.com/wp-cron.php?doing_wp_cron > /dev/null 2>&1

WP-CLI

*/15 * * * * cd /var/www/example.com/htdocs; wp cron event run --due-now > /dev/null 2>&1

And finally PHP

*/15 * * * * cd /var/www/example.com/htdocs; php /var/www/example.com/htdocs/wp-cron.php?doing_wp_cron > /dev/null 2>&1

Once the cron job has been set you should also disable the default WP Cron settings in your wp-config.php file.

define('DISABLE_WP_CRON', true);