Interact safely with WordPress content via REST API for posts, pages, media, taxonomies, supporting drafts, updates, pagination, search, and retry handling.
---
name: wordpress-content-rest-api
description: Use the WordPress REST API for content operations only: auth setup (Application Password and Bearer), safe read/write flows for posts/pages/media, draft/publish/update patterns, taxonomy assignment, pagination/search, retry/rate-limit handling, and dry-run-first safety.
metadata: {"openclaw":{"emoji":"🧩"}}
---
# WordPress Content REST API
Use this skill only for WordPress content API work (posts, pages, media, categories, tags).
Do not use it for server admin, plugin/theme management, or shell/WP-CLI tasks.
## Safety Rules (Always)
1. Start with a dry run before any write.
2. Confirm base URL and target environment (`production` vs `staging`).
3. Read current object first, then patch minimally.
4. Prefer `status=draft` until explicit approval to publish.
5. Avoid bulk destructive updates unless explicitly approved.
6. Use least-privilege credentials.
Read [references/reliability-and-safety.md](references/reliability-and-safety.md) first when operating on live sites.
## Workflow
1. Set auth model (Application Password or Bearer):
[references/auth.md](references/auth.md)
2. Discover and validate target content:
use read/list endpoints with pagination and filters.
3. Execute dry-run pass:
- fetch current object
- prepare intended payload
- verify taxonomy/media IDs exist
4. Write safely:
- create/update as draft first
- verify response
- publish only with explicit instruction
5. Handle retries/rate-limits/errors using standard policy:
[references/reliability-and-safety.md](references/reliability-and-safety.md)
## Endpoint Scope
Focus on these route families:
- `/wp-json/wp/v2/posts`
- `/wp-json/wp/v2/pages`
- `/wp-json/wp/v2/media`
- `/wp-json/wp/v2/categories`
- `/wp-json/wp/v2/tags`
For usage patterns and payload examples, read:
- [references/content-flows.md](references/content-flows.md)
- [references/query-and-taxonomy.md](references/query-and-taxonomy.md)
## Default Execution Pattern
- Read first (`GET`).
- Validate dependent IDs (author/category/tag/media).
- Write to draft (`POST`/`PUT`/`PATCH` with `status=draft`).
- Re-read object and compare expected fields.
- Publish (`status=publish`) only after explicit approval.
## Done Criteria
Treat a content task as complete only when:
- API response is successful and parsed.
- Changed fields match requested outcome.
- Final status (`draft`/`publish`) matches explicit instruction.
- Any partial failures are listed with next action.
don't have the plugin yet? install it then click "run inline in claude" again.
expanded safety rules into explicit decision points, added comprehensive error handling and retry logic with concrete backoff timings, detailed external connection requirements and env var guidance, broke workflow into 9 discrete numbered procedure steps with explicit inputs and outputs, added edge cases for network timeouts and rate limits, and defined success/failure criteria in output contract and outcome signal sections.
use this skill to safely read, create, update, and delete wordpress content (posts, pages, media, categories, tags) via the wordpress rest api. apply it when you need to manage content programmatically without touching server admin, plugins, themes, or cli commands. the skill enforces a dry-run-first pattern, draft-by-default writing, and explicit approval gates before publishing or bulk changes on live sites.
wordpress instance details:
https://example.com or https://staging.example.com)production or staging) to guard destructive operationswp/v2, which is stable and widely supported)authentication:
Authorization: Basic headerAuthorization: Bearer headerWP_AUTH_USER, WP_AUTH_PASS, WP_AUTH_TOKEN (never hardcode)external connections:
{base_url}/wp-json/wp/v2/...context from earlier steps:
optional filters and search:
per_page, page, offset)draft, publish, pending, scheduled)validate auth and connectivity
GET {base_url}/wp-json/wp/v2/posts?per_page=1 with auth headerdiscover target content
GET {base_url}/wp-json/wp/v2/posts?search={term}&status={status}&per_page={per_page}&page={page} (or equivalent for pages/media)X-WP-Total header)fetch current object for update or read
GET {base_url}/wp-json/wp/v2/{type}/{id}?_fields=id,title,content,excerpt,status,author,featured_media,categories,tags,date,modified,metavalidate dependent ids (dry-run phase)
GET {base_url}/wp-json/wp/v2/{resource_type}/{id} (author via /users/{id}, category via /categories/{id}, tag via /tags/{id}, media via /media/{id})prepare and preview payload (dry-run phase)
draft unless explicitly instructed to publish<script> tags, report if found)execute write (create or update)
POST {base_url}/wp-json/wp/v2/{type} with payloadPUT {base_url}/wp-json/wp/v2/{type}/{id} or PATCH {base_url}/wp-json/wp/v2/{type}/{id} with payloadre-read and compare (verification)
GET {base_url}/wp-json/wp/v2/{type}/{id}?_fields=id,title,content,status,author,featured_media,categories,tags,modifieddraft and was requested to be draft, mark as successpublish only on explicit instruction
approve_publish (defaults to false), content idapprove_publish is false, stop here and report that content is in draft and waiting for approvalapprove_publish is true and environment is production, call PATCH {base_url}/wp-json/wp/v2/{type}/{id} with payload {"status":"publish"}publishhandle errors and retries
if base url is staging and operation is marked destructive (bulk delete, publish), stop and ask for explicit environment override. else proceed normally.
if auth type is application password, use http basic auth (base64-encoded user:pass in Authorization header). else if auth type is bearer token, use Bearer header with token value.
if search or filter returns zero results, return empty list and stop. else proceed to discover content.
if any referenced id (author, media, category, tag) does not exist, halt and report missing ids. else proceed to write.
if status is not explicitly set in the payload, default to draft. else respect the requested status.
if approve_publish is true and environment is production, attempt to publish. else if approve_publish is false or environment is staging, leave content in draft status.
if http response is 429 (rate limit), apply exponential backoff (2s, then 4s), retry twice, then fail. else if response is 5xx (server error), wait 3s and retry up to 2 times, then fail.
if http response is 401 (unauthorized), request fresh auth credentials. else if response is 403 (forbidden), request elevated credentials or different api user.
if network timeout occurs after 30s, log and retry once; if timeout persists, fail. else proceed normally.
if re-read in step 7 reveals mismatched fields, retry write once, then report partial failure. else mark operation as complete.
success response format (json):
{
"id": 123,
"title": "post title",
"content": "post body html",
"status": "draft",
"author": 1,
"featured_media": 456,
"categories": [10, 11],
"tags": [20, 21],
"date": "2024-01-15T10:30:00",
"modified": "2024-01-15T11:45:00",
"link": "https://example.com/2024/01/15/post-title/",
"_fields": ["id", "title", "content", "status", "author", "featured_media", "categories", "tags", "date", "modified", "link"]
}
file location: none (all operations are api calls; responses are json in memory or logged to stdout)
changelog entry (for content updates):
post 123 updated: title changed from 'old' to 'new', status remains draft, modified 2024-01-15T11:45:00error response format:
{
"code": "rest_invalid_param",
"message": "Invalid parameter(s): <field_name>",
"data": {
"status": 400,
"params": { "field_name": "error detail" }
}
}
partial failure log:
the skill has worked when:
publish_date field and status: publishuser-facing confirmation:
logging: