コーポレートサイトのリニューアルにあたり、「ヘッドレスWordPress」構成を検討することになりました。WordPressをCMS/APIとして使い、フロントエンドはReactとします。検討のために開発環境を構築してみたので、備忘録を兼ねてその手順をまとめました。
サムネイル画像作成の時間短縮のためにAI生成してみましたが、今までとは全く違うテイスト画像になり、いかにもAIでつくったなっていう感じ(汗
まあ、技術ブログなのでご愛嬌ということで…
プロジェクト構成
採用した構成は以下のとおり
- バックエンド:WordPress(投稿管理、カスタム投稿、ACF Pro、REST API、WPGraphQL)
- フロントエンド:Vite + React + TypeScript + TailwindCSS v4
- データ取得:SWR
- 本番サーバー:レンタルサーバー(エックスサーバー)
- ローカル開発:WordPress側はwp-env、React側はVite
ディレクトリ構成
corporate-site/
├── cms/ # WordPress (wp-env)
│ ├── .wp-env.json
│ ├── package.json
│ └── wp-content/
│ ├── themes/
│ │ └── headless-api/ # API専用テーマ
│ ├── plugins/
│ │ └── cors-config/ # CORS設定プラグイン
│ └── uploads/
└── web/ # React
├── .env.local # 開発用
├── .env.production # 本番用
├── package.json
├── vite.config.ts
├── dist/ # ビルドされたファイル群を格納
└── src/ # ソースコードを格納デプロイ構成:完全分離パターン
サブディレクトリ配置やサブドメイン共存も検討しましたが、最終的にはWordPressとReactを完全に別ドメインで分離する構成にしました。
cms.example.com → WordPress(管理画面・API専用、フロント表示は無効化)
example.com → React(公開サイト、www付きはリダイレクト)WordPressのテーマ側で、管理画面とAPIリクエスト以外へのアクセスを template_redirect フックでブロックし、意図的に「フロントエンドを持たないCMS」として運用する形にしています。URLの重複や構造の混乱を避けられるのがメリットです。
WordPress開発環境(wp-env)
ディレクトリ構成の cms/ 側から構築していきます。要するにバックエンドです。
WordPressをインストール
package.jsonと.wp-env.jsonファイルを準備してWordpressをインストールします。
{
"name": "corporate-cms",
"scripts": {
"start": "wp-env start",
"stop": "wp-env stop",
"clean": "wp-env clean all"
},
"devDependencies": {
"@wordpress/env": "^10.0.0"
}
}{
"core": "https://ja.wordpress.org/latest-ja.zip",
"plugins": [
"./wordpress/plugins/advanced-custom-fields-pro",
"https://downloads.wordpress.org/plugin/taxonomy-terms-order.zip",
"https://downloads.wordpress.org/plugin/contact-form-7.zip",
"https://downloads.wordpress.org/plugin/duplicate-page.zip",
"https://downloads.wordpress.org/plugin/ewww-image-optimizer.zip",
"https://downloads.wordpress.org/plugin/flamingo.zip",
"https://downloads.wordpress.org/plugin/wp-multibyte-patch.zip",
"https://downloads.wordpress.org/plugin/wp-pagenavi.zip",
"https://downloads.wordpress.org/plugin/wp-graphql.latest-stable.zip",
"https://downloads.wordpress.org/plugin/all-in-one-seo-pack.zip",
"https://downloads.wordpress.org/plugin/siteguard.zip",
"https://downloads.wordpress.org/plugin/wp-mail-smtp.zip"
],
"config": {
"WP_DEBUG": true,
"WP_DEBUG_LOG": true,
"WP_ENVIRONMENT_TYPE": "local"
},
"mappings": {
"wp-content/uploads": "./wordpress/uploads",
"wp-content/themes": "./wordpress/themes",
"wp-content/plugins": "./wordpress/plugins"
}
}
プラグインは私がよく使用しているものです。
WordPressコア、プラグインは最新を取得できる記述にしています。ADF PROは自動取得できないので事前にファイルを取得しておき、./wordpress/plugins に配置しておきます。
以下をマッピングしています。
| マッピング先 | |
| wp-content/themes | ./wordpress/themes |
| wp-content/plugins | ./wordpress/plugins |
| wp-content/uploads | ./wordpress/uploads |
ここまで準備できたら、以下を実行して、いざ!インストール
npm install
npm startwp-envはデフォルトでadmin / password で管理者を作成します。本番環境へのDB以降を見据えて、初回セットアップ完了後すぐにデフォルトユーザーを変更しておきます。
一度だけ実行すればOK。DBはDockerボリュームに永続化されるので、wp-env destroy しない限り再実行不要です。
npx wp-env run cli wp db query "UPDATE wp_users SET user_login='新ユーザー名' WHERE ID=1"
npx wp-env run cli wp user update 1 --user_email='新ユーザーメールアドレス'
npx wp-env run cli wp user update 1 --user_pass='新ユーザーパスワード'シェルコマンドでパスワードを扱う場合は、必ずシングルクォートで囲む!(囲み忘れると $ } { ! などシェルにとって意味ある記号が展開されてしまいます)
React開発環境(Vite + TyepScript + Tailwind v4)
次はフロントエンドの開発環境を準備します。ディレクトリ構成の web/ 側 です。
npm create vite@latest web -- --template react-ts
# Which linter to use?
# ESLint
# Install with npm and start now?
# Nocd web
npm install
npm install react-router-dom swr
npm install tailwindcss @tailwindcss/vite
npm install -D @types/nodeTailwind CSS v4 では、これまでとセットアップ方法が変わっているので注意が必要です。
- @tailwindcss/vite をViteプラグインとして直接組み込む
- tailwind.config.ts 不要
- CSSでインポート
import { defineConfig } from "vite";
import react from "@vitejs/plugin-react";
import tailwindcss from "@tailwindcss/vite";
import path from "path";
export default defineConfig({
plugins: [react(), tailwindcss()],
resolve: {
alias: {
"@": path.resolve(__dirname, "./src"),
},
},
server: {
port: 5173,
open: true,
},
build: {
outDir: "dist",
assetsDir: "assets",
sourcemap: false,
rollupOptions: {
output: {
manualChunks: {
vendor: ["react", "react-dom", "react-router-dom"],
swr: ["swr"],
},
},
},
},
});
@import "tailwindcss";リポジトリ構成
WordPress側(cms/) と React側(web/) は、デプロイ先ドメインも技術スタックも異なるため、Gitリポジトリを分ける構成にしました。
cms/ ← WordPress独立リポジトリ
web/ ← React独立リポジトリcms/ 側では基本的なプラグインはURLからの自動ダウンロードなので、Git管理対象は自作のCORS設定プラグインのみとします。
wordpress/plugins/*
!wordpress/plugins/cors-config/
!wordpress/plugins/cors-config/**本番環境へデプロイ
完全分離構成なので、WordPressとReactは別々にデプロイします。(※デプロイまでは実際には試していません。想定で書いています。予めご了承ください。)
WordPress側 (cms.example.com)
- サブドメインを用意しておき、エックスサーバーの「WEordPress簡単インストール」を使ってサーバーにWordPressをインストールします。
- FTPでローカルの以下をそれぞれ該当ディレクトリにアップロード
- wordpress/theme
- wordpress/plugins
- wordpress/uploads
- 管理画面からプラグインを有効化
- テーマを有効化
- パーマリンク設定を「投稿名」に変更
- wp-config.php に本番用のURLを追記
define('WP_HOME', 'https://cms.example.com');
define('WP_SITEURL', 'https://cms.example.com');
define('WP_DEBUG', false);
define('WP_ENVIRONMENT_TYPE', 'production');CROS設定は、開発環境用に作った cors-cxonfig プラグインの中で、許可オリジンのリストに本番ドメインを含めておきます。
$allowed_origins = [
'http://localhost:5173',
'https://example.com',
'https://www.example.com',
];React側(example.com)
ローカルでビルドし、静的ファイルをアップロードするだけです。
cd web
npm run builddist/配下の中身(index.html・assets/)を、example.comのドキュメントルート直下にアップロードします。
.htaccessは、以下のようにします。
RewriteEngine On
# HTTPS強制
RewriteCond %{HTTPS} off
RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [R=301,L]
# www → non-www リダイレクト
RewriteCond %{HTTP_HOST} ^www\.example\.com$ [NC]
RewriteRule ^(.*)$ https://example.com/$1 [R=301,L]
# React SPAルーティング
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^.*$ /index.html [L]まとめ
WordPressをヘッドレスCMS化してみました。今回はフロントエンドに Vite + React (CSR、クライアントサイドレンダリング)を選びましたが、SEOを考えるとNext.jsにしてSSR(サーバーサイドレンダリング)やSSG(静的サイト生成)を活用した方が良かったように思いました。
別の機会にNext.js(App Router) + WordPress REST API / GraphQL という組み合わせでやってみようと思います。
