WordPress REST API自動投稿で初日に6回失敗したので、動く最小コードだけ残します

WordPressにPythonから投稿できた瞬間、思ったより感動しました。

ただし、その前に6回失敗しています。認証で2回、URLで1回、ステータス指定で1回、JSONで1回、最後はただのスラッグ重複でした。地方の夜は静かですが、エラー画面だけは妙ににぎやかです。

この記事では、遠回りして残った「まずこれで動かす」コードだけを書きます。

目次

何をしたかったのか

やりたかったのは単純です。

Markdownで書いた記事を、WordPress REST API経由で下書き投稿する。管理画面に毎回貼り付けるのではなく、Pythonから送る。まずは1記事だけで十分です。

最初からカテゴリ自動作成、画像アップロード、予約投稿まで入れようとすると転びます。私は転びました。

事前に必要なもの

必要なのは3つです。

1つ目はWordPressのURL。2つ目はユーザー名。3つ目はアプリケーションパスワードです。

パスワードをコードに直書きしないため、環境変数に入れます。

$env:WP_BASE_URL="https://example.com"
$env:WP_USER="your-user"
$env:WP_APP_PASSWORD="xxxx xxxx xxxx xxxx xxxx xxxx"

実際の値は自分の環境に合わせてください。ここで1文字でも違うと、かなり冷たい401が返ってきます。

動く最小コード

私は最終的に、このくらいまで削りました。

import os
import requests
from requests.auth import HTTPBasicAuth


def create_post(title: str, content: str, status: str = "draft") -> dict:
    base_url = os.environ["WP_BASE_URL"].rstrip("/")
    user = os.environ["WP_USER"]
    app_password = os.environ["WP_APP_PASSWORD"]

    endpoint = f"{base_url}/wp-json/wp/v2/posts"
    payload = {
        "title": title,
        "content": content,
        "status": status,
    }

    response = requests.post(
        endpoint,
        json=payload,
        auth=HTTPBasicAuth(user, app_password),
        timeout=20,
    )

    # ハマりポイント: 失敗時に本文を出さないと原因が見えない
    if response.status_code >= 400:
        raise RuntimeError(f"{response.status_code}: {response.text}")

    return response.json()


if __name__ == "__main__":
    post = create_post(
        "API投稿テスト",
        "<p>Pythonから投稿した下書きです。</p>",
    )
    print(post["id"], post["link"])

最初の成功まで、ここから始めればよかったです。余計な機能を足すのは、1件投稿できてからで十分でした。

私が踏んだ6つの穴

1つ目は、通常のログインパスワードを使ったことです。REST APIではアプリケーションパスワードを使います。ここで15分消えました。

2つ目は、URLの末尾スラッシュ問題です。rstrip("/") を入れておくと、//wp-json のような地味な事故を防げます。

3つ目は、statuspublish にしてしまったことです。テスト投稿がそのまま公開されるのは心臓に悪いです。初回は必ず draft にします。

4つ目は、HTMLとMarkdownの扱いを混ぜたことです。WordPressに送る本文は、まずHTMLとして送るほうが分かりやすいです。

5つ目は、エラー本文を捨てたことです。response.raise_for_status() だけだと、なぜ落ちたのか見えにくい場面があります。

6つ目は、同じタイトルで何度も投稿して管理画面が散らかったことです。テスト記事は3本までと決めたほうがいいです。

MarkdownをHTMLにする

Markdownから投稿したい場合は、変換を1段挟みます。

import markdown


def markdown_to_html(path: str) -> str:
    text = open(path, encoding="utf-8").read()
    # ハマりポイント: 拡張を固定しておくとコードブロックが崩れにくい
    return markdown.markdown(text, extensions=["fenced_code", "tables"])

ただし、装飾やブロックの見え方はテーマに左右されます。最初から完璧な見た目を狙うより、下書きに送って管理画面で確認するほうが速いです。

予約投稿やカテゴリは後でいい

REST APIはできることが多いです。

カテゴリ、タグ、アイキャッチ、予約投稿、更新、削除。調べるほど全部やりたくなります。でも、初日に全部入れると、どこで失敗したか分からなくなります。

私の場合、最初の目標を「下書き1本」に絞ったら、ようやく進みました。成功体験が1つあると、次の機能追加が落ち着いてできます。

投稿前に必ず見る3項目

自動投稿で一番怖いのは、意図しない公開です。

私は初回から publish を使いかけて、送信直前に手が止まりました。公開サイトに「API投稿テスト」が出る未来が見えて、正直かなり怖かったです。

そこで、投稿スクリプトには確認用の出力を入れるようにしました。

def print_preview(payload: dict) -> None:
    print("title:", payload.get("title"))
    print("status:", payload.get("status"))
    print("content_chars:", len(payload.get("content", "")))
    # ハマりポイント: draft以外なら人間が一度止まれるようにする
    if payload.get("status") != "draft":
        raise ValueError("first run must use draft status")

見るのは、タイトル、ステータス、本文の文字数です。この3つだけで、空本文、公開指定、タイトル間違いにかなり気づけます。

自動化は、成功時の速さだけでなく、失敗直前に止まれる仕組みまで含めて作るべきでした。

まとめ

WordPress REST API自動投稿は、動くとかなり便利です。記事作成フローをファイルベースにできるので、下書き、レビュー、投稿の流れが整理されます。

でも初日に必要なのは、立派な投稿システムではありません。必要なのは、20行前後で下書きを1本作れる最小コードです。

自動投稿の第一歩は、公開ボタンを押すことではなく、安心して失敗できる下書きを作ることです。

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

この記事を書いた人

コメント

コメントする

目次