Skills wordpress-api-pro
git clone https://github.com/openclaw/skills
T=$(mktemp -d) && git clone --depth=1 https://github.com/openclaw/skills "$T" && mkdir -p ~/.claude/skills && cp -r "$T/skills/benkalsky/wordpress-api-pro" ~/.claude/skills/clawdbot-skills-wordpress-api-pro && rm -rf "$T"
skills/benkalsky/wordpress-api-pro/SKILL.mdWordPress API
Interact with WordPress sites via the REST API. Create, update, and manage posts, pages, media, and more on any WordPress installation.
Quick Start
Single Site (Direct)
# Update a post python3 scripts/update_post.py \ --url "https://example.com" \ --username "admin" \ --app-password "xxxx xxxx xxxx xxxx" \ --post-id 123 \ --content "New content here" \ --status "publish"
Multi-Site (CLI Wrapper) ⭐
# Setup: Copy config template and add your sites cp config/sites.example.json config/sites.json # Edit config/sites.json with your sites # List configured sites ./wp.sh --list-sites # Update post on specific site ./wp.sh digitizer-studio update-post --id 123 --content "New content" # Run on all sites in a group ./wp.sh digitizer update-post --id 456 --status "publish" # Batch update across multiple sites python3 scripts/batch_update.py --group digitizer --post-ids 123,456 --status "publish"
Authentication
WordPress REST API supports two authentication methods:
1. Application Password (Recommended) ⭐
Setup:
- Go to:
https://yoursite.com/wp-admin/profile.php - Scroll to "Application Passwords"
- Name: "OpenClaw API" (or any name)
- Click "Add New Application Password"
- Copy the password (shows only once!)
Format:
xxxx xxxx xxxx xxxx xxxx xxxx (24 characters with spaces)
Usage: Pass as
--app-password to scripts or set WP_APP_PASSWORD environment variable
2. Basic Auth (Legacy)
Requires Basic Auth plugin. Less secure, not recommended for production.
Environment Variables
Set these to avoid passing credentials every time:
export WP_URL="https://example.com" export WP_USERNAME="admin" export WP_APP_PASSWORD="xxxx xxxx xxxx xxxx xxxx xxxx"
Multi-Site Management
Configuration
- Copy the example config:
cp config/sites.example.json config/sites.json
- Edit
with your sites:config/sites.json
{ "sites": { "my-site": { "url": "https://mysite.com", "username": "admin", "app_password": "xxxx xxxx xxxx", "description": "My WordPress site" } }, "groups": { "all": ["my-site"] } }
CLI Wrapper (./wp.sh
)
./wp.sh# List sites ./wp.sh --list-sites ./wp.sh --list-groups # Single site operations ./wp.sh my-site update-post --id 123 --content "..." ./wp.sh my-site create-post --title "..." --content "..." ./wp.sh my-site get-post --id 123 ./wp.sh my-site list-posts --per-page 10 # Group operations (runs on all sites in group) ./wp.sh all update-post --id 123 --status "publish"
Batch Operations
# Update multiple posts across multiple sites python3 scripts/batch_update.py \ --group digitizer \ --post-ids 123,456,789 \ --status "publish" # Update meta field on all sites python3 scripts/batch_update.py \ --sites all \ --post-ids 100 \ --meta-key "seo_score" \ --meta-value "95" # Dry run (see what would happen) python3 scripts/batch_update.py \ --group all \ --post-ids 123 \ --status "draft" \ --dry-run
Individual Scripts
All scripts support both command-line arguments and environment variables.
Update Post
python3 scripts/update_post.py \ --post-id 123 \ --content "Updated content" \ --title "New Title" \ --status "publish"
Supports:
- Content (HTML or Gutenberg blocks)
- Title
- Status (publish, draft, pending, private)
- Featured image ID
- Custom fields (meta)
Create Post
python3 scripts/create_post.py \ --title "New Post" \ --content "Post content" \ --status "draft"
Get Post
python3 scripts/get_post.py --post-id 123
Returns full post data as JSON.
List Posts
python3 scripts/list_posts.py --per-page 10 --status "publish"
Options:
- Posts per page (default: 10, max: 100)--per-page N
- Page number--page N
- Filter by status (publish, draft, pending, private)--status STATUS
- Filter by author--author ID
Plugin Integration
Detect Plugins
Automatically detect installed WordPress plugins (ACF, Rank Math, Yoast, JetEngine):
python3 scripts/detect_plugins.py python3 scripts/detect_plugins.py --verbose
ACF (Advanced Custom Fields)
Read and write ACF fields with automatic fallback to postmeta:
# Get all ACF fields python3 scripts/acf_fields.py --post-id 123 # Get specific field python3 scripts/acf_fields.py --post-id 123 --field my_field # Set fields from JSON python3 scripts/acf_fields.py --post-id 123 --set '{"field1": "value1", "field2": "value2"}' # Set single field python3 scripts/acf_fields.py --post-id 123 --field my_field --value "my value"
Features:
- Automatic REST API detection with postmeta fallback
- Support for simple, repeater, and group fields
- JSON input/output for complex field structures
SEO Meta (Rank Math & Yoast)
Read and write SEO meta fields with auto-detection:
# Auto-detect plugin and get meta python3 scripts/seo_meta.py --post-id 123 # Detect which SEO plugin is active python3 scripts/seo_meta.py --post-id 123 --detect # Get specific plugin's meta python3 scripts/seo_meta.py --post-id 123 --plugin rankmath python3 scripts/seo_meta.py --post-id 123 --plugin yoast # Set SEO meta python3 scripts/seo_meta.py --post-id 123 --set '{"title": "SEO Title", "description": "Meta description"}' # Set with specific plugin python3 scripts/seo_meta.py --post-id 123 --plugin rankmath --set '{"focus_keyword": "keyword"}'
Supported fields:
- Rank Math: title, description, focus_keyword, robots, canonical_url, schema
- Yoast: title, description, focus_keyword, canonical, meta_robots_noindex, meta_robots_nofollow
JetEngine Fields
Read and write JetEngine custom fields (stored as postmeta):
# Get all JetEngine fields python3 scripts/jetengine_fields.py --post-id 123 # Get specific field python3 scripts/jetengine_fields.py --post-id 123 --field my_field # Set fields from JSON python3 scripts/jetengine_fields.py --post-id 123 --set '{"field1": "value1", "field2": "value2"}' # Set single field python3 scripts/jetengine_fields.py --post-id 123 --field my_field --value "my value"
Elementor Content
Manage Elementor page builder content via
_elementor_data meta field:
# Get Elementor data for a page python3 scripts/elementor_content.py --post-id 123 --action get # Update specific widget content python3 scripts/elementor_content.py \ --post-id 123 \ --action update \ --widget-id "abc123" \ --content "New heading text"
Supported widget types:
- Headings (
)heading - Text Editor (
)text-editor - Buttons (
)button - Generic fallback for other widgets
How it works:
- Gets page data with
meta field_elementor_data - Parses JSON structure
- Finds widget by ID (recursively through nested elements)
- Updates content based on widget type
- Saves back to WordPress
Media Upload
Upload images and files to WordPress media library:
# Upload local file python3 scripts/upload_media.py \ --file "/path/to/image.jpg" \ --title "My Image" \ --alt-text "Description for accessibility" # Upload from URL python3 scripts/upload_media.py \ --file "https://example.com/image.jpg" \ --title "Remote Image" # Upload and set as featured image python3 scripts/upload_media.py \ --file "image.jpg" \ --set-featured \ --post-id 123
Features:
- Supports local files and URLs
- Auto-detects MIME type
- Returns media ID for further operations
- Can set as featured image in one call
WooCommerce Products
Manage WooCommerce products via REST API v3:
# List products python3 scripts/woo_products.py \ --consumer-key "ck_..." \ --consumer-secret "cs_..." \ --action list \ --per-page 10 # Get single product python3 scripts/woo_products.py \ --consumer-key "ck_..." \ --consumer-secret "cs_..." \ --action get \ --product-id 456 # Create product python3 scripts/woo_products.py \ --consumer-key "ck_..." \ --consumer-secret "cs_..." \ --action create \ --title "New Product" \ --price "29.99" \ --description "Product description" \ --status "publish" # Update product python3 scripts/woo_products.py \ --consumer-key "ck_..." \ --consumer-secret "cs_..." \ --action update \ --product-id 456 \ --price "39.99" \ --status "publish"
Authentication:
- Requires WooCommerce Consumer Key and Consumer Secret
- Get from: WooCommerce → Settings → Advanced → REST API
- Environment variables:
,WC_CONSUMER_KEYWC_CONSUMER_SECRET
Supported fields:
/--title
- Product name--name
- Regular price--price
- Sale price--sale-price
- Full description--description
- Short description--short-description
- publish, draft, pending, private--status
- Stock keeping unit--sku
- Stock amount--stock-quantity
- Enable stock management--manage-stock
Gutenberg Blocks
WordPress uses Gutenberg block format for content. See references/gutenberg-blocks.md for details.
Example block:
<!-- wp:paragraph --> <p>This is a paragraph.</p> <!-- /wp:paragraph -->
API Reference
See references/api-reference.md for complete WordPress REST API documentation.
Common endpoints:
- Posts/wp-json/wp/v2/posts
- Pages/wp-json/wp/v2/pages
- Media/wp-json/wp/v2/media
- Users/wp-json/wp/v2/users
- Categories/wp-json/wp/v2/categories
- Tags/wp-json/wp/v2/tags
Error Handling
All scripts return:
- Exit code 0 on success
- Exit code 1 on error
- JSON output to stdout
- Error messages to stderr
Security
- ✅ DO: Use Application Passwords
- ✅ DO: Use HTTPS only
- ✅ DO: Store credentials in environment variables
- ❌ DON'T: Hardcode passwords in scripts
- ❌ DON'T: Use Basic Auth in production
- ❌ DON'T: Commit credentials to git
Limitations
- Requires WordPress 4.7+ (REST API built-in)
- Requires Application Passwords plugin for WordPress <5.6
- Some endpoints require specific user permissions
- Rate limiting depends on host configuration