
If you’ve built WordPress features that should run in the background, you’ve probably hit this:
- Email should send every hour → doesn’t
- Cleanup should run nightly → skips
- One-time reminder after signup → never fires
The code looks fine. Local works. Production doesn’t.
After 6 years building WordPress themes, plugins, and WooCommerce projects, I can tell you: most cron issues are not syntax errors. They’re misunderstanding how WordPress scheduling works.
What is a scheduled task in WordPress?
A scheduled task is a job WordPress runs later — automatically.
Examples:
- Send reminder emails
- Clean old logs
- Sync data to a CRM
- Fire a one-time follow-up after purchase
WordPress calls this system WP Cron.
WP Cron ≠ Server Cron
Server cron runs at an exact time (e.g. 3:00 AM daily).
WP Cron runs based on traffic.
WP Cron behavior
| Site type | Behavior |
|---|---|
| High traffic | Reliable |
| Low traffic | Delayed |
| Staging | Unpredictable |
The mental model
Schedule → Hook name → add_action() → Function runs
The 2 functions you’ll use most
// Check if already scheduled
wp_next_scheduled( $hook, $args );
// Schedule repeating task
wp_schedule_event( $timestamp, $recurrence, $hook, $args );
Safe pattern
-
wp_next_scheduled()→ check first -
wp_schedule_event()→ schedule -
add_action()→ connect callback
1. Repeating task (hourly email)
Hook registration
add_action( 'butterfly_hourly_email_hook', 'butterfly_send_email_func' );
Schedule it
function butterfly_create_cron_event() {
$args = [
'hemal.akanda.39@gmail.com'
];
if ( ! wp_next_scheduled( 'butterfly_hourly_email_hook', $args ) ) {
wp_schedule_event(
time(),
'hourly',
'butterfly_hourly_email_hook',
$args
);
}
}
Callback
function butterfly_send_email_func( $email ) {
wp_mail(
sanitize_email( $email ),
__( 'Reminder', 'butterfly-cron' ),
__( 'Hey Butterfly. Its a custom message from butterfly', 'butterfly-cron' )
);
}
2. One-time task
add_action( 'butterfly_single_event_hook', 'butterfly_send_email' );
function schedule_single_event() {
$args = [
'hemal.akanda.39@gmail.com'
];
if ( ! wp_next_scheduled( 'butterfly_single_event_hook', $args ) ) {
wp_schedule_single_event(
time() + 3600,
'butterfly_single_event_hook',
$args
);
}
}
function butterfly_send_email( $email ) {
wp_mail(
sanitize_email( $email ),
__( 'Send a email subject', 'butterfly-cron' ),
__( 'Send email message', 'butterfly-cron' )
);
}
3. Remove a scheduled task
function butterfly_schedule_an_event() {
wp_schedule_event( time(), 'hourly', 'butterfly_schedule_an_wp_event' );
}
add_action( 'butterfly_schedule_an_wp_event', 'butterfly_create_an_wp_event' );
function butterfly_unschedule_an_event() {
$timestamps = wp_next_scheduled( 'butterfly_schedule_an_wp_event' );
if ( $timestamps ) {
wp_unschedule_event( $timestamps, 'butterfly_schedule_an_wp_event' );
}
}
function butterfly_create_an_wp_event() {
wp_mail(
sanitize_email( 'hemal.akanda.39@gmail.com' ),
__( 'Create a meetup on wordpress in dhaka', 'butterfly-cron' ),
__( 'Hey! Lets create a meetup for WordPress Community in Dhaka/Bangladesh', 'butterfly-cron' )
);
}
4. Custom intervals
add_filter( 'cron_schedules', 'butterfly_cron_schedule' );
function butterfly_cron_schedule( $schedules ) {
$schedules['weekly'] = [
'interval' => 604800,
'display' => __( 'Once a week', 'butterfly-cron' )
];
return $schedules;
}
Use it
wp_schedule_event( time(), 'weekly', 'my_weekly_hook' );
5. Debug scheduled tasks
$cron = _get_cron_array();
$all_schedules = wp_get_schedules();
?>
<?php foreach ( $cron as $timestamp => $hooks ) : ?>
<?php foreach ( (array) $hooks as $hook => $events ) : ?>
<?php foreach ( (array) $events as $event ) : ?>
<tr>
<td>
<?php echo date_i18n( 'M j, Y @ G:i', wp_next_scheduled( $hook ) ); ?>
</td>
<td>
<?php echo ! empty( $event['schedule'] )
? esc_html( $all_schedules[ $event['schedule'] ]['display'] )
: 'Once'; ?>
</td>
<td>
<code><?php echo esc_html( $hook ); ?></code>
</td>
</tr>
<?php endforeach; ?>
<?php endforeach; ?>
<?php endforeach; ?>
Quick reference
-
wp_schedule_event()→ repeating task -
wp_schedule_single_event()→ one-time task -
wp_next_scheduled()→ check exists -
wp_unschedule_event()→ remove task -
cron_schedules→ custom intervals
Common mistakes
- No
wp_next_scheduled()→ duplicates - Never unscheduling → ghost jobs
- Low traffic sites → delayed cron
- Heavy tasks on page load
- Missing
add_action()
Production tip
define( 'DISABLE_WP_CRON', true );
Top comments (0)