Publish wordpress
Claude Code Skills for content marketers — briefs, drafts, SEO audits, competitor analysis, publishing
npx -y skills add busyeugene/content-marketing-skills --skill publish-wordpressAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
One thing to look at
- 1 stars1 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
What its author says it does
Copied from the file, not written here
Use when the user wants to publish a blog post draft to WordPress via the REST API. Reads a markdown draft, maps frontmatter to post fields, uploads the hero image, creates or updates the post, and optionally publishes it live.
The file declares its own license as MIT. That is the author’s claim about this one file, and it is not the same thing as the license GitHub reports for the repository, which is listed with the other numbers below.
SKILL.md
6.7 KB, as published. Nobody here has run it
Publish → WordPress
Publish a local markdown draft to WordPress using the WordPress REST API v2. Works with self-hosted WordPress and WordPress.com Business or higher.
Setup
Required:
WORDPRESS_BASE_URL— e.g.https://example.com(no trailing slash). The REST endpoint is{BASE}/wp-json/wp/v2.WORDPRESS_USERNAME— WP user withedit_postsandupload_filescapabilities.WORDPRESS_APP_PASSWORD— an Application Password (Users → Profile → Application Passwords in WP admin). Not your login password.
Auth header for every request:
Authorization: Basic <base64(username:app_password)>
Content-Type: application/json
Optional:
SLACK_WEBHOOK_URL— Slack notification on publish.
Inputs
- Draft path — markdown file under
posts/. - Post status —
draft,pending,private,publish. Defaultdraft. - Update existing? —
skip,update,create-new. Defaultupdateif a post with the same slug exists. - Categories — comma-separated names or IDs. Will be created if they don't exist.
- Tags — comma-separated; same behavior as categories.
- Featured image — from the draft's
hero_imagefrontmatter, or user override path/URL. - Field mapping override — optional JSON for custom post types or ACF fields.
Use AskUserQuestion for post status and existing-item handling.
Process
1. Preflight
GET {BASE}/wp-json/to confirm REST is reachable and auth works. A 401 means wrong username or app password.GET {BASE}/wp-json/wp/v2/users/meto confirm the user has the required capabilities.- Cache the site's categories and tags for the session.
2. Load and transform
- Read the draft.
- Parse frontmatter.
- Convert markdown body to HTML. WordPress accepts HTML directly in the
contentfield. Preserve: headings, paragraphs, lists, code, blockquotes, images, links. Convert fenced code blocks to<pre><code class="language-{lang}">. - Strip HTML comments and any markdown-specific artifacts (e.g. inline frontmatter).
3. Featured image upload
If hero_image is a local path:
POST {BASE}/wp-json/wp/v2/media
Content-Disposition: attachment; filename="{name}.webp"
Content-Type: image/webp (or png/jpeg)
<binary>
Capture the returned id → use it as featured_media. Set alt_text via:
POST {BASE}/wp-json/wp/v2/media/{id}
{ "alt_text": "{hero_alt}", "caption": "{optional}" }
If hero_image is a URL, download it first, then upload — don't point WP at a remote URL.
4. Resolve taxonomies
For each category:
- Look up by name in the cache. If found, use the ID.
- If not found:
POST /wp/v2/categories { "name": "{name}" }, use the returned ID.
Same for tags via /wp/v2/tags.
5. Check for existing post
GET /wp/v2/posts?slug={slug}&status=any&per_page=1
- Found +
skip→ stop and report. - Found +
update→POST /wp/v2/posts/{id}with updated fields. - Found +
create-new→ append-2,-3, … to the slug until unique. - Not found → create.
6. Create or update
POST /wp/v2/posts
{
"title": "{title}",
"slug": "{slug}",
"status": "{status}",
"content": "{html body}",
"excerpt": "{meta_description}",
"featured_media": {media_id},
"categories": [ids],
"tags": [ids],
"meta": {
"_yoast_wpseo_title": "{meta_title}",
"_yoast_wpseo_metadesc": "{meta_description}",
"_yoast_wpseo_focuskw": "{keyword}"
}
}
Notes:
- Yoast and Rank Math meta keys are NOT writable via the WP REST API by default. The Yoast REST API is read-only, and neither plugin registers its meta fields with
show_in_rest: true. Writing them via the standardmetablock will silently fail or return a 400 unless the site has either (a)register_post_meta()calls infunctions.phpexposing the keys, or (b) a bridge plugin such as "WP REST Yoast Meta" installed. Before posting, attempt a test write and read it back. If the write didn't take, skip the meta block, log a warning, and tell the user which fields couldn't be set so they can update them manually in WP admin. - For Yoast, the meta keys are
_yoast_wpseo_title,_yoast_wpseo_metadesc,_yoast_wpseo_focuskw. For Rank Math, they arerank_math_title,rank_math_description,rank_math_focus_keyword. Ask which plugin is installed once per session and cache the answer. - For ACF fields, post to
/wp/v2/posts/{id}withacf: { field_name: value }after creation (requires the "ACF to REST API" plugin or ACF Pro 5.11+). - Date fields: set
datein ISO 8601 (site-local timezone). If publishing now, omit to use the server's current time.
7. Verify the live URL (if publishing)
- Fetch
GET /wp/v2/posts/{id}to confirm the new values took. - If
status = publish, hit the returnedlinkwith a HEAD request and expect 200. If it's 404 or 5xx, warn the user.
8. Optional Slack notification
Same pattern as publish-webflow.
9. Publish log
Append to publish-log.md:
| {YYYY-MM-DD HH:mm} | wordpress | {status} | {title} | {post_id} | {link or "—"} | {result} |
10. Print summary
One block: post ID, status, live URL (if published), SEO plugin used, Slack notified, publish-log updated.
Fallbacks
- App password wrong or 2FA blocking: fail fast with the exact fix instruction ("Generate an Application Password under Users → Profile → Application Passwords").
- REST endpoint 404 or disabled: the site has REST API disabled by a security plugin; report the exact failing URL and tell the user to re-enable.
- Featured media upload fails: retry once; if it still fails, create the post without the featured image and log a warning.
- Yoast/Rank Math not installed: skip the SEO meta block and note it in the summary.
- Network error mid-upload: do not retry blindly — first check whether the post was created to avoid duplicates.
Safety
- Default status is
draft. Never publish live without explicit user confirmation in the current session. - Never delete posts. On slug collision in
skipmode, stop and report.
Verification
GET /wp/v2/posts/{id}returns 200 with the expected title, slug, and body.- Featured image field is populated if
hero_imagewas set. - Category and tag IDs match the requested names.
- If published, the public URL returns 200.
publish-log.mdhas a new row.