Amazon11/12まで!スマイルSale開催中!セール会場へ

AIでWordPress記事を下書き保存する方法|REST API・画像・投稿前チェック

AIでWordPress記事を下書き保存する方法

AIに書かせた記事をWordPressに入れるときは、公開ではなく「下書き」として保存し、人が管理画面で確かめてから公開する流れにすると安全です。

やり方は、WordPressでアプリケーションパスワードを発行し、REST APIで記事を status を draft にして送るだけです。

画像は先にメディアとしてアップロードし、返ってきたIDを記事のアイキャッチ画像に指定します。

この記事は、2026年10月18日に確認したWordPressの公式ドキュメント(REST APIハンドブック・権限グループの説明)と、当サイトのWordPress 7.1.3の日本語の表示ファイルをもとにしています。

当サイトでも、AIと一緒に作った記事を同じ流れ(画像のアップロード→下書き保存→読み直して照合)で入れています。

元のコードは2026年10月18日に模擬サーバーで確認しています。

10月23日の改訂ではHTTPS以外とリダイレクトを拒否し、引数不足や保存後の不一致で停止する処理を追加しました。

改訂版は外部へ送信しない模擬応答テストで確認しています。

実際のサイトへの送信はこのコードでは試していないので、使う前にテスト用のサイトか、消してよい下書きで確かめてください。

目次

全体の流れ

  1. WordPressで、AIの作業用のユーザーとアプリケーションパスワードを用意する
  2. AIに記事の本文(HTMLかブロックの形)と題名を書かせる
  3. 画像があれば、メディアとしてアップロードし、代替テキストを付ける
  4. 記事を下書き(draft)として保存する
  5. 保存された記事を読み直し、下書きになっているか、本文が送ったとおりかを確かめる
  6. 人が管理画面のプレビューで確かめ、直してから公開する

AIに公開まで任せず、最後の公開ボタンは人が押す、というところが要点です。

スポンサーリンク

1. AI用のユーザーとアプリケーションパスワードを用意する

WordPressの公式ドキュメントによると、アプリケーションパスワードはWordPress 5.6から標準で入っていて、ユーザーの編集画面で発行できます。

  1. 管理画面の「ユーザー」から、AIの作業に使うユーザーを開く
  2. 「アプリケーションパスワード」の欄で、「新しいアプリケーションパスワード名」に用途が分かる名前を入れる
  3. 「アプリケーションパスワードを追加」を押し、表示されたパスワードを控える

管理画面にも「このパスワードを再度取得することはできません。」と表示されるので、すぐに安全な場所へ保存します。

公式ドキュメントでは、アプリケーションパスワードは https:// のサイトに対してBasic認証で送ると説明されています。

ユーザーの権限は小さくする

AIの作業用には、管理者のユーザーを使わないでください。

WordPressの公式ドキュメントにある権限グループの一覧では、次のようになっています。

権限グループ(日本語の表示)記事の公開画像のアップロード
寄稿者(Contributor)できない(自分の記事を書いて管理するだけ)できない
投稿者(Author)できるできる
編集者(Editor)できる(ほかの人の記事も)できる
WordPressの権限グループと、この作業に関わる権限

標準の権限設定で本文だけを下書き保存するなら、公開権限のない「寄稿者」が候補です。

プラグインなどで権限が変更されている場合は、実際に公開権限がないことを確認してください。

画像も扱うにはupload_files権限が必要です。

標準の「投稿者」はこの権限と公開権限の両方を持つため、下書き保存ではstatusをdraftに固定します。

公開を権限で禁止したい場合は、管理者が投稿編集・アップロードを許可し、公開を許可しない専用の権限設定を用意してください。

2. AIに本文を書かせるときの注意

AIには、題名と本文を分けて出してもらい、本文はWordPressにそのまま入れられる形(HTML、またはブロックエディターの形)にしてもらいます。

  • 見出し・段落・箇条書きだけにして、装飾の指定は少なくする
  • 事実や数字には、確かめた出典のURLを添えてもらう(あとで人が確かめるため)
  • 本文に、パスワードやAPIキーなどの認証情報を書かせない

AIが書いた事実や数字はまちがっていることがあるので、出典と見比べる前提で下書きに入れます。

3. 下書きとして保存するコード(Python)

Pythonの標準ライブラリだけで動くようにしてあります。

ユーザー名とアプリケーションパスワードはコードに書かず、環境変数(WP_URL・WP_USER・WP_APP_PASSWORD)から読みます。

# AIが書いた記事を、WordPressに「下書き」として保存する
# 使い方: python save_draft.py 記事.html "記事の題名" [アイキャッチ画像.jpg] [画像の代替テキスト]
import base64, json, mimetypes, os, re, sys, urllib.request
from urllib.parse import urlsplit
from pathlib import Path

SITE = os.environ["WP_URL"].rstrip("/")      # 例 https://example.com
parts = urlsplit(SITE)
if (parts.scheme != "https" or not parts.hostname or parts.username is not None
        or parts.password is not None or parts.query or parts.fragment):
    raise ValueError("WP_URLには認証情報やクエリを含まないHTTPS URLを指定してください")

class NoRedirect(urllib.request.HTTPRedirectHandler):
    def redirect_request(self, req, fp, code, msg, headers, newurl):
        raise RuntimeError("リダイレクトを拒否しました。WP_URLの正規URLを確認してください")

OPENER = urllib.request.build_opener(NoRedirect())
USER = os.environ["WP_USER"]                 # WordPressのユーザー名
APP_PASSWORD = os.environ["WP_APP_PASSWORD"] # アプリケーションパスワード
AUTH = "Basic " + base64.b64encode(f"{USER}:{APP_PASSWORD}".encode()).decode()


def api(method, path, body=None, headers=None):
    h = {"Authorization": AUTH}
    if isinstance(body, dict):
        body = json.dumps(body).encode("utf-8")
        h["Content-Type"] = "application/json"
    h.update(headers or {})
    req = urllib.request.Request(SITE + "/wp-json/wp/v2" + path, data=body, headers=h, method=method)
    with OPENER.open(req, timeout=60) as r:
        return json.load(r)


def upload_image(path, alt):
    # ファイル名は半角の英数字にしておく(ヘッダーに日本語は入れられない)
    p = Path(path)
    if not re.fullmatch(r"[A-Za-z0-9][A-Za-z0-9_.-]*", p.name):
        raise ValueError("画像のファイル名は半角英数字・_・-・.にしてください")
    ctype = mimetypes.guess_type(p.name)[0]
    if ctype not in {"image/jpeg", "image/png", "image/webp", "image/gif"}:
        raise ValueError("この例ではJPEG・PNG・WebP・GIFを指定してください")
    media = api("POST", "/media", p.read_bytes(), {
        "Content-Type": ctype,
        "Content-Disposition": f'attachment; filename="{p.name}"',
    })
    print("メディア作成 id =", media["id"])
    api("POST", f"/media/{media['id']}", {"alt_text": alt})
    saved = api("GET", f"/media/{media['id']}?context=edit")
    if saved["alt_text"] != alt:
        raise RuntimeError("代替テキストが一致しません。作成済みメディアを確認してください")
    return media["id"]


def main():
    if len(sys.argv) not in (3, 5):
        raise SystemExit('使い方: python save_draft.py 記事.html "題名" [画像.jpg "代替テキスト"]')
    html_file, title = sys.argv[1], sys.argv[2]
    content = Path(html_file).read_text(encoding="utf-8")
    post = {"title": title, "content": content, "status": "draft"}
    if len(sys.argv) == 5:
        post["featured_media"] = upload_image(sys.argv[3], sys.argv[4])
    created = api("POST", "/posts", post)
    print("投稿作成 id =", created["id"])

    # 保存されたものを読み直して確かめる
    back = api("GET", f"/posts/{created['id']}?context=edit")
    if back["status"] != "draft":
        raise RuntimeError("下書きになっていません。作成済み投稿を直ちに確認してください")
    if back["content"]["raw"] != content or back["title"]["raw"] != title:
        raise RuntimeError("題名または本文が一致しません。作成済み投稿を確認してください")
    if back["featured_media"] != post.get("featured_media", 0):
        raise RuntimeError("アイキャッチ画像が一致しません。作成済み投稿を確認してください")
    print("下書きを保存しました id =", created["id"])
    print("編集画面:", f"{SITE}/wp-admin/post.php?post={created['id']}&action=edit")


if __name__ == "__main__":
    main()

使い方は、記事の本文を保存したHTMLファイルと題名を渡します。

python save_draft.py article.html "記事の題名" eyecatch.jpg "画像の代替テキスト"

画像が無い場合は、HTMLファイル名と題名の2つだけを渡します。

画像を指定する場合は代替テキストも渡してください。

WP_URLには転送を必要としない正規のHTTPS URLを設定します。

途中でエラーやタイムアウトになっても、画像や下書きが作成済みの場合があります。

管理画面と表示されたIDを確認してから再実行し、重複登録を避けてください。

コードがしていること

順番送る先内容
1/wp/v2/media画像のファイルを送り、メディアとして登録する
2/wp/v2/media/(ID)登録した画像に代替テキストを付ける
3/wp/v2/posts題名・本文・アイキャッチ画像のIDを、status を draft にして送る
4/wp/v2/posts/(ID)保存された記事を読み直し、下書きになっているか、本文が同じかを確かめる
save_draft.py の処理の順番

REST APIハンドブックでは、記事の status に指定できるのは publish・future・draft・pending・private の5つで、アイキャッチ画像は featured_media に画像のIDを入れると書かれています。

人の確認待ちであることを示すpendingは、管理画面で「レビュー待ち」と表示されます。

上記のコードを変更して使う場合は、送信するstatusと読み直し時の期待値を両方pendingに変えてください。

画像のアップロードでは、ファイルの中身をそのまま送り、Content-Disposition というヘッダーでファイル名を伝えます。

当サイトでアイキャッチ画像を登録するときも、この形で送っています。

4. 公開する前に確かめること

下書きが入ったら、管理画面で開いてプレビューを見ながら、次の点を確かめます。

確かめること見るところ
事実・数字・料金AIが添えた出典を開いて、本文と同じことが書かれているか
リンクリンク先が開けるか、意図したページか
見出しの順番h2・h3の順番がくずれていないか
画像アイキャッチ画像が付いているか、代替テキストが入っているか
カテゴリー・タグ決まったカテゴリーに入っているか
題名とURL(スラッグ)題名が内容を表しているか、スラッグがサイトの命名方針に合うか。既存記事のURLを不用意に変更しない
記号の変化コマンドやコードのハイフン2つや引用符が、表示で別の記号に変わっていないか
公開前の確認表

最後の記号の変化は、当サイトで実際に起きたことです。

WordPressは本文の段落や表の中の -- を「–」のような記号に、まっすぐな引用符を曲がった引用符に変えて表示するため、コマンドをコピーすると動かなくなります。

コマンドやオプションは、本文でも <code> のタグで囲むか、コードのブロックに入れてください。

うまくいかないとき

起きていること確かめること
401が返るユーザー名とアプリケーションパスワードの組み合わせ。ログイン用のパスワードではなく、アプリケーションパスワードを使っているか
403が返るユーザーの権限(寄稿者は画像をアップロードできない)。セキュリティ系のプラグインがREST APIを止めていないか
画像のアップロードだけ失敗するファイル名に日本語が入っていないか。画像の形式がサイトで許可されているか
本文の形が変わって保存される保存後に読み直した本文と、送った本文を見比べる
うまくいかないときの確認点

認証が届かない、セキュリティのプラグインに止められるといった、REST API全般のつまずきは、WordPress REST APIとは?できること・エンドポイント一覧・構築方法で詳しく説明しています。

アプリケーションパスワードの扱い

  • AIとの会話の中に、アプリケーションパスワードを貼らない
  • コードやリポジトリに書かず、環境変数などに入れる
  • 使い道ごとに別のアプリケーションパスワードを発行し、使わなくなったら取り消す
  • AIの作業用ユーザーは、必要な権限だけにする

Claude Codeのクラウドで動かす場合に、パスワードをClaudeに見せずに渡す方法は、Claude CodeのクラウドからWordPress REST APIにつなぐ方法で説明しています。

REST API以外のつなぎ方(MCP・SSHなど)との違いは、WordPressとAIを接続する方法まとめをご覧ください。

スポンサーリンク

参考にした資料

いずれも2026年10月18日に確認しました。

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

この記事を書いた人

須澤 元貴のアバター 須澤 元貴 代表社員

MOTOKI合同会社 代表社員。
アニメ・映像業界とゲーム業界で、2D・UI・3D・アニメーション制作、映像編集、ツール制作に携わってきました。
現在はWordPressを中心にWebサイトの制作とカスタマイズを手がけています。
著書に『Unity デザイナーズ・バイブル』『Unityゲーム プログラミング・バイブル 2nd Generation』(ボーンデジタル)。
岡山県出身、埼玉県在住。

次に学ぶ・作業環境を選ぶ

学習を続けたい方や、作業環境を整えたい方は、目的に合うガイドをご覧ください。

生成AIのおすすめ書籍

周辺機器の優先度

目次