WP-Cron is a pseudo-cron that fires on page load. On production with consistent traffic, replace it with real server cron.
Schedule an Event
// Register on plugin/theme activation
if (!wp_next_scheduled('my_daily_cleanup')) {
wp_schedule_event(time(), 'daily', 'my_daily_cleanup');
}
// Hook the callback
add_action('my_daily_cleanup', 'run_daily_cleanup');
function run_daily_cleanup() {
global $wpdb;
// Delete expired transients
$wpdb->query(
"DELETE FROM {$wpdb->options}
WHERE option_name LIKE '_transient_timeout_%'
AND option_value < " . time()
);
}
// Clean up on deactivation (IMPORTANT — don't leave orphan events)
register_deactivation_hook(__FILE__, function() {
wp_clear_scheduled_hook('my_daily_cleanup');
});
Custom Schedule Intervals
add_filter('cron_schedules', function($schedules) {
$schedules['every_15_minutes'] = [
'interval' => 900,
'display' => 'Every 15 Minutes',
];
$schedules['every_6_hours'] = [
'interval' => 21600,
'display' => 'Every 6 Hours',
];
return $schedules;
});
Replace WP-Cron With Real Server Cron
Step 1 — Disable WP-Cron in wp-config.php:
define('DISABLE_WP_CRON', true);
Step 2 — Add real cron job (runs every 15 minutes):
# Via crontab -e
*/15 * * * * /usr/local/bin/wp cron event run --due-now \
--path=/var/www/html --quiet
# Or via PHP directly
*/15 * * * * /usr/bin/php /var/www/html/wp-cron.php > /dev/null 2>&1
WP-CLI Cron Management
# List all scheduled events
wp cron event list
# Run all due events immediately
wp cron event run --due-now
# Check when specific event runs next
wp cron event list --fields=hook,next_run_gmt | grep my_daily_cleanup
# Delete a stuck event
wp cron event delete my_daily_cleanup
# Test cron (simulates triggering)
wp cron test
Built-In WordPress Schedules
| Interval | Slug | Seconds |
|----------|------|---------|
| Every hour | hourly | 3600 |
| Twice daily | twicedaily | 43200 |
| Daily | daily | 86400 |
| Weekly | weekly | 604800 |