feat: template registry + queued variant for datamachine/send-email#2068
feat: template registry + queued variant for datamachine/send-email#2068chubes4 wants to merge 5 commits into
Conversation
…es filter
Adds optional 'template' and 'context' inputs to datamachine/send-email.
When 'template' is set, the body is resolved via the datamachine_email_templates
filter ([ template_id => callable( array $context ): string ]); the rendered
string is then run through the existing placeholder replacement so templates
may emit {site_name}, {date}, etc. Unknown template ids return a structured
error with a log entry.
Backwards compatible: omitting 'template' preserves verbatim 'body' behavior.
The schema now requires only 'to' and 'subject'; execute() enforces that one
of 'body' or 'template' is provided.
…er worker
Adds datamachine/send-email-queued ability that defers delivery to Action
Scheduler under the datamachine-email group. Same input schema as
datamachine/send-email plus optional send_at (ISO 8601 or unix ts) and
priority (default 10).
- Omitting send_at uses as_enqueue_async_action for immediate async dispatch.
- Providing send_at uses as_schedule_single_action at that timestamp.
- Worker hook 'datamachine_send_email_worker' is registered on init so
Action Scheduler can dispatch it outside the originating request.
- Worker calls the synchronous datamachine/send-email ability, logs the
structured result, and re-enqueues itself with exponential backoff
(60s, 300s, 1500s) up to 3 total attempts on failure.
- Internal _attempt counter rides in the worker payload and is not part
of the public input_schema.
Output: { success, action_id, scheduled_for, error, logs }.
Wired up in data-machine.php alongside SendEmailAbility.
Mirrors the existing 'wp datamachine email send' flag surface and adds: - --template / --context for template-rendered bodies - --send-at for one-shot scheduled delivery (ISO 8601 or @unix) - --priority for Action Scheduler priority hint Delegates to datamachine/send-email-queued ability and reports the returned action id + scheduled time.
Covers:
- Template render runs before placeholder replacement (template-emitted
{site_name} and {date} are resolved on the post-render pass)
- Unknown template id returns structured error with no wp_mail() call
- Missing body AND missing template returns structured error
- Backwards-compat: raw body path still works with placeholder resolution
- Queued send-now uses as_enqueue_async_action under the datamachine-email
group with _attempt=1 payload (send_at/priority stripped)
- Queued with send_at uses as_schedule_single_action at the resolved ts
- Worker invokes synchronous datamachine/send-email and does not retry on
success
- Worker reschedules with exponential backoff (60s baseline) on failure
and caps at MAX_ATTEMPTS total attempts
Adds a small PermissionHelper stub fixture so the abilities autoload
cleanly outside the full plugin bootstrap.
Run with: php tests/email-template-and-queued-smoke.php
Homeboy Results —
|
Closes #2064
Summary
datamachine/send-emailwith optionaltemplate+contextinputs backed by newdatamachine_email_templatesfilter ([ template_id => callable( array $context ): string ]). Template render runs before placeholder replacement so templates may emit{site_name},{date}, etc.datamachine/send-email-queuedability backed by Action Scheduler. Same input asdatamachine/send-emailplus optionalsend_at(ISO 8601 or unix ts) andpriority(default 10). Async dispatch viaas_enqueue_async_actionwhensend_atis omitted, scheduled viaas_schedule_single_actionotherwise.datamachine_send_email_worker(registered oninit) calls the synchronous ability, logs the structured result, and re-enqueues with exponential backoff (60s, 300s, 1500s). Hard cap of 3 total attempts._attemptrides in the worker payload and is not part of the public input schema.wp datamachine email send-queuedCLI subcommand mirroringsendplus--template,--context,--send-at,--priority.MAX_ATTEMPTS.Backwards compatibility
datamachine/send-emailcallers omittingtemplatesee no behavior change. The schema now requires onlytoandsubject;execute()enforces that one ofbodyortemplateis provided.wp datamachine email sendCLI is unchanged.inc/Api/Email.phpis unchanged (the new fields are optional).extrachill-events→QualifyDigestAbilitiesconsumer continues to work unmodified (rawbodypath).Layer purity
Vendor-name grep clean:
grep -riE 'extrachill|sendy|easy.wp.smtp|kimaki|cc-connect|telegram|slack|whatsapp' inc/returns 35 matches — identical to baseline; zero new matches in the modified or added files (inc/Abilities/Publish/SendEmailAbility.php,inc/Abilities/Publish/SendEmailQueuedAbility.php,inc/Cli/Commands/EmailCommand.php).How to verify
All 44 assertions pass.
See issue #2064 for full acceptance criteria.