VercelにWordPress本体をそのまま載せることはできません。Vercelの公式ランタイムにPHPが無く、関数のファイルシステムも読み取り専用だからです。VercelとWordPressを組み合わせる現実的な形は、WordPressを別のサーバーに置いて管理画面とAPIだけを担わせ、表示側のNext.jsをVercelにデプロイするヘッドレス構成になります。この記事では、PHPを置けない根拠、WordPress本体の置き場所と関数リージョン、Vercel側の環境変数と画像の設定、WordPressで記事を公開した瞬間に表示を更新する再検証の実装までを、コード付きで順に説明します。版番号と仕様は2026年10月19日時点の公式ドキュメントで確かめた値です。
まとめ:VercelとWordPressを組み合わせる構成と採用判断の結論
WordPress本体はPHPが動く別のサーバーに置き、VercelにはNext.jsの表示側だけを置く構成です。
更新の反映は、時間ベースの再生成だけに頼りません。WordPressの公開時にVercel側の再検証用エンドポイントへ通知を送り、該当記事のキャッシュタグを失効させます。サイト全体を作り直すDeploy Hooksは、テンプレートを変えたときの再ビルド用に分けて使います。
採用するのは、記事の更新が日に数回程度で、表示速度とフロントの作り替えやすさに価値がある企業サイトです。フォーム・会員機能・ECなど、プラグインに頼る機能が多いサイトでは、表示側で作り直す工数が増えるので見送ります。HobbyプランはVercelの規約で非商用に限られるため、企業サイトならPro以上が前提です。
VercelにWordPress本体を置けない理由:公式ランタイムとPHPの扱い
Vercelは静的ファイルをCDNから配り、動的な処理を関数として実行するサービスです。仕組みの全体はVercel(ヴァーセル)とは?サーバー不要の仕組みとできること・料金で扱っています。ここではWordPressを載せようとしたときに当たる制約に絞ります。
公式ランタイムにPHPが無く、vercel-phpはコミュニティ製という位置づけ
Vercelのランタイム一覧に載る公式ランタイムは、Node.js・Bun・Python・Rust・Go・Ruby・Wasm・Edge・Containerです。PHPは公式に含まれていません。PHPは「Vercelが推奨するコミュニティランタイム」の表に、Bash・Denoと並んでvercel-phpとして載っています。
vercel-communityのPHPランタイムのREADMEによると、[email protected]がPHP 8.5系に対応します。対応フレームワークの例はSlimやSymfonyなどで、WordPressへの言及はありません。APIを数本PHPで書く用途向けで、ファイルを書き換えながら動くWordPressの置き場所にはなりません。
読み取り専用ファイルシステムとwp-content/uploadsの衝突
Vercelの関数は、ファイルシステムが読み取り専用です。書き込めるのは容量500MBまでの/tmpだけで、インスタンスが入れ替われば中身は消えます。
WordPressは、メディアのアップロードでwp-content/uploadsに、プラグインの更新でwp-content/pluginsに書き込みます。読み取り専用の環境では管理画面の基本操作が成立せず、MySQLも関数の中には置けません。
Container Runtime(ベータ)でWordPressコンテナを動かす案の限界
2026年10月時点では、Container Runtimeがベータとして全プランに提供されています。Dockerfile.vercelを置けば任意のOCIイメージを関数として動かせるので、WordPressの公式イメージを載せる案は技術的には試せます。
ただし、関数と同じ制限と課金がそのまま適用されます。本番環境では5分間アクセスが無いとインスタンスが縮退し、終了時には30秒の猶予で止められます。アップロード画像の保存先とMySQLは、結局どちらも外部に用意する必要がある構成です。普通のサーバーより手間が増えるだけなので、WordPress本体の置き場所には選びません。
ヘッドレス構成の全体像:WordPress本体の置き場所とドメインの分け方
ヘッドレス構成では、WordPressは記事の編集とAPIの提供だけを担います。訪問者が見るHTMLを作るのは、Vercel上で動くNext.jsの役割です。ヘッドレスCMS全般の仕組みと製品比較はヘッドレスCMSとは?従来型との違い・料金比較とプレビュー実装にまとめています。
WordPress本体の置き場所と関数リージョンを近づける判断基準
WordPress本体は、PHPとMySQLが動くマネージドWordPressホスティングか、VPS・クラウドの仮想サーバーに置きます。表示側のアクセスはVercelが受けるので、WordPress側のサーバーは編集者とVercelの関数からのリクエストをさばければ足ります。
見落としやすいのが関数リージョンです。Vercelの関数は新規プロジェクトで既定がワシントンD.C.(iad1)になっています。WordPressを国内のサーバーに置いたまま既定のままにすると、ページを再生成するたびに太平洋を往復して記事を取りに行きます。プロジェクトの設定かvercel.jsonのregionsで、東京(hnd1)に変えてください。Hobbyプランで選べる関数リージョンは1つです。
cms.サブドメインに管理画面を寄せ、公開URLをVercelに一本化する設計
ドメインは、公開URL(例:www.example.com)をVercelに向け、WordPressはcms.example.comのようなサブドメインに分けるのが扱いやすい形です。WordPressの「サイトアドレス」が公開URLのままだと、プレビューやリンク生成がWordPress側の表示に向いてしまうので、管理画面の設定と表示側のURLを最初に決めておきます。
Vercel側のドメイン設定はVercelの独自ドメイン設定手順:Aレコード・CNAME・ネームサーバーの選び方とSSL発行待ちの対処で手順を追えます。
Next.jsをVercelへデプロイする手順:テンプレートと環境変数の登録
表示側のNext.jsで記事を取得する処理の基本(REST APIでの一覧・記事の取得、CORSの切り分け、Draft Modeによるプレビュー)は、WordPressとReactの連携方法:ヘッドレス化とテーマ組み込みの手順で詳しく書いています。ここではVercelに載せるときに追加で要る設定を扱います。
公式KBとcms-wordpressテンプレートの違いと必要なプラグイン
Vercelの公式KB「Using Headless WordPress with Next.js and Vercel」は2026年10月2日に更新されています。WPGraphQLで記事を取得し、環境変数WORDPRESS_API_URLにGraphQLのエンドポイントを入れる構成です。ただし例のコードはPages RouterのgetStaticPropsで、10秒ごとの時間ベースの再生成だけを扱っています。
一方、Next.jsリポジトリのexamples/cms-wordpressはApp Router版です。READMEが求めるWordPressのプラグインは、WPGraphQL・WPGraphQL JWT Authentication・Yoast SEO・Add WPGraphQL SEO・Redirection・Classic Editorで、WordPressのfunctions.phpから/api/revalidateへ通知を送る仕組みも含みます。READMEはNext.js 14を前提と書いているので、2026年10月時点の最新である16.4.2で使う場合は、後述するrevalidateTagの引数の変更を反映させてください。
WPGraphQLは2.24.2(2026年10月16日更新)が最新で、WordPress 6.0以上・PHP 7.4以上が動作条件です。記事と一覧の取得だけならREST APIで足ります。選び方はREST APIとGraphQLの違いと使い分けを参照してください。
vercel env addでWordPressのAPIのURLと再検証の秘密鍵を登録
Vercelに登録する値は2つです。WordPressのAPIのURLと、WordPressからの再検証の通知を本物と見分けるための秘密鍵です。秘密鍵はProductionとPreviewで別の値にし、プレビュー環境の鍵で本番のキャッシュを消せないようにします。
# WordPressのREST APIのURL(例: https://cms.example.com/wp-json/wp/v2)
vercel env add WORDPRESS_API_URL production
vercel env add WORDPRESS_API_URL preview
# 再検証の通知を照合する秘密鍵を作り、環境ごとに別の値で登録する
openssl rand -hex 32
vercel env add REVALIDATE_SECRET production
vercel env add REVALIDATE_SECRET preview
# ローカル開発用に.env.localへ取り込む
vercel env pull .env.local
NEXT_PUBLIC_で始まる名前にすると、値がブラウザ向けのJavaScriptに埋め込まれます。秘密鍵には付けないでください。環境の分け方やSecret型の扱いはVercelの環境変数の設定手順:Production・Previewの分け方とvercel env pull・Secret型で説明しています。
remotePatternsでWordPressの画像の配信元とパスを許可
WordPressのメディアライブラリの画像をnext/imageで表示するには、配信元を許可する設定が要ります。Next.jsのImageコンポーネントの仕様では、remotePatternsに一致しないホストやパスの画像は400 Bad Requestになります。
// next.config.ts
import type { NextConfig } from 'next'
const nextConfig: NextConfig = {
images: {
// WordPressのアップロード領域だけを許可する
remotePatterns: [new URL('https://cms.example.com/wp-content/uploads/**')],
},
}
export default nextConfig
ホスト名だけを許可すると、WordPressのサーバー上の任意の画像が変換の対象になります。パスまで絞れば、意図しない画像の変換でHobbyで月5,000回までのImage Transformationsを使い切る事態を防げます。古いdomains設定はNext.js 14から非推奨です。
記事の更新を即時に反映させる:WordPressの通知とrevalidateTag
時間ベースの再生成だけでは、記事の修正が表示に出るまで設定した秒数を待つことになります。誤字や価格の訂正をすぐに出したい場合は、WordPressの公開をきっかけに再検証を呼ぶ仕組みの追加が必要です。SSG・ISR・SSRの違いそのものはNext.jsのレンダリング方式|SSG・ISR・SSR・CSRの違いとApp Routerでの選び方で比べています。
fetchにキャッシュタグを付け、再検証の単位を記事ごとに分ける
WordPressから取得するfetchに、一覧用のpostsと記事ごとのpost-スラッグの2種類のタグを付けます。この2種類のタグが、記事を1本直したときに、その記事と一覧だけを失効させるための指定です。revalidateTagの仕様では、タグは大文字と小文字を区別し、256文字を超えるタグは無視されます。
// lib/wp.ts
const WP = process.env.WORDPRESS_API_URL
export async function getPost(slug: string) {
const res = await fetch(
`${WP}/posts?slug=${encodeURIComponent(slug)}&_fields=id,slug,title,content,modified`,
// 通知が届かなかった場合の保険として1時間で再生成する
{ next: { revalidate: 3600, tags: ['posts', `post-${slug}`] } },
)
// WordPressが落ちているときは例外にして、古いキャッシュの配信を続けさせる
if (!res.ok) throw new Error(`WordPress API: ${res.status}`)
const [post] = await res.json()
return post ?? null
}
取得に失敗したら例外を投げているのは、後述するVercelの再生成の失敗時の挙動を使うためです。空のデータを返すと、空の記事ページがキャッシュに保存されてしまいます。
Route Handlerで秘密鍵を照合してrevalidateTagを呼ぶ実装
Vercel側には、WordPressからの通知を受けるapp/api/revalidate/route.tsを置きます。Next.js 16ではrevalidateTagの第2引数が必須になり、引数1つの呼び方は非推奨です。公式ドキュメントは、Server Action以外(Webhookなど)からすぐに失効させる場合に{ expire: 0 }を渡すよう案内しています。
// app/api/revalidate/route.ts
import { revalidateTag } from 'next/cache'
import type { NextRequest } from 'next/server'
export async function POST(request: NextRequest) {
// 秘密鍵が一致しない通知は受け付けない
if (request.headers.get('x-revalidate-secret') !== process.env.REVALIDATE_SECRET) {
return Response.json({ revalidated: false }, { status: 401 })
}
const { slug } = await request.json()
if (typeof slug !== 'string' || slug.length === 0 || slug.length > 200) {
return Response.json({ revalidated: false, message: 'invalid slug' }, { status: 400 })
}
// 一覧と該当記事のキャッシュをすぐに失効させる
revalidateTag('posts', { expire: 0 })
revalidateTag(`post-${slug}`, { expire: 0 })
return Response.json({ revalidated: true, now: Date.now() })
}
アクセスの多いサイトでは、{ expire: 0 }の代わりに推奨値の'max'を渡す選択もあります。失効直後の1人目にも古いページを返しつつ裏で作り直すので、WordPressへのリクエストが集中しません。訂正をすぐに見せたいか、WordPressの負荷を抑えたいかで決めます。
デプロイしたら、curlで通知を再現して動作を確かめます。
curl -X POST https://www.example.com/api/revalidate \
-H "Content-Type: application/json" \
-H "x-revalidate-secret: $REVALIDATE_SECRET" \
-d '{"slug":"hello-world"}'
# 成功すると {"revalidated":true,"now":...} が返る
WordPressのtransition_post_statusで公開時に通知を送る
WordPress側では、投稿の状態が変わるたびに呼ばれるtransition_post_statusフックからwp_remote_postで通知を送ります。テーマを差し替えても止まらないよう、wp-content/mu-pluginsに置きます。
<?php
// wp-content/mu-plugins/vercel-revalidate.php
// 秘密鍵はwp-config.phpで define('VERCEL_REVALIDATE_SECRET', '...'); として定義しておく
add_action('transition_post_status', function ($new_status, $old_status, $post) {
if ($post->post_type !== 'post') {
return;
}
// 公開、公開済み記事の更新、非公開への変更のときだけ通知する
if ($new_status !== 'publish' && $old_status !== 'publish') {
return;
}
wp_remote_post('https://www.example.com/api/revalidate', [
'headers' => [
'Content-Type' => 'application/json',
'x-revalidate-secret' => VERCEL_REVALIDATE_SECRET,
],
'body' => wp_json_encode(['slug' => $post->post_name]),
'timeout' => 5,
// 応答を待たないので、Vercel側が遅くても保存操作は止まらない
'blocking' => false,
]);
}, 10, 3);
公開済みの記事のスラッグを変えると、旧スラッグのページはキャッシュに残ります。スラッグ変更を運用で許すなら、通知の本文に旧スラッグも入れて両方を失効させるか、旧URLからのリダイレクトを登録してください。
Deploy Hooksとの使い分け:1時間60回の上限と再ビルド時間
WordPressの更新でVercelを再デプロイする方法として、Deploy Hooksもあります。URLにPOSTするだけでビルドが走るので設定は簡単です。ただし、プロジェクト全体で1時間に60回までという上限があり、毎回ビルドの時間がかかります。URL自体が認証情報なので、漏れると誰でもデプロイを起こせます。
記事の追加・修正は前の節の再検証で反映し、Deploy Hooksは使いません。メニューなど全ページに出る要素を変えたときだけ、手動でデプロイするかrevalidatePath('/', 'layout')を呼びます。
運用で詰まる箇所:WordPress停止時のISRキャッシュと管理画面の守り方
稼働後に問い合わせが来やすいのは、WordPressの停止時の表示、デプロイ直後の遅さ、管理画面の公開範囲です。
WordPressが停止しても配信が続く条件と31日で消えるキャッシュ
VercelのISRの仕様では、再生成が失敗すると既存のキャッシュを配信し続け、30秒後に再試行します。失敗と見なされるのは、通信エラー、200・301・302・307・308・404・410以外のステータス、関数の実行エラーです。
ただし、ISRキャッシュは31日間アクセスが無いと消えます。アクセスの少ない古い記事は、WordPressが止まっている間に初めて開かれると表示できません。WordPress側の停止を許容する設計にするなら、監視で停止に気づける状態にしておきます。
デプロイごとにISRキャッシュが分かれ、初回アクセスで再生成される
ISRキャッシュはデプロイ単位で分かれていて、新しいデプロイは前のデプロイのキャッシュを引き継ぎません。表示側のコードを更新するたびに、各ページの初回アクセスでWordPressへ記事を取りに行きます。
記事が数千本あるサイトでデプロイ直後にクローラーが巡回すると、WordPress側に負荷が集中します。WordPressのサーバーの性能は、このデプロイ直後の再生成の山を基準に見積もってください。
wp-adminの接続元制限とApplication Passwordsの権限の分け方
ヘッドレス構成でも、WordPress本体はインターネット上で動いています。管理画面を社内のIPアドレスに限定し、REST APIのユーザー一覧など表示側が使わないエンドポイントを閉じる対策は、通常どおり必要です。本体やプラグインの脆弱性の影響もそのまま受けます。直近の事例はwp2shellとは?WordPress未認証RCEの仕組みと影響バージョン・確認手順で確認できます。
下書きのプレビューなどで表示側から認証付きでAPIを呼ぶ場合は、WordPress 5.6から標準のApplication Passwordsを使います。認証情報はHTTPSでのみ送り、プレビュー専用の権限の低いユーザーで発行してください。管理者のApplication PasswordsをVercelの環境変数に置くと、漏れた時の被害が投稿の改ざんまで広がります。Next.js側のプレビュー実装はDraft Modeの公式ガイドに沿って組みます。
VercelとWordPressの構成を採用する条件と見送る場面の判断
最後に、この構成を選ぶかどうかを費用と機能の両面から判断します。結論から言うと、表示速度とフロントの自由度が売上や採用に効くサイトなら採用し、プラグインで機能を足してきたサイトなら見送ります。
Hobbyは非商用限定のため、企業サイトはProの1席月20ドルから
VercelのHobbyプランは無料ですが、利用規約で非商用の個人利用に限られます。企業のコーポレートサイトやオウンドメディアはProが前提で、開発者の席は1人あたり月20ドルです。これにWordPress本体のサーバー代が加わるので、WordPressだけを動かす場合より月額の固定費は必ず増えます。
月数万PV程度で、WordPressのキャッシュ系プラグインで十分に速いサイトなら、構成を分ける費用に見合いません。
採用と見送りの判断基準:既存サイトでプラグインに頼る機能の数
採用するのは、記事・お知らせ・事例が中心で更新は日に数回まで、デザインの作り替えを社内か外部のフロントエンド開発者が担える体制のサイトです。表示側をReactで作れるので、WordPressのテーマの制約を受けずに画面を作れます。
見送るのは、問い合わせフォーム・会員ログイン・EC・予約などをWordPressのプラグインで実現しているサイトです。ヘッドレス化するとプラグインの画面は表示側に出ないため、機能ごとに作り直しが要ります。見送る場合でも、WordPressのまま速度と保守を改善する方法は選択肢に残るため、改善の検討は可能です。運用体制の見直しはWordPress保守運用とは:作業範囲・費用相場と内製か外注かの判断基準で整理しています。
既存サイトをヘッドレス構成に移すか、WordPressのまま作り直すかの判断から相談したい場合は、一創のWordPressサイト制作・CMS構築で構成の比較と移行の見積もりを承っています。
よくある質問
VercelとWordPressの組み合わせについて、検索で多い質問に答えます。
VercelにWordPressをそのままデプロイできますか?
できません。Vercelの公式ランタイムにPHPは無く、関数のファイルシステムも/tmp以外は読み取り専用です。コミュニティ製のvercel-phpやベータのContainer Runtimeを使っても、画像のアップロード先とMySQLは外部に要ります。WordPressは別のサーバーに置き、表示側のNext.jsだけをVercelに載せるヘッドレス構成が現実的です。
WordPressのテーマはヘッドレス構成でも使えますか?
使えません。訪問者が見る画面はNext.jsが作るので、テーマのテンプレートは表示に使われません。ブロックエディタで作った本文のHTMLはAPIで取得できますが、ブロックの見た目を再現するCSSは表示側で用意します。
WordPressのプレビューボタンはそのまま動きますか?
そのままでは動きません。プレビューボタンはWordPress側の表示を開くため、Vercel上の表示側には届きません。Next.jsのDraft Modeで、トークンを確かめてから下書きを認証付きで取得するルートを作ります。認証にはWordPress 5.6以降に標準で入っているApplication Passwordsを、権限の低いプレビュー専用ユーザーで発行して使います。
Vercelの無料プランで企業のブログを運用できますか?
できません。Hobbyプランは利用規約で非商用の個人利用に限られています。企業のブログやオウンドメディアはProプランが前提で、開発者の席は1人あたり月20ドルです。
WordPressで記事を更新したのにVercelの表示が変わりません。原因は何ですか?
多いのは3つです。WordPressからの通知が届いていない(秘密鍵の不一致で401が返っている)、fetchに付けたタグと失効させたタグの文字列が違う、スラッグを変えたため旧スラッグのページが残っている、のいずれかです。curlで再検証のエンドポイントを直接呼んでrevalidated: trueが返るかを確かめ、返るならWordPress側の送信を、返らないなら秘密鍵の値を疑ってください。
関連記事
- Vercel(ヴァーセル)とは?サーバー不要の仕組みとできること・料金【2026年】:Vercelの仕組みと料金の全体像
- WordPressとReactの連携方法:ヘッドレス化とテーマ組み込みの手順【WordPress 7.1・Next.js 16】:REST APIでの取得とDraft Modeの実装
- ヘッドレスCMSとは?従来型との違い・料金比較とプレビュー実装【2026年10月】:WordPress以外のヘッドレスCMSとの比較
- Vercelの環境変数の設定手順:Production・Previewの分け方とvercel env pull・Secret型【2026年10月】:WordPressのURLと秘密鍵の登録の詳細
- Vercelの独自ドメイン設定手順:Aレコード・CNAME・ネームサーバーの選び方とSSL発行待ちの対処【2026年10月】:公開URLをVercelに向ける手順