Driver FixRecommendedSound, Wi-Fi or graphics acting up? Check drivers firstFind missing or outdated drivers fast.Check DriversOctober DealsAmazon USOctober deal check: compare before you payAmazon US: current deals, useful picks and tech finds.Check DealsPC HealthRecommendedCrashes, freezes, slowdowns? Check your PC nowSpot repairable issues before they interrupt work.Check PC×
Skip to content
World desk10 min

How to Set Up and Manage a WordPress Cron Job (WP-Cron)

A practical guide to WordPress cron jobs: write recurring and one-time events, inspect and run them with WP-CLI, configure server scheduling, prevent duplicates and clean up on deactivation.

What’s actually slowing this PC down?

Pick the symptom - the matching free tool is one click away.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

WordPress cron, usually called WP-Cron, runs scheduled plugin and core tasks such as publishing posts, sending queued mail and cleaning data. It is triggered during site requests rather than by a continuously running daemon, so low-traffic sites can run tasks late. You can create and maintain events with WordPress PHP APIs, inspect or execute them with WP-CLI, and hand timing to the server’s scheduler when a predictable run time matters.

This guide shows how to register a recurring event safely, schedule one-off work, prevent duplicate events, migrate execution to Linux, macOS or Windows scheduling, remove obsolete jobs and diagnose missed or repeated runs.

As an Amazon Associate I earn from qualifying purchases.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

What WP-Cron is and why timing can drift

WP-Cron is WordPress’s hook-based scheduling system. A plugin registers a uniquely named hook and connects it to a callback. It then places an event for that hook in WordPress’s scheduled-event queue. When a request reaches the site, WordPress checks whether work is due and attempts to spawn a cron request that executes the callbacks.

There is no permanent WP-Cron worker checking the clock every second. A site with few visitors may not receive a request near the intended time, while a busy site can generate many opportunities to check the queue. The WordPress Developer Resources Plugin Handbook therefore cautions that WP-Cron does not run continuously and can be unsuitable for critical tasks that must run on time.

WP-Cron is appropriate for ordinary asynchronous work where a delay of a few minutes is acceptable. If an invoice, import, backup or other operation must start on a predictable schedule, use the operating system’s scheduler to invoke WordPress and disable request-triggered spawning.

How a scheduled event moves from code to execution

  1. Registration: the plugin calls add_action() with its unique hook and callback.
  2. Scheduling: activation code calls wp_schedule_event() for recurring work or wp_schedule_single_event() for a one-time run.
  3. Due check: a normal page request causes WordPress to look for due events and attempt a cron request.
  4. Callback: WordPress invokes the function attached to the hook. A recurring event is rescheduled according to its interval.
  5. Lifecycle management: deactivation code removes events that the plugin no longer needs.

The first-run timestamp is separate from the recurrence name. Choosing hourly, for example, does not mean the callback runs at the top of every clock hour; it means WordPress calculates later runs from the event’s schedule after the first timestamp.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Choose the execution model

Characteristic Visitor-triggered WP-Cron Server-triggered scheduling
Execution trigger WordPress requests caused by page loads, feeds, API calls or other traffic Linux/macOS cron, Windows Task Scheduler or another host scheduler requests WordPress at a configured interval
Timing predictability Variable on low-traffic or overloaded sites More predictable, subject to the host scheduler and task duration
Server access Works with ordinary WordPress access Requires shell, hosting-panel or Task Scheduler access
Duplicate-event risk High if scheduling code runs on every request instead of a controlled activation path The scheduler starts execution, but duplicate WordPress events still have to be prevented in plugin code
Visibility WP-CLI can show the queue and next-run times WP-CLI plus the server scheduler show both the WordPress queue and the external trigger
Cleanup Use WordPress unscheduling APIs and a deactivation hook Remove the WordPress event and, if applicable, the operating-system schedule

Keep visitor-triggered execution when approximate timing is acceptable and you do not control the server. Move to an operating-system scheduler when lateness has a business or operational cost.

Prerequisites and design rules

  • Use a hook name with a project-specific prefix, such as bl_cron_hook, to avoid collisions with another plugin.
  • Put event registration in plugin activation or another explicitly controlled setup path, not in code that executes on every page load.
  • Check wp_next_scheduled() before adding a recurring event.
  • Make callbacks idempotent: a retry should not create duplicate records, send the same message twice or corrupt state.
  • Keep callbacks defensive. Check input, handle remote or database failures and record enough information to diagnose a failed run.
  • Plan deactivation cleanup before shipping the feature. Deactivating a plugin does not automatically erase its scheduled events.

Build a recurring WP-Cron event in a plugin

1. Attach a uniquely prefixed hook

Place the action registration in the plugin’s main file or another file that is loaded on every request:

add_action( 'bl_cron_hook', 'bl_cron_exec' );

function bl_cron_exec() {
    update_option( 'bl_cron_last_run', current_time( 'mysql', true ) );
    // Perform a small, repeatable unit of work here.
}

The callback above records a UTC timestamp as a simple health marker. Replace the comment with the task your plugin owns. Do not put a long, unbounded batch in one callback; process a bounded page of work and leave the next page for a later run.

2. Schedule once during activation

Use the activation hook to create the event and guard it with wp_next_scheduled():

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
register_activation_hook( __FILE__, 'bl_cron_activate' );

function bl_cron_activate() {
    if ( ! wp_next_scheduled( 'bl_cron_hook' ) ) {
        wp_schedule_event( time() + 300, 'hourly', 'bl_cron_hook' );
    }
}

time() + 300 gives the site five minutes before the first attempt. The second argument, hourly, is a registered recurrence name; the final argument is the hook that identifies the callback. The guard means reactivation or another initialization path does not create a second copy of the same event.

Use a recurrence that matches the work. A frequent schedule is not a substitute for an efficient callback: if a run can take longer than the interval, design the callback to claim and finish discrete items so overlapping work cannot repeat side effects.

3. Use a one-time event when recurrence is wrong

For a delayed, one-off operation, use the single-event API instead of creating a recurring schedule:

wp_schedule_single_event( time() + 3600, 'bl_cron_hook' );

This places one execution approximately one hour in the future, subject to the trigger model. If the callback needs arguments, pass them as the API’s additional argument array and define the callback to accept the same values. Before scheduling a one-off event that could be requested repeatedly, apply your own unique order, post or job identifier so a user refresh cannot enqueue the same work many times.

Free tools Windows power users keep installed

One-click scans. No signup required.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Inspect and control events with WP-CLI

Run these commands from the WordPress installation directory as the site’s appropriate system user. WP-CLI’s cron commands provide operational visibility without opening the database directly.

Test the spawning mechanism

wp cron test

This checks whether WordPress can start its cron-spawning mechanism. A failure points to a loopback request, HTTP authentication, DNS, firewall, SSL or server-configuration problem rather than to one particular plugin callback.

List hooks, next runs and recurrence

wp cron event list --fields=hook,next_run_gmt,recurrence --format=table

The table shows each scheduled hook, its next run in GMT and recurrence data. Use it to spot an unexpectedly large queue, a hook with no recurrence when you expected one, or several rows for the same hook that indicate duplicate scheduling.

Run all currently due events

wp cron event run --due-now

This executes events whose scheduled time has arrived. It is useful after correcting a blocked loopback request or when you need to drain due work during maintenance. Run it with care on a production site: every due callback will execute, and a callback that is not idempotent can repeat its side effects.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Schedule a test event

wp cron event schedule cron_test now hourly

The command creates a recurring cron_test event starting now. WP-CLI also accepts a Unix timestamp or textual date-time and optional callback arguments. Use a uniquely named test hook in a staging environment when possible, then verify it with the list command and remove it after testing.

Delete or unschedule an event

wp cron event delete cron_test
wp cron event unschedule cron_test

delete removes all events for the specified hook. unschedule removes scheduled events for that hook where supported by the installed WP-CLI version. Confirm the command’s result with wp cron event list; do not remove a shared hook until you know which plugin owns it.

Move execution to the server scheduler

Use an operating-system scheduler when visitor traffic is too irregular for the required timing. The WordPress handbook recommends requesting wp-cron.php from Linux or macOS cron, or from Windows Task Scheduler, at the interval you choose.

1. Disable request-triggered spawning

Add this line to wp-config.php before the file’s stop-editing comment:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
define( 'DISABLE_WP_CRON', true );

Without this setting, page loads continue trying to spawn WP-Cron even after you configure the server scheduler. That creates needless work and can make it difficult to tell which trigger is responsible for a run.

2. Configure Linux or macOS cron

Open the crontab for the account that can run WordPress commands:

crontab -e

A practical WP-CLI schedule is:

*/5 * * * * cd /var/www/html && wp cron event run --due-now

This asks WP-CLI to execute due events every five minutes. Replace /var/www/html with the actual document root and use the correct PHP/WP-CLI environment for the site. Alternatively, configure the scheduler to make an HTTP request to the site’s wp-cron.php endpoint. Protect that endpoint and account for authentication, redirects, SSL and firewall rules when testing.

3. Configure Windows Task Scheduler

  1. Create a basic task with a trigger at the interval your workload requires.
  2. Set the action to run the PHP executable with the site’s WP-CLI command, or to request the site’s wp-cron.php endpoint.
  3. Run the task whether or not the account is logged in if your hosting policy permits it.
  4. Review the task’s history and the WordPress event list after the first run.

Do not configure both an external scheduler and visitor-triggered spawning unintentionally. After the first scheduled run, use wp cron event list and application logs to verify that events advance once per interval.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Prevent duplicate cron events

The most common cause is scheduling code that runs during normal initialization:

// Risky: this can run on every request.
wp_schedule_event( time(), 'hourly', 'bl_cron_hook' );

Each request can add another row before the previous event is due. The safe pattern is a controlled activation path plus a guard:

if ( ! wp_next_scheduled( 'bl_cron_hook' ) ) {
    wp_schedule_event( time() + 300, 'hourly', 'bl_cron_hook' );
}

If a migration or settings-save routine must repair a missing event, keep the same check and make the repair operation deliberate. When diagnosing duplicates, list the hook with WP-CLI, note how many rows exist and identify which deployment or activation path created them. Remove surplus rows only after confirming that the callback does not belong to another component.

Unschedule obsolete work during deactivation

WordPress can continue attempting a task after its plugin is deactivated or removed. The Plugin Handbook says it is important to unschedule tasks when they are no longer needed. Add a deactivation hook that retrieves the next timestamp and removes that event:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
register_deactivation_hook( __FILE__, 'bl_cron_deactivate' );

function bl_cron_deactivate() {
    $timestamp = wp_next_scheduled( 'bl_cron_hook' );

    if ( $timestamp ) {
        wp_unschedule_event( $timestamp, 'bl_cron_hook' );
    }
}

This pattern targets the next occurrence for the hook. If your plugin can create multiple occurrences or one-off events with different arguments, enumerate and remove each event your version supports, then verify the queue with WP-CLI. Deactivation should stop future work without deleting business data unless that behavior is explicitly part of the plugin’s documented uninstall process.

Troubleshoot late, missing or repeated jobs

The scheduled post or task is late

  • Check whether the site has enough requests to trigger WP-Cron near the intended time.
  • Run wp cron event list --fields=hook,next_run_gmt,recurrence --format=table and compare the expected hook with its next-run time.
  • Use wp cron test to test spawning. Investigate loopback HTTP failures, blocked DNS, SSL errors, basic authentication and firewall rules.
  • If exact timing matters, configure the server scheduler and set DISABLE_WP_CRON instead of relying on visitors.

The same task runs more than once

  • Look for multiple rows of the hook in the event list.
  • Search plugin code for scheduling calls that execute during ordinary requests.
  • Add the wp_next_scheduled() guard and move registration to activation or a controlled repair routine.
  • Make the callback idempotent so a retry cannot duplicate its external effect.

A task never appears in the queue

  • Confirm the activation hook ran for the main plugin file that contains it.
  • Check that the hook name in add_action() exactly matches the name passed to wp_schedule_event().
  • Verify that the recurrence name is registered and that the scheduling call did not return a failure.
  • Use WP-CLI to schedule a temporary test event and determine whether the problem is queue creation or callback code.

Due events accumulate

  • Run due events manually with wp cron event run --due-now while monitoring resource use.
  • Inspect the callback for unbounded loops, slow remote requests or database operations that fail without advancing state.
  • Break large work into bounded batches and store progress so a later run can continue safely.
  • Check whether the external scheduler is disabled, misconfigured or running under an account without the required PHP or WordPress environment.

Operational practices for reliable callbacks

  • Use explicit ownership: prefix hooks and document which plugin creates each one.
  • Record outcomes: store a last-run timestamp or structured log entry, including failures and the item being retried.
  • Protect against overlap: claim a batch before processing it, use a lock with an expiry, or otherwise ensure two workers cannot perform the same irreversible action simultaneously.
  • Respect limits: design around PHP execution time, memory limits, remote API rate limits and database lock duration rather than assuming one callback can process an entire backlog.
  • Separate scheduling from work: the scheduler should decide when to start; the callback should determine what remains and what can be safely retried.
  • Test the complete lifecycle: activate, inspect, run a due event, deactivate, and confirm the hook is gone.

Quick management checklist

  1. Create a unique hook and attach a callback with add_action().
  2. Schedule recurring work with wp_schedule_event() only from activation or another controlled path.
  3. Guard registration with wp_next_scheduled().
  4. Use wp_schedule_single_event() for one-off jobs.
  5. Inspect the queue with wp cron event list and test spawning with wp cron test.
  6. Run due work with wp cron event run --due-now when diagnosing or draining a queue.
  7. If timing must be predictable, schedule WP-Cron from the server and define DISABLE_WP_CRON in wp-config.php.
  8. Unschedule events in the plugin deactivation hook and verify cleanup.

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.

Leave a Reply

Your email address will not be published. Required fields are marked *

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

More from the Wire

  1. World desk4 min
    How to Spot an AI Voice Scam Before Sending MoneyDon’t rely on how a caller sounds. Pause, call back through a known number, and verify the emergency with another trusted person before sending money.
  2. Mountain View desk4 min
    Google’s SynthID Detector: How to Check AI-Generated Images, Video and AudioGoogle’s SynthID Detector looks for an embedded watermark in supported images, video and audio. Here is what its results do—and do not—show.
  3. Redmond desk20 min
    How to create a link to File or Folder in Windows 11Windows 11 gives you several ways to point to a file or folder without moving or duplicating it. You can create a desktop shortcut,…
Recommended PC Tool
Recommended PC Tool
Windows Errors? Fix Them Before They SpreadFree repair scan
Crashes, No Sound, or Screen Glitches?Free driver scan

Two free Windows tools

One Free Minute Could Fix That PC

Before you go - each of these free tools takes about a minute and tackles what quietly slows a Windows PC down.

Special offer. View Outbyte info, uninstall instructions, EULA, and Privacy Policy.