Install
openclaw skills install @hugogu/wordpress-bloggerPublish articles to WordPress blogs via REST API. Handles post creation, category/tag management, and SEO-friendly English slug generation. Use when user asks to publish blog posts, create WordPress articles, or post content to their blog. TRIGGER this skill whenever user mentions publishing to blog, WordPress posting, or creating articles on their WordPress site.
openclaw skills install @hugogu/wordpress-bloggerPublish articles to WordPress blogs safely with automatic category/tag management and English URL slugs.
WordPress credentials must be configured in the workspace .env file:
# WordPress Blog Credentials
WP_BLOG_URL="https://blog.example.com" # Blog base URL (no trailing slash)
WP_USERNAME="your_username" # WordPress admin username
WP_APP_PASSWORD="xxxx xxxx xxxx xxxx xxxx" # Application password
How to create an Application Password:
Read credentials from workspace .env:
# Load credentials from .env file
source /root/.openclaw/workspace/.env
WP_URL="${WP_BLOG_URL:-https://blog.example.com}"
WP_USER="${WP_USERNAME:-admin}"
WP_PASS="${WP_APP_PASSWORD}"
# Verify credentials exist
if [ -z "$WP_PASS" ]; then
echo "❌ Error: WP_APP_PASSWORD not found in .env file"
exit 1
fi
Before publishing, analyze the article content to generate appropriate metadata:
Create a URL-friendly English slug from the article title or content:
Examples:
ryzen-7950x-vs-i9-13900k-benchmark-comparisonoptimize-database-performance-productionunderstanding-container-orchestration-kubernetesBased on article content, suggest appropriate WordPress categories and tags:
| Content Type | Suggested Categories | Suggested Tags |
|---|---|---|
| Hardware reviews | Hardware, Reviews | CPU, benchmark, performance, AMD, Intel |
| Software development | Development, Programming | coding, best-practices, architecture |
| AI/LLM related | AI, Technology | machine-learning, LLM, artificial-intelligence |
| Career development | Career | career-growth, soft-skills, productivity |
| DevOps/Infrastructure | DevOps, Infrastructure | docker, kubernetes, ci-cd, cloud |
If user doesn't specify, use these reasonable defaults:
Check if category exists, create if not:
CATEGORY_NAME="Hardware" # Use suggested or user-specified category
# Try to find existing category
CAT_ID=$(curl -s "${WP_URL}/wp-json/wp/v2/categories?search=${CATEGORY_NAME}&per_page=1" \
-u "${WP_USER}:${WP_PASS}" | grep -o '"id":[0-9]*' | head -1 | cut -d: -f2)
# Create if not exists
if [ -z "$CAT_ID" ]; then
CAT_RESULT=$(curl -s -X POST "${WP_URL}/wp-json/wp/v2/categories" \
-u "${WP_USER}:${WP_PASS}" \
-H "Content-Type: application/json" \
-d "{\"name\": \"${CATEGORY_NAME}\"}")
CAT_ID=$(echo "$CAT_RESULT" | grep -o '"id":[0-9]*' | head -1 | cut -d: -f2)
fi
echo "Category ID: $CAT_ID"
For each tag, check existence and create if needed:
TAGS=("CPU" "Benchmark" "AMD" "Performance") # Use suggested or user-specified tags
TAG_IDS=""
for TAG in "${TAGS[@]}"; do
# Try to find existing tag
TID=$(curl -s "${WP_URL}/wp-json/wp/v2/tags?search=${TAG}&per_page=1" \
-u "${WP_USER}:${WP_PASS}" | grep -o '"id":[0-9]*' | head -1 | cut -d: -f2)
# Create if not exists
if [ -z "$TID" ]; then
TAG_RESULT=$(curl -s -X POST "${WP_URL}/wp-json/wp/v2/tags" \
-u "${WP_USER}:${WP_PASS}" \
-H "Content-Type: application/json" \
-d "{\"name\": \"${TAG}\"}")
TID=$(echo "$TAG_RESULT" | grep -o '"id":[0-9]*' | head -1 | cut -d: -f2)
fi
TAG_IDS="${TAG_IDS},${TID}"
done
# Remove leading comma
TAG_IDS=$(echo "$TAG_IDS" | sed 's/^,//')
echo "Tag IDs: $TAG_IDS"
TITLE="AMD Ryzen 9 7950X vs Intel Core i9-13900K: A Detailed Benchmark Comparison"
CONTENT="<p>In this comprehensive benchmark analysis...</p>" # Convert markdown to HTML
SLUG="ryzen-7950x-vs-i9-13900k-benchmark-comparison"
EXCERPT="We compare two flagship processors across gaming, productivity, and power efficiency."
# Create post
POST_RESULT=$(curl -s -X POST "${WP_URL}/wp-json/wp/v2/posts" \
-u "${WP_USER}:${WP_PASS}" \
-H "Content-Type: application/json" \
-d "{
\"title\": \"${TITLE}\",
\"content\": \"${CONTENT}\",
\"slug\": \"${SLUG}\",
\"status\": \"publish\",
\"categories\": [${CAT_ID}],
\"tags\": [${TAG_IDS}],
\"excerpt\": \"${EXCERPT}\"
}")
POST_ID=$(echo "$POST_RESULT" | grep -o '"id":[0-9]*' | head -1 | cut -d: -f2)
echo "Created post ID: $POST_ID"
If updating an existing post (e.g., adding categories/tags to a draft):
POST_ID="123" # Existing post ID
UPDATE_RESULT=$(curl -s -X POST "${WP_URL}/wp-json/wp/v2/posts/${POST_ID}" \
-u "${WP_USER}:${WP_PASS}" \
-H "Content-Type: application/json" \
-d "{
\"categories\": [${CAT_ID}],
\"tags\": [${TAG_IDS}],
\"slug\": \"${SLUG}\"
}")
Construct the public viewing URL (not the API endpoint):
# WordPress permalink structure: /{slug}/
PUBLIC_URL="${WP_URL}/${SLUG}/"
# If slug not set, use post ID format
if [ -z "$SLUG" ]; then
PUBLIC_URL="${WP_URL}/?p=${POST_ID}"
fi
echo "✅ Article published successfully!"
echo ""
echo "📄 Title: ${TITLE}"
echo "🔗 URL: ${PUBLIC_URL}"
echo "📁 Category: ${CATEGORY_NAME}"
echo "🏷️ Tags: ${TAGS[*]}"
WordPress content field requires HTML. Convert markdown:
| Markdown | HTML |
|---|---|
# Title | <h1>Title</h1> |
## Subtitle | <h2>Subtitle</h2> |
### H3 | <h3>H3</h3> |
**bold** | <strong>bold</strong> |
*italic* | <em>italic</em> |
- list item | <ul><li>list item</li></ul> |
1. item | <ol><li>item</li></ol> |
[text](url) | <a href="url">text</a> |
`code` | <code>code</code> |
code block | <pre><code>code block</code></pre> |
Escape double quotes in content when building JSON:
# Escape quotes for JSON
ESCAPED_CONTENT=$(echo "$CONTENT" | sed 's/"/\\"/g')
#!/bin/bash
# Load credentials
source /root/.openclaw/workspace/.env
WP_URL="${WP_BLOG_URL:-https://blog.example.com}"
WP_USER="${WP_USERNAME:-admin}"
WP_PASS="${WP_APP_PASSWORD}"
# Article content - CPU Benchmark example
TITLE="AMD Ryzen 9 7950X vs Intel Core i9-13900K: A Detailed Benchmark Comparison"
SLUG="ryzen-7950x-vs-i9-13900k-benchmark-comparison"
CATEGORY="Hardware"
TAGS=("CPU" "Benchmark" "AMD" "Intel" "Performance")
CONTENT="<p>The battle for desktop CPU supremacy continues...</p><h2>Test Methodology</h2><p>All tests were conducted on identical platforms...</p>"
# Step 1: Create/Get Category
CAT_RESULT=$(curl -s -X POST "${WP_URL}/wp-json/wp/v2/categories" \
-u "${WP_USER}:${WP_PASS}" \
-H "Content-Type: application/json" \
-d "{\"name\": \"${CATEGORY}\"}")
CAT_ID=$(echo "$CAT_RESULT" | grep -o '"id":[0-9]*' | head -1 | cut -d: -f2)
# Step 2: Create/Get Tags
TAG_IDS=""
for TAG in "${TAGS[@]}"; do
TAG_RESULT=$(curl -s -X POST "${WP_URL}/wp-json/wp/v2/tags" \
-u "${WP_USER}:${WP_PASS}" \
-H "Content-Type: application/json" \
-d "{\"name\": \"${TAG}\"}")
TID=$(echo "$TAG_RESULT" | grep -o '"id":[0-9]*' | head -1 | cut -d: -f2)
TAG_IDS="${TAG_IDS},${TID}"
done
TAG_IDS=$(echo "$TAG_IDS" | sed 's/^,//')
# Step 3: Create Post
POST_RESULT=$(curl -s -X POST "${WP_URL}/wp-json/wp/v2/posts" \
-u "${WP_USER}:${WP_PASS}" \
-H "Content-Type: application/json" \
-d "{
\"title\": \"${TITLE}\",
\"content\": \"${CONTENT}\",
\"slug\": \"${SLUG}\",
\"status\": \"publish\",
\"categories\": [${CAT_ID}],
\"tags\": [${TAG_IDS}]
}")
POST_ID=$(echo "$POST_RESULT" | grep -o '"id":[0-9]*' | head -1 | cut -d: -f2)
PUBLIC_URL="${WP_URL}/${SLUG}/"
echo "✅ Published: ${PUBLIC_URL}"
| Error | Cause | Solution |
|---|---|---|
401 Unauthorized | Invalid credentials | Check username and app password |
403 Forbidden | Insufficient permissions | Use admin account or check user capabilities |
rest_cannot_create | Missing edit_posts capability | Verify user has publishing permissions |
term_exists | Category/tag already exists | Fetch existing ID instead of creating |
Always check API responses for errors:
if echo "$RESULT" | grep -q '"code":"'; then
ERROR_CODE=$(echo "$RESULT" | grep -o '"code":"[^"]*"' | head -1)
ERROR_MSG=$(echo "$RESULT" | grep -o '"message":"[^"]*"' | head -1)
echo "❌ API Error: $ERROR_CODE - $ERROR_MSG"
exit 1
fi
After successful publication, respond with:
✅ Article published successfully!
📄 Title: [Article Title]
🔗 URL: [Public Viewing URL]
📁 Category: [Category Name]
🏷️ Tags: [Tag List]