ima-claude 2.15.0 → 2.16.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -0
- package/dist/cli.js +14 -1
- package/package.json +1 -1
- package/plugins/ima-claude/.claude-plugin/plugin.json +2 -2
- package/plugins/ima-claude/skills/ima-copywriting/SKILL.md +232 -0
- package/plugins/ima-claude/skills/ima-copywriting/references/format-blog-post.md +51 -0
- package/plugins/ima-claude/skills/ima-copywriting/references/format-fundraising-email.md +54 -0
- package/plugins/ima-claude/skills/ima-copywriting/references/format-newsletter.md +54 -0
- package/plugins/ima-claude/skills/ima-copywriting/references/format-op-ed.md +41 -0
- package/plugins/ima-claude/skills/ima-copywriting/references/format-press-release.md +45 -0
- package/plugins/ima-claude/skills/ima-copywriting/references/format-social-media.md +141 -0
- package/plugins/ima-claude/skills/ima-copywriting/references/format-webinar-email.md +37 -0
- package/plugins/ima-claude/skills/ima-copywriting/references/ima-copy-frameworks.md +299 -0
- package/plugins/ima-claude/skills/ima-copywriting/references/ima-transitions.md +199 -0
- package/plugins/ima-claude/skills/ima-editorial-scorecard/SKILL.md +159 -0
- package/plugins/ima-claude/skills/ima-editorial-scorecard/references/format-expectations.md +66 -0
- package/plugins/ima-claude/skills/ima-editorial-scorecard/references/scoring-rubrics.md +73 -0
- package/plugins/ima-claude/skills/ima-editorial-workflow/SKILL.md +171 -0
- package/plugins/ima-claude/skills/ima-email-creator/SKILL.md +104 -0
- package/plugins/ima-claude/skills/ima-email-creator/assets/base-template.html +256 -0
- package/plugins/ima-claude/skills/ima-email-creator/references/drip-sequence.md +66 -0
- package/plugins/ima-claude/skills/ima-email-creator/references/email-css-safe.md +104 -0
- package/plugins/ima-claude/skills/ima-email-creator/references/espocrm-compat.md +58 -0
- package/plugins/ima-claude/skills/ima-email-creator/references/newsletter-layout.md +127 -0
- package/plugins/ima-claude/skills/ima-email-creator/references/wp-transactional.md +77 -0
- package/plugins/ima-claude/skills/ima-email-creator/scripts/css-inliner.py +47 -0
- package/plugins/ima-claude/skills/ima-email-creator/scripts/espocrm-prep.py +52 -0
- package/plugins/ima-claude/skills/ima-email-creator/scripts/requirements.txt +2 -0
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
# PHP Email Template Patterns for WordPress
|
|
2
|
+
|
|
3
|
+
## Architecture: Pure Function + WordPress Wrapper
|
|
4
|
+
|
|
5
|
+
The IMA codebase separates email generation from sending:
|
|
6
|
+
- **Pure functions** generate HTML/text with zero WordPress dependencies (testable)
|
|
7
|
+
- **WordPress wrappers** handle side effects (wp_mail, user lookups, logging)
|
|
8
|
+
|
|
9
|
+
## Brand Alignment Note
|
|
10
|
+
|
|
11
|
+
WordPress transactional emails use the **ima-brand plugin colors**: `#00066F` Indigo headers, `#00B8B8` Aquatic Pulse CTAs, `#494949` Gravel text — applied via `ima_brand_email_wrapper()`.
|
|
12
|
+
|
|
13
|
+
Marketing emails (BeeFree/EspoCRM drip and campaign) are now aligned to the same brand book colors: `#00B8B8` Aquatic Pulse CTAs, `#494949` Gravel text — replacing the old `#0296a1`/`#374751` palette. The only distinction is that transactional emails also use `#00066F` Indigo for headers (via `ima_brand_email_wrapper()`), which marketing email templates handle in their own header blocks.
|
|
14
|
+
|
|
15
|
+
## The Brand Wrapper
|
|
16
|
+
|
|
17
|
+
`ima_brand_email_wrapper()` from `ima-brand` plugin provides:
|
|
18
|
+
- Consistent outer HTML structure (header with logo, footer)
|
|
19
|
+
- Brand colors and typography
|
|
20
|
+
- Location: `wp-content/plugins/ima-brand/includes/email-template.php`
|
|
21
|
+
|
|
22
|
+
```php
|
|
23
|
+
$html = ima_brand_email_wrapper($inner_html, $subject);
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
## Pure Template Pattern
|
|
27
|
+
|
|
28
|
+
```php
|
|
29
|
+
// inc/pure/email-templates.php
|
|
30
|
+
declare(strict_types=1);
|
|
31
|
+
|
|
32
|
+
function ima_build_invitation_email(array $data): string {
|
|
33
|
+
// Pure function — no WordPress calls, no side effects
|
|
34
|
+
$name = htmlspecialchars($data['name'], ENT_QUOTES, 'UTF-8');
|
|
35
|
+
// ... build HTML with inline styles ...
|
|
36
|
+
return $html;
|
|
37
|
+
}
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
## WordPress Wrapper Pattern
|
|
41
|
+
|
|
42
|
+
```php
|
|
43
|
+
// inc/invitation-emails.php
|
|
44
|
+
function ima_send_invitation_email(int $user_id, string $code): bool {
|
|
45
|
+
$user = get_userdata($user_id);
|
|
46
|
+
$html = ima_build_invitation_email([
|
|
47
|
+
'name' => $user->display_name,
|
|
48
|
+
'code' => $code,
|
|
49
|
+
]);
|
|
50
|
+
$wrapped = ima_brand_email_wrapper($html, 'Your Invitation');
|
|
51
|
+
return wp_mail($user->user_email, 'Your Invitation', $wrapped, [
|
|
52
|
+
'Content-Type: text/html; charset=UTF-8',
|
|
53
|
+
]);
|
|
54
|
+
}
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
## Existing Email Modules
|
|
58
|
+
|
|
59
|
+
| Module | Location | Purpose |
|
|
60
|
+
|--------|----------|---------|
|
|
61
|
+
| Invitations | child theme `inc/pure/email-templates.php` | Invitation, activation, application emails |
|
|
62
|
+
| Payments | `ima-payments` plugin | Receipt emails with PDF attachments |
|
|
63
|
+
| Memberships | `ima-memberships` plugin | Retention and welcome emails |
|
|
64
|
+
| Registration | `ima-registration` plugin | Email verification codes |
|
|
65
|
+
| Contact forms | `ima-forms` plugin | Form submission notifications |
|
|
66
|
+
|
|
67
|
+
## Key Rules
|
|
68
|
+
|
|
69
|
+
- Always escape: `htmlspecialchars($value, ENT_QUOTES, 'UTF-8')`
|
|
70
|
+
- Set content type header: `Content-Type: text/html; charset=UTF-8`
|
|
71
|
+
- Use `do_action('ima_log_info', 'Email sent to: ' . $email)` for logging
|
|
72
|
+
- Plain text fallback via `wp_mail` multipart (optional but good practice)
|
|
73
|
+
|
|
74
|
+
## When to Use This vs. Newsletter/Campaign
|
|
75
|
+
|
|
76
|
+
- **This pattern**: System-triggered emails (verification, receipts, notifications) — lives in PHP, runs in WordPress
|
|
77
|
+
- **Newsletter/Campaign**: Marketing emails created in Claude, pasted into EspoCRM — platform-agnostic HTML
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
Inline <style> blocks into element style attributes.
|
|
4
|
+
|
|
5
|
+
Uses premailer to handle CSS specificity correctly. Designed for emails
|
|
6
|
+
built with style blocks (e.g. BeeFree exports) that need inlining for
|
|
7
|
+
Gmail compatibility.
|
|
8
|
+
|
|
9
|
+
Usage:
|
|
10
|
+
python3 css-inliner.py input.html
|
|
11
|
+
python3 css-inliner.py input.html --out output.html
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
import argparse
|
|
15
|
+
import sys
|
|
16
|
+
import premailer
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def inline_css(html: str) -> str:
|
|
20
|
+
return premailer.transform(
|
|
21
|
+
html,
|
|
22
|
+
remove_classes=False,
|
|
23
|
+
strip_important=True,
|
|
24
|
+
keep_style_tags=False,
|
|
25
|
+
)
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def main():
|
|
29
|
+
parser = argparse.ArgumentParser(description="Inline CSS for email compatibility")
|
|
30
|
+
parser.add_argument("input", help="Input HTML file")
|
|
31
|
+
parser.add_argument("--out", help="Output file (default: stdout)")
|
|
32
|
+
args = parser.parse_args()
|
|
33
|
+
|
|
34
|
+
with open(args.input, "r", encoding="utf-8") as f:
|
|
35
|
+
html = f.read()
|
|
36
|
+
|
|
37
|
+
result = inline_css(html)
|
|
38
|
+
|
|
39
|
+
if args.out:
|
|
40
|
+
with open(args.out, "w", encoding="utf-8") as f:
|
|
41
|
+
f.write(result)
|
|
42
|
+
else:
|
|
43
|
+
sys.stdout.write(result)
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
if __name__ == "__main__":
|
|
47
|
+
main()
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
Extract body content from any HTML email and wrap it in a styled div.
|
|
4
|
+
|
|
5
|
+
Strips document-level tags (<html>, <head>, <body>) and migrates body styles
|
|
6
|
+
to a wrapping div. Works on BeeFree exports, IMA emails, or any HTML.
|
|
7
|
+
|
|
8
|
+
Usage:
|
|
9
|
+
python3 espocrm-prep.py input.html
|
|
10
|
+
python3 espocrm-prep.py input.html --out output.html
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
import argparse
|
|
14
|
+
import sys
|
|
15
|
+
from bs4 import BeautifulSoup
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def extract_body_content(html: str) -> str:
|
|
19
|
+
soup = BeautifulSoup(html, "html.parser")
|
|
20
|
+
body = soup.find("body")
|
|
21
|
+
|
|
22
|
+
if body is None:
|
|
23
|
+
return html
|
|
24
|
+
|
|
25
|
+
style = body.get("style", "")
|
|
26
|
+
inner_html = body.decode_contents()
|
|
27
|
+
|
|
28
|
+
if style:
|
|
29
|
+
return f'<div style="{style}">{inner_html}</div>'
|
|
30
|
+
return inner_html
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def main():
|
|
34
|
+
parser = argparse.ArgumentParser(description="Prepare HTML email for EspoCRM")
|
|
35
|
+
parser.add_argument("input", help="Input HTML file")
|
|
36
|
+
parser.add_argument("--out", help="Output file (default: stdout)")
|
|
37
|
+
args = parser.parse_args()
|
|
38
|
+
|
|
39
|
+
with open(args.input, "r", encoding="utf-8") as f:
|
|
40
|
+
html = f.read()
|
|
41
|
+
|
|
42
|
+
result = extract_body_content(html)
|
|
43
|
+
|
|
44
|
+
if args.out:
|
|
45
|
+
with open(args.out, "w", encoding="utf-8") as f:
|
|
46
|
+
f.write(result)
|
|
47
|
+
else:
|
|
48
|
+
sys.stdout.write(result)
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
if __name__ == "__main__":
|
|
52
|
+
main()
|