WordPress runs background tasks (publishing scheduled posts, checking for updates, sending emails, plugin maintenance, WooCommerce jobs) through WP-Cron, a list of scheduled events stored in the database. When scheduled posts miss their time, emails aren’t sent, or the site slows down because of a runaway task, the first step is to look at the cron event list.

For running WP-Cron reliably from the system cron, see WordPress real cron.

List all scheduled events

With WP-CLI, from the WordPress root:

wp cron event list
+------------------------------------+---------------------+-----------------------+------------+
| hook                               | next_run_gmt        | next_run_relative     | recurrence |
+------------------------------------+---------------------+-----------------------+------------+
| wp_version_check                   | 2026-10-14 14:02:11 | 3 hours 12 minutes    | 12 hours   |
| woocommerce_cleanup_sessions       | 2026-10-14 11:30:00 | 40 minutes            | 12 hours   |
| action_scheduler_run_queue         | 2026-10-14 10:51:00 | now                   | 1 minute   |
| my_plugin_hourly_sync              | 2026-10-14 10:20:05 | 30 minutes ago        | 1 hour     |

Useful variations:

wp cron event list --fields=hook,next_run_relative,recurrence --format=table
wp cron event list --next_run_relative=now          # overdue events
wp cron schedule list                                # available intervals (hourly, twicedaily, daily, custom)
wp cron test                                         # can WP-Cron spawn at all?

See WP-CLI.

Without WP-CLI: the WP Crontrol plugin shows the same list in Tools → Cron Events, and lets you run, edit and delete events.

Read the list: what to look for

  • Overdue events (“30 minutes ago”): WP-Cron isn’t running often enough. That’s typical on low-traffic sites, or when DISABLE_WP_CRON is set without a system cron replacement.
  • Unknown hooks: find their source (below). Leftovers from removed plugins can be deleted.
  • Duplicate events: the same hook scheduled many times, which is a plugin bug. That causes repeated work and database bloat.
  • Very frequent events (every minute) from plugins you don’t need.

Find which plugin owns a hook

grep -rn "my_plugin_hourly_sync" wp-content/plugins/ wp-content/themes/ wp-content/mu-plugins/ | head

The add_action('hook_name', …) line shows which code runs, and wp_schedule_event shows where it was scheduled.

Run, schedule or delete events

wp cron event run my_plugin_hourly_sync          # run now (good for testing)
wp cron event run --due-now                       # run everything that's due
wp cron event delete old_plugin_hook              # remove all events for a hook
wp cron event schedule my_hook now hourly          # schedule a hook

Deleting an event of an active plugin is temporary. It usually reschedules itself. Disable the feature in the plugin, or remove the plugin.

Clean up cron bloat

The full schedule is stored in a single option, cron, in wp_options. It’s autoloaded on every request. Thousands of stale or duplicate events make it huge:

wp option get cron --format=json | wc -c        # size in bytes
wp cron event list --format=count

If it’s very large, back up the database, remove events for hooks that no longer exist, and fix the plugin creating duplicates. See WordPress autoloaded options.

WooCommerce and the Action Scheduler

WooCommerce and many plugins use the Action Scheduler library for heavier background work (emails, webhooks, subscription renewals). It has its own queue tables, triggered by WP-Cron or WP-CLI:

  • Tools → Scheduled Actions shows pending, failed and completed actions;
  • run the queue from the system cron for reliability: wp action-scheduler run;
  • clean up old completed actions if the tables grow (retention settings, or WP-CLI cleanup commands).

Make WP-Cron reliable

Default WP-Cron only runs when someone visits the site, and spawns on page loads, which adds latency for some visitors. On a VPS, run it from the system cron instead:

// wp-config.php
define('DISABLE_WP_CRON', true);
*/5 * * * * cd /var/www/example.com/public && wp cron event run --due-now --quiet

Full guide: WordPress real cron. See also crontab.

Quick reference

Task Command
List events wp cron event list
Overdue wp cron event list --next_run_relative=now
Run due events wp cron event run --due-now
Run one hook wp cron event run HOOK
Delete a hook wp cron event delete HOOK
Schedules wp cron schedule list
Test spawning wp cron test
GUI WP Crontrol plugin

Related: WordPress white screen and WordPress on a VPS.

  • WordPress
  • WP-CLI
  • Performance