Publishing to WordPress
Once you've drafted a blog post, you can publish it directly to WordPress via the REST API.
Setup (One Time)
You'll need three things:
- WordPress site URL: Your blog URL (e.g.,
https://yourblog.com) - WordPress username: Your WordPress account username
- Application Password: Generate one at WordPress.com → Account Settings → Security → Application Passwords
- Important: Use an Application Password, NOT your regular WordPress password
- Application Passwords can be revoked independently for better security
Add these to your Claude Code settings (~/.claude/settings.json) under the env key:
{
"env": {
"WORDPRESS_URL": "https://yourblog.com",
"WORDPRESS_USERNAME": "your_username",
"WORDPRESS_APP_PASSWORD": "xxxx xxxx xxxx xxxx"
}
}Installing Dependencies
The publishing script requires two Python packages:
pip install requests markdown2Publishing Your Post
After creating a blog post (automatically saved to .drafts/), you can save it to WordPress as a draft:
Save to WordPress:
Save this to WordPressSave with specific tags:
Save this to WordPress with tags: nextjs, voice-ai, developmentUpdate an existing post:
Update the voice planner post on WordPressThe script will automatically:
- Check if the post already exists (tracks via
.drafts/wordpress.json) - If exists: Update the existing draft (no duplicate posts!)
- If new: Create new draft and save the mapping
- Extract the title from the first H1 heading in your markdown
- Convert markdown to Gutenberg blocks
- Fetch your WordPress categories and suggest the best match
- Create or find WordPress tags
- Always saves as draft (never publishes immediately - you publish manually from WordPress admin)
- Return the post URL, edit URL, suggested category, and tags
Smart Updates:
- First time saving: Creates new WordPress draft post
- Subsequent saves: Updates the same WordPress post
- No duplicate posts - each markdown file maps to one WordPress post
- Mapping stored in
.drafts/wordpress.json
How It Works
When you ask to save to WordPress, the skill runs:
python scripts/publish-to-wordpress.py .drafts/2025-12-29-voice-planner.md --tags nextjs,voice-aiFirst time (creates new post):
{
"success": true,
"message": "Post created as draft",
"title": "Planning Out Loud",
"post_id": 123,
"post_url": "https://yourblog.com/?p=123",
"edit_url": "https://yourblog.com/wp-admin/post.php?post=123&action=edit",
"status": "draft",
"action": "created",
"category": "Development",
"tags": ["nextjs", "voice-ai"]
}Subsequent times (updates existing post):
{
"success": true,
"message": "Post updated as draft",
"title": "Planning Out Loud",
"post_id": 123,
"post_url": "https://yourblog.com/?p=123",
"edit_url": "https://yourblog.com/wp-admin/post.php?post=123&action=edit",
"status": "draft",
"action": "updated",
"category": "Development",
"tags": ["nextjs", "voice-ai"]
}Notice the post_id stays the same (123) - it updates the existing post instead of creating duplicates.
Workflow:
- All blog drafts are stored in
.drafts/with date-based filenames - Mapping of markdown files to WordPress posts is tracked in
.drafts/wordpress.json - First save creates a new WordPress draft
- Subsequent saves update the same WordPress draft
- You can preview, edit, and publish from WordPress admin when ready
Troubleshooting
"Missing WordPress credentials" error:
- Make sure environment variables are set in
~/.claude/settings.jsonunder theenvkey
Connection errors:
- Verify your
WORDPRESS_URLis correct (includehttps://) - Check your internet connection
- Ensure your WordPress site is accessible
Authentication errors:
- Generate a fresh Application Password
- Don't use your regular WordPress password
- Check username spelling
Python package errors:
- Run
pip install requests markdown2