Action Triggers
Queuety::on_action() lets you turn a normal WordPress action into a durable workflow dispatch.
That gives you a clean bridge:
WordPress action -> mapped payload -> durable workflow
This is useful when the interesting event already exists in WordPress and the expensive or long-running response should happen asynchronously.
Example: review content when a post is saved
use Queuety\Queuety;
Queuety::on_action(
'save_post',
workflow: 'content_review',
map: static fn ( int $post_id, object $post, bool $update ): array => [
'post_id' => $post_id,
'post_type' => $post->post_type,
'update' => $update,
],
when: static fn ( int $post_id, object $post ): bool => 'post' === $post->post_type,
idempotency_key: static fn ( int $post_id ): string => "save_post:{$post_id}",
);In that example:
save_postis still the original WordPress eventmapturns raw hook arguments into plain workflow statewhenskips unwanted events before anything is queuedidempotency_keykeeps repeated hook fires from dispatching duplicate runs
What runs synchronously
The action callback itself still runs inside the current WordPress request.
That means these parts are synchronous:
whenmapidempotency_key
Only the workflow steps run asynchronously after dispatch.
Payload rules
Mapped payloads should contain plain arrays, scalars, and null.
Do not pass raw WordPress objects like WP_Post straight into workflow state. Normalize them inside map() first:
Queuety::on_action(
'save_post',
workflow: 'content_review',
map: static fn ( int $post_id, object $post, bool $update ): array => [
'post_id' => $post_id,
'post_type' => $post->post_type,
'post_status' => $post->post_status,
'update' => $update,
],
);Keys that start with _ are rejected because those names are reserved for internal workflow state.
Accepted arguments
WordPress requires an accepted_args count when registering an action callback.
Queuety infers it from your map, when, and idempotency_key callbacks by default, so the common case does not need extra configuration:
Queuety::on_action(
'save_post',
workflow: 'content_review',
map: static fn ( int $post_id, object $post, bool $update ): array => [
'post_id' => $post_id,
'update' => $update,
],
);If you need a manual override, pass accepted_args explicitly:
Queuety::on_action(
'comment_post',
workflow: 'comment_review',
accepted_args: 2,
);Inline workflow builders
You can dispatch a registered workflow name or an inline WorkflowBuilder.
Inline builders are useful when the hook-specific workflow is defined in the same bootstrap file:
$review = Queuety::workflow( 'comment_review' )
->then( ModerateCommentStep::class )
->then( NotifyModeratorStep::class );
Queuety::on_action(
'comment_post',
workflow: $review,
map: static fn ( int $comment_id ): array => [
'comment_id' => $comment_id,
],
idempotency_key: static fn ( int $comment_id ): string => "comment:{$comment_id}",
);When this is a good fit
Use action triggers when:
- WordPress already emits the event you care about
- the response should survive request timeouts or worker restarts
- the follow-up work may branch, wait, or require approval
- duplicate hook fires need durable idempotency
Use a direct Queuety::dispatch() or Queuety::workflow() call instead when the work is not tied to a WordPress event boundary.
Not for filters
Queuety::on_action() is intentionally action-only.
Filters are synchronous request-time transformations. They should usually stay synchronous, because WordPress expects a filtered value to be returned immediately.