claude-plugin-wordpress-manager 2.12.2 → 2.14.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 +8 -3
- package/CHANGELOG.md +94 -2
- package/agents/wp-accessibility-auditor.md +1 -1
- package/agents/wp-content-strategist.md +2 -2
- package/agents/wp-deployment-engineer.md +1 -1
- package/agents/wp-distribution-manager.md +1 -1
- package/agents/wp-monitoring-agent.md +1 -1
- package/agents/wp-performance-optimizer.md +1 -1
- package/agents/wp-security-auditor.md +1 -1
- package/agents/wp-site-manager.md +3 -3
- package/commands/wp-setup.md +2 -2
- package/docs/GUIDE.md +260 -21
- package/docs/VALIDATION.md +341 -0
- package/docs/guides/wp-ecommerce.md +4 -4
- package/docs/plans/2026-03-01-tier3-wcop-implementation.md +1 -1
- package/docs/plans/2026-03-01-tier4-5-implementation.md +1 -1
- package/docs/plans/2026-03-02-content-framework-architecture.md +612 -0
- package/docs/plans/2026-03-02-content-framework-strategic-reflections.md +228 -0
- package/docs/plans/2026-03-02-content-intelligence-phase2.md +560 -0
- package/docs/plans/2026-03-02-content-pipeline-phase1.md +456 -0
- package/docs/plans/2026-03-02-dashboard-kanban-design.md +761 -0
- package/docs/plans/2026-03-02-dashboard-kanban-implementation.md +598 -0
- package/docs/plans/2026-03-02-dashboard-strategy.md +363 -0
- package/docs/plans/2026-03-02-editorial-calendar-phase3.md +490 -0
- package/docs/validation/.gitkeep +0 -0
- package/docs/validation/dashboard.html +286 -0
- package/docs/validation/results.json +1705 -0
- package/package.json +16 -3
- package/scripts/context-scanner.mjs +446 -0
- package/scripts/dashboard-renderer.mjs +553 -0
- package/scripts/run-validation.mjs +1132 -0
- package/servers/wp-rest-bridge/build/server.js +17 -6
- package/servers/wp-rest-bridge/build/tools/index.js +0 -9
- package/servers/wp-rest-bridge/build/tools/plugin-repository.js +23 -31
- package/servers/wp-rest-bridge/build/tools/schema.js +10 -2
- package/servers/wp-rest-bridge/build/tools/unified-content.js +10 -2
- package/servers/wp-rest-bridge/build/wordpress.d.ts +0 -3
- package/servers/wp-rest-bridge/build/wordpress.js +16 -98
- package/servers/wp-rest-bridge/package.json +1 -0
- package/skills/wp-analytics/SKILL.md +153 -0
- package/skills/wp-analytics/references/signals-feed-schema.md +417 -0
- package/skills/wp-content/references/content-templates.md +1 -1
- package/skills/wp-content/references/seo-optimization.md +8 -8
- package/skills/wp-content-attribution/references/roi-calculation.md +1 -1
- package/skills/wp-content-attribution/references/utm-tracking-setup.md +5 -5
- package/skills/wp-content-generation/references/generation-workflow.md +2 -2
- package/skills/wp-content-pipeline/SKILL.md +461 -0
- package/skills/wp-content-pipeline/references/content-brief-schema.md +377 -0
- package/skills/wp-content-pipeline/references/site-config-schema.md +431 -0
- package/skills/wp-content-repurposing/references/auto-transform-pipeline.md +1 -1
- package/skills/wp-content-repurposing/references/email-newsletter.md +1 -1
- package/skills/wp-content-repurposing/references/platform-specs.md +2 -2
- package/skills/wp-content-repurposing/references/transform-templates.md +27 -27
- package/skills/wp-dashboard/SKILL.md +121 -0
- package/skills/wp-deploy/references/ssh-deploy.md +2 -2
- package/skills/wp-editorial-planner/SKILL.md +262 -0
- package/skills/wp-editorial-planner/references/editorial-schema.md +268 -0
- package/skills/wp-multilang-network/references/content-sync.md +3 -3
- package/skills/wp-multilang-network/references/network-architecture.md +1 -1
- package/skills/wp-multilang-network/references/seo-international.md +7 -7
- package/skills/wp-structured-data/references/schema-types.md +4 -4
- package/skills/wp-webhooks/references/payload-formats.md +3 -3
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: wp-dashboard
|
|
3
|
+
description: This skill should be used when the user asks to "show dashboard",
|
|
4
|
+
"show editorial status", "open kanban", "visualize content state",
|
|
5
|
+
"show content overview", "mostra dashboard", "apri kanban", "stato editoriale",
|
|
6
|
+
"dove siamo con i post", or wants a visual overview of the editorial pipeline.
|
|
7
|
+
Generates a self-contained HTML Kanban board from .content-state/ files
|
|
8
|
+
and opens it in the browser.
|
|
9
|
+
version: 1.0.0
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
# WordPress Dashboard Skill
|
|
13
|
+
|
|
14
|
+
## Overview
|
|
15
|
+
|
|
16
|
+
Generates a self-contained HTML Kanban dashboard from `.content-state/` files and opens it in the default browser. The dashboard provides a visual overview of the editorial pipeline — all content entries grouped by lifecycle status (planned, draft, ready, scheduled, published) — plus aggregate metrics and active signals.
|
|
17
|
+
|
|
18
|
+
The HTML file has zero external dependencies. It reads the same `.content-state/` files used by `wp-content-pipeline` and `wp-editorial-planner`, computes aggregate metrics, and renders a static report.
|
|
19
|
+
|
|
20
|
+
## When to Use
|
|
21
|
+
|
|
22
|
+
- User wants to see the overall editorial status before starting work
|
|
23
|
+
- User asks "dove siamo con i post?" or "show me the editorial status"
|
|
24
|
+
- User wants to share a visual overview with stakeholders
|
|
25
|
+
- Before a planning session (to identify gaps in the calendar)
|
|
26
|
+
- After a publishing session (to confirm progress)
|
|
27
|
+
- When investigating why content is stuck in a particular status
|
|
28
|
+
|
|
29
|
+
## Workflow
|
|
30
|
+
|
|
31
|
+
### Step 1: Determine Target Site
|
|
32
|
+
|
|
33
|
+
- If the user specifies a site → use it
|
|
34
|
+
- If only one `.config.md` exists in `.content-state/` → use that site automatically
|
|
35
|
+
- If multiple sites exist → ask the user which site to visualize
|
|
36
|
+
|
|
37
|
+
### Step 2: Determine Target Month
|
|
38
|
+
|
|
39
|
+
- Default: the most recent editorial calendar found in `.content-state/`
|
|
40
|
+
- If the user specifies a month → use `--month=YYYY-MM`
|
|
41
|
+
|
|
42
|
+
### Step 3: Generate Dashboard
|
|
43
|
+
|
|
44
|
+
Run the renderer script:
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
node scripts/dashboard-renderer.mjs --site={siteId}
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
Optional flags:
|
|
51
|
+
- `--month=YYYY-MM` — specific month
|
|
52
|
+
- `--output=/path/to/file.html` — custom output path
|
|
53
|
+
- `--no-open` — generate HTML without opening browser
|
|
54
|
+
|
|
55
|
+
The script will:
|
|
56
|
+
1. SCAN `.content-state/` files (config, calendar, briefs, signals)
|
|
57
|
+
2. AGGREGATE metrics (progress, pipeline counts, fill rate, next deadline)
|
|
58
|
+
3. RENDER self-contained HTML Kanban
|
|
59
|
+
4. Write to `.content-state/.dashboard-{site}-{month}.html`
|
|
60
|
+
5. Open in default browser
|
|
61
|
+
|
|
62
|
+
### Step 4: Report to User
|
|
63
|
+
|
|
64
|
+
After generation, report:
|
|
65
|
+
- File path and size
|
|
66
|
+
- Key metrics: posts published/target, pipeline status, signals count
|
|
67
|
+
- Suggest next actions based on what the dashboard reveals
|
|
68
|
+
|
|
69
|
+
## Reading the Dashboard
|
|
70
|
+
|
|
71
|
+
### Kanban Columns
|
|
72
|
+
|
|
73
|
+
| Column | Meaning | Next Action |
|
|
74
|
+
|--------|---------|-------------|
|
|
75
|
+
| **Planned** | Calendar slot exists, no brief yet. Grey cards may have no title. | Assign topics, create briefs → `wp-editorial-planner` BRIEF step |
|
|
76
|
+
| **Draft** | Brief created, content being written. | Fill brief content, then set `status: ready` |
|
|
77
|
+
| **Ready** | Content validated, waiting for scheduling. | Schedule to WordPress → `wp-editorial-planner` SCHEDULE step |
|
|
78
|
+
| **Scheduled** | WordPress future post created, waiting for publish date. | Wait, or run SYNC to check status |
|
|
79
|
+
| **Published** | Live on WordPress. Green border, shows WP post ID. | Distribute to channels → `wp-content-pipeline` DISTRIBUTE step |
|
|
80
|
+
|
|
81
|
+
### Card Elements
|
|
82
|
+
|
|
83
|
+
- **Date**: target publish date from the editorial calendar
|
|
84
|
+
- **Title**: content title (or `[da assegnare]` for unassigned slots)
|
|
85
|
+
- **Brief ID**: `BRF-YYYY-NNN` identifier linking to the brief file
|
|
86
|
+
- **WP #ID**: WordPress post ID (only for scheduled/published)
|
|
87
|
+
- **Channel badges**: colored pills showing distribution channels (in=LinkedIn, tw=Twitter, nl=Newsletter, bf=Buffer)
|
|
88
|
+
|
|
89
|
+
### Progress Bar
|
|
90
|
+
|
|
91
|
+
Shows `published / target` ratio. The target comes from the calendar's `goals.posts_target`.
|
|
92
|
+
|
|
93
|
+
### Signals Strip
|
|
94
|
+
|
|
95
|
+
Shows anomalies from `signals-feed.md` with delta percentage, entity, and suggested action. Only appears if signals data exists.
|
|
96
|
+
|
|
97
|
+
## Next Actions by Observation
|
|
98
|
+
|
|
99
|
+
| What You See | What To Do | Skill |
|
|
100
|
+
|-------------|------------|-------|
|
|
101
|
+
| Empty "Planned" slots | Assign topics from signals or strategy | `wp-editorial-planner` PLAN |
|
|
102
|
+
| Planned entries without briefs | Convert to briefs | `wp-editorial-planner` BRIEF |
|
|
103
|
+
| Many entries stuck in "Draft" | Fill content in brief files | Manual editing |
|
|
104
|
+
| "Ready" entries waiting | Schedule to WordPress | `wp-editorial-planner` SCHEDULE |
|
|
105
|
+
| "Scheduled" not moving to "Published" | Run sync check | `wp-editorial-planner` SYNC |
|
|
106
|
+
| High-delta signals | Investigate and create content | `wp-analytics`, `wp-search-console` |
|
|
107
|
+
| Low fill rate (<50%) | Plan more content | `wp-editorial-planner` PLAN |
|
|
108
|
+
|
|
109
|
+
## Safety Rules
|
|
110
|
+
|
|
111
|
+
- This skill is **read-only**: it reads `.content-state/` files but never modifies them
|
|
112
|
+
- The generated HTML is an ephemeral artifact — regenerate anytime for fresh data
|
|
113
|
+
- Dashboard files are gitignored (`.content-state/.dashboard-*.html`)
|
|
114
|
+
- No external network calls are made during generation
|
|
115
|
+
|
|
116
|
+
## Related Skills
|
|
117
|
+
|
|
118
|
+
- **`wp-editorial-planner`** — manages the editorial calendar that feeds the dashboard
|
|
119
|
+
- **`wp-content-pipeline`** — processes briefs shown in the Kanban cards
|
|
120
|
+
- **`wp-analytics`** — generates the signals feed shown in the signals strip
|
|
121
|
+
- **`wp-search-console`** — contributes search data to the signals feed
|
|
@@ -47,10 +47,10 @@ ssh user@host 'rm /tmp/theme-name.tar.gz'
|
|
|
47
47
|
## SSH Config for Hostinger
|
|
48
48
|
|
|
49
49
|
```
|
|
50
|
-
Host
|
|
50
|
+
Host mysite-hostinger
|
|
51
51
|
HostName <ip-or-hostname>
|
|
52
52
|
User <hostinger-username>
|
|
53
|
-
IdentityFile ~/.ssh/
|
|
53
|
+
IdentityFile ~/.ssh/hostinger_mysite_20250904
|
|
54
54
|
IdentitiesOnly yes
|
|
55
55
|
```
|
|
56
56
|
|
|
@@ -0,0 +1,262 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: wp-editorial-planner
|
|
3
|
+
description: This skill should be used when the user asks to "create an editorial
|
|
4
|
+
plan", "update the calendar", "schedule posts", "plan content for March",
|
|
5
|
+
"convert calendar to briefs", "sync calendar with WordPress", "show editorial
|
|
6
|
+
status", or mentions planning content over time. Orchestrates monthly editorial
|
|
7
|
+
calendars that bridge signals intelligence to content publishing.
|
|
8
|
+
version: 1.0.0
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
# WordPress Editorial Planner Skill
|
|
12
|
+
|
|
13
|
+
## Overview
|
|
14
|
+
|
|
15
|
+
The editorial planner manages monthly content calendars as `.state.md` files stored in `.content-state/`. It reads site configuration for publishing cadence, optionally consumes the signals feed generated by `wp-analytics` for data-driven topic ideas, and produces structured briefs that flow into the content pipeline for WordPress publishing. The workflow follows four sequential steps: **PLAN** (create or update the monthly calendar), **BRIEF** (convert planned entries into pipeline brief files), **SCHEDULE** (create WordPress future posts from ready briefs), and **SYNC** (synchronize WordPress publish status back to the calendar). Each step is idempotent and can be run independently.
|
|
16
|
+
|
|
17
|
+
## When to Use
|
|
18
|
+
|
|
19
|
+
- User wants to create a new monthly editorial plan
|
|
20
|
+
- User asks to update or view the current calendar
|
|
21
|
+
- User wants to convert planned entries into content briefs
|
|
22
|
+
- User asks to schedule ready briefs as WordPress future posts
|
|
23
|
+
- User wants to sync WordPress publish status back to the calendar
|
|
24
|
+
- User mentions "piano editoriale", "calendario", "schedula"
|
|
25
|
+
|
|
26
|
+
## Workflow Overview
|
|
27
|
+
|
|
28
|
+
```
|
|
29
|
+
PLAN --> BRIEF --> SCHEDULE --> SYNC
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
---
|
|
33
|
+
|
|
34
|
+
## Step 1: PLAN -- Create or update editorial calendar
|
|
35
|
+
|
|
36
|
+
**When to run:** User asks to create a new plan or update an existing one.
|
|
37
|
+
|
|
38
|
+
**Procedure:**
|
|
39
|
+
|
|
40
|
+
1. **Read site configuration** from `.content-state/{site_id}.config.md`:
|
|
41
|
+
- `cadence.posts_per_week` -- calculate `goals.posts_target` as `posts_per_week * weeks_in_month`
|
|
42
|
+
- `cadence.preferred_days` -- determine which weekdays to assign calendar entries
|
|
43
|
+
- `cadence.publish_time` -- note for the SCHEDULE step
|
|
44
|
+
- `defaults.categories`, `defaults.content_type` -- pre-fill the entry Tipo column
|
|
45
|
+
|
|
46
|
+
2. **Read signals feed** from `.content-state/signals-feed.md` if it exists:
|
|
47
|
+
- Extract anomalies with action containing "content cluster" or "Investigate"
|
|
48
|
+
- Suggest these as topics for `[da assegnare]` entries
|
|
49
|
+
- Present suggestions to user for approval before inserting into the calendar
|
|
50
|
+
|
|
51
|
+
3. **Optional strategic planning:** If the user wants a higher-level content strategy, suggest invoking GenMarketing for content calendar strategy development before populating individual entries.
|
|
52
|
+
|
|
53
|
+
4. **Generate or update** `.content-state/{YYYY-MM}-editorial.state.md`:
|
|
54
|
+
- Create YAML frontmatter with `calendar_id`, `site_id`, `period`, `goals`
|
|
55
|
+
- Create weekly tables with one row per `preferred_day`
|
|
56
|
+
- Fill known titles where provided, leave others as `[da assegnare]`
|
|
57
|
+
- Set all new entries as `status: planned`
|
|
58
|
+
|
|
59
|
+
5. **Present the calendar** to the user for review before writing to disk.
|
|
60
|
+
|
|
61
|
+
**Safety rules:**
|
|
62
|
+
- ALWAYS show the generated calendar to the user before writing the file
|
|
63
|
+
- If a calendar for the month already exists, show the diff and ask before overwriting
|
|
64
|
+
- Preserve existing entries that have `status: draft` or higher -- never reset them to `planned`
|
|
65
|
+
|
|
66
|
+
---
|
|
67
|
+
|
|
68
|
+
## Step 2: BRIEF -- Convert calendar entries to brief files
|
|
69
|
+
|
|
70
|
+
**When to run:** User asks to "create briefs from calendar" or "convert planned entries to briefs".
|
|
71
|
+
|
|
72
|
+
**Procedure:**
|
|
73
|
+
|
|
74
|
+
1. Read the current editorial calendar `.state.md` file.
|
|
75
|
+
|
|
76
|
+
2. For each entry with `status: planned` AND a defined title (not `[da assegnare]`):
|
|
77
|
+
a. Generate a new `brief_id` as `BRF-YYYY-NNN` (sequential; scan existing briefs in both `pipeline-active/` and `pipeline-archive/` to determine the next number)
|
|
78
|
+
b. Read `.content-state/{site_id}.config.md` for site defaults
|
|
79
|
+
c. Create `.content-state/pipeline-active/{brief_id}.brief.md` with:
|
|
80
|
+
- `source.skill: wp-editorial-planner`
|
|
81
|
+
- `source.domain: editorial-calendar`
|
|
82
|
+
- `target.site_id`: from calendar `site_id`
|
|
83
|
+
- `target.content_type`: from entry Tipo column
|
|
84
|
+
- `target.scheduled_date`: from entry Data column (convert to ISO 8601)
|
|
85
|
+
- `target.categories`: from site config defaults
|
|
86
|
+
- `distribution.channels`: from entry Canali column (parse comma-separated)
|
|
87
|
+
- `content.title`: from entry Titolo column
|
|
88
|
+
- `status: draft` (brief starts as draft; user fills content)
|
|
89
|
+
d. Update the calendar entry: `status: planned` becomes `draft`, set the Brief ID column
|
|
90
|
+
|
|
91
|
+
3. For entries with an existing Brief ID (already has a brief): skip creation, just verify the brief file exists in `pipeline-active/`. If the file is missing, report it.
|
|
92
|
+
|
|
93
|
+
4. Write the updated calendar back to the `.state.md` file.
|
|
94
|
+
|
|
95
|
+
5. Report to user:
|
|
96
|
+
```
|
|
97
|
+
N brief creati in pipeline-active/. Compila il contenuto e imposta status: ready.
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
**Safety rules:**
|
|
101
|
+
- NEVER create briefs for entries with `[da assegnare]` title -- report them as needing titles first
|
|
102
|
+
- NEVER overwrite existing brief files -- if a Brief ID already exists as a file, skip and report
|
|
103
|
+
- Show a summary of briefs to be created and ask user confirmation before writing any files
|
|
104
|
+
|
|
105
|
+
---
|
|
106
|
+
|
|
107
|
+
## Step 3: SCHEDULE -- Convert ready briefs to WordPress scheduled posts
|
|
108
|
+
|
|
109
|
+
**When to run:** User asks to "schedule ready posts" or "schedula i post pronti".
|
|
110
|
+
|
|
111
|
+
**Procedure:**
|
|
112
|
+
|
|
113
|
+
1. Read the current editorial calendar `.state.md` file.
|
|
114
|
+
|
|
115
|
+
2. For each entry with `status: ready`:
|
|
116
|
+
a. Read the corresponding brief file from `pipeline-active/{brief_id}.brief.md`
|
|
117
|
+
b. Verify the brief has `status: ready` (consistency check between calendar and brief)
|
|
118
|
+
c. Create the WordPress post using MCP tool:
|
|
119
|
+
```
|
|
120
|
+
create_content:
|
|
121
|
+
content_type: {entry.Tipo}
|
|
122
|
+
title: {brief.content.title}
|
|
123
|
+
content: {brief body markdown}
|
|
124
|
+
excerpt: {brief.content.excerpt}
|
|
125
|
+
status: "future"
|
|
126
|
+
date: {entry.Data as ISO 8601 datetime with site config publish_time}
|
|
127
|
+
slug: {auto-generated from title}
|
|
128
|
+
```
|
|
129
|
+
d. Assign taxonomy terms using MCP tool:
|
|
130
|
+
```
|
|
131
|
+
assign_terms_to_content:
|
|
132
|
+
content_type: {entry.Tipo}
|
|
133
|
+
id: {post_id}
|
|
134
|
+
categories: {brief.target.categories}
|
|
135
|
+
tags: {brief.target.tags}
|
|
136
|
+
```
|
|
137
|
+
e. Update the calendar entry: `status: ready` becomes `scheduled`, set Post ID column
|
|
138
|
+
f. Update the brief file: add `post_id` and `post_url` to frontmatter
|
|
139
|
+
|
|
140
|
+
3. If the entry has `distribution.channels` (from the Canali column):
|
|
141
|
+
- Compute `scheduled_at` using the entry date + `config.cadence.publish_time` + `distribution.schedule_offset_hours`
|
|
142
|
+
- For Buffer: call `buf_create_update` with the computed `scheduled_at`
|
|
143
|
+
```
|
|
144
|
+
buf_create_update:
|
|
145
|
+
profile_ids: [{config.channels.buffer.profile_id}]
|
|
146
|
+
text: {adapted content}
|
|
147
|
+
media:
|
|
148
|
+
photo: {featured image URL if available}
|
|
149
|
+
scheduled_at: {ISO 8601 UTC timestamp}
|
|
150
|
+
```
|
|
151
|
+
- For Mailchimp: note for manual campaign creation (not auto-scheduled at this step)
|
|
152
|
+
|
|
153
|
+
4. Write the updated calendar back to the `.state.md` file.
|
|
154
|
+
|
|
155
|
+
5. Report to user:
|
|
156
|
+
```
|
|
157
|
+
N post schedulati su WordPress. Verranno pubblicati automaticamente alla data prevista.
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
**Safety rules:**
|
|
161
|
+
- ALWAYS create WordPress posts as `status: future` (never directly `publish`)
|
|
162
|
+
- ALWAYS confirm with user before scheduling, showing the list of posts and their dates
|
|
163
|
+
- If `create_content` fails for any entry, stop processing that entry, report the error, and keep the entry as `ready`
|
|
164
|
+
- Verify the scheduled date is in the future before calling `create_content` -- if the date is in the past, report to user and skip
|
|
165
|
+
|
|
166
|
+
---
|
|
167
|
+
|
|
168
|
+
## Step 4: SYNC -- Synchronize WordPress status back to calendar
|
|
169
|
+
|
|
170
|
+
**When to run:** User asks to "sync calendar" or "aggiorna stato calendario".
|
|
171
|
+
|
|
172
|
+
**Procedure:**
|
|
173
|
+
|
|
174
|
+
1. Read the current editorial calendar `.state.md` file.
|
|
175
|
+
|
|
176
|
+
2. For each entry with a Post ID (status: `scheduled` or `published`):
|
|
177
|
+
a. Call `list_content` with the content type and filter by post ID:
|
|
178
|
+
```
|
|
179
|
+
list_content:
|
|
180
|
+
content_type: {entry.Tipo}
|
|
181
|
+
search: {post_id}
|
|
182
|
+
per_page: 1
|
|
183
|
+
```
|
|
184
|
+
b. Check the returned post status and update the calendar accordingly:
|
|
185
|
+
- If WP status = `publish` and calendar status = `scheduled` --> update to `published`
|
|
186
|
+
- If WP status = `future` --> keep as `scheduled`
|
|
187
|
+
- If WP status = `draft` --> note: post was reverted, update calendar to `draft`
|
|
188
|
+
- If WP status = `trash` --> note: post was deleted, report to user
|
|
189
|
+
|
|
190
|
+
3. Recalculate `goals.posts_published` = count of entries with `status: published`.
|
|
191
|
+
|
|
192
|
+
4. Write the updated calendar back to the `.state.md` file.
|
|
193
|
+
|
|
194
|
+
5. Report to user:
|
|
195
|
+
```
|
|
196
|
+
Sync calendario {calendar_id}:
|
|
197
|
+
- Post pubblicati: {posts_published}/{posts_target}
|
|
198
|
+
- Post schedulati: {scheduled_count}
|
|
199
|
+
- Post in lavorazione: {draft_count + ready_count}
|
|
200
|
+
- Slot da assegnare: {planned_count}
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
**Safety rules:**
|
|
204
|
+
- NEVER modify WordPress post status during sync -- sync is read-only from WordPress
|
|
205
|
+
- If a post was deleted or trashed, report to user but do not remove the calendar entry (mark with a note instead)
|
|
206
|
+
|
|
207
|
+
---
|
|
208
|
+
|
|
209
|
+
## Creating a Calendar Manually
|
|
210
|
+
|
|
211
|
+
When the user wants to create a calendar without running the full PLAN step:
|
|
212
|
+
|
|
213
|
+
1. Copy the structure from `references/editorial-schema.md`
|
|
214
|
+
2. Fill in `site_id`, dates for each entry, and known titles
|
|
215
|
+
3. Set `status: planned` for all entries
|
|
216
|
+
4. Save as `.content-state/{YYYY-MM}-editorial.state.md`
|
|
217
|
+
5. Then run the BRIEF step to generate brief files from the planned entries
|
|
218
|
+
|
|
219
|
+
---
|
|
220
|
+
|
|
221
|
+
## Safety Rules Summary
|
|
222
|
+
|
|
223
|
+
- **ALWAYS** show the calendar and briefs to the user before writing any files
|
|
224
|
+
- **ALWAYS** create WordPress posts as `status: future` (never `publish` directly)
|
|
225
|
+
- **NEVER** overwrite existing briefs or calendar entries with higher status
|
|
226
|
+
- **NEVER** modify WordPress posts during SYNC (read-only operation)
|
|
227
|
+
- **ALWAYS** confirm with the user before scheduling posts to WordPress
|
|
228
|
+
- **LOG** all scheduling actions in the calendar state file
|
|
229
|
+
|
|
230
|
+
---
|
|
231
|
+
|
|
232
|
+
## Known Limitations
|
|
233
|
+
|
|
234
|
+
### AIWU MCP Server (cloud-based)
|
|
235
|
+
|
|
236
|
+
The AIWU MCP server (`mcp__claude_ai_AIWU`) does **not** support the `post_date` field in `wp_create_post` or `wp_update_post`. This means `post_status: "future"` cannot be achieved through AIWU — WordPress auto-publishes the post when no future date is provided.
|
|
237
|
+
|
|
238
|
+
**E2E test results (2026-03-02):**
|
|
239
|
+
- `wp_create_post` with `post_status: "future"` → auto-published (no `post_date` parameter available)
|
|
240
|
+
- `wp_update_post` with `post_date` + `post_status: "future"` from `draft` → auto-published (`post_date` not passed through)
|
|
241
|
+
- `wp_update_post` on already-published post → `post_date` updated but status cannot revert from `publish` to `future`
|
|
242
|
+
|
|
243
|
+
**Workaround:** Use the wp-rest-bridge MCP server's `create_content` tool, which natively supports the `date` parameter for scheduling future posts. AIWU can still be used for SYNC (read-only) and for content management tasks that don't require future scheduling.
|
|
244
|
+
|
|
245
|
+
---
|
|
246
|
+
|
|
247
|
+
## Reference Files
|
|
248
|
+
|
|
249
|
+
- `references/editorial-schema.md` -- complete schema for editorial calendar `.state.md` files
|
|
250
|
+
- `../wp-content-pipeline/references/content-brief-schema.md` -- brief file format and frontmatter fields
|
|
251
|
+
- `../wp-content-pipeline/references/site-config-schema.md` -- site configuration defaults and cadence settings
|
|
252
|
+
- `../wp-analytics/references/signals-feed-schema.md` -- signals feed format for topic suggestions
|
|
253
|
+
|
|
254
|
+
---
|
|
255
|
+
|
|
256
|
+
## Related Skills
|
|
257
|
+
|
|
258
|
+
- **`wp-content-pipeline`** -- publishes briefs created by the BRIEF step through the full pipeline workflow
|
|
259
|
+
- **`wp-analytics`** -- generates the signals feed consumed by the PLAN step for data-driven topic ideas
|
|
260
|
+
- **`wp-content`** -- content creation and management (provides `create_content`, `list_content` MCP tools)
|
|
261
|
+
- **`wp-social-email`** -- distribution channel scheduling (Buffer via `buf_create_update`, Mailchimp campaigns)
|
|
262
|
+
- **`wp-content-repurposing`** -- multi-format adaptation for social distribution channels
|
|
@@ -0,0 +1,268 @@
|
|
|
1
|
+
# Editorial Calendar Schema
|
|
2
|
+
|
|
3
|
+
Schema reference for `{YYYY-MM}-editorial.state.md` files -- the monthly editorial calendar format used by the `wp-editorial-planner` skill to plan, track, and synchronize content across the publishing lifecycle.
|
|
4
|
+
|
|
5
|
+
Each editorial calendar is a Markdown file with YAML frontmatter containing monthly goals and metadata, followed by weekly Markdown tables for content planning. Each table row represents a content entry that progresses through a five-stage status lifecycle and bridges to Phase 1 briefs (`.brief.md` files in the content pipeline) and Phase 2 signals (from the signals intelligence feed).
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## File Format
|
|
10
|
+
|
|
11
|
+
Each `{YYYY-MM}-editorial.state.md` file consists of:
|
|
12
|
+
|
|
13
|
+
1. **YAML frontmatter** between `---` delimiters (monthly goals, metadata, SEO targets)
|
|
14
|
+
2. **Markdown body** with weekly table sections, one per week of the month
|
|
15
|
+
|
|
16
|
+
```
|
|
17
|
+
---
|
|
18
|
+
calendar_id: "CAL-2026-03"
|
|
19
|
+
site_id: mysite
|
|
20
|
+
# ... other fields ...
|
|
21
|
+
---
|
|
22
|
+
|
|
23
|
+
# Piano Editoriale — Marzo 2026
|
|
24
|
+
|
|
25
|
+
## Settimana 1 (1-7 Mar)
|
|
26
|
+
|
|
27
|
+
| Data | Titolo | Tipo | Status | Brief ID | Post ID | Canali |
|
|
28
|
+
|------|--------|------|--------|----------|---------|--------|
|
|
29
|
+
| Mar 4 | Article title here | post | planned | — | — | — |
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
---
|
|
33
|
+
|
|
34
|
+
## Frontmatter Fields
|
|
35
|
+
|
|
36
|
+
| Field | Type | Required | Default | Description |
|
|
37
|
+
|-------|------|----------|---------|-------------|
|
|
38
|
+
| `calendar_id` | `string` | **Yes** | -- | Unique calendar identifier. Format: `CAL-YYYY-MM` |
|
|
39
|
+
| `site_id` | `string` | **Yes** | -- | WordPress site identifier. Must match an existing `.content-state/{site_id}.config.md` |
|
|
40
|
+
| `period` | `string` | **Yes** | -- | Date range the calendar covers. Format: `YYYY-MM-DD..YYYY-MM-DD` (month boundaries) |
|
|
41
|
+
| `created` | `string` (ISO 8601) | **Yes** | -- | Date the calendar was first created |
|
|
42
|
+
| `last_updated` | `string` (ISO 8601) | **Yes** | -- | Auto-updated on each modification |
|
|
43
|
+
| `status` | `enum` | No | `active` | Calendar status: `active` \| `archived` |
|
|
44
|
+
| `goals.posts_target` | `integer` | **Yes** | -- | Total posts planned for the month |
|
|
45
|
+
| `goals.posts_published` | `integer` | No | `0` | Counter updated by SYNC step |
|
|
46
|
+
| `goals.focus_topics` | `string[]` | No | `[]` | Topic clusters to prioritize this month |
|
|
47
|
+
| `goals.seo_targets` | `object[]` | No | `[]` | Each object: `{keyword, target_position}` |
|
|
48
|
+
|
|
49
|
+
### `goals.seo_targets` object fields
|
|
50
|
+
|
|
51
|
+
| Field | Type | Required | Description |
|
|
52
|
+
|-------|------|----------|-------------|
|
|
53
|
+
| `keyword` | `string` | **Yes** | Target keyword or keyphrase |
|
|
54
|
+
| `target_position` | `string` | **Yes** | SERP target: `top-3`, `top-5`, `top-10`, `top-20` |
|
|
55
|
+
|
|
56
|
+
---
|
|
57
|
+
|
|
58
|
+
## Weekly Table Structure
|
|
59
|
+
|
|
60
|
+
The body contains one `## Settimana N (date range)` section per week of the month. Each section contains a single Markdown table with 7 columns:
|
|
61
|
+
|
|
62
|
+
| Column | Type | Description |
|
|
63
|
+
|--------|------|-------------|
|
|
64
|
+
| Data | `date` | Planned publication date. Format: `Mon DD` (e.g., `Mar 4`) |
|
|
65
|
+
| Titolo | `string` | Content title, or `[da assegnare]` if not yet defined |
|
|
66
|
+
| Tipo | `enum` | WordPress content type: `post` \| `page` \| `custom_type` |
|
|
67
|
+
| Status | `enum` | Entry lifecycle status: `planned` \| `draft` \| `ready` \| `scheduled` \| `published` |
|
|
68
|
+
| Brief ID | `string` | Reference to `.brief.md` file. Format: `BRF-YYYY-NNN`, or `—` if not yet created |
|
|
69
|
+
| Post ID | `integer` | WordPress post ID after creation, or `—` if not yet created |
|
|
70
|
+
| Canali | `string` | Comma-separated distribution channels (e.g., `linkedin, newsletter`), or `—` |
|
|
71
|
+
|
|
72
|
+
**Notes:**
|
|
73
|
+
- Each week section covers 7 calendar days
|
|
74
|
+
- The final week of the month may extend beyond 7 days to cover the remaining days (e.g., `Settimana 4 (22-31 Mar)`)
|
|
75
|
+
- Table headers must be repeated in every weekly section
|
|
76
|
+
- The `—` character (em dash, U+2014) is used as the null/empty marker
|
|
77
|
+
|
|
78
|
+
---
|
|
79
|
+
|
|
80
|
+
## Entry Status Lifecycle
|
|
81
|
+
|
|
82
|
+
Calendar entries progress through a linear five-stage lifecycle:
|
|
83
|
+
|
|
84
|
+
```
|
|
85
|
+
planned → draft → ready → scheduled → published
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
| Status | Description | Calendar state | Brief state |
|
|
89
|
+
|--------|-------------|----------------|-------------|
|
|
90
|
+
| `planned` | Slot reserved in the calendar. Title may be `[da assegnare]` | Entry exists in weekly table | No brief file yet |
|
|
91
|
+
| `draft` | Title assigned, brief created | Title is final | Brief in `pipeline-active/` with `status: draft` |
|
|
92
|
+
| `ready` | Brief content finalized, quality gates passed | No change | Brief in `pipeline-active/` with `status: ready` |
|
|
93
|
+
| `scheduled` | WordPress post created with future publication date | Post ID populated | Brief `target.status: future` |
|
|
94
|
+
| `published` | WordPress post is live, confirmed by SYNC step | Post ID present, status updated | Brief moves to `pipeline-archive/` |
|
|
95
|
+
|
|
96
|
+
**Transition rules:**
|
|
97
|
+
- `planned` -> `draft`: Requires a final title and Brief ID assignment
|
|
98
|
+
- `draft` -> `ready`: Requires brief quality gates to pass (see `gates` block in content-brief-schema)
|
|
99
|
+
- `ready` -> `scheduled`: Requires successful WordPress API call creating a post with `status: future`
|
|
100
|
+
- `scheduled` -> `published`: Confirmed by the SYNC step when WordPress reports `post_status: publish`
|
|
101
|
+
|
|
102
|
+
---
|
|
103
|
+
|
|
104
|
+
## Integration with Phase 1 (Content Pipeline)
|
|
105
|
+
|
|
106
|
+
The editorial calendar bridges directly to the content pipeline's brief system:
|
|
107
|
+
|
|
108
|
+
- Each calendar entry with a Brief ID references a file at `.content-state/pipeline-active/BRF-YYYY-NNN.brief.md`
|
|
109
|
+
- When the BRIEF step creates a new brief, it uses the site config defaults from `.content-state/{site_id}.config.md`
|
|
110
|
+
- The brief's `target.scheduled_date` is set from the calendar entry's **Data** column
|
|
111
|
+
- The brief's `distribution.channels` is set from the calendar entry's **Canali** column
|
|
112
|
+
- When `wp-content-pipeline` archives a brief (`status: published`), the SYNC step updates the calendar entry accordingly
|
|
113
|
+
|
|
114
|
+
### Data flow: Calendar -> Brief
|
|
115
|
+
|
|
116
|
+
| Calendar column | Brief field | Notes |
|
|
117
|
+
|-----------------|-------------|-------|
|
|
118
|
+
| Data | `target.scheduled_date` | Converted to ISO 8601 with site default publish time |
|
|
119
|
+
| Titolo | `content.title` | Exact match |
|
|
120
|
+
| Tipo | `target.content_type` | Direct mapping |
|
|
121
|
+
| Canali | `distribution.channels` | Comma-separated string parsed to array |
|
|
122
|
+
| (site_id from frontmatter) | `target.site_id` | Inherited from calendar |
|
|
123
|
+
|
|
124
|
+
---
|
|
125
|
+
|
|
126
|
+
## Integration with Phase 2 (Signals Intelligence)
|
|
127
|
+
|
|
128
|
+
The editorial calendar consumes signals intelligence data to inform content planning:
|
|
129
|
+
|
|
130
|
+
- The PLAN step can read `.content-state/signals-feed.md` to suggest topics for `[da assegnare]` entries
|
|
131
|
+
- Anomalies from the signals feed with action containing "content cluster opportunity" are prime candidates for planned entries
|
|
132
|
+
- The `goals.focus_topics` field can be informed by high-scoring signal patterns
|
|
133
|
+
|
|
134
|
+
### Signal-to-calendar workflow
|
|
135
|
+
|
|
136
|
+
1. SCAN step generates `.content-state/signals-feed.md` with scored anomalies
|
|
137
|
+
2. PLAN step reads the signals feed and identifies actionable opportunities
|
|
138
|
+
3. Opportunities map to `[da assegnare]` slots in the current or next month's calendar
|
|
139
|
+
4. When a topic is assigned, the entry title is updated and a `[da assegnare — topic da signals]` annotation may be used as an intermediate step
|
|
140
|
+
|
|
141
|
+
---
|
|
142
|
+
|
|
143
|
+
## Notes Section
|
|
144
|
+
|
|
145
|
+
The body may end with a `# Note` section containing free-form editorial notes.
|
|
146
|
+
|
|
147
|
+
Common uses:
|
|
148
|
+
- **Newsletter aggregation rules**: How posts are grouped for newsletter distribution (e.g., biweekly digest)
|
|
149
|
+
- **Distribution timing preferences**: When posts should be distributed on specific channels (e.g., LinkedIn at 09:00)
|
|
150
|
+
- **Topic dependencies on signals data**: Which `[da assegnare]` slots depend on future signals analysis
|
|
151
|
+
- **Cross-calendar references**: Links to related months or seasonal content plans
|
|
152
|
+
- **Team coordination notes**: Reviewer assignments, approval deadlines
|
|
153
|
+
|
|
154
|
+
---
|
|
155
|
+
|
|
156
|
+
## File Naming Convention
|
|
157
|
+
|
|
158
|
+
Editorial calendar files follow this naming pattern:
|
|
159
|
+
|
|
160
|
+
```
|
|
161
|
+
{YYYY-MM}-editorial.state.md
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
Examples:
|
|
165
|
+
- `2026-03-editorial.state.md`
|
|
166
|
+
- `2026-04-editorial.state.md`
|
|
167
|
+
|
|
168
|
+
Files are stored in:
|
|
169
|
+
- **Location**: `.content-state/` directory at the project root
|
|
170
|
+
- **One file per month per site**: The `site_id` is stored in the frontmatter, not the filename
|
|
171
|
+
- **Previous months**: Calendars for past months remain in `.content-state/` with `status: archived`
|
|
172
|
+
- **Gitignored**: Calendar files are site-specific instance data and should be listed in `.gitignore`
|
|
173
|
+
|
|
174
|
+
---
|
|
175
|
+
|
|
176
|
+
## Example Calendar
|
|
177
|
+
|
|
178
|
+
A complete `2026-03-editorial.state.md` for the mysite site:
|
|
179
|
+
|
|
180
|
+
```markdown
|
|
181
|
+
---
|
|
182
|
+
calendar_id: "CAL-2026-03"
|
|
183
|
+
site_id: mysite
|
|
184
|
+
period: "2026-03-01..2026-03-31"
|
|
185
|
+
created: "2026-02-28"
|
|
186
|
+
last_updated: "2026-03-02"
|
|
187
|
+
status: active
|
|
188
|
+
|
|
189
|
+
goals:
|
|
190
|
+
posts_target: 8
|
|
191
|
+
posts_published: 2
|
|
192
|
+
focus_topics: [premium-water, sustainability, wellness]
|
|
193
|
+
seo_targets:
|
|
194
|
+
- keyword: "acqua premium"
|
|
195
|
+
target_position: top-5
|
|
196
|
+
- keyword: "bevanda zero calorie naturale"
|
|
197
|
+
target_position: top-10
|
|
198
|
+
---
|
|
199
|
+
|
|
200
|
+
# Piano Editoriale — Marzo 2026
|
|
201
|
+
|
|
202
|
+
## Settimana 1 (1-7 Mar)
|
|
203
|
+
|
|
204
|
+
| Data | Titolo | Tipo | Status | Brief ID | Post ID | Canali |
|
|
205
|
+
|------|--------|------|--------|----------|---------|--------|
|
|
206
|
+
| Mar 4 | Acqua premium: 5 benefici scientifici | post | published | BRF-2026-001 | 1234 | linkedin, newsletter |
|
|
207
|
+
| Mar 6 | Come il frutto mediterraneo diventa bevanda | post | published | BRF-2026-002 | 1235 | linkedin, twitter |
|
|
208
|
+
|
|
209
|
+
## Settimana 2 (8-14 Mar)
|
|
210
|
+
|
|
211
|
+
| Data | Titolo | Tipo | Status | Brief ID | Post ID | Canali |
|
|
212
|
+
|------|--------|------|--------|----------|---------|--------|
|
|
213
|
+
| Mar 11 | Zero calorie, tutto gusto: la scienza | post | ready | BRF-2026-003 | — | linkedin, newsletter |
|
|
214
|
+
| Mar 13 | Mediterraneo e sostenibilità: la filiera | post | draft | BRF-2026-004 | — | linkedin |
|
|
215
|
+
|
|
216
|
+
## Settimana 3 (15-21 Mar)
|
|
217
|
+
|
|
218
|
+
| Data | Titolo | Tipo | Status | Brief ID | Post ID | Canali |
|
|
219
|
+
|------|--------|------|--------|----------|---------|--------|
|
|
220
|
+
| Mar 18 | [da assegnare — topic da signals] | post | planned | — | — | — |
|
|
221
|
+
| Mar 20 | [da assegnare] | post | planned | — | — | — |
|
|
222
|
+
|
|
223
|
+
## Settimana 4 (22-31 Mar)
|
|
224
|
+
|
|
225
|
+
| Data | Titolo | Tipo | Status | Brief ID | Post ID | Canali |
|
|
226
|
+
|------|--------|------|--------|----------|---------|--------|
|
|
227
|
+
| Mar 25 | [da assegnare] | post | planned | — | — | — |
|
|
228
|
+
| Mar 27 | [da assegnare] | post | planned | — | — | — |
|
|
229
|
+
|
|
230
|
+
# Note
|
|
231
|
+
|
|
232
|
+
- Settimana 3-4: topic da definire basandosi su signals-feed.md del 15 marzo
|
|
233
|
+
- Newsletter quindicinale: raccoglie i 4 post della quindicina precedente
|
|
234
|
+
- LinkedIn: ogni post va distribuito il giorno stesso alle 09:00
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
---
|
|
238
|
+
|
|
239
|
+
## Validation Rules
|
|
240
|
+
|
|
241
|
+
The following rules are enforced when reading and writing editorial calendar files:
|
|
242
|
+
|
|
243
|
+
### Format validations
|
|
244
|
+
|
|
245
|
+
| Rule | Description |
|
|
246
|
+
|------|-------------|
|
|
247
|
+
| `calendar_id` format | Must follow `CAL-YYYY-MM` pattern (e.g., `CAL-2026-03`) |
|
|
248
|
+
| `site_id` existence | Must match an existing `.content-state/{site_id}.config.md` file |
|
|
249
|
+
| `period` span | Must span exactly one calendar month (`YYYY-MM-DD..YYYY-MM-DD`) |
|
|
250
|
+
| Table columns | Each weekly table must have all 7 columns: Data, Titolo, Tipo, Status, Brief ID, Post ID, Canali |
|
|
251
|
+
|
|
252
|
+
### Field validations
|
|
253
|
+
|
|
254
|
+
| Rule | Description |
|
|
255
|
+
|------|-------------|
|
|
256
|
+
| `Status` values | Must be one of: `planned`, `draft`, `ready`, `scheduled`, `published` |
|
|
257
|
+
| `Brief ID` format | Must follow `BRF-YYYY-NNN` pattern when present (not `—`) |
|
|
258
|
+
| `Post ID` type | Must be a positive integer when present (not `—`) |
|
|
259
|
+
|
|
260
|
+
### Consistency validations
|
|
261
|
+
|
|
262
|
+
| Rule | Description |
|
|
263
|
+
|------|-------------|
|
|
264
|
+
| Published count | `goals.posts_published` must not exceed `goals.posts_target` |
|
|
265
|
+
| Scheduled requires Post ID | Entries with `status: scheduled` must have a Post ID (not `—`) |
|
|
266
|
+
| Published requires Post ID | Entries with `status: published` must have a Post ID (not `—`) |
|
|
267
|
+
| Draft requires Brief ID | Entries with `status: draft` or higher must have a Brief ID (not `—`) |
|
|
268
|
+
| Planned allows empty | Entries with `status: planned` may have `—` for Brief ID, Post ID, and Canali |
|
|
@@ -109,17 +109,17 @@ When no multilingual plugin is used, sync content manually via MCP tools:
|
|
|
109
109
|
```bash
|
|
110
110
|
# 1. Create content on primary site
|
|
111
111
|
switch_site(site_id=1) # Switch to English site
|
|
112
|
-
create_content(type="post", title="
|
|
112
|
+
create_content(type="post", title="Sparkling Water Benefits", slug="sparkling-water-benefits",
|
|
113
113
|
content="...", status="publish")
|
|
114
114
|
|
|
115
115
|
# 2. Replicate structure on Italian site
|
|
116
116
|
switch_site(site_id=2) # Switch to Italian site
|
|
117
|
-
create_content(type="post", title="Benefici dell'Acqua
|
|
117
|
+
create_content(type="post", title="Benefici dell'Acqua Premium", slug="sparkling-water-benefits",
|
|
118
118
|
content="[Italian translation]", status="draft")
|
|
119
119
|
|
|
120
120
|
# 3. Replicate on German site
|
|
121
121
|
switch_site(site_id=3) # Switch to German site
|
|
122
|
-
create_content(type="post", title="Vorteile von Kaktuswasser", slug="
|
|
122
|
+
create_content(type="post", title="Vorteile von Kaktuswasser", slug="sparkling-water-benefits",
|
|
123
123
|
content="[German translation]", status="draft")
|
|
124
124
|
|
|
125
125
|
# 4. Switch back to primary
|