TL;DR: as_schedule_single_action() queues a one-time background job that fires at a specific Unix timestamp by calling do_action( $hook, ...$args ).
- Signature:
as_schedule_single_action( int $timestamp, string $hook, array $args = [], string $group = '', bool $unique = false, int $priority = 10 ) - Returns the integer action ID from
wp_actionscheduler_actions; with$unique = trueit returns the existing ID instead of inserting a duplicate. - It is the persistent, retryable equivalent of
wp_schedule_single_event()— backed by database tables, not thecronoption.
/ Signature
What is the as_schedule_single_action signature?
as_schedule_single_action() schedules one background action to run once, at or after a given Unix timestamp. It is a global function shipped with Action Scheduler, the background-job library maintained by WooCommerce and bundled inside WooCommerce, Jetpack, and hundreds of other plugins. When the scheduled time arrives, the queue runner calls do_action( $hook, ...$args ), so the code that actually runs is an ordinary WordPress hook callback registered with add_action().
PHP — as_schedule_single_action full signature
as_schedule_single_action( int $timestamp, // Unix time of the earliest run string $hook, // action hook fired via do_action() array $args = [], // args spread into the callback string $group = '', // label for filtering / bulk cancel bool $unique = false, // skip if an identical action is pending int $priority = 10 // 0-255, lower runs first (AS 3.5+) ): int; // returns the action ID, or 0 on failure
The $unique parameter was added in Action Scheduler 3.3.0 and $priority in 3.5.0. On older bundled versions those trailing arguments are simply ignored, so passing them is safe but has no effect until the host site ships a recent enough copy.
/ Parameters
What does each as_schedule_single_action parameter do?
The first two arguments are required; the rest are optional. Getting $args and $group right matters most, because they are what the deduplication and cancellation functions match on.
| Parameter | Type | Purpose |
|---|---|---|
$timestamp | int | Earliest Unix time to run. The action fires on the first queue pass at or after this moment — not exactly on it. |
$hook | string | The action hook name. Register a callback with add_action( $hook, … ) or nothing runs. |
$args | array | Values spread into the callback as do_action( $hook, ...$args ). Keep it small — args are serialised into the row. |
$group | string | Free-text label used to filter in the admin UI and to bulk-cancel with as_unschedule_all_actions(). |
$unique | bool | When true, skip insertion if a pending/running action with the same hook, args and group already exists. |
$priority | int | 0–255 (default 10). Lower numbers are claimed first within the same timestamp. Added in AS 3.5.0. |
/ Timestamp
How precise is the $timestamp argument?
The timestamp is a floor, not an alarm clock. Action Scheduler runs a queue on each WP-Cron pass (or Action Scheduler's own runner), claims a batch of actions whose scheduled_date is in the past, and executes them. So an action set for time() + 5 runs on the first queue pass after those five seconds — which could be a few seconds late on a busy site, or longer if no traffic triggers WP-Cron. If you need clock-aligned execution (always at 06:00), use as_schedule_cron_action() instead; if you need it to run as soon as possible with no delay target at all, use as_enqueue_async_action().
/ Return value
What does as_schedule_single_action return?
It returns the integer action ID — the primary key of the new row in the wp_actionscheduler_actions table. Store it if you plan to cancel or inspect the action later. Two edge cases change what you get back:
- Duplicate skipped. When
$unique = trueand a matching pending or in-progress action already exists, the call returns that existing action's ID and inserts nothing. - Failure. If the action store cannot save the row, the function returns
0. Treat a falsy return as "not scheduled" rather than assuming success.
Every scheduled action maps to a WordPress hook. When the action runs, Action Scheduler calls do_action($hook, ...$args) — the callback is just a normal hook handler. — Action Scheduler usage guide / Deduplication
How does $unique prevent duplicate single actions?
Passing $unique = true makes the scheduling call idempotent: before inserting, Action Scheduler looks for a pending or running action with the same hook, the same serialised $args, and the same group. If one exists, no new row is created. This is the race-safe way to guarantee "at most one queued job" for an event, because the check and the insert happen inside the same call rather than in your application code. The matching is exact, though — a different argument value, order, or type counts as a distinct action. For the guard-based alternative and the exact matching rules, see preventing duplicate scheduled actions.
PHP — schedule one delayed, deduplicated webhook
// Deliver a webhook 30s after checkout — but only once per order $action_id = as_schedule_single_action( time() + 30, 'myplugin_deliver_order_webhook', [ 'order_id' => $order_id ], 'order-webhooks', true // unique: repeated saves won't queue a 2nd delivery ); add_action( 'myplugin_deliver_order_webhook', function( $order_id ) { $order = wc_get_order( $order_id ); wp_remote_post( 'https://example.com/hook', [ 'body' => wp_json_encode( $order->get_data() ), ] ); } );
/ vs WP-Cron
How is it different from wp_schedule_single_event?
Both schedule a one-time hook, but the storage and reliability differ sharply. wp_schedule_single_event() stores every event in a single serialised cron row in wp_options, runs on visitor page loads, keeps no history, and never retries. as_schedule_single_action() stores one row per action, is claimed by a dedicated queue runner, retries failures, and logs every attempt.
| Feature | wp_schedule_single_event | as_schedule_single_action |
|---|---|---|
| Storage | One serialised cron option row | One DB row per action, indexed |
| Trigger | Visitor page loads (WP-Cron) | Dedicated queue runner batch |
| Retry | None — one attempt | Automatic retry on failure |
| History | None once it runs | Full attempt log in wp-admin |
| Dedup | Manual — read the cron array | $unique = true, race-safe |
| Cancel | wp_unschedule_event by timestamp | as_unschedule_action by hook/args/group |
/ In practice
Do you call as_schedule_single_action for webhooks directly?
Usually not. Firing an outbound webhook when a WordPress or WooCommerce event happens is event-driven, not time-delayed: you hook do_action and POST on the event itself, ideally behind a queue that adds retry with exponential backoff and a delivery log. You reach for as_schedule_single_action() in your own code when you need a delayed one-off job that is not a webhook: a reminder email, a cleanup pass, a deferred API sync. For the full function family — async, recurring, cron, query and cancel — see the Action Scheduler PHP API reference.