Install
$ agentstack add skill-mralaminahamed-wp-dev-skills-wp-email-templates ✓ scanned · ✓ verified — works with Claude Code, Cursor, and more.
Security review
✓ PassedNo issues found. Passed automated security review. · v0.1.0 How review works →
- ✓ Prompt-injection patterns
- ✓ Secret / credential exfiltration
- ✓ Dangerous shell & filesystem operations
- ✓ Untrusted network calls
- ✓ Known-malicious package signatures
What it can access
- ✓ Network access No
- ✓ Filesystem access No
- ✓ Shell / process execution No
- ✓ Environment & secrets No
- ✓ Dynamic code execution No
From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.
About
Reusable HTML Email Templates (WordPress plugin)
> Model note: Mechanical refactoring — extract strings, create template files, wire wp_mail(). haiku handles end-to-end.
Move email bodies out of inline PHP strings into templates/emails/, where every message reuses one branded shell. Adding a new email = adding one content file.
When to use
- "Move email content to templates", "branded/HTML emails", "reuse an email template".
- Any plugin building messages inline with
wp_mail()heredocs.
Not for: REST API webhooks, push notifications, or Slack integrations. Transactional email in themes — this skill targets plugin-delivered mail only.
Structure
templates/emails/
base.php shared shell: header, body slot ($content), footer
.php per-email content (greeting, copy, CTA button)
- base.php — table-based, inline-CSS responsive shell (email clients ignore `
/external CSS). Receives$subject,$preheader,$content,$sitename,$siteurl. Echoes$contentraw (// phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped` — content templates escape their own values). - content templates — escape every variable (
esc_html,esc_url); wrap copy in__()/esc_html__()with the text domain; use_n()for plurals. Guard each$var = $var ?? default;so the file is robust if rendered standalone.
Render helpers (in your Helpers class)
public static function render_template( string $path, array $vars = [] ): string {
if ( ! is_readable( $path ) ) return '';
// phpcs:ignore WordPress.PHP.DontExtract.extract_extract -- controlled template vars
extract( $vars, EXTR_SKIP );
ob_start();
include $path;
return (string) ob_get_clean();
}
public static function render_email( string $template, array $vars = [] ): string {
$dir = (string) plugin_config( 'templates' ) . 'emails/'; // your assets/templates path helper
$vars['content'] = self::render_template( $dir . $template . '.php', $vars );
$vars['site_name'] = $vars['site_name'] ?? get_bloginfo( 'name' );
$vars['site_url'] = $vars['site_url'] ?? home_url( '/' );
return self::render_template( $dir . 'base.php', $vars ); // always wrap in the shell
}
A missing content template yields an empty body but the shell still renders — callers always get a valid document.
Sending
$body = Helpers::render_email( 'welcome', [ 'subject' => $subject, 'user_name' => $u->display_name, ... ] );
$headers = [ 'Content-Type: text/html; charset=UTF-8' ]; // REQUIRED for HTML
return wp_mail( $to, $subject, $body, $headers );
Drive any TTL/expiry copy from the same constant the code uses (e.g. a token transient TTL) so email text can't drift from behavior.
Gotchas
- Entities in translated strings:
©double-escapes throughesc_html__→ use the literal©. - Don't assign WordPress globals in templates (
$yearetc. tripWordPress.WP.GlobalVariablesOverride) — inlinegmdate('Y')instead.
Testing
WP's test suite captures wp_mail via MockPHPMailer:
reset_phpmailer_instance();
// ... trigger the send ...
$sent = tests_retrieve_phpmailer_instance()->get_sent();
$this->assertStringContainsString( 'text/html', $sent->header );
$this->assertStringContainsString( 'body ); // base shell used
$this->assertStringContainsString( $expected_cta, $sent->body );
Force a send failure with add_filter( 'pre_wp_mail', '__return_false' ) to test the error branch.
References
references/base.php— the full responsive HTML base shell (header/body/footer, inline CSS), copy intotemplates/emails/base.php.references/content-example.php— an example content template (greeting, CTA button, optional expiry, fallback link) to copy and adapt per email.references/html-email-patterns.md— HTML email patterns: table-based layout rules, inline CSS requirements, dark-mode support, and Outlook-specific fixesreferences/wp-mail-api.md— WordPress mail API reference:wp_mail()parameters,phpmailer_inithook, SMTP configuration, and deliverability checklist
Source & license
This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.
- Author: mralaminahamed
- Source: mralaminahamed/wp-dev-skills
- License: MIT
- Homepage: https://github.com/mralaminahamed/wp-dev-skills/blob/trunk/README.md
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet — be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.