claude-plugin-wordpress-manager 2.4.0 → 2.9.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/.claude-plugin/plugin.json +10 -3
- package/CHANGELOG.md +103 -0
- package/agents/wp-content-strategist.md +104 -0
- package/agents/wp-monitoring-agent.md +44 -0
- package/agents/wp-site-manager.md +19 -0
- package/docs/GUIDE.md +183 -23
- package/docs/plans/2026-03-01-tier4-5-implementation.md +1783 -0
- package/docs/plans/2026-03-01-tier4-5-observability-automation-design.md +426 -0
- package/docs/plans/2026-03-01-wcop-reassessment-v2.6.0.md +403 -0
- package/hooks/hooks.json +9 -0
- package/package.json +19 -3
- package/servers/wp-rest-bridge/build/tools/comments.d.ts +6 -6
- package/servers/wp-rest-bridge/build/tools/cwv.d.ts +3 -0
- package/servers/wp-rest-bridge/build/tools/cwv.js +196 -0
- package/servers/wp-rest-bridge/build/tools/ga4.d.ts +3 -0
- package/servers/wp-rest-bridge/build/tools/ga4.js +323 -0
- package/servers/wp-rest-bridge/build/tools/gsc.d.ts +3 -0
- package/servers/wp-rest-bridge/build/tools/gsc.js +354 -0
- package/servers/wp-rest-bridge/build/tools/index.d.ts +38 -38
- package/servers/wp-rest-bridge/build/tools/index.js +18 -0
- package/servers/wp-rest-bridge/build/tools/media.d.ts +2 -2
- package/servers/wp-rest-bridge/build/tools/multisite-sites.d.ts +2 -2
- package/servers/wp-rest-bridge/build/tools/plausible.d.ts +3 -0
- package/servers/wp-rest-bridge/build/tools/plausible.js +207 -0
- package/servers/wp-rest-bridge/build/tools/plugin-repository.d.ts +1 -1
- package/servers/wp-rest-bridge/build/tools/search.d.ts +2 -2
- package/servers/wp-rest-bridge/build/tools/slack.d.ts +3 -0
- package/servers/wp-rest-bridge/build/tools/slack.js +129 -0
- package/servers/wp-rest-bridge/build/tools/unified-content.d.ts +8 -8
- package/servers/wp-rest-bridge/build/tools/unified-taxonomies.d.ts +4 -4
- package/servers/wp-rest-bridge/build/tools/users.d.ts +6 -6
- package/servers/wp-rest-bridge/build/tools/wc-coupons.d.ts +1 -1
- package/servers/wp-rest-bridge/build/tools/wc-customers.d.ts +3 -3
- package/servers/wp-rest-bridge/build/tools/wc-orders.d.ts +4 -4
- package/servers/wp-rest-bridge/build/tools/wc-products.d.ts +8 -8
- package/servers/wp-rest-bridge/build/tools/wc-webhooks.d.ts +4 -4
- package/servers/wp-rest-bridge/build/tools/wc-workflows.d.ts +3 -0
- package/servers/wp-rest-bridge/build/tools/wc-workflows.js +222 -0
- package/servers/wp-rest-bridge/build/wordpress.d.ts +23 -0
- package/servers/wp-rest-bridge/build/wordpress.js +178 -0
- package/servers/wp-rest-bridge/package.json +1 -0
- package/skills/wordpress-router/SKILL.md +1 -1
- package/skills/wordpress-router/references/decision-tree.md +12 -2
- package/skills/wp-alerting/SKILL.md +142 -0
- package/skills/wp-alerting/references/alert-thresholds.md +79 -0
- package/skills/wp-alerting/references/escalation-paths.md +92 -0
- package/skills/wp-alerting/references/report-scheduling.md +142 -0
- package/skills/wp-alerting/references/slack-integration.md +109 -0
- package/skills/wp-alerting/scripts/alerting_inspect.mjs +150 -0
- package/skills/wp-analytics/SKILL.md +158 -0
- package/skills/wp-analytics/references/analytics-dashboards.md +83 -0
- package/skills/wp-analytics/references/cwv-monitoring.md +101 -0
- package/skills/wp-analytics/references/ga4-integration.md +76 -0
- package/skills/wp-analytics/references/plausible-setup.md +92 -0
- package/skills/wp-analytics/references/traffic-attribution.md +92 -0
- package/skills/wp-analytics/scripts/analytics_inspect.mjs +153 -0
- package/skills/wp-content/SKILL.md +1 -0
- package/skills/wp-content-attribution/SKILL.md +3 -0
- package/skills/wp-content-optimization/SKILL.md +173 -0
- package/skills/wp-content-optimization/references/content-freshness.md +234 -0
- package/skills/wp-content-optimization/references/headline-optimization.md +171 -0
- package/skills/wp-content-optimization/references/meta-optimization.md +243 -0
- package/skills/wp-content-optimization/references/readability-analysis.md +201 -0
- package/skills/wp-content-optimization/references/seo-content-scoring.md +245 -0
- package/skills/wp-content-optimization/scripts/content_optimization_inspect.mjs +237 -0
- package/skills/wp-content-workflows/SKILL.md +142 -0
- package/skills/wp-content-workflows/references/content-lifecycle-hooks.md +131 -0
- package/skills/wp-content-workflows/references/multi-channel-actions.md +151 -0
- package/skills/wp-content-workflows/references/schedule-triggers.md +118 -0
- package/skills/wp-content-workflows/references/trigger-management.md +159 -0
- package/skills/wp-content-workflows/references/wp-action-hooks.md +114 -0
- package/skills/wp-content-workflows/scripts/workflow_inspect.mjs +202 -0
- package/skills/wp-monitoring/SKILL.md +3 -0
- package/skills/wp-programmatic-seo/SKILL.md +2 -0
- package/skills/wp-search-console/SKILL.md +122 -0
- package/skills/wp-search-console/references/competitor-gap-analysis.md +226 -0
- package/skills/wp-search-console/references/content-seo-feedback.md +181 -0
- package/skills/wp-search-console/references/gsc-setup.md +110 -0
- package/skills/wp-search-console/references/indexing-management.md +182 -0
- package/skills/wp-search-console/references/keyword-tracking.md +181 -0
- package/skills/wp-search-console/scripts/search_console_inspect.mjs +178 -0
- package/skills/wp-social-email/SKILL.md +1 -0
- package/skills/wp-webhooks/SKILL.md +1 -0
|
@@ -0,0 +1,245 @@
|
|
|
1
|
+
# SEO Content Scoring
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
SEO content scoring evaluates how well a piece of WordPress content is optimized for search engines. Claude performs keyword density analysis, heading hierarchy assessment, internal and external linking checks, image alt text coverage, and content structure evaluation. When GSC data is available, Claude cross-references actual search queries to validate keyword targeting.
|
|
6
|
+
|
|
7
|
+
## Keyword Density Analysis
|
|
8
|
+
|
|
9
|
+
### Target Ranges
|
|
10
|
+
|
|
11
|
+
| Keyword Type | Target Density | Minimum | Maximum |
|
|
12
|
+
|-------------|---------------|---------|---------|
|
|
13
|
+
| Primary keyword | 1-2% | 0.5% | 3% |
|
|
14
|
+
| Secondary keywords | 0.5-1% each | 0.3% | 1.5% |
|
|
15
|
+
| LSI/related terms | Natural occurrence | — | — |
|
|
16
|
+
|
|
17
|
+
### Density Calculation
|
|
18
|
+
```
|
|
19
|
+
Keyword Density = (Number of keyword occurrences / Total word count) × 100
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
### Placement Rules
|
|
23
|
+
1. **Title (H1)** — primary keyword must appear (preferably front-loaded)
|
|
24
|
+
2. **First paragraph** — primary keyword within first 100 words
|
|
25
|
+
3. **Subheadings** — primary or secondary keyword in at least 1 H2
|
|
26
|
+
4. **Body distribution** — keyword spread throughout, not clustered
|
|
27
|
+
5. **Last paragraph** — primary keyword in conclusion
|
|
28
|
+
6. **URL slug** — primary keyword in the URL
|
|
29
|
+
|
|
30
|
+
### Keyword Stuffing Detection
|
|
31
|
+
Flag when:
|
|
32
|
+
- Primary keyword density exceeds 3%
|
|
33
|
+
- Same keyword appears in consecutive sentences
|
|
34
|
+
- Keyword is forced into unnatural phrasing
|
|
35
|
+
- Multiple exact-match keyword repetitions in one paragraph
|
|
36
|
+
|
|
37
|
+
### Example Analysis
|
|
38
|
+
```
|
|
39
|
+
Post: "WordPress Speed Optimization Guide" (1500 words)
|
|
40
|
+
Primary keyword: "wordpress speed optimization"
|
|
41
|
+
|
|
42
|
+
Occurrences: 18 times
|
|
43
|
+
Density: 18/1500 × 100 = 1.2% ✓ Within target
|
|
44
|
+
|
|
45
|
+
Distribution:
|
|
46
|
+
- Title: ✓ Present
|
|
47
|
+
- First paragraph: ✓ Present (word 12)
|
|
48
|
+
- H2 headings: ✓ 1 of 4 H2s contains keyword
|
|
49
|
+
- Last paragraph: ✓ Present
|
|
50
|
+
- URL: ✓ /wordpress-speed-optimization-guide
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
## H2/H3 Hierarchy Coverage
|
|
54
|
+
|
|
55
|
+
### Structure Requirements
|
|
56
|
+
|
|
57
|
+
| Element | Requirement | Check |
|
|
58
|
+
|---------|------------|-------|
|
|
59
|
+
| H1 | Exactly 1 per page, contains primary keyword | Required |
|
|
60
|
+
| H2 | 2-6 per post, secondary keywords in 50%+ | Required |
|
|
61
|
+
| H3 | As needed under H2, long-tail keywords | Recommended |
|
|
62
|
+
| H4+ | Rare, deep detail only | Optional |
|
|
63
|
+
| Skip levels | Never (H1 → H3 without H2) | Flag as error |
|
|
64
|
+
|
|
65
|
+
### Heading Optimization Checklist
|
|
66
|
+
- [ ] One H1 only, matching the post title
|
|
67
|
+
- [ ] H2s outline the main sections (scannable table of contents)
|
|
68
|
+
- [ ] At least one H2 contains the primary keyword
|
|
69
|
+
- [ ] H3s provide detail under their parent H2
|
|
70
|
+
- [ ] No heading level is skipped
|
|
71
|
+
- [ ] Headings are descriptive (not generic like "More Info")
|
|
72
|
+
- [ ] Secondary keywords distributed across H2/H3 headings
|
|
73
|
+
|
|
74
|
+
### Example Heading Audit
|
|
75
|
+
```
|
|
76
|
+
H1: WordPress Speed Optimization: Complete Guide ✓ Primary keyword
|
|
77
|
+
H2: Why WordPress Speed Matters ✓ Descriptive
|
|
78
|
+
H3: Impact on SEO Rankings ✓ Secondary keyword
|
|
79
|
+
H3: Impact on User Experience ✓ Related term
|
|
80
|
+
H2: How to Measure WordPress Speed ✓ Secondary keyword
|
|
81
|
+
H2: 10 WordPress Speed Optimization Techniques ✓ Primary keyword
|
|
82
|
+
H3: Enable Caching ✓ Specific
|
|
83
|
+
H3: Optimize Images ✓ Specific
|
|
84
|
+
H3: Minimize CSS and JavaScript ✓ Specific
|
|
85
|
+
H2: Conclusion ⚠ Generic, add keyword
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
## Internal Linking Analysis
|
|
89
|
+
|
|
90
|
+
### Minimum Standards
|
|
91
|
+
|
|
92
|
+
| Content Length | Internal Links | Rationale |
|
|
93
|
+
|---------------|---------------|-----------|
|
|
94
|
+
| < 500 words | 1-2 links | Short content, few linking opportunities |
|
|
95
|
+
| 500-1000 words | 2-3 links | Standard blog post |
|
|
96
|
+
| 1000-2000 words | 3-5 links | In-depth article |
|
|
97
|
+
| 2000+ words | 5-8 links | Pillar content, extensive topic |
|
|
98
|
+
|
|
99
|
+
### What to Check
|
|
100
|
+
1. **Link count** — meets minimum for content length
|
|
101
|
+
2. **Anchor text** — descriptive, keyword-rich (not "click here")
|
|
102
|
+
3. **Link relevance** — linked pages are topically related
|
|
103
|
+
4. **Link distribution** — links spread throughout content, not clustered
|
|
104
|
+
5. **Orphan detection** — identify posts with zero inbound internal links
|
|
105
|
+
6. **Reciprocal links** — pillar pages link to cluster posts and vice versa
|
|
106
|
+
|
|
107
|
+
### Link Opportunity Detection
|
|
108
|
+
Claude identifies linking opportunities by:
|
|
109
|
+
- Finding mentions of topics that have dedicated pages on the site
|
|
110
|
+
- Detecting keyword phrases that match other post titles
|
|
111
|
+
- Identifying related content that could provide context
|
|
112
|
+
- Suggesting links to pillar pages from cluster content
|
|
113
|
+
|
|
114
|
+
## External Linking
|
|
115
|
+
|
|
116
|
+
### Guidelines
|
|
117
|
+
|
|
118
|
+
| Metric | Target |
|
|
119
|
+
|--------|--------|
|
|
120
|
+
| External links per post | 1-2 minimum |
|
|
121
|
+
| Link targets | Authoritative, relevant sources (.gov, .edu, industry leaders) |
|
|
122
|
+
| Link freshness | Source content should be current (not outdated) |
|
|
123
|
+
| Nofollow | Use for sponsored or untrusted links |
|
|
124
|
+
| Open in new tab | Yes for external links (target="_blank") |
|
|
125
|
+
|
|
126
|
+
### What to Avoid
|
|
127
|
+
- Linking to direct competitors' commercial pages
|
|
128
|
+
- Linking to low-authority or spammy sites
|
|
129
|
+
- Excessive external links (>5 per 1000 words)
|
|
130
|
+
- Broken external links (check periodically)
|
|
131
|
+
|
|
132
|
+
## Image Alt Text Coverage
|
|
133
|
+
|
|
134
|
+
### Requirements
|
|
135
|
+
| Check | Standard |
|
|
136
|
+
|-------|----------|
|
|
137
|
+
| All images have alt text | 100% coverage required |
|
|
138
|
+
| Alt text includes keyword | At least 1 image per post |
|
|
139
|
+
| Alt text is descriptive | Describes the image content |
|
|
140
|
+
| Alt text length | 5-15 words |
|
|
141
|
+
| Decorative images | Empty alt="" (not missing alt) |
|
|
142
|
+
|
|
143
|
+
### Example
|
|
144
|
+
```
|
|
145
|
+
Good: alt="WordPress performance optimization dashboard showing page load times"
|
|
146
|
+
Bad: alt="image1" or alt="" (on informational image) or alt missing
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
## Combining with GSC Data
|
|
150
|
+
|
|
151
|
+
When Google Search Console is available, enrich the SEO scoring with real search data:
|
|
152
|
+
|
|
153
|
+
### Step 1: Fetch Search Queries for the Page
|
|
154
|
+
```
|
|
155
|
+
Use gsc_search_analytics with the page URL to get actual queries driving traffic.
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
### Step 2: Compare Target vs Actual Keywords
|
|
159
|
+
```
|
|
160
|
+
Target keyword: "wordpress speed optimization"
|
|
161
|
+
Actual top queries from GSC:
|
|
162
|
+
1. "wordpress speed" (pos 8, 500 impressions)
|
|
163
|
+
2. "wordpress performance" (pos 12, 300 impressions)
|
|
164
|
+
3. "how to speed up wordpress" (pos 15, 200 impressions)
|
|
165
|
+
|
|
166
|
+
Analysis: Content ranks for related terms but not the exact target.
|
|
167
|
+
Action: Strengthen primary keyword presence, add "how to speed up wordpress" as H2.
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
### Step 3: Identify Keyword Gaps
|
|
171
|
+
- Queries with high impressions but low CTR → meta description issue
|
|
172
|
+
- Queries with high position (>10) → content depth issue
|
|
173
|
+
- Queries the page ranks for that are not in the content → add sections
|
|
174
|
+
|
|
175
|
+
## SEO Content Score Card
|
|
176
|
+
|
|
177
|
+
### Scoring Template
|
|
178
|
+
```
|
|
179
|
+
SEO Content Score for: "Post Title"
|
|
180
|
+
═════════════════════════════════════
|
|
181
|
+
Keyword Density: 1.2% ✓ (target: 1-2%)
|
|
182
|
+
Keyword in H1: Yes ✓
|
|
183
|
+
Keyword in First 100: Yes ✓
|
|
184
|
+
Keyword in URL: Yes ✓
|
|
185
|
+
|
|
186
|
+
H2 Count: 4 ✓ (target: 2-6)
|
|
187
|
+
H2 with Keywords: 2/4 ✓ (target: 50%+)
|
|
188
|
+
H3 Count: 6 ✓
|
|
189
|
+
Heading Hierarchy: Valid ✓ (no skipped levels)
|
|
190
|
+
|
|
191
|
+
Internal Links: 2 ⚠ (target: 3-5 for 1200 words)
|
|
192
|
+
External Links: 1 ✓ (target: 1-2)
|
|
193
|
+
Anchor Text Quality: Good ✓
|
|
194
|
+
|
|
195
|
+
Image Alt Coverage: 3/4 ⚠ (1 image missing alt text)
|
|
196
|
+
Keyword in Alt: 1/4 ✓
|
|
197
|
+
|
|
198
|
+
Overall Score: 7.5/10
|
|
199
|
+
Priority Fixes:
|
|
200
|
+
1. Add 1-2 more internal links to related content
|
|
201
|
+
2. Add alt text to image in section 3
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
## Step-by-Step Workflow
|
|
205
|
+
|
|
206
|
+
### Step 1: Fetch Content
|
|
207
|
+
```
|
|
208
|
+
Use get_content to retrieve the full post HTML.
|
|
209
|
+
Parse headings, links, images, and body text.
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
### Step 2: Identify Target Keyword
|
|
213
|
+
Either provided by user or extracted from:
|
|
214
|
+
- Post title analysis
|
|
215
|
+
- GSC top query for the URL
|
|
216
|
+
- Content theme analysis
|
|
217
|
+
|
|
218
|
+
### Step 3: Run All Checks
|
|
219
|
+
Claude analyzes in sequence:
|
|
220
|
+
1. Keyword density and placement
|
|
221
|
+
2. Heading hierarchy and keyword coverage
|
|
222
|
+
3. Internal and external link audit
|
|
223
|
+
4. Image alt text coverage
|
|
224
|
+
5. GSC data cross-reference (if available)
|
|
225
|
+
|
|
226
|
+
### Step 4: Generate Score Card
|
|
227
|
+
Produce the formatted score card with pass/fail for each criterion.
|
|
228
|
+
|
|
229
|
+
### Step 5: Prioritize Fixes
|
|
230
|
+
Rank issues by impact:
|
|
231
|
+
1. Missing keyword in title/H1 (highest impact)
|
|
232
|
+
2. Keyword density out of range
|
|
233
|
+
3. No internal links
|
|
234
|
+
4. Missing alt text
|
|
235
|
+
5. Heading hierarchy issues
|
|
236
|
+
6. External link additions
|
|
237
|
+
|
|
238
|
+
## Best Practices
|
|
239
|
+
|
|
240
|
+
- Run SEO scoring before publishing (pre-publish checklist)
|
|
241
|
+
- Re-score after content updates to ensure changes did not break optimization
|
|
242
|
+
- Use GSC data to validate keyword targeting against real search behavior
|
|
243
|
+
- Do not sacrifice readability for SEO score — readability comes first
|
|
244
|
+
- Update scoring analysis quarterly as search patterns evolve
|
|
245
|
+
- Track score changes over time to measure optimization impact
|
|
@@ -0,0 +1,237 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* content_optimization_inspect.mjs — Detect content optimization readiness.
|
|
3
|
+
*
|
|
4
|
+
* Checks WordPress content volume, content age distribution, SEO plugins,
|
|
5
|
+
* readability plugins, GSC availability, and WooCommerce presence.
|
|
6
|
+
*
|
|
7
|
+
* Usage:
|
|
8
|
+
* node content_optimization_inspect.mjs [--cwd=/path/to/project]
|
|
9
|
+
*
|
|
10
|
+
* Exit codes:
|
|
11
|
+
* 0 — content optimization readiness found
|
|
12
|
+
* 1 — no content optimization readiness found
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
import { readFileSync, existsSync, readdirSync } from 'node:fs';
|
|
16
|
+
import { join, resolve } from 'node:path';
|
|
17
|
+
import { argv, stdout, exit } from 'node:process';
|
|
18
|
+
|
|
19
|
+
// ---------------------------------------------------------------------------
|
|
20
|
+
// Helpers
|
|
21
|
+
// ---------------------------------------------------------------------------
|
|
22
|
+
|
|
23
|
+
function readFileSafe(filePath) {
|
|
24
|
+
try { return readFileSync(filePath, 'utf-8'); } catch { return null; }
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function existsSafe(filePath) {
|
|
28
|
+
try { return existsSync(filePath); } catch { return false; }
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function globDir(dirPath) {
|
|
32
|
+
try { return readdirSync(dirPath); } catch { return []; }
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// ---------------------------------------------------------------------------
|
|
36
|
+
// Detectors
|
|
37
|
+
// ---------------------------------------------------------------------------
|
|
38
|
+
|
|
39
|
+
function detectContent(cwd) {
|
|
40
|
+
const indicators = [];
|
|
41
|
+
|
|
42
|
+
// Check wp-content directory exists
|
|
43
|
+
if (!existsSafe(join(cwd, 'wp-content'))) {
|
|
44
|
+
return { has_content: false, indicators };
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
indicators.push('wp-content directory exists');
|
|
48
|
+
|
|
49
|
+
// Check for uploads (indicator of content)
|
|
50
|
+
const uploads = globDir(join(cwd, 'wp-content', 'uploads'));
|
|
51
|
+
if (uploads.length > 0) {
|
|
52
|
+
indicators.push(`wp-content/uploads contains ${uploads.length} entries`);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// Check for themes presence
|
|
56
|
+
const themes = globDir(join(cwd, 'wp-content', 'themes'));
|
|
57
|
+
if (themes.length > 0) {
|
|
58
|
+
indicators.push(`${themes.length} theme(s) installed`);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
const hasContent = uploads.length > 0 || themes.length > 0;
|
|
62
|
+
return { has_content: hasContent, indicators };
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
function detectContentAge(cwd) {
|
|
66
|
+
const indicators = [];
|
|
67
|
+
const yearsFound = [];
|
|
68
|
+
|
|
69
|
+
const uploadsPath = join(cwd, 'wp-content', 'uploads');
|
|
70
|
+
if (!existsSafe(uploadsPath)) {
|
|
71
|
+
return { years_found: yearsFound, indicators };
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
const entries = globDir(uploadsPath);
|
|
75
|
+
const yearPattern = /^(20\d{2})$/;
|
|
76
|
+
|
|
77
|
+
for (const entry of entries) {
|
|
78
|
+
const match = entry.match(yearPattern);
|
|
79
|
+
if (match) {
|
|
80
|
+
yearsFound.push(parseInt(match[1], 10));
|
|
81
|
+
indicators.push(`upload directory found for year ${match[1]}`);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
yearsFound.sort();
|
|
86
|
+
|
|
87
|
+
if (yearsFound.length > 1) {
|
|
88
|
+
indicators.push(`content spans ${yearsFound.length} years (${yearsFound[0]}–${yearsFound[yearsFound.length - 1]})`);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
return { years_found: yearsFound, indicators };
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
function detectSeoPlugins(cwd) {
|
|
95
|
+
const indicators = [];
|
|
96
|
+
const plugins = globDir(join(cwd, 'wp-content', 'plugins'));
|
|
97
|
+
|
|
98
|
+
const seoPlugins = [
|
|
99
|
+
{ dir: 'wordpress-seo', name: 'Yoast SEO' },
|
|
100
|
+
{ dir: 'seo-by-rank-math', name: 'RankMath' },
|
|
101
|
+
{ dir: 'all-in-one-seo-pack', name: 'AIOSEO' },
|
|
102
|
+
];
|
|
103
|
+
|
|
104
|
+
for (const plugin of plugins) {
|
|
105
|
+
const lower = plugin.toLowerCase();
|
|
106
|
+
for (const seo of seoPlugins) {
|
|
107
|
+
if (lower === seo.dir) {
|
|
108
|
+
indicators.push(`seo_plugin: ${seo.name} (${plugin})`);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
return { found: indicators.length > 0, indicators };
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
function detectReadability(cwd) {
|
|
117
|
+
const indicators = [];
|
|
118
|
+
const plugins = globDir(join(cwd, 'wp-content', 'plugins'));
|
|
119
|
+
|
|
120
|
+
// Yoast and RankMath both include readability analysis
|
|
121
|
+
const readabilityPlugins = [
|
|
122
|
+
{ dir: 'wordpress-seo', name: 'Yoast SEO (readability analysis)' },
|
|
123
|
+
{ dir: 'seo-by-rank-math', name: 'RankMath (readability analysis)' },
|
|
124
|
+
];
|
|
125
|
+
|
|
126
|
+
for (const plugin of plugins) {
|
|
127
|
+
const lower = plugin.toLowerCase();
|
|
128
|
+
for (const rp of readabilityPlugins) {
|
|
129
|
+
if (lower === rp.dir) {
|
|
130
|
+
indicators.push(`readability_plugin: ${rp.name}`);
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
return { found: indicators.length > 0, indicators };
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
function detectGsc() {
|
|
139
|
+
const indicators = [];
|
|
140
|
+
let configured = false;
|
|
141
|
+
|
|
142
|
+
const raw = process.env.WP_SITES_CONFIG;
|
|
143
|
+
if (!raw) return { configured, indicators };
|
|
144
|
+
|
|
145
|
+
let sites;
|
|
146
|
+
try { sites = JSON.parse(raw); } catch { return { configured, indicators }; }
|
|
147
|
+
if (!Array.isArray(sites)) return { configured, indicators };
|
|
148
|
+
|
|
149
|
+
for (const site of sites) {
|
|
150
|
+
const label = site.name || site.url || 'unknown';
|
|
151
|
+
if (site.gsc_service_account_key) {
|
|
152
|
+
configured = true;
|
|
153
|
+
indicators.push(`gsc_service_account_key configured for ${label}`);
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
return { configured, indicators };
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
function detectWoocommerce(cwd) {
|
|
161
|
+
const indicators = [];
|
|
162
|
+
const plugins = globDir(join(cwd, 'wp-content', 'plugins'));
|
|
163
|
+
|
|
164
|
+
for (const plugin of plugins) {
|
|
165
|
+
if (plugin.toLowerCase() === 'woocommerce') {
|
|
166
|
+
indicators.push(`woocommerce plugin detected (${plugin})`);
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
return { found: indicators.length > 0, indicators };
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
// ---------------------------------------------------------------------------
|
|
174
|
+
// Main
|
|
175
|
+
// ---------------------------------------------------------------------------
|
|
176
|
+
|
|
177
|
+
function main() {
|
|
178
|
+
const cwdArg = argv.find(a => a.startsWith('--cwd='));
|
|
179
|
+
const cwd = cwdArg ? resolve(cwdArg.split('=')[1]) : process.cwd();
|
|
180
|
+
|
|
181
|
+
const content = detectContent(cwd);
|
|
182
|
+
const contentAge = detectContentAge(cwd);
|
|
183
|
+
const seoPlugins = detectSeoPlugins(cwd);
|
|
184
|
+
const readability = detectReadability(cwd);
|
|
185
|
+
const gscAvailable = detectGsc();
|
|
186
|
+
const woocommerce = detectWoocommerce(cwd);
|
|
187
|
+
|
|
188
|
+
const found = content.has_content &&
|
|
189
|
+
(seoPlugins.found || readability.found || gscAvailable.configured);
|
|
190
|
+
|
|
191
|
+
const recommendations = [];
|
|
192
|
+
|
|
193
|
+
if (content.has_content) {
|
|
194
|
+
recommendations.push('Content detected — ready for AI-driven optimization analysis');
|
|
195
|
+
}
|
|
196
|
+
if (seoPlugins.found) {
|
|
197
|
+
recommendations.push('SEO plugin detected — headline and meta description optimization can use plugin data');
|
|
198
|
+
}
|
|
199
|
+
if (readability.found) {
|
|
200
|
+
recommendations.push('Readability analysis available — use wp-content-optimization for Flesch-Kincaid scoring');
|
|
201
|
+
}
|
|
202
|
+
if (gscAvailable.configured) {
|
|
203
|
+
recommendations.push('GSC configured — combine search data with content optimization for data-driven improvements');
|
|
204
|
+
}
|
|
205
|
+
if (woocommerce.found) {
|
|
206
|
+
recommendations.push('WooCommerce detected — prioritize optimization of high-revenue content');
|
|
207
|
+
}
|
|
208
|
+
if (contentAge.years_found.length > 1) {
|
|
209
|
+
recommendations.push('Content spans multiple years — run Content Freshness Audit to identify stale content');
|
|
210
|
+
}
|
|
211
|
+
if (!content.has_content && !seoPlugins.found && !readability.found && !gscAvailable.configured) {
|
|
212
|
+
recommendations.push('No content or optimization tools detected — create content first, then use wp-content-optimization');
|
|
213
|
+
}
|
|
214
|
+
if (content.has_content && seoPlugins.found && gscAvailable.configured) {
|
|
215
|
+
recommendations.push('Full optimization stack ready — use wp-content-optimization for comprehensive content triage');
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
const report = {
|
|
219
|
+
tool: 'content_optimization_inspect',
|
|
220
|
+
version: '1.0.0',
|
|
221
|
+
timestamp: new Date().toISOString(),
|
|
222
|
+
cwd,
|
|
223
|
+
found,
|
|
224
|
+
content,
|
|
225
|
+
content_age: contentAge,
|
|
226
|
+
seo_plugins: seoPlugins,
|
|
227
|
+
readability,
|
|
228
|
+
gsc_available: gscAvailable,
|
|
229
|
+
woocommerce,
|
|
230
|
+
recommendations,
|
|
231
|
+
};
|
|
232
|
+
|
|
233
|
+
stdout.write(JSON.stringify(report, null, 2) + '\n');
|
|
234
|
+
exit(found ? 0 : 1);
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
main();
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: wp-content-workflows
|
|
3
|
+
description: This skill should be used when the user asks about "workflow automation",
|
|
4
|
+
"triggers", "scheduled tasks", "WP-Cron", "content publishing triggers",
|
|
5
|
+
"hook-based actions", "post status transitions", "automated notifications",
|
|
6
|
+
"workflow triggers", "event-driven actions", "content lifecycle hooks",
|
|
7
|
+
"multi-channel actions", "trigger management", or mentions setting up
|
|
8
|
+
automated workflows that fire on WordPress events or schedules.
|
|
9
|
+
version: 1.0.0
|
|
10
|
+
tags: [workflows, triggers, cron, automation, hooks, scheduling]
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
# WordPress Content Workflows Skill
|
|
14
|
+
|
|
15
|
+
## Overview
|
|
16
|
+
|
|
17
|
+
Event-driven workflow automation system for WordPress. Combines WP-Cron scheduling, content lifecycle hooks, and WordPress action/filter hooks to trigger multi-channel actions (Slack, email, webhook). Provides trigger creation, management, testing (dry-run), and audit logging. This skill connects WordPress events to notification and action channels, enabling automated responses to content changes, user actions, and scheduled tasks.
|
|
18
|
+
|
|
19
|
+
## When to Use
|
|
20
|
+
|
|
21
|
+
- User wants to create automated triggers for WordPress events
|
|
22
|
+
- User needs scheduled tasks (cron-based publishing, periodic reports)
|
|
23
|
+
- User asks about post status transitions (draft to published, trash, etc.)
|
|
24
|
+
- User wants to hook into WordPress actions (user_register, comment_post, etc.)
|
|
25
|
+
- User needs multi-channel action routing (Slack + email + webhook on same event)
|
|
26
|
+
- User asks about trigger management (list, test, enable/disable, delete)
|
|
27
|
+
- User wants to set up WooCommerce order-based workflows
|
|
28
|
+
- User needs to audit or troubleshoot existing workflow triggers
|
|
29
|
+
|
|
30
|
+
## Decision Tree
|
|
31
|
+
|
|
32
|
+
1. **What type of trigger?**
|
|
33
|
+
- "cron" / "scheduled" / "periodic" → Schedule-Based Triggers (Procedure 1)
|
|
34
|
+
- "on publish" / "post status" / "content change" → Content Lifecycle Hooks (Procedure 2)
|
|
35
|
+
- "on login" / "user register" / "comment" / "plugin" → WP Action/Filter Hooks (Procedure 3)
|
|
36
|
+
- "notify Slack and email" / "multi-channel" → Multi-Channel Action Configuration (Procedure 4)
|
|
37
|
+
- "list triggers" / "test" / "disable" / "delete" → Trigger Management (Procedure 5)
|
|
38
|
+
|
|
39
|
+
2. **Run detection first:**
|
|
40
|
+
```bash
|
|
41
|
+
node skills/wp-content-workflows/scripts/workflow_inspect.mjs [--cwd=/path/to/project]
|
|
42
|
+
```
|
|
43
|
+
This identifies configured action channels, automation plugins, WP-Cron status, and webhook setup.
|
|
44
|
+
|
|
45
|
+
## Procedures
|
|
46
|
+
|
|
47
|
+
### Procedure 1: Schedule-Based Triggers
|
|
48
|
+
|
|
49
|
+
See `references/schedule-triggers.md`
|
|
50
|
+
- Configure WP-Cron intervals (hourly, twicedaily, daily, weekly, custom)
|
|
51
|
+
- Set up scheduled content publishing triggers
|
|
52
|
+
- Create recurring health check and report triggers
|
|
53
|
+
- External cron setup (server cron vs WP-Cron)
|
|
54
|
+
- Test scheduled trigger with `wf_create_trigger` using cron schedule type
|
|
55
|
+
|
|
56
|
+
### Procedure 2: Content Lifecycle Hooks
|
|
57
|
+
|
|
58
|
+
See `references/content-lifecycle-hooks.md`
|
|
59
|
+
- Hook into post status transitions (draft→published, published→trash)
|
|
60
|
+
- Support custom post types (products, portfolios, events)
|
|
61
|
+
- Monitor taxonomy and term changes
|
|
62
|
+
- Track media upload events
|
|
63
|
+
- Create trigger with `wf_create_trigger` using content lifecycle event type
|
|
64
|
+
|
|
65
|
+
### Procedure 3: WP Action/Filter Hooks
|
|
66
|
+
|
|
67
|
+
See `references/wp-action-hooks.md`
|
|
68
|
+
- Hook into core WordPress actions (user_register, wp_login, comment_post)
|
|
69
|
+
- WooCommerce hooks (woocommerce_new_order, woocommerce_order_status_changed)
|
|
70
|
+
- Plugin activation/deactivation hooks
|
|
71
|
+
- Filter hooks for content transformation workflows
|
|
72
|
+
- Create trigger with `wf_create_trigger` using action hook event type
|
|
73
|
+
|
|
74
|
+
### Procedure 4: Multi-Channel Action Configuration
|
|
75
|
+
|
|
76
|
+
See `references/multi-channel-actions.md`
|
|
77
|
+
- Map triggers to one or more action channels (Slack, email, webhook)
|
|
78
|
+
- Configure template variables ({{post_title}}, {{user_name}}, {{order_total}})
|
|
79
|
+
- Channel-specific formatting (Block Kit for Slack, HTML for email, JSON for webhook)
|
|
80
|
+
- Rate limiting per channel to prevent flooding
|
|
81
|
+
- Update trigger actions with `wf_update_trigger`
|
|
82
|
+
|
|
83
|
+
### Procedure 5: Trigger Management
|
|
84
|
+
|
|
85
|
+
See `references/trigger-management.md`
|
|
86
|
+
- List and filter triggers with `wf_list_triggers`
|
|
87
|
+
- Activate/deactivate triggers without deleting (via `wf_update_trigger`)
|
|
88
|
+
- Test triggers in dry-run mode
|
|
89
|
+
- Review trigger audit log
|
|
90
|
+
- Bulk operations (enable/disable all, export/import)
|
|
91
|
+
- Delete stale triggers with `wf_delete_trigger`
|
|
92
|
+
|
|
93
|
+
## MCP Tools Reference
|
|
94
|
+
|
|
95
|
+
| Tool | Description |
|
|
96
|
+
|------|-------------|
|
|
97
|
+
| `wf_list_triggers` | List all workflow triggers with optional status/type filters |
|
|
98
|
+
| `wf_create_trigger` | Create a new workflow trigger (cron, lifecycle, action hook) |
|
|
99
|
+
| `wf_update_trigger` | Update trigger config, actions, or status (active/inactive) |
|
|
100
|
+
| `wf_delete_trigger` | Delete a workflow trigger (with safety confirmation) |
|
|
101
|
+
|
|
102
|
+
## Reference Files
|
|
103
|
+
|
|
104
|
+
| File | Content |
|
|
105
|
+
|------|---------|
|
|
106
|
+
| `references/schedule-triggers.md` | WP-Cron patterns, custom intervals, external cron setup |
|
|
107
|
+
| `references/content-lifecycle-hooks.md` | Post status transitions, CPT support, taxonomy changes, media events |
|
|
108
|
+
| `references/wp-action-hooks.md` | Core WP actions, WooCommerce hooks, plugin hooks, filter hooks |
|
|
109
|
+
| `references/multi-channel-actions.md` | Channel config, template variables, formatting, rate limiting |
|
|
110
|
+
| `references/trigger-management.md` | Listing, activate/deactivate, dry-run testing, audit log, bulk ops |
|
|
111
|
+
|
|
112
|
+
## Recommended Agent
|
|
113
|
+
|
|
114
|
+
Use the **`wp-site-manager`** for automated workflow orchestration that combines trigger creation, multi-channel action routing, and lifecycle management.
|
|
115
|
+
|
|
116
|
+
## Related Skills
|
|
117
|
+
|
|
118
|
+
- **`wp-alerting`** — shares Slack and SendGrid channels for notification delivery
|
|
119
|
+
- **`wp-monitoring`** — source of health/performance data that may trigger workflows
|
|
120
|
+
- **`wp-webhooks`** — outbound/inbound webhook infrastructure for webhook action channel
|
|
121
|
+
- **`wp-social-email`** — shares SendGrid and Mailchimp config for email actions
|
|
122
|
+
|
|
123
|
+
## Cross-references
|
|
124
|
+
|
|
125
|
+
- Workflow triggers pair with `wp-alerting` for severity-based notification routing
|
|
126
|
+
- Scheduled triggers depend on WP-Cron config detectable via `wp-monitoring`
|
|
127
|
+
- Webhook actions use `wp-webhooks` infrastructure for outbound delivery
|
|
128
|
+
- Email actions share SendGrid/Mailchimp config with `wp-social-email`
|
|
129
|
+
- WooCommerce hooks connect to `wp-woocommerce` for order-based workflows
|
|
130
|
+
|
|
131
|
+
## Troubleshooting
|
|
132
|
+
|
|
133
|
+
| Issue | Cause | Resolution |
|
|
134
|
+
|-------|-------|------------|
|
|
135
|
+
| Cron trigger not firing | DISABLE_WP_CRON is true and no server cron configured | Set up server cron job: `*/5 * * * * wget -qO- https://example.com/wp-cron.php` |
|
|
136
|
+
| Content hook missed | Post updated via direct DB query (bypasses hooks) | Ensure content changes go through `wp_update_post()` or REST API |
|
|
137
|
+
| Slack action fails | slack_webhook_url or slack_bot_token not configured | Add Slack credentials to WP_SITES_CONFIG |
|
|
138
|
+
| Email action 403 | SendGrid API key lacks Mail Send permission | Regenerate key with "Mail Send" access in SendGrid dashboard |
|
|
139
|
+
| Duplicate triggers firing | Multiple hooks registered for same event | Review triggers with `wf_list_triggers` and deduplicate |
|
|
140
|
+
| Trigger test fails | Action channel unreachable or credentials expired | Run `workflow_inspect.mjs` to verify channel configuration |
|
|
141
|
+
| WooCommerce hooks silent | WooCommerce not active or hooks not registered | Verify WooCommerce is active; hooks fire only after `woocommerce_init` |
|
|
142
|
+
| Detection script exit 1 | No workflow config found | Add action channel credentials to WP_SITES_CONFIG and install wp-crontrol |
|