#!/bin/bash # Shared by post.sh and terms.sh: layered config loading and base URL # construction. The caller sets SITE (possibly empty) and CONFIG_DIR before # calling wp_load_config, and USER/PASSWORD/SERVER/... end up in scope. CONFIG_DIR="${WORDPRESS_REST_CURL_CONFIG_DIR:-$HOME/.config/wordpress-rest-curl}" wp_load_config() { local default_config_file="$CONFIG_DIR/config.sh" [[ -e "$default_config_file" ]] && source "$default_config_file" if [[ -n "$SITE" ]]; then local 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 } # Prints $SERVER normalized into a scheme-qualified, slash-trimmed base URL. wp_base_url() { local base_url="$SERVER" [[ "$base_url" != http://* && "$base_url" != https://* ]] && base_url="https://$base_url" echo "${base_url%/}" } # Runs curl against the WP REST API with shared auth/UA/error-handling. # Usage: wp_api_call METHOD PATH [curl-args...] # Prints the response body on success; on a non-2xx status prints the error # to stderr and returns 1 (does not exit, so callers can decide what to do). wp_api_call() { local method="$1" path="$2" shift 2 local response http_code body response=$(curl --silent --show-error --user "$USER:$PASSWORD" -X "$method" \ -A "$USER_AGENT" \ -w '\n%{http_code}' \ "$@" \ "$(wp_base_url)$path") 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 return 1 fi echo "$body" } # Prints every item across all pages of a paginated WP list endpoint at # PATH, one JSON object per line. wp_api_list_all() { local path="$1" page=1 count body while :; do body=$(wp_api_call GET "$path?per_page=100&page=$page") || exit 1 count=$(echo "$body" | jq 'length') [[ "$count" -eq 0 ]] && break echo "$body" | jq -c '.[]' [[ "$count" -lt 100 ]] && break page=$((page + 1)) done } # Resolves NAME to a numeric term ID under taxonomy endpoint PATH (e.g. # /wp-json/wp/v2/categories), creating the term first if it doesn't exist. wp_resolve_term() { local path="$1" name="$2" found_id payload body found_id=$(wp_api_list_all "$path" | jq -r --arg name "$name" 'select(.name == $name) | .id' | head -n1) if [[ -n "$found_id" ]]; then echo "$found_id" return fi payload=$(jq -n --arg name "$name" '{name: $name}') body=$(wp_api_call POST "$path" -H "Content-Type: application/json" --data "$payload") || exit 1 echo "$body" | jq -r '.id' }