How to Set Up Cron Jobs in WordPress (WP-Cron Guide)
Learn how to set up scheduled tasks in WordPress using WP-Cron and system cron. Covers wp_schedule_event, custom intervals, debugging, and production tips.
Prerequisites
- WordPress 6.0+
- Access to wp-config.php
- Server access for system cron (optional)
In this guide
What Is WP-Cron?
WordPress has its own cron system called WP-Cron. Unlike system cron which runs on a fixed schedule, WP-Cron is triggered by page visits. When someone visits your site, WordPress checks if any scheduled tasks are due and runs them.
This means tasks may not run exactly on time if your site has low traffic. For reliable scheduling, you should disable WP-Cron and use system cron instead.
Quick Start: wp_schedule_event
Schedule a recurring event in your plugin or theme:
// Schedule the event on plugin activation
register_activation_hook(__FILE__, function () {
if (!wp_next_scheduled('my_daily_cleanup')) {
wp_schedule_event(time(), 'daily', 'my_daily_cleanup');
}
});
// Define what happens when the event fires
add_action('my_daily_cleanup', function () {
// Your cleanup logic here
error_log('Daily cleanup ran at ' . date('Y-m-d H:i:s'));
});
// Clean up on plugin deactivation
register_deactivation_hook(__FILE__, function () {
wp_clear_scheduled_hook('my_daily_cleanup');
});Built-in recurrence intervals: hourly, twicedaily, daily, weekly.
Custom Cron Intervals
Add custom intervals using the cron_schedules filter:
add_filter('cron_schedules', function ($schedules) {
$schedules['every_five_minutes'] = [
'interval' => 300,
'display' => 'Every Five Minutes',
];
$schedules['every_fifteen_minutes'] = [
'interval' => 900,
'display' => 'Every Fifteen Minutes',
];
return $schedules;
});
// Now use your custom interval
wp_schedule_event(time(), 'every_five_minutes', 'my_frequent_task');Disabling WP-Cron and Using System Cron
For reliable scheduling, disable WP-Cron and use real system cron:
Step 1: Disable WP-Cron in wp-config.php:
define('DISABLE_WP_CRON', true);Step 2: Add system cron entry:
crontab -e
# Run WP-Cron every 5 minutes via HTTP
*/5 * * * * curl -s https://example.com/wp-cron.php?doing_wp_cron > /dev/null 2>&1
# Or use WP-CLI (more reliable)
*/5 * * * * cd /var/www/html && wp cron event run --due-now >> /var/log/wp-cron.log 2>&1The WP-CLI approach is preferred because it runs in the PHP CLI context and avoids HTTP overhead.
WP-CLI Cron Commands
WP-CLI provides useful commands for managing cron:
# List all scheduled events
wp cron event list
# Run all due events
wp cron event run --due-now
# Run a specific event
wp cron event run my_daily_cleanup
# Delete a scheduled event
wp cron event delete my_daily_cleanup
# List registered schedules
wp cron schedule listCommon Cron Expressions (for system cron)
When using system cron to trigger WP-Cron:
*/5 * * * *— Every 5 minutes (recommended minimum)*/15 * * * *— Every 15 minutes0 * * * *— Every hour0 0 * * *— Daily at midnight0 */6 * * *— Every 6 hours
Every weekday at 9:00 AM
Next runs (UTC):
Mon, May 18, 2026 09:00
Tue, May 19, 2026 09:00
Wed, May 20, 2026 09:00
Debugging WP-Cron Issues
Check if WP-Cron is disabled:
// In wp-config.php, look for:
define('DISABLE_WP_CRON', true);List upcoming events:
wp cron event listCommon issues:
- Events not firing on low-traffic sites — WP-Cron depends on page visits. Switch to system cron
- Duplicate events — Always check
wp_next_scheduled()before scheduling - Events lost after migration — Cron events are stored in the
wp_optionstable. They survive database migrations but may need rescheduling if URLs change
Debug plugin: Install the "WP Crontrol" plugin to view and manage all scheduled events from the WordPress admin.
Production Tips
Always use system cron in production. WP-Cron's dependency on page visits makes it unreliable for time-sensitive tasks.
Logging: Log task execution for monitoring:
add_action('my_daily_cleanup', function () {
$start = microtime(true);
do_cleanup();
$duration = round(microtime(true) - $start, 2);
error_log("[wp-cron] my_daily_cleanup completed in {$duration}s");
});Timeout prevention: For long-running tasks, increase the PHP execution time:
add_action('my_heavy_task', function () {
set_time_limit(300); // 5 minutes
process_large_dataset();
});