Thinking in the Grey

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]
  • このプラグインでは公開済み投稿・固定ページの公開、更新、非公開化、削除などを通知する
  1. WordPress REST API — Discovery
  2. ACF — WP REST API Integration
  3. 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/                        ビルド結果
ACFで取得したフィールドをastroで取得して反映

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 }}
  1. GitHub Docs — repository_dispatch
github actionsの様子

備考

  • 問い合わせフォームは今回の検証対象外である
    • 外部フォームサービスの利用を含め、送信先と個人情報の扱いを別途検討する

所感

  • WordPressとGithub、Githubとデプロイ先のサーバーの通信を確立するのに時間がかかった
  • WordPress側から通知するプラグインもGithub ActionsのyamlもAIなしではかなりの時間がかかっていた
    • 実装してみようという発想にならなかったはず
  • microCMSのwebhookとVercelやCloudflareの自動ビルド&デプロイがいかに楽か思い知った

WordPressのヘッドレス構成を試してみた

Latest Articles