#!/bin/bash # WordPress posting script # config: EDITOR=vim TRANSFORM=() # empty or a subset of: 'title' 'markdown' USER="" # WP user to create the post PASSWORD="" # application password generated for your WP user SERVER="" # server hostname, optionally with subdirectories STATUS="draft" # one of publish,future,draft,pending,private CATEGORIES="" # comma separated integer IDs of categories TAGS="" # comma separated integer IDs of tags TMPFILE=/tmp/wordpress-post.txt # location of a temporary file with the post text CONFIG_DIR="${WORDPRESS_REST_CURL_CONFIG_DIR:-$HOME/.config/wordpress-rest-curl}" # CLI options: # --site NAME after config.sh, also source $CONFIG_DIR/NAME.sh, whose # values override config.sh's (lets you keep just the # per-instance bits — USER/PASSWORD/SERVER — in each site # file, and shared defaults in config.sh) # --edit POST_ID update an existing post instead of creating a new one # --publish shortcut for STATUS=publish # --file PATH use PATH as the post source instead of opening $EDITOR SITE="" POST_ID="" SOURCE_FILE="" PUBLISH=0 while [[ $# -gt 0 ]]; do case "$1" in --site) SITE="$2"; shift 2 ;; --edit) POST_ID="$2"; shift 2 ;; --publish) PUBLISH=1; shift ;; --file) SOURCE_FILE="$2"; shift 2 ;; *) echo "Unknown argument: $1" >&2 exit 1 ;; esac done DEFAULT_CONFIG_FILE="$CONFIG_DIR/config.sh" [[ -e "$DEFAULT_CONFIG_FILE" ]] && source "$DEFAULT_CONFIG_FILE" if [[ -n "$SITE" ]]; then SITE_CONFIG_FILE="$CONFIG_DIR/$SITE.sh" [[ -e "$SITE_CONFIG_FILE" ]] || { echo "Config file not found: $SITE_CONFIG_FILE" >&2; exit 1; } source "$SITE_CONFIG_FILE" elif [[ ! -e "$DEFAULT_CONFIG_FILE" ]]; then echo "No site specified and no default config found. Pass --site NAME or create $DEFAULT_CONFIG_FILE" >&2 exit 1 fi [[ "$PUBLISH" -eq 1 ]] && STATUS="publish" # let the user provide the post content if [[ -n "$SOURCE_FILE" ]]; then cp "$SOURCE_FILE" "$TMPFILE" || exit 1 else $EDITOR $TMPFILE || exit 1 fi [[ -e $TMPFILE ]] || exit 1 # transformations cp $TMPFILE $TMPFILE.trans for T in "${TRANSFORM[@]}"; do if [[ "$T" == "title" ]]; then python3 >$TMPFILE.trans2 <$TMPFILE.trans2 < 0) | tonumber' | jq -s '.') fi TAGS_JSON="[]" if [[ -n "$TAGS" ]]; then TAGS_JSON=$(echo "$TAGS" | tr ',' '\n' | jq -R 'select(length > 0) | tonumber' | jq -s '.') fi PAYLOAD=$(jq -n \ --arg title "$TITLE" \ --arg content "$CONTENT" \ --arg status "$STATUS" \ --argjson categories "$CATEGORIES_JSON" \ --argjson tags "$TAGS_JSON" \ '{title: $title, content: $content, status: $status, categories: $categories, tags: $tags}') BASE_URL="$SERVER" [[ "$BASE_URL" != http://* && "$BASE_URL" != https://* ]] && BASE_URL="https://$BASE_URL" URL="$BASE_URL/wp-json/wp/v2/posts/" [[ -n "$POST_ID" ]] && URL="$BASE_URL/wp-json/wp/v2/posts/$POST_ID" # push the post! RESPONSE=$(curl --silent --show-error --user "$USER:$PASSWORD" -X POST \ -H "Content-Type: application/json" \ --data "$PAYLOAD" \ -w '\n%{http_code}' \ "$URL") HTTP_CODE=$(echo "$RESPONSE" | tail -n1) BODY=$(echo "$RESPONSE" | sed '$d') if [[ "$HTTP_CODE" -lt 200 || "$HTTP_CODE" -ge 300 ]]; then echo "Error: WordPress API returned HTTP $HTTP_CODE" >&2 echo "$BODY" >&2 exit 1 fi echo "$BODY" # backup the posted data (temporarily until it is auto-removed) mv $TMPFILE $TMPFILE.posted