beginner 10 min read

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)

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:

php
// 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:

php
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:

php
define('DISABLE_WP_CRON', true);

Step 2: Add system cron entry:

bash
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>&1

The 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:

bash
# 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 list

Common Cron Expressions (for system cron)

When using system cron to trigger WP-Cron:

  • */5 * * * * — Every 5 minutes (recommended minimum)
  • */15 * * * * — Every 15 minutes
  • 0 * * * * — Every hour
  • 0 0 * * * — Daily at midnight
  • 0 */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:

php
// In wp-config.php, look for:
define('DISABLE_WP_CRON', true);

List upcoming events:

bash
wp cron event list

Common 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_options table. 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:

php
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:

php
add_action('my_heavy_task', function () {
    set_time_limit(300); // 5 minutes
    process_large_dataset();
});

Frequently Asked Questions