WP-Cron Event Generator

Generate a scheduled WP-Cron event: the schedule, the callback, scheduling on activation and the cleanup that stops it running after deactivation.

Live output

Enable JavaScript to customise; default output below.

The name WP-Cron stores. Prefix it, because two plugins sharing a hook run each other's callbacks.

weekly needs WordPress 5.4 or later. once schedules a single event instead of a repeating one.

Used when Runs is set to custom. Registered through the cron_schedules filter.

Anything under a minute is pointless: WP-Cron only runs when someone visits the site.

Live preview cron-event.php
<?php
/**
 * The "my_plugin_daily_cleanup" scheduled event.
 */

/**
 * Puts the event in the schedule if it is not there already.
 */
function my_plugin_run_daily_cleanup_activate() {
	$args = array();

	if ( wp_next_scheduled( 'my_plugin_daily_cleanup', $args ) ) {
		return;
	}

	$first = time();

	wp_schedule_event( $first, 'daily', 'my_plugin_daily_cleanup', $args );
}
register_activation_hook( __FILE__, 'my_plugin_run_daily_cleanup_activate' );

/**
 * Removes the event so it stops firing once the plugin is gone.
 */
function my_plugin_run_daily_cleanup_deactivate() {
	$args = array();

	$timestamp = wp_next_scheduled( 'my_plugin_daily_cleanup', $args );

	if ( $timestamp ) {
		wp_unschedule_event( $timestamp, 'my_plugin_daily_cleanup', $args );
	}
}
register_deactivation_hook( __FILE__, 'my_plugin_run_daily_cleanup_deactivate' );

/**
 * Runs when the event fires.
 */
function my_plugin_run_daily_cleanup() {
	// WP-Cron can start a second run before a slow one finishes.
	$lock = 'my_plugin_daily_cleanup_lock';

	if ( get_transient( $lock ) ) {
		return;
	}

	set_transient( $lock, 1, 10 * MINUTE_IN_SECONDS );

	// Your work here.

	delete_transient( $lock );
}
add_action( 'my_plugin_daily_cleanup', 'my_plugin_run_daily_cleanup' );

Output is valid and updates as you type.

Pick how often the job runs and the generator writes the whole event: the schedule, the code that books it, the callback, and the cleanup that stops it firing after the plugin is gone.

How to use

  1. Name the event hook. WP-Cron stores that string, so prefix it: two plugins sharing a hook run each other’s callbacks.
  2. Choose the recurrence. Hourly, twice daily, daily and weekly come with WordPress; custom registers your own interval through the cron_schedules filter.
  3. Decide where scheduling happens. Activation books it once; init re-checks on every request, which recovers the event if it is ever lost.
  4. Keep the deactivation cleanup on. Without it the event stays booked, firing a hook nothing answers.
  5. Leave the overlap guard on for anything slow. WP-Cron will happily start a second run while the first is still going.

Example

A fifteen-minute sync with two arguments, booked from init so a lost event comes back, first run pushed an hour out:

function acme_run_inventory_sync_activate() {
	$args = array(
		'batch',
		'full',
	);

	if ( wp_next_scheduled( 'acme_sync_inventory', $args ) ) {
		return;
	}

	$first = time() + HOUR_IN_SECONDS;

	wp_schedule_event( $first, 'every_fifteen_minutes', 'acme_sync_inventory', $args );
}
add_action( 'init', 'acme_run_inventory_sync_activate' );

Arguments are part of the event’s identity. Unscheduling needs the same values in the same order, which is why the generated cleanup rebuilds that array rather than passing an empty one.

Pitfalls

  • WP-Cron is not cron. Nothing runs until someone visits the site, so a daily job on a quiet site can be days late.
  • Scheduling without wp_next_scheduled() books a duplicate on every run. On init that means a new event on every page load.
  • Deactivation cleanup is not automatic. An uncleared event stays in the schedule after the plugin is gone, firing a hook with no listener.
  • The arguments array is part of the event identity. Unscheduling with different arguments finds nothing and silently leaves the event booked.
  • A custom interval under 60 seconds is wasted: WP-Cron is triggered by traffic and coalesces anything due.
  • Two overlapping runs are normal on a busy site. Without the transient lock a slow job can run against itself.
  • A fatal in the callback stops every later event in that run, not just yours.
  • wp_schedule_single_event() fires once and is then gone, so it never needs unscheduling, but it also never retries if it fails.

Compatibility

wp_schedule_event(), wp_next_scheduled() and wp_unschedule_event() have been stable since WordPress 2.1. The weekly schedule needs WordPress 5.4 or later; on older versions register it yourself with a custom interval. The generated code targets PHP 7.0 and up, and the tool runs entirely in your browser.

Frequently asked questions

Why has my event not run?
WP-Cron only fires on a page request. On a low-traffic site, schedule a real cron job to hit wp-cron.php and set DISABLE_WP_CRON to true.
How do I check what is scheduled?
wp cron event list with WP-CLI shows every event and its next run. It is the fastest way to catch a duplicate.
What happens to the event when I deactivate the plugin?
Nothing, unless you clear it. The generated deactivation hook is what removes it; without it the hook keeps firing and finds no callback.
Should I schedule on activation or on init?
Activation is tidier and runs once. Use init when losing the event would matter, since it re-books anything missing on the next request.
Can two events share one hook?
Only with different arguments, because the arguments are part of the identity. Same hook and same arguments is one event, booked once.

From the people who built this tool

WP Adminify

The WordPress admin, rebuilt: a dashboard worth looking at, menu and column control, a real file manager and the login page your client sees.

See WP Adminify Free version on WordPress.org

Weekly drops

New tools, when there are new tools

One email when something worth using ships. No schedule to fill, so no filler.

Your address goes nowhere else, and one click unsubscribes.