Anyone who works with WordPress regularly has probably used the built-in scheduling system known as WP-Cron. But WP-Cron behaves very differently from the normal Linux Cron system.
- Linux Cron: as long as the system is running, the task executes automatically when the scheduled time arrives.
- WP-Cron: it is not a true operating-system cron service.
- WordPress stores scheduled event information in the database.
- When a visitor opens the site, WordPress checks whether any scheduled tasks should already have run.
- If there are due tasks, WordPress executes them immediately during that request.
The problem with WordPress’s built-in scheduling system
This design leads to two main problems:
- Execution time is not precise: the task does not necessarily run at the exact scheduled time.
- Tasks can be missed entirely: if no one visits the site around the scheduled time, nothing triggers the event.
That limitation is not a huge issue on a busy website, but it is a poor fit for jobs that really must run on time.
A realistic example
Imagine we need to check a specific directory every hour for CSV files, import them into the database if they exist, and then delete them. If that logic depends only on WP-Cron, the task may not run at the right time or may not run at all.
The better solution: use system Cron to trigger WP-Cron
The operating system’s scheduler does not need page visits to do its work. Once it is configured, it runs on time automatically. The standard fix is to create an operating-system-level cron task that periodically calls the site and triggers WordPress Cron manually.
To avoid conflicts and duplicate execution, we first disable WordPress’s traffic-triggered cron behavior, then schedule our real task with wp_schedule_event().
1. Disable the default WP-Cron trigger
Add the following line to wp-config.php:
define('DISABLE_WP_CRON', true);
2. Register the action that should run
First, define the action hook name and the callback function that should be executed. In the example below, the callback is update_db_hourly.
add_action( 'my_hourly_event', 'update_db_hourly' );
3. Schedule the event in WordPress
Now define the code that schedules the event. If this lives in a plugin, it is common to schedule the event on plugin activation and remove it on plugin deactivation.
public static function activate() {
wp_schedule_event( time(), 'hourly', 'my_hourly_event' );
}
public static function deactivate() {
wp_clear_scheduled_hook('my_hourly_event');
}
And finally, define the callback that does the real work:
public function update_db_hourly() {
// 1. Check whether the file exists
// 2. If it exists, import it and delete it
// 3. If it does not exist, do nothing
}
4. Configure the operating-system cron job
On hosting platforms with cPanel or similar control panels, this can usually be set through a web interface. On servers without a graphical panel, you can configure it from the command line with crontab -e. Add the following line and save the file.
*/15 * * * * wget -q -O - http://yourdomain.com/wp-cron.php?doing_wp_cron
You can do the same thing with curl if you prefer:
*/15 * * * * curl --silent "https://yourdomain.com/wp-cron.php?doing_wp_cron" > /dev/null 2>&1
That setup triggers WordPress every 15 minutes so the scheduled task system has a chance to process any due events.
Setting up scheduled tasks is not especially complicated, but if you do not understand how WP-Cron works internally, it is easy to run into exactly these timing problems. Once this foundation is in place, you can build more advanced patterns on top of it too, such as asynchronous PHP processing and scheduled task queues.
