🎁 Get the FREE AI Skills Starter Guide β€” Subscribe β†’
BytesAgainBytesAgain
πŸ¦€ ClawHub

Blog with Wordpress

by @hugogu

Publish articles to WordPress blogs via REST API. Handles post creation, category/tag management, and SEO-friendly English slug generation. Use when user ask...

Versionv1.0.0
Downloads329
Stars⭐ 1
TERMINAL
clawhub install wordpress-blogger

πŸ“– About This Skill


name: wordpress-blogger description: > Publish 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. license: MIT allowed-tools: Bash

WordPress Blog Publisher

Publish articles to WordPress blogs safely with automatic category/tag management and English URL slugs.


Prerequisites

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: 1. Log in to WordPress admin dashboard 2. Go to Users β†’ Profile 3. Scroll to "Application Passwords" section 4. Click "Add New Application Password" 5. Copy the generated password


Step 1 β€” Read Credentials

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


Step 2 β€” Analyze Content & Generate Metadata

Before publishing, analyze the article content to generate appropriate metadata:

Generate English Slug

Create a URL-friendly English slug from the article title or content:

  • Use lowercase with hyphens as separators
  • Keep it under 50 characters when possible
  • Include main keywords
  • Remove stop words (a, an, the, and, or, etc.)
  • Examples:

  • "AMD Ryzen 9 7950X vs Intel Core i9-13900K: A Detailed Benchmark Comparison" β†’ ryzen-7950x-vs-i9-13900k-benchmark-comparison
  • "How to Optimize Database Performance in Production" β†’ optimize-database-performance-production
  • "Understanding Container Orchestration with Kubernetes" β†’ understanding-container-orchestration-kubernetes
  • Suggest Categories & Tags

    Based 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:

  • Category: Based on content topic (create if not exists)
  • Tags: Extract 2-4 keywords from content

  • Step 3 β€” Create Category (if needed)

    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"


    Step 4 β€” Create Tags (if needed)

    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"


    Step 5 β€” Create or Update Post

    Create New Post

    TITLE="AMD Ryzen 9 7950X vs Intel Core i9-13900K: A Detailed Benchmark Comparison"
    CONTENT="

    In this comprehensive benchmark analysis...

    " # 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"

    Update Existing Post

    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}\" }")


    Step 6 β€” Generate Public URL

    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[*]}"


    Content Conversion

    Markdown to HTML

    WordPress content field requires HTML. Convert markdown:

    | Markdown | HTML | |----------|------| | # Title |

    Title

    | | ## Subtitle |

    Subtitle

    | | ### H3 |

    H3

    | | bold | bold | | *italic* | italic | | - list item |
    • list item
    | | 1. item |
    1. item
    | | text | text | | ` code | code | | ``code block`` |
    code block
    |

    Handling Special Characters

    Escape double quotes in content when building JSON:

    # Escape quotes for JSON
    ESCAPED_CONTENT=$(echo "$CONTENT" | sed 's/"/\\"/g')
    


    Complete Workflow Example

    #!/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="

    The battle for desktop CPU supremacy continues...

    Test Methodology

    All tests were conducted on identical platforms...

    "

    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 Handling

    Common Errors

    | 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 |

    API Response Check

    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
    


    Safety Rules

  • βœ… Always generate English slug for SEO-friendly URLs
  • βœ… Create reasonable category/tags if user doesn't specify
  • βœ… Return public viewing URL, not API endpoint
  • βœ… Escape content properly for JSON payload
  • βœ… Verify credentials before attempting API calls
  • ❌ Never hardcode credentials in scripts
  • ❌ Never return API URLs (with /wp-json/) as the result

  • Response Format

    After successful publication, respond with:

    βœ… Article published successfully!

    πŸ“„ Title: [Article Title] πŸ”— URL: [Public Viewing URL] πŸ“ Category: [Category Name] 🏷️ Tags: [Tag List]

    βš™οΈ Configuration

    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: 1. Log in to WordPress admin dashboard 2. Go to Users β†’ Profile 3. Scroll to "Application Passwords" section 4. Click "Add New Application Password" 5. Copy the generated password