If you want a script or an AI agent to help with your blog, the WordPress REST API is the way in. The trick is setting it up so the script can write drafts but can never publish anything by accident. Here’s the pattern.
1. A dedicated user and an Application Password
- Create a separate WordPress user for the script with the lowest role that does the job.
- Under Users, Profile, Application Passwords, make a password just for it. You can revoke it any time without touching your real login.
- Keep the credentials in an env file with
chmod 600, outside any git repo.
2. Pick the right endpoint
The normal endpoint is /wp-json/wp/v2/posts. If pretty permalinks are off or /wp-json is blocked, this form works everywhere:
https://example.com/index.php?rest_route=/wp/v2/posts
3. Create the post as a draft, every time
import os, requests
B = "https://example.com/index.php?rest_route=/wp/v2"
A = (os.environ["WP_USER"], os.environ["WP_APP_PASSWORD"])
post = dict(title="My draft", content="<p>Hello</p>", status="draft",
categories=[5], tags=[21], featured_media=0)
r = requests.post(B + "/posts", auth=A, json=post, timeout=60)
r.raise_for_status()
j = r.json()
assert j["status"] == "draft", j["status"]
print(j["id"], j["link"])
Hard-code status="draft" in the script itself, not in whatever calls it. Then read the post back with ?context=edit and confirm the status and author really are what you expect.
4. Look before you write
- Dedupe:
GET /posts?status=any&search=term(authenticated) shows drafts too, so you don’t write the same story twice. - IDs, not names: categories and tags are numbers. Pull
/categoriesand/tagsonce and keep a map. - Paging: lists max out at 100 per page. Follow the
X-WP-TotalPagesheader.
5. Back up before bulk edits
Before a script edits existing posts, save each one with GET /posts/<id>?context=edit to a JSON file. If something goes sideways, you can put it back exactly.
My take
Let the script do the typing and keep the publish button for yourself. Drafts are cheap to throw away. A bad post that went live isn’t.
Have a blessed day! And Happy Hacking!