WordPressのヘッドレス構成を試してみた
要約
- WordPressを編集画面として使い、Astroで公開用の静的サイトを生成した
- Basic認証で保護したWordPressから、ビルド時にREST APIでデータを取得する
- ACFの繰り返しフィールドを取得し、本文やアイキャッチなどの画像もビルドに含めた
- 投稿や固定ページの更新通知を受け、GitHub ActionsでビルドとFTPS転送を行う
きっかけ
- PHP2shellへの対応をきっかけにCMSの構成を見直す動きが勤務先で発生
- ヘッドレスCMSとしてはmicroCMSが第一選択だが、勤務先はレンタルサーバーにWordPressを設置する構成しか運用していない
- そこで、既存のWordPressの運用を活かしつつ、公開側を静的化する方法として今回の構成を試した
構成
- コアサーバーV1プランにWordPressを設置し、管理画面とREST APIを含むサイト全体をBasic認証で保護する
- 非公開のGitHubリポジトリにAstroのソースとGitHub Actionsの設定を置く
- WordPressの公開済み投稿や固定ページが更新されると、自作プラグインがGitHubに通知する
- GitHub Actionsがデータを取得してAstroをビルドし、生成したファイルをFTPSで公開先へ転送する
WordPressの設定
- WordPress 4.7以降は投稿や固定ページを取得する標準のREST APIエンドポイントを利用できる[1]
- パーマリンク設定を保存し、Basic認証後に
/wp-json/wp/v2/postsから公開済み投稿のJSONを取得できることを確認する - Advanced Custom Fields(ACF)のフィールドグループは「Show in REST API」を有効にする。[2]
- 更新通知には自作プラグインを使用し、リポジトリ名とGitHubトークンをサーバーの
wp-config.phpに設定する - トークンは対象リポジトリに必要な権限を絞り、有効期限と更新方法を決める。
repository_dispatchにはContentsの書き込み権限が必要である[3] - このプラグインでは公開済み投稿・固定ページの公開、更新、非公開化、削除などを通知する
- WordPress REST API — Discovery
- ACF — WP REST API Integration
- GitHub Docs — Create a repository dispatch event
Astroで開発
.envに、WordPressのHTTPS URL、Basic認証情報、公開先のベースパスを環境変数に設定するnpm run devとnpm run buildはAstroの起動前に取得スクリプトを実行するscripts/fetch-wordpress.mjsが公開済みの投稿と固定ページをREST APIから取得し、src/data/のJSONに保存する- 同一オリジンの画像を
public/wp-media/にコピーし、生成ページから参照する
scripts/fetch-wordpress.mjs WordPress のデータと画像を取得
src/data/ 取得した投稿・固定ページの JSON
src/pages/ Astro のページ
public/wp-media/ 取得した画像
dist/ ビルド結果

GitHub Actionsの設定
.github/workflows/wordpress-build.ymlはWordPressからのrepository_dispatchと手動実行を受け付ける[4]npm run buildの成果物dist/を保存後、scripts/deploy-ftps.pyで転送する
- Actions Variablesに
WP_URL、SITE_BASE、FTPS_HOST、SecretsにWP_BASIC_USER、WP_BASIC_PASSWORD、FTPS_USER、FTPS_PASSWORDを登録する - 今回はFTPSでデプロイする
- 利用可能な接続方式や証明書を確認し、環境に合った安全な転送方法を選ぶ
wordpress-build.yml
name: Build Astro from WordPress
on:
repository_dispatch:
types: [wordpress_updated]
workflow_dispatch:
permissions:
contents: read
concurrency:
group: wordpress-build
cancel-in-progress: false
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Check out repository
uses: actions/checkout@v4
- name: Set up Node.js
uses: actions/setup-node@v4
with:
node-version: '24'
cache: npm
- name: Install dependencies
run: npm ci
- name: Build site
run: npm run build
env:
WP_URL: ${{ vars.WP_URL }}
SITE_BASE: ${{ vars.SITE_BASE }}
WP_BASIC_USER: ${{ secrets.WP_BASIC_USER }}
WP_BASIC_PASSWORD: ${{ secrets.WP_BASIC_PASSWORD }}
- name: Save build artifact
uses: actions/upload-artifact@v4
with:
name: astro-dist
path: dist/
if-no-files-found: error
- name: Deploy to CoreServer over FTPS
run: python3 scripts/deploy-ftps.py
env:
FTPS_HOST: ${{ vars.FTPS_HOST }}
FTPS_USER: ${{ secrets.FTPS_USER }}
FTPS_PASSWORD: ${{ secrets.FTPS_PASSWORD }}

備考
- 問い合わせフォームは今回の検証対象外である
- 外部フォームサービスの利用を含め、送信先と個人情報の扱いを別途検討する
所感
- WordPressとGithub、Githubとデプロイ先のサーバーの通信を確立するのに時間がかかった
- WordPress側から通知するプラグインもGithub ActionsのyamlもAIなしではかなりの時間がかかっていた
- 実装してみようという発想にならなかったはず
- microCMSのwebhookとVercelやCloudflareの自動ビルド&デプロイがいかに楽か思い知った