as_schedule_single_action, as_schedule_recurring_action, as_enqueue_async_action, as_schedule_cron_action — every scheduling function with its full parameter list, return values, and real examples you can drop into production.
TL;DR
Action Scheduler is a scalable, auditable background-job library for WordPress, maintained by WooCommerce and documented at actionscheduler.org. It ships inside WooCommerce and is available as a standalone plugin. Its PHP API is a set of global functions that let you enqueue, schedule, and cancel background actions without touching WordPress's built-in WP-Cron machinery.
Every scheduled action maps to a WordPress hook. When the action fires, Action Scheduler calls do_action( $hook, ...$args ), so the callback is a regular hook handler. The queue runner — a separate process that pulls and executes pending actions — is the part that makes delivery reliable: it runs outside the page-load cycle, retries failed actions, and keeps a full attempt log.
The API has four scheduling functions, two query functions, and two cancellation functions. All are documented in the official usage guide.
as_schedule_single_action schedules a one-time action to run at a specific Unix timestamp. It is the Action Scheduler equivalent of wp_schedule_single_event — but backed by a persistent database queue instead of the cron option.
The return value is the integer action ID stored in the wp_actionscheduler_actions table. When $unique is true and an identical pending action exists, the existing action's ID is returned without creating a duplicate. This is the primary idempotency mechanism in the Action Scheduler API.
as_schedule_recurring_action schedules an action to fire repeatedly at a fixed interval in seconds. After each execution, Action Scheduler automatically re-enqueues the next occurrence at $timestamp + N * $interval. Unlike WP-Cron's wp_schedule_event, missed runs do not stack — Action Scheduler always schedules the next slot after the previous one completes.
as_enqueue_async_action queues an action to run as soon as the next queue-processing cycle picks it up — no future timestamp required. It is the right choice when you want work to happen in the background immediately, without the overhead of computing a timestamp or managing intervals.
The function has the same signature as the scheduling functions but without $timestamp. The action is stored with a status of pending and the queue runner claims it in its next batch.
as_schedule_cron_action schedules an action on a cron schedule expression (e.g. 0 6 * * * for 6 AM daily). Unlike as_schedule_recurring_action, which fires at a fixed interval from the previous run, a cron action fires at wall-clock times — it will always run at 6 AM regardless of when the previous run finished. Use it when clock-alignment matters (nightly reports, hourly syncs at the top of the hour).
Two query functions let you inspect the queue before scheduling. as_has_scheduled_action( $hook, $args, $group ) returns true if any matching action is pending or running — use it to avoid duplicate scheduling. as_next_scheduled_action( $hook, $args, $group ) returns the Unix timestamp of the next run, or false if nothing is scheduled.
To remove actions: as_unschedule_action cancels the next occurrence; as_unschedule_all_actions cancels every matching action across all future occurrences. Both accept the same ($hook, $args, $group) signature and are safe to call even if no action is scheduled.
When $unique = true, Action Scheduler checks whether an identical action — same $hook, $args, and $group — already exists in a pending or running state before inserting. If one exists, the scheduling call returns the existing action's ID without creating a duplicate.
This is critical for webhook dispatch: if an order is saved multiple times in quick succession (common during WooCommerce checkout), you only want one delivery queued. Without $unique = true, every save fires a new action and the receiving endpoint gets duplicate payloads. The deduplication check compares the serialized $args array, so different argument values always create separate actions even with $unique = true.
Alternatively, the Webhook Actions plugin handles deduplication automatically via its built-in queue: each bound hook fires at most one queued delivery per trigger per webhook, without requiring manual $unique management in application code.
| Feature | Raw WP-Cron (wp_schedule_*) | Action Scheduler (as_schedule_*) |
|---|---|---|
| Storage | wp_options row — no per-action record | Dedicated DB tables — one row per action |
| Delivery log | None — no attempt history | Full attempt log with timestamps and error text |
| Retry | No retry — one attempt only | Automatic retry with configurable attempts |
| Concurrency | No concurrency control — all jobs share one process | Configurable concurrent batches via filter |
| Claim locking | No — duplicate processing possible under load | DB-level claim lock prevents duplicate execution |
| Deduplication | None — manual workaround required | $unique parameter checks pending/running queue |
| Admin UI | None in core | Status, logs, and manual cancel in WP admin |
The Webhook Actions plugin auto-detects Action Scheduler and uses it as the queue runner when available. When Action Scheduler is present, every triggered webhook delivery is enqueued via as_enqueue_async_action and executed outside the current PHP request. When Action Scheduler is absent, the plugin falls back to WP-Cron automatically.
From a developer perspective you do not call the AS API directly. You bind a WordPress hook (e.g. woocommerce_order_status_changed) to a webhook endpoint in the plugin's admin UI, and the plugin handles the rest: payload serialisation, queuing, header injection (X-Event-Id, X-Event-Timestamp, X-Webhook-Id), exponential-backoff retry (1 min → 2 min → 4 min → 8 min, capped at 1 hour, 5 attempts default), and delivery logging. The fswa_max_attempts and fswa_backoff_delay filters let you tune the retry schedule.
See the Action Scheduler overview for the queue-runner architecture and the concurrent batches guide for tuning under high load.
wp_actionscheduler_actions. When $unique = true and a matching pending action already exists, it returns that existing action's ID without inserting a new row.
as_enqueue_async_action runs the action in the next available queue cycle with no specific timestamp — as soon as the queue runner picks it up. as_schedule_single_action runs at a specific future Unix timestamp. Use async when you want immediate background execution; use single when you need to delay or throttle execution to a specific time.
$unique = true as the fifth argument to any scheduling function. Action Scheduler checks for an existing pending or running action with the same hook, args, and group before inserting. The check compares serialised args, so different argument values always create separate actions.
as_unschedule_action and as_unschedule_all_actions are safe to call with no matching actions. They perform a no-op rather than raising an error. It is safe to call these on plugin deactivation regardless of whether any actions were ever scheduled.
woocommerce/action-scheduler) or as a standalone plugin. Multiple plugins can bundle their own copy; Action Scheduler automatically resolves version conflicts and uses the highest version present.