MENU

WordPress REST API|Pythonで下書き投稿

当ページのリンクには広告(PR)が含まれていることがあります。
【コピペOK】WordPress REST APIで記事を自動投稿する方法|Pythonで安全に下書き作成のアイキャッチ
お悩み女子

Excelにまとめた記事案を、Pythonで一気にWordPressの下書きへ入れたい。でも、間違えて公開してしまったらと思うと怖い……

WordPress REST APIを使うと、Pythonから記事の下書きを作れます。タイトルと本文のデータがあれば、管理画面で1件ずつ貼り付ける作業を減らせます。

この記事ではPythonで下書きを作り、IDと状態を確かめ、更新前に本文を控えるまでの安全な手順を、動くコードつきで紹介します。コードはWindows 11 と Python 3.12 で、手元に立てた検証用の WordPress(バージョン7.1.3)に対して動くことを確かめています。実際に公開しているサイトには送っていません。REST API全体の仕組みはWordPress REST APIでできることにまとめています。

この記事でわかること
  • Pythonで下書きを作るコードと、実行結果の読み方
  • アプリケーションパスワードを環境変数に置く方法
  • 更新前に本文を控えてから直す手順
  • 401・403・400エラーが出たときの見方
  • 実行前・実行後のチェックリスト
目次

WordPress REST APIとPython|下書き投稿の準備と流れ

Pythonから下書きを作る流れは、認証の準備、下書きの作成、IDと状態の確認、必要なら更新(更新前に控えを保存)の4段階です。準備するものは次の表のとおりです。

スクロールできます
項目内容補足
WordPressHTTPSのサイト(5.6以降)アプリケーションパスワードを使うため
ユーザー下書きを作れる権限のあるユーザー寄稿者でも作れる
PythonPython 3 と requestspip install requests で入れる
認証情報ユーザー名とアプリケーションパスワード環境変数に置く

アプリケーションパスワードの発行

管理画面で自分のユーザーの編集画面(ユーザーのプロフィール)を開き、アプリケーションパスワードの欄に名前(例:python-draft)を入れて追加します。表示されたパスワードはあとから見直せないので、その場で保管します。権限や仕組みは、Application Passwordとは?WordPress API認証を安全に使う基本で詳しく扱っています。

環境変数への設定

パスワードをコードに直接書くと、ファイルを共有したときに漏れます。そこで、環境変数(PCの設定として持たせておく値)に置き、コードからは読み出すだけにします。PowerShellでは、次のように設定します。

$env:WP_URL = "https://(自分のサイトのアドレス)"
$env:WP_USER = "(ユーザー名)"
$env:WP_APP_PASSWORD = "(発行したアプリケーションパスワード)"

この設定は開いているPowerShellのウィンドウの中だけで有効です。閉じると消えます。入力した内容が履歴に残る環境もあるので、共有のPCでは使いません。環境変数の考え方は環境変数で設定を管理する方法にまとめています。

Pythonでの下書き作成とID・状態の確認

下書きを1件作るコードです。タイトル・本文・スラッグを渡して、作れたらIDと状態を表示します。

下書きを作るコードと実行結果

create_draft.py という名前で保存し、環境変数を設定した同じPowerShellのウィンドウで、py create_draft.py と実行します。

import os
import sys

import requests

WP_URL = os.environ["WP_URL"].rstrip("/")
AUTH = (os.environ["WP_USER"], os.environ["WP_APP_PASSWORD"])
API = f"{WP_URL}/wp-json/wp/v2"


def create_draft(title, html_body, slug):
    res = requests.post(
        f"{API}/posts",
        auth=AUTH,
        json={"title": title, "content": html_body, "status": "draft", "slug": slug},
        timeout=15,
    )
    if res.status_code != 201:
        print("作成に失敗しました:", res.status_code, res.text[:200])
        sys.exit(1)
    post = res.json()
    if post["status"] != "draft":  # 下書き以外で作られていたら止める
        print("draft ではありません:", post["status"])
        sys.exit(1)
    return post


post = create_draft(
    "PythonからのテストA",
    "<p>REST APIで作った下書きです。</p>",
    "python-rest-api-test-a",
)
print("ID:", post["id"])
print("状態:", post["status"])
print("スラッグ:", post["slug"])
print("編集画面:", f"{WP_URL}/wp-admin/post.php?post={post['id']}&action=edit")

実行結果は次のとおりです。

ID: 10
状態: draft
スラッグ: python-rest-api-test-a
編集画面: http://127.0.0.1:9401/wp-admin/post.php?post=10&action=edit

最後に表示された編集画面のURLを開くと、管理画面で下書きの中身を確かめられます。出力例の127.0.0.1は検証用のアドレスで、実際には自分のサイトのアドレスが表示されます。

コードの読み方

  • “status”: “draft” を毎回書く:検証用のWordPressでは省略しても下書きになりましたが、明記しておけば公開の事故を防げます。
  • 201 かどうかを確かめる:201 は「作成できた」の意味です。それ以外が返ったら、中身を表示して止めます。
  • 応答の status を確かめる:下書き以外で作られていたら、その場で止めます。
  • slug は英語で指定する:下書きは、指定しないとスラッグが空のままです。日本語のタイトルから作られるURLは、%e8%ab… のような長い文字列になります。

下書きにしておけば、公開するかどうかは管理画面で内容を見てから、人が決められます。

WordPress下書きの重複・カテゴリ・スラッグ

エラーにならないまま、想定と違う結果になるケースがあります。検証用のWordPressで確かめた3つを紹介します。

同じコードで下書きが増える

上のコードをもう一度実行すると、別の下書きがもう1件できました(ID 11)。REST APIは同じ内容かどうかを見ずに作ります。重複を避けるには、作る前に GET /posts?status=draft&search=(タイトル)で既存の下書きを調べます。下書きの一覧を見るには、認証が必要です。

存在しないカテゴリIDは無視される

categories に存在しないIDを入れて送ると、エラーにならず 201 が返り、カテゴリは空のままでした。カテゴリやタグを付けるときは、応答の categories が想定どおりかを確かめます。IDの調べ方はWordPressカテゴリ・タグをREST APIで取得する方法で扱っています。

同じスラッグには連番が付く

同じスラッグで2件目を作ると、スラッグの末尾に連番が付きました(python-rest-api-test-a-2)。URLを狙った名前にしたいときは、既存の記事と重ならないスラッグを指定します。

3つとも、エラーで止まらずに先へ進んでしまいます。実行後に応答の categories とスラッグを見る習慣があれば、違いに早く気づけます。

WordPress REST APIでPythonから更新|更新前に本文を控える

下書きの本文を直すときは、更新の前に今の本文を控え、変える項目だけを送ります。公開済みの記事を直す場合は、別の点にも注意が必要です。

控えを保存して本文だけ更新するコード

次のコードは記事のIDを引数で受け取り、下書きのときだけ更新します。控えのファイルを保存してから、本文(content)だけを送ります。

import json
import os
import sys
from datetime import datetime

import requests

WP_URL = os.environ["WP_URL"].rstrip("/")
AUTH = (os.environ["WP_USER"], os.environ["WP_APP_PASSWORD"])
API = f"{WP_URL}/wp-json/wp/v2"

post_id = int(sys.argv[1])
new_content = "<p>更新後の本文です。</p>"

# 1. 更新前の状態を取得する(context=edit で、本文の元の形 raw が取れる)
res = requests.get(f"{API}/posts/{post_id}", auth=AUTH, params={"context": "edit"}, timeout=15)
res.raise_for_status()
before = res.json()
if before["status"] != "draft":
    sys.exit(f"draft ではないので中止します: {before['status']}")

# 2. 控えをファイルに保存する
backup = f"backup_{post_id}_{datetime.now():%Y%m%d_%H%M%S}.json"
with open(backup, "w", encoding="utf-8") as f:
    json.dump(
        {"id": post_id, "status": before["status"], "title": before["title"]["raw"], "content": before["content"]["raw"]},
        f, ensure_ascii=False, indent=2,
    )
print("控えを保存:", backup)

# 3. 変える項目(content)だけを送る
res = requests.post(f"{API}/posts/{post_id}", auth=AUTH, json={"content": new_content}, timeout=15)
res.raise_for_status()
after = res.json()
print("状態:", after["status"], "/ 本文が更新された:", after["content"]["raw"] == new_content)

環境変数を設定したウィンドウで py update_with_backup.py 10 のようにIDを付けて実行すると、次のように表示されます。

控えを保存: backup_10_20261018_221443.json
状態: draft / 本文が更新された: True

保存された控えは次の内容でした。本文の元の形(raw)が入っています。

{
  "id": 10,
  "status": "draft",
  "title": "PythonからのテストA",
  "content": "<p>REST APIで作った下書きです。</p>"
}

公開済みの記事のIDを渡すと、「draft ではないので中止します: publish」と表示して止まりました。公開済みの記事を更新する手順は、WordPress REST APIで既存記事を更新する方法で扱っています。

控えから元に戻す

更新を取り消したいときは、控えの content を同じ要領で送ります。検証用のWordPressでは、控えの content を POST して、更新前の本文に戻ることを確かめました。

控えのファイルは更新のたびに日時つきの名前で残ります。上書きされないので、あとから「どの時点の本文か」を見分けられます。

なべくん

更新するときは控えを取ってから、変える項目だけを送ります。この順番を崩さないことが、事故を減らす近道です。

WordPress REST APIとPythonのエラー|401・403・400の見方

失敗したときは、応答の中身(res.text)の先頭を表示します。そこにある code と message が、原因を探す手がかりです。

スクロールできます
状況ステータスcode見る場所
認証情報がない・誤り401rest_cannot_createWP_USER と WP_APP_PASSWORD、URLがHTTPSか
権限が足りない(寄稿者が公開)403rest_cannot_publishユーザーのロール、status
値が不正(status に foo、categories に文字)400rest_invalid_param送る値の型と選択肢
URLの書き間違い(/post と書いた)404rest_no_routeURLのパス
存在しない記事ID404rest_post_invalid_idID

パスワードを間違えて実行すると、次のように表示されました。

作成に失敗しました: 401 {"code":"rest_cannot_create","message":"Sorry, you are not allowed to create posts as this user.","data":{"status":401}}

検証用のWordPressでは、ユーザー名やパスワードを間違えた場合も、認証なしと同じ 401 の rest_cannot_create が返りました。このメッセージだけでは、原因がユーザー名かパスワードかは見分けられません。環境変数の中身を順に確かめます。切り分けの流れはWordPress REST APIの401・403・400エラー切り分け、失敗を記録する方法はWordPress API投稿失敗ログの残し方をご覧ください。

WordPressへの送信前後のチェックリスト

実行の前後で確かめる項目を、表にまとめました。印刷して手元に置いたり、スプレッドシートに写して使ったりできます。

スクロールできます
段階確認すること理由
実行前WP_URL が、本番ではなく検証用のサイトを指している初回は送り先の取り違えが起きやすい
実行前パスワードが環境変数にあり、コードに書かれていないファイルの共有で漏れるのを防ぐ
実行前使うユーザーの権限が、必要最小限になっている寄稿者なら、誤って公開できない
実行中最初は1件だけ動かす想定外の結果が大量に出るのを防ぐ
実行中201 以外が返ったら止まる失敗に気づかず次へ進まない
実行後管理画面の下書き一覧で、タイトルと本文を目で確認する応答の status だけでは中身までは分からない
実行後応答のスラッグとカテゴリが想定どおりか見るエラーなしで無視される項目がある
更新時更新前の控えが保存されている元に戻せる状態にする

実行前の3項目を満たしてから、1件だけ動かす。この順番を守るだけで、取り返しのつかない失敗はかなり減らせます。

WordPress REST APIとPythonに関するよくある質問

公開、画像の追加、Pythonを入れられないPCについての疑問をまとめました。

公開まで自動で行ってもよいですか?

status を publish にすれば公開までできますが、この記事では勧めていません。下書きまでをコードで行い、公開は管理画面で内容を見てから人が行う分け方が、事故の少ない進め方です。

画像も一緒に入れられますか?

画像はメディアのAPIで別にアップロードします。手順はWordPressメディアAPIで画像をアップロードする基本とアイキャッチ画像を設定する方法にあります。寄稿者のユーザーは画像をアップロードできません。

Pythonを入れられない会社のPCでは使えませんか?

Googleのスプレッドシートにデータがあるなら、GAS(Google Apps Script)で同じことができます。手順はGASでWordPressに下書きを作る方法にまとめています。

PythonでWordPressの下書きを扱う要点

PythonでWordPressの下書きを作る手順を整理します。

この記事のまとめ

準備:アプリケーションパスワードを発行し、環境変数 WP_URL・WP_USER・WP_APP_PASSWORD に置く。
下書き作成:status は draft を明記し、201 と応答の status を確かめる。スラッグは英語で指定する。
更新:下書きだけを対象にし、更新前に本文を控えて、変える項目だけを送る。
エラー:res.text の code を見る。パスワードの誤りは認証なしと同じ 401 になる。

最初は検証用のサイトで下書きを1件作り、管理画面で確かめるところまで進めるのが近道です。

関連する手順は次の記事で扱っています。

参考資料
Posts | REST API Handbook
Authentication | REST API Handbook
Application Passwords Integration Guide | Make WordPress Core
Requests: HTTP for Humans

この記事を書いた人

Watanabeのアバター Watanabe サイト運営者

2020年よりブログ開始。
SEOが思いのほか性にあっていたようで現在に至る。
モットーは「勝率の高い選択をする」
AIは活用するが吉、最後は人間が息を吹き込む。
アートと科学を追求し、日々精進。
―――
収益:6~7桁をウゴウゴ。
サイト:ペラサイト~中規模サイトまで運営中。
案件:1000円以上の案件をメインに取組中。
打ち手:ブラックSEO~ホワイトSEOまで
―――

目次