WordPressには「REST API」という機能が標準で組み込まれています。
REST APIを使うと、管理画面を開かずに、外部のプログラムやAIツールからWordPressのデータを取得・作成・更新・削除できます。
この記事では、WordPress REST APIでできることを整理したうえで、実際に接続して使えるようにするまでの構築手順を解説します。
カスタム投稿タイプやカスタムフィールドをAPIに対応させる方法、独自エンドポイントの追加方法、つまずきやすいポイントまでまとめています。
WordPress REST APIとは
WordPress REST APIは、WordPressのデータをHTTP経由で操作するための公式インターフェースです。
WordPress 4.7以降、プラグインなしで標準搭載されています。
データのやり取りはすべてJSON形式で行われます。
まずは自分のサイトで有効になっているか確認してみます。
https://example.com/wp-json/このURLにアクセスしてJSONが表示されれば、REST APIは有効です。
投稿一覧を取得する場合は次のURLです。
https://example.com/wp-json/wp/v2/postsここまでは認証不要で、公開済みの情報であれば誰でも取得できます。
一方で、下書きの取得や記事の作成・更新には認証が必要になります。
REST APIの基本構造
エンドポイントは次のような構造になっています。
https://example.com/wp-json/{名前空間}/{バージョン}/{リソース}WordPress本体の機能は wp/v2 という名前空間にまとまっています。
プラグインが独自機能を追加する場合は、woocommerce/v3 のように別の名前空間が使われます。
操作はHTTPメソッドで指定します。
- GET:取得
- POST:作成・更新
- PUT / PATCH:更新
- DELETE:削除
WordPressの場合、更新はPUTではなくPOSTでも受け付けてくれるため、実務ではPOSTを使うことが多いです。
WordPress REST APIでできること
標準で用意されている主なエンドポイントは以下のとおりです。
/wp/v2/posts:投稿の取得・作成・更新・削除/wp/v2/pages:固定ページの操作/wp/v2/media:画像などメディアのアップロード・編集/wp/v2/categories:カテゴリーの操作/wp/v2/tags:タグの操作/wp/v2/comments:コメントの操作/wp/v2/users:ユーザー情報の取得・編集/wp/v2/taxonomies:登録済みタクソノミーの一覧/wp/v2/types:登録済み投稿タイプの一覧/wp/v2/settings:サイトタイトルなど基本設定の取得・変更/wp/v2/search:横断検索/wp/v2/block-types:ブロックタイプの一覧
このうち settings は管理者権限が必要で、認証しないと表示されません。
投稿・固定ページで編集できる項目
投稿と固定ページでは、次のような項目をAPI経由で扱えます。
- タイトル
- 本文
- 抜粋
- スラッグ
- 公開状態(publish / draft / private / pending / future)
- 公開日時
- 投稿者
- アイキャッチ画像
- カテゴリー・タグ
- 親ページ・メニュー順(固定ページのみ)
- テンプレート
- コメント許可設定
ブロックエディタで作成した記事も、本文はブロックコメント付きのHTMLとしてそのまま取得・更新できます。
メディアで編集できる項目
画像のアップロードに加えて、次の項目も編集できます。
- タイトル
- 代替テキスト(alt)
- キャプション
- 説明
altの一括修正などをスクリプトで処理したい場合に便利です。
認証方法を決める
外部から記事を編集するには認証が必要です。
WordPressで使える主な認証方法は次の4つです。
アプリケーションパスワード
WordPress 5.6以降に標準搭載されている方式です。
追加のプラグインが不要で、外部ツールから接続する場合はこれが第一候補になります。
HTTPS環境が必須である点だけ注意が必要です。
Cookie認証(nonce)
管理画面内のJavaScriptから叩く場合に使う方式です。
外部サーバーやAIツールからの接続には使えません。
JWT認証
プラグインを導入してトークンで認証する方式です。
トークンの有効期限を管理できるため、アプリケーション連携で使われることがあります。
OAuth 2.0
複数ユーザーに権限を委譲するような、本格的なサービス連携向けの方式です。
個人サイトの運用で使うことはあまりありません。
以下ではアプリケーションパスワードを前提に進めます。
構築手順1:アプリケーションパスワードを発行する
WordPressの管理画面にログインします。
次にプロフィール画面を開きます。
ユーザー > プロフィールページ下部にある「アプリケーションパスワード」の欄に、用途がわかる名前を入力します。
AI連携用「新しいアプリケーションパスワードを追加」を押すと、パスワードが発行されます。

発行されるのは次のような形式の文字列です。
abcd EFGH ijkl MNOP qrst UVWXこのパスワードは一度しか表示されないため、その場で控えておきます。
空白は含めたままでも、削除しても、どちらでも認証は通ります。
なお、この項目が表示されない場合はHTTPSになっていない可能性が高いので、まずはSSL設定を確認します。
構築手順2:接続を確認する
認証が必要なエンドポイントを叩いて、疎通を確認します。
curl -u "ユーザー名:abcd EFGH ijkl MNOP qrst UVWX" \
https://example.com/wp-json/wp/v2/users/meログイン中のユーザー情報がJSONで返ってくれば成功です。
401が返る場合は、認証情報かサーバー設定に問題があります。
403が返る場合は、認証は通っているものの権限が足りていない状態です。
構築手順3:記事を取得する
公開済みの投稿を5件取得する例です。
curl "https://example.com/wp-json/wp/v2/posts?per_page=5"下書きを含めて取得したい場合は、認証したうえでstatusを指定します。
curl -u "ユーザー名:アプリケーションパスワード" \
"https://example.com/wp-json/wp/v2/posts?status=draft"記事を編集する目的で本文を取得する場合は、context=edit を付けます。
curl -u "ユーザー名:アプリケーションパスワード" \
"https://example.com/wp-json/wp/v2/posts/123?context=edit"これを付けないと、本文はショートコードやブロックが展開された表示用HTMLで返ってきます。
context=edit を付けると content.raw にエディタ上のままのブロックHTMLが入るため、リライト用途ではこちらを使います。
レスポンスが大きすぎる場合は _fields で項目を絞れます。
curl "https://example.com/wp-json/wp/v2/posts?_fields=id,title,slug,link&per_page=100"per_page の上限は100件です。
全件を扱うときは、レスポンスヘッダーの X-WP-Total と X-WP-TotalPages を見ながら page を進めます。
構築手順4:記事を作成・更新する
下書き記事を新規作成する例です。
curl -X POST https://example.com/wp-json/wp/v2/posts \
-u "ユーザー名:アプリケーションパスワード" \
-H "Content-Type: application/json" \
-d '{
"title": "テスト記事",
"content": "<!-- wp:paragraph --><p>本文です。</p><!-- /wp:paragraph -->",
"status": "draft",
"slug": "test-post",
"categories": [3]
}'既存記事を更新する場合は、URLに投稿IDを付けてPOSTします。
curl -X POST https://example.com/wp-json/wp/v2/posts/123 \
-u "ユーザー名:アプリケーションパスワード" \
-H "Content-Type: application/json" \
-d '{"title": "更新後のタイトル"}'送信した項目だけが更新され、指定しなかった項目はそのまま残ります。
JavaScriptから扱う場合は次のようになります。
const auth = btoa(`${username}:${appPassword}`);
const res = await fetch("https://example.com/wp-json/wp/v2/posts", {
method: "POST",
headers: {
"Content-Type": "application/json",
Authorization: `Basic ${auth}`,
},
body: JSON.stringify({
title: "テスト記事",
content: "本文です。",
status: "draft",
}),
});
const data = await res.json();
console.log(data.id, data.link);
なお、この書き方はブラウザ上で実行すると認証情報が丸見えになります。
認証を伴う処理は、必ずサーバー側やローカル環境から実行します。
構築手順5:画像をアップロードする
メディアのアップロードはJSONではなくバイナリを送信します。
curl -X POST https://example.com/wp-json/wp/v2/media \
-u "ユーザー名:アプリケーションパスワード" \
-H "Content-Disposition: attachment; filename=sample.jpg" \
-H "Content-Type: image/jpeg" \
--data-binary @sample.jpg返ってきたIDを使えば、アイキャッチ画像として設定できます。
curl -X POST https://example.com/wp-json/wp/v2/posts/123 \
-u "ユーザー名:アプリケーションパスワード" \
-H "Content-Type: application/json" \
-d '{"featured_media": 456}'代替テキストを後から編集する場合はmediaエンドポイントを更新します。
curl -X POST https://example.com/wp-json/wp/v2/media/456 \
-u "ユーザー名:アプリケーションパスワード" \
-H "Content-Type: application/json" \
-d '{"alt_text": "サンプル画像の説明"}'カスタム投稿タイプをREST APIに対応させる
カスタム投稿タイプは、登録時に show_in_rest を有効にしないとAPIに現れません。
functions.php またはプラグイン側で次のように登録します。
add_action('init', function () {
register_post_type('works', [
'label' => '実績',
'public' => true,
'has_archive' => true,
'show_in_rest' => true,
'rest_base' => 'works',
'supports' => ['title', 'editor', 'excerpt', 'thumbnail', 'custom-fields'],
]);
});これで次のエンドポイントが使えるようになります。
https://example.com/wp-json/wp/v2/worksすでに動いているサイトで対応状況を確認したい場合は、typesエンドポイントを見ます。
https://example.com/wp-json/wp/v2/typesここに載っていて rest_base が設定されていれば、API経由で操作できます。
既存のカスタム投稿タイプがテーマやプラグインで登録されていて直接編集できない場合は、フィルターで後から有効化する方法もあります。
add_filter('register_post_type_args', function ($args, $post_type) {
if ($post_type === 'works') {
$args['show_in_rest'] = true;
$args['rest_base'] = 'works';
}
return $args;
}, 10, 2);カスタムタクソノミーをREST APIに対応させる
考え方は投稿タイプと同じです。
add_action('init', function () {
register_taxonomy('works_cat', ['works'], [
'label' => '実績カテゴリー',
'public' => true,
'hierarchical' => true,
'show_in_rest' => true,
'rest_base' => 'works_cat',
]);
});公開されているタクソノミーの一覧はこちらで確認できます。
https://example.com/wp-json/wp/v2/taxonomiesターム一覧の取得や、記事へのターム紐付けもAPIから行えます。
curl -X POST https://example.com/wp-json/wp/v2/works/123 \
-u "ユーザー名:アプリケーションパスワード" \
-H "Content-Type: application/json" \
-d '{"works_cat": [5, 8]}'カスタムフィールド・メタディスクリプションを扱う
カスタムフィールドは、標準ではREST APIに公開されていません。
register_post_meta で明示的に登録する必要があります。
add_action('init', function () {
register_post_meta('post', 'my_custom_field', [
'show_in_rest' => true,
'single' => true,
'type' => 'string',
'auth_callback' => function () {
return current_user_can('edit_posts');
},
]);
});
登録すると、レスポンスの meta 内に含まれるようになります。
curl -X POST https://example.com/wp-json/wp/v2/posts/123 \
-u "ユーザー名:アプリケーションパスワード" \
-H "Content-Type: application/json" \
-d '{"meta": {"my_custom_field": "任意の値"}}'
SEOプラグインのメタディスクリプションも、実体はカスタムフィールドです。
プラグインによってキー名が異なり、REST API対応の有無も変わります。
- SEO SIMPLE PACK:
ssp_meta_descriptionなどのメタキー - Rank Math:
rank_math_description - Yoast SEO:
_yoast_wpseo_metadesc - All in One SEO:独自テーブルに保存されるため通常のメタでは扱えない
プラグイン側でREST公開されていない場合は、自分で register_post_meta を追加して公開する形になります。
add_action('init', function () {
register_post_meta('post', 'rank_math_description', [
'show_in_rest' => true,
'single' => true,
'type' => 'string',
'auth_callback' => function () {
return current_user_can('edit_posts');
},
]);
});
アンダースコアで始まるメタキーは保護されたメタとして扱われるため、auth_callback の指定が必須になります。
プラグインのアップデートで保存先の仕様が変わることもあるため、更新前に必ずバックアップを取ります。
独自エンドポイントを追加する
標準のエンドポイントで足りない場合は、自分でルートを追加できます。
add_action('rest_api_init', function () {
register_rest_route('motoki/v1', '/summary', [
'methods' => 'GET',
'callback' => function (WP_REST_Request $request) {
$count = wp_count_posts('post');
return new WP_REST_Response([
'publish' => (int) $count->publish,
'draft' => (int) $count->draft,
], 200);
},
'permission_callback' => function () {
return current_user_can('edit_posts');
},
]);
});
呼び出しはこうなります。
https://example.com/wp-json/motoki/v1/summary
permission_callback は省略できません。
省略すると警告が出るうえ、誰でもアクセスできる状態になってしまいます。
読み取り専用で公開したい場合でも、明示的に __return_true を書きます。
ChatGPTなどのAIツールと接続する
接続に必要な情報は次の3つだけです。
WORDPRESS_URL=https://example.com
WORDPRESS_USERNAME=
WORDPRESS_APP_PASSWORD=
これを .env に保存し、.gitignore に .env を追加して公開されないようにします。
AIツール側との接続方法は、大きく3パターンあります。
MCPサーバー経由で接続する
Claude DesktopやAI開発ツールから使う場合は、MCPサーバーを立てる方法が主流です。
WordPress REST APIをラップしたMCPサーバーを用意し、環境変数に上記3つを渡します。
ツール単位で権限を絞れるため、削除系の操作を最初から外しておけるのが利点です。
GPTsのActionsとして登録する
ChatGPTのGPTsから使う場合は、OpenAPIスキーマを定義してActionsに登録します。
認証方式にBasic認証を指定し、ユーザー名とアプリケーションパスワードを設定します。
必要なエンドポイントだけをスキーマに書くことで、実質的な権限制御になります。
スクリプト経由で処理する
まとまった件数を機械的に処理するなら、Node.jsやPythonのスクリプトが確実です。
AIには文章生成だけを任せ、WordPressへの反映は自分のスクリプトから行う形が一番安全です。
つまずきやすいポイント
Authorizationヘッダーが届かない
サーバー設定によっては、Authorizationヘッダーが削除されて401になることがあります。
Apacheの場合は .htaccess に次を追記します。
SetEnvIf Authorization "(.*)" HTTP_AUTHORIZATION=$1
エックスサーバーなど一部のレンタルサーバーでは、この対応が必要になるケースがあります。
セキュリティプラグインにブロックされる
SiteGuard WP PluginやWordfenceなどが、REST APIやXML-RPCへのアクセスを制限していることがあります。
401や403が解消しない場合は、プラグインの設定も確認します。
権限が足りない
投稿の作成には edit_posts、公開には publish_posts の権限が必要です。
寄稿者権限のユーザーでは公開まで到達できません。
APIの接続元ごとに専用ユーザーを作り、必要最小限の権限を割り当てるのがおすすめです。
本文が意図した形で保存されない
content に生のHTMLを渡すと、ブロックエディタ側では「クラシックブロック」として扱われます。
ブロックとして正しく認識させたい場合は、<!-- wp:paragraph --> などのブロックコメントを含めた形式で送信します。
日時の扱い
date はサイトのタイムゾーン基準、date_gmt はUTC基準です。
予約投稿を作る場合は、status を future にしたうえで date を指定します。
安全に運用するためのルール
編集権限を持つ認証情報を外部ツールに渡すことになるため、運用ルールを決めておきます。
- 接続用のユーザーは専用に作り、管理者権限は避ける
- アプリケーションパスワードは用途ごとに分けて発行する
- 使わなくなったパスワードはすぐに失効させる
- 新規記事は必ず下書きとして作成する
- 公開済み記事の上書きは人の確認を挟む
- 削除系の操作はAIに任せない
.envは絶対にリポジトリに含めない- 一括更新の前にデータベースをバックアップする
まずは読み取りと下書き作成から始めて、問題がないことを確認してから範囲を広げるのが安全です。
まとめ
WordPress REST APIを使えば、投稿・固定ページ・メディア・カテゴリー・タグを外部から自由に操作できます。
カスタム投稿タイプやカスタムタクソノミーも、show_in_rest を有効にすれば同じように扱えます。
カスタムフィールドやSEOのメタディスクリプションは、register_post_meta でAPIに公開することで編集可能になります。
さらに register_rest_route を使えば、自分のサイト専用のエンドポイントも追加できます。
接続に必要なのは、サイトURL・ユーザー名・アプリケーションパスワードの3つだけです。
まずは wp-json/wp/v2/users/me で疎通を確認し、下書き作成から試してみるとイメージがつかみやすいはずです。
権限とバックアップの管理さえ押さえておけば、記事のリライトや情報整理を大幅に効率化できます。



