AIに書かせた記事をWordPressに入れるときは、公開ではなく「下書き」として保存し、人が管理画面で確かめてから公開する流れにすると安全です。
やり方は、WordPressでアプリケーションパスワードを発行し、REST APIで記事を status を draft にして送るだけです。
画像は先にメディアとしてアップロードし、返ってきたIDを記事のアイキャッチ画像に指定します。
この記事は、2026年10月18日に確認したWordPressの公式ドキュメント(REST APIハンドブック・権限グループの説明)と、当サイトのWordPress 7.1.3の日本語の表示ファイルをもとにしています。
当サイトでも、AIと一緒に作った記事を同じ流れ(画像のアップロード→下書き保存→読み直して照合)で入れています。
掲載したPythonのコードは、2026年10月18日にWordPressのREST APIをまねた手元の模擬サーバーで、画像のアップロード・代替テキストの設定・下書き保存・読み直しまでを確かめたものです。
実際のサイトへの送信はこのコードでは試していないので、使う前にテスト用のサイトか、消してよい下書きで確かめてください。
全体の流れ
- WordPressで、AIの作業用のユーザーとアプリケーションパスワードを用意する
- AIに記事の本文(HTMLかブロックの形)と題名を書かせる
- 画像があれば、メディアとしてアップロードし、代替テキストを付ける
- 記事を下書き(draft)として保存する
- 保存された記事を読み直し、下書きになっているか、本文が送ったとおりかを確かめる
- 人が管理画面のプレビューで確かめ、直してから公開する
AIに公開まで任せず、最後の公開ボタンは人が押す、というところが要点です。
1. AI用のユーザーとアプリケーションパスワードを用意する
WordPressの公式ドキュメントによると、アプリケーションパスワードはWordPress 5.6から標準で入っていて、ユーザーの編集画面で発行できます。
- 管理画面の「ユーザー」から、AIの作業に使うユーザーを開く
- 「アプリケーションパスワード」の欄で、「新しいアプリケーションパスワード名」に用途が分かる名前を入れる
- 「アプリケーションパスワードを追加」を押し、表示されたパスワードを控える
管理画面にも「このパスワードを再度取得することはできません。」と表示されるので、すぐに安全な場所へ保存します。
公式ドキュメントでは、アプリケーションパスワードは https:// のサイトに対してBasic認証で送ると説明されています。
ユーザーの権限は小さくする
AIの作業用には、管理者のユーザーを使わないでください。
WordPressの公式ドキュメントにある権限グループの一覧では、次のようになっています。
| 権限グループ(日本語の表示) | 記事の公開 | 画像のアップロード |
|---|---|---|
| 寄稿者(Contributor) | できない(自分の記事を書いて管理するだけ) | できない |
| 投稿者(Author) | できる | できる |
| 編集者(Editor) | できる(ほかの人の記事も) | できる |
本文だけを下書きで入れるなら、公開の権限を持たない「寄稿者」にすると、まちがって公開される心配がありません。
画像もアップロードさせたい場合は「投稿者」が必要ですが、投稿者は公開もできるので、コードの側で 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, sys, urllib.request
from pathlib import Path
SITE = os.environ["WP_URL"].rstrip("/") # 例 https://example.com
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 urllib.request.urlopen(req, timeout=60) as r:
return json.load(r)
def upload_image(path, alt):
# ファイル名は半角の英数字にしておく(ヘッダーに日本語は入れられない)
p = Path(path)
ctype = mimetypes.guess_type(p.name)[0] or "application/octet-stream"
media = api("POST", "/media", p.read_bytes(), {
"Content-Type": ctype,
"Content-Disposition": f'attachment; filename="{p.name}"',
})
api("POST", f"/media/{media['id']}", {"alt_text": alt})
return media["id"]
def main():
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)
# 保存されたものを読み直して確かめる
back = api("GET", f"/posts/{created['id']}?context=edit")
assert back["status"] == "draft", "下書きになっていない: " + back["status"]
if back["content"]["raw"] != content:
print("注意: 保存された本文が送ったものと違う。管理画面で確かめる")
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 "画像の代替テキスト"画像が無い場合は、ファイル名と題名の2つだけを渡します。
コードがしていること
| 順番 | 送る先 | 内容 |
|---|---|---|
| 1 | /wp/v2/media | 画像のファイルを送り、メディアとして登録する |
| 2 | /wp/v2/media/(ID) | 登録した画像に代替テキストを付ける |
| 3 | /wp/v2/posts | 題名・本文・アイキャッチ画像のIDを、status を draft にして送る |
| 4 | /wp/v2/posts/(ID) | 保存された記事を読み直し、下書きになっているか、本文が同じかを確かめる |
REST APIハンドブックでは、記事の status に指定できるのは publish・future・draft・pending・private の5つで、アイキャッチ画像は featured_media に画像のIDを入れると書かれています。
人の確認待ちであることをはっきりさせたい場合は、draft の代わりに 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を接続する方法まとめをご覧ください。
参考にした資料
- WordPress REST API Handbook「Authentication」(アプリケーションパスワード)
- WordPress REST API Handbook「Posts」(status・featured_media)
- WordPress REST API Handbook「Media」(alt_text)
- WordPress.org「Roles and Capabilities」(権限グループ)
- 当サイトのWordPress 7.1.3の日本語の表示ファイル(下書き・レビュー待ち・アプリケーションパスワード・権限グループの名前)
いずれも2026年10月18日に確認しました。
