Schedule tasks with WordPress

A blog is mainly an interactive application. Interactive for the visitors, who see pages that they request, interactive for authors or administrators, who can enter information, and manage them.
However, some of operations don’t need any action from users, and require to be run periodically. Backups are a good example: backups require to be executed regularly, and don’t need any human action.
WordPress offers functions to launch actions, according time parameters, rather than human requests.
In this post, we will see how work these scheduled tasks, the concept of cron, and the WordPress’ API for this subject.

Scheduled tasks

In computer science, scheduled tasks are often synonymous of cron.

Cron

According Wikipedia,
Cron is the name of program that enables Unix users to execute commands or scripts (groups of commands) automatically at a specified time/date. (Cron. (2009, March 10). In Wikipedia, The Free Encyclopedia. Retrieved March 13, 2009, from http://en.wikipedia.org/w/index.php?title=Cron&oldid=276169732)

To summarize, a service / process / daemon, reads periodically a table containing a list of tasks, and launches them, according time parameters. These parameters are date, time and/or a frequency.

In most of operating systems are multi-tasks

  • The daemon runs in background mode, in parallel with the other tasks of the system,
  • The tasks start precisely at the time specified,
  • And run also in background mode.

Crons and WordPress

The concept of scheduled tasks is first appeared in WordPress with a plugin named WP-Cron.
Then, since version 2.0, these functions are included in the WordPress core.

WordPress gives the ability to start tasks, without specific request from a user. But WordPress is not a multi-tasks operating system or a parallel system. So the cron functions don’t have the same behavior than an operating systems.

WordPress is more or less a (big) PHP script, that get HTTP requests, and send pages:

  • Evenif the web server is able to interact with several users at the same time, for a specific user, actions are ran one after another. The execution is sequential. The scheduled tasks are not executed in parallel with the other blog actions, but before or after these actions.
  • A blog doesn’t work when it don’t receive request. Then, if there is no visitor to click on links, if no page are requested, nothing will be started.

Consequences:

  • The scheduled tasks impact directly the response time of the blog, because their execution duration is added to the execution duration of the blog itself.,
  • The time and frequencies specified are not always precisely followed, because to be started at the right time, we need a request from a user. If the blog has a low traffic, requests are few

I will discuss of these two points later.

Principle

When create the tasks?

Most of tasks of WordPress (functions, hooks or filters) are executed each time a page is loaded. So, if we use usual hooks or filter, the risk is to create several time the same task.

The method often described uses the hooks register_activation_hook and register_deactivation_hook to create or delete a scheduled tasks. These hooks are, in fact, called once during activation or deactivation of plugins.

Be careful with tasks that are activated by default during activation of plugins. They can be annoying. I will speak about that, at the end of this post.

Time parameters

The creation phase of scheduled tasks requires to specify the function to launch, and a time or a frequency. Specify a function to execute, requires two step:

  • Create a hook add_action( $hook, 'my_function');
  • Specify this hook as a scheduled task: wp_schedule_event( $timestamp, $recurrance, $hook, $args )

In the call of wp_schedule_event, the parameter $timestamp specifies the requested date to start the action. If we want to run the tasks several time, regularly, we have to specify a frequency such as daily, weekly, hourly …

To give some flexibility to developers, WordPress embeds a list of pre-defined frequency, and give the ability to add our own frequency.
to start, the table of frequencies can be viewed with the function wp_get_schedules(). This function returns a table such as the following:

1
2
3
4
5
6
7
8
9
10
11
Array ( 
    [hourly] => Array ( 
        [interval] => 3600 
        [display] => 'Once hour' ) 
    [twicedaily] => Array ( 
        [interval] => 43200 
        [display] => 'Twice a day' ) 
    [daily] => Array ( 
        [interval] => 86400 
        [display] => 'Once a day' ) 
)

The method to add our own frequencies is based on a filter:

1
2
3
4
5
6
7
8
9
10
11
12
13
function my_schedules() {
    return array( 
		'halfhour' => array(
			'interval' => 1800, /* 60 seconds * 30 minutes */
			'display' => 'Twice hour'
		),
		'weekly' => array(
			'interval' => 604800, /* 60 seconds * 60 minutes * 24 hours * 7 days */
			'display' => 'Weekly'
		)
);
}
add_filter('cron_schedules', 'my_schedules');

Create a task

At this step, we know how to specify a time and a frequency, we just have to specify what we want to do:

1
2
3
4
5
6
7
8
if (!wp_next_scheduled('my_task_hook')) {
    wp_schedule_event( time(), 'hourly', 'my_task_hook' );
} 
add_action( 'my_task_hook', 'my_task_function' ); 
 
function my_task_function() { 
    // actions to execute
}

Some comments:

  • In line 1, we check that the task doesn’t already exist,
  • We add the task in line 2,
  • The function wp_schedule_event is based on a hook, that we have to create (line 3),
  • Then, in line 6, we create the task itself.

The API

Most of functions are stored in the file wp-includes/cron.php. The API includes two components: functions and filters.

Functions

Function Parameters Comments
wp_schedule_single_event timestamp,
hook
Allow to schedule a task that will be run once.
wp_schedule_event >timestamp,
hook,
recurrance,
$args
Allow to schedule a task to run several times. The first start will occur at the time specified.
wp_clear_scheduled_hook hook Delete a scheduled task. There is also the function wp_unschedule_event, but it’s almost unusable, because it requires the exact time of the next start
wp_next_scheduled hook,
[args]
Allow to get the time of the next start of the specified task. This function is useful to know if a task is already scheduled or not (before create it for example).
wp_get_schedule hook,
[args]
Returns the time and frequency parameters
wp_get_schedules none Return the list of available frequency

Filters

Function Parameters Comments
cron_schedules none Allow to add frequencies to the existing list

Constraints and precautions

The scheduled tasks can be executed without logged users. So in these tasks, we can’t use any users’ information such as name, or ID.

These tasks are not interactives. So, the commands echo, print, or the i18n commands __(), or _e() are not useful. All actions must be use either database, either files.

As we see previously, WordPress is not a multi-tasks operating system. So scheduled tasks don’t run in parallel with the interative tasks (administration interface, or public interface).

When a tasks is launched, WordPress must run its own tasks and the scheduled task. Heavier will be the task, longer will be the page loading.

We must be reasonable on two aspects:

  • The execution frequency: schedule a task every 5 minutes, will be, of course, heavier than schedule the same task every hour,
  • The workload: avoid too heavy queries.

We can use two approaches to hide the impact of scheduled tasks on the performances:

  • Plan the tasks during off-peak periods. At these periods, the workload is lower than during peak periods, but if we have too few visits, the risk is that task won’t be started at the right time,
  • Divide required action in several smaller sub-actions: the initial action will be completed when all of the sub-actions will be finished. So, the work is done after several run, rather than only one.

I think that the second approach is the better, but also the most complex.

Conclusion

The functions provided by WordPress, to manage scheduled tasks, are basic, but easy to use, and widely cover the needs.
According the structure and behavior of WordPress, these needs must be limited. Too many or too heavy scheduled tasks will lead to slow down or other problems of performances.
So, evenif it’s easy to create and manage scheduled tasks, we must create these tasks ony if they are mandatory.

An another point is important for me: administrators must keep a total control of their blog. That means two things:

  • First, we have to document clearly plugins, describing with details the scheduled tasks: what they do? When they work? What is the workload? …
  • Then, we have to give to administrators, the ability to activate or desactivate the task at any time.

So, despite of what we can often read, I don’t advise to create the scheduled tasks during plugin activation, but give the ability to the administrators, to create the tasks in an administration page (options page for example). In this manner, the creation of the task is explicit, visible, and the administrators can easily study the impact on performances, by analyzing response time with, then without the task.