WordPressブログをNext.js(App Router)に移行する
0.はじめに
Next.js 13.4 から、App Router が正式リリースとなりました。この新しいバージョンでは、これまでの Pages Router とは大幅に異なる変更が加えられており、より強力で柔軟なルーティングオプションを提供しています。
Wordpress をヘッドレス CMS(Headless CMS)として活用します。Wordpress はコンテンツ管理の強力なツールとして広く知られており、その柔軟性を活かしてコンテンツを管理し、Next.js アプリケーションと統合することができます。
App Router を使用して Wordpress のコンテンツを表示し、豊富なコンテンツとパフォーマンスを組み合わせた魅力的なウェブアプリケーションの開発を目指します。
この記事では、実際にアプリケーションを開発していきます。
1.開発環境の準備
nextjs のインストール
まずは、nextjs をインストールしてきます。
npx create-next-app@latest
すると、いくつか質問されるので、次の通り設定します。
✔ What is your project named? … sample-nextjs-wordpress
✔ Would you like to use TypeScript? … Yes
✔ Would you like to use ESLint? … Yes
✔ Would you like to use Tailwind CSS? … Yes
✔ Would you like to use `src/` directory? … Yes
✔ Would you like to use App Router? (recommended) … Yes
✔ Would you like to customize the default import alias (@/*)? … Yes
✔ What import alias would you like configured? … @/*
WordPress の準備
次に WordPress の準備をします。
今回は、docker
を用いて、WordPress を用意します。
docker インストールが済んでない人は、下記公式サイトよりダウンロードください。
docker-compose.yml
まずは、docker-compose.yml
を作ります。
version: "3.7"
services:
db:
image: mysql:5.7
platform: linux/amd64 # M1Macを使う場合
container_name: mysql
restart: always
environment:
MYSQL_ROOT_PASSWORD: password # rootユーザのパスワード
MYSQL_DATABASE: db_local # WordPress用データベース名
MYSQL_USER: wp_user # WordPress用データベース接続ユーザ名
MYSQL_PASSWORD: password # WordPress用データベース接続パスワード
volumes:
- db_data:/var/lib/mysql
WordPress:
depends_on:
- db
image: wordpress:latest
container_name: wordpress
ports:
- 8000:80
restart: always
environment:
WORDPRESS_DB_HOST: db:3306 # データベースサーバ名:ポート番号
WORDPRESS_DB_USER: wp_user # WordPress用データベース接続ユーザ名(dbの内容に合わせる)
WORDPRESS_DB_PASSWORD: password # WordPress用データベース接続パスワード(dbの内容に合わせる)
WORDPRESS_DB_NAME: db_local # WordPress用データベース名(dbの内容に合わせる)
WORDPRESS_DEBUG: 1 # デバッグモードON
volumes:
- ./wp-content:/var/www/html/wp-content/
app:
build:
context: . # contextはdocker buildを実行する時のワーキングディレクトリ
dockerfile: Dockerfile # dockerfileはDockerfileのパスを指定
# ホスト側のディレクトリ./srcを、コンテナのディレクトリ/appにマウント
volumes:
- .:/app # 現在のディレクトリとコンテナ内の/app/ディレクトリが同期
- node_modules:/app/node_modules
# ホットリロード
environment:
- WATCHPACK_POLLING=true
# ホスト側のポート:コンテナ側のポート
ports:
- "3000:3000"
# コンテナを起動したままにするために設定
tty: true
volumes:
node_modules:
db_data:
Dockerfile
次に Dockerfile を作っていきます。
# ベースイメージを指定
FROM node:20.8.0
# 作業ディレクトリを設定
WORKDIR /app
# キャッシュ利用で効率化するために別でコピー
COPY ./package.json ./
# 依存関係をインストール
RUN npm install
# アプリケーションを起動
CMD ["npm","run","dev"]
docker を起動
docker-compose up -d
で環境構築・立ち上げを行なっていきます。
Docker の画面はこんな感じ
nextjs と wordpress がそれぞれ起動しているか、チェックしていきましょう!
nextjs:http://localhost:3000
WordPress:http://localhost:8000
これで環境設定は完了です。
2.WordPress に GraphQL を設定する
WordPress に GraphQL を設定していきます。
ここでは、WordPress のプラグインであるWP GraphQL
を導入していきます。
まずは、WordPress を設定
WordPress(http://localhost:8000)から言語や必要情報を設定していきます。
WordPress のパーマリンク設定
/graphql
エンドポイントで GraphQL を公開するには、パーマリンクの変更が必要です。
設定 > パーマリンクより WordPress パーマリンク設定を開け、基本(http://localhost:8000/?p=123
)以外を選択します。
次に、プラグイン > 新規追加 > WPGraphQL > 今すぐインストールと進みます。
有効化が終わったら、GraphiQL IDE をクリックします。
GraphiQL IDE ではクエリを簡単に作って試すことができます。
3.Next.js から呼び出す
まずは、実装
Dcocker を起動したままsrc/app/page.tsx
に下記コードを貼り付けて下さい。
type Post = {
node: { title: string; id: string; content: string };
};
export default async function Home() {
const query = `query NewQuery {
posts {
edges {
node {
title
id
content
}
}
}
}`;
const posts = await fetch("http://wordpress:80/graphql", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({ query }),
next: { revalidate: 10 },
})
.then((res) => {
if (!res.ok) {
throw new Error("HTTPエラー " + res.status);
}
return res.json();
})
.then((json) => {
return json.data.posts.edges;
})
.catch((error) => {
console.error("エラー: " + error.message);
});
return (
<main>
{posts.map((post: Post, i: number) => {
return (
<div key={i}>
<div>{post.node.title}</div>
<div>{post.node.id}</div>
<div dangerouslySetInnerHTML={{ __html: post.node.content }}></div>
</div>
);
})}
</main>
);
}
その後、nextjs:http://localhost:3000を開くと次のようなページが開くと思います。
App Router Fetch vs Pages Router GetStaticProps
Pages Router を使用する場合、データの取得には getStaticProps メソッドを活用していました。
しかし、App Router を使用する場合、拡張された fetch 機能を使います。
Next.js は、ネイティブの Web API である fetch を拡張し、サーバー上での各フェッチリクエストのキャッシュと再検証動作を拡張しています。これにより、データの取得とキャッシュの管理を簡単に行えるようになっています。
React コンポーネントツリーのレンダリング中に自動的にフェッチリクエストをメモ化します。つまり、同じデータを複数回フェッチすることなく、必要なデータを一度取得すれば、そのデータは再利用されます。これにより、パフォーマンスが向上し、無駄なデータのフェッチが減ります。
App Router Fetch Revalidate vs ISR Revalidate
Incremental Static Regeneration(ISR)は、静的なページ生成を前提としながら、一定の間隔でページを再生成する仕組みです。この再生成の間隔は、getStaticProps の revalidate オプションを使用して設定できます。これにより、ページの最新のデータを保持しながら、定期的にページを更新できます。
App Router でも、ISR に相当する機能が存在し、以前よりも細かい制御が可能です。以前の ISR はページ単位での制御でしたが、App Router からは個々の fetch()リクエストごとに revalidate 期間を制御できます。具体的には、fetch()のオプションに revalidate を指定することで、個別のリクエストの再生成タイミングを設定できます。これにより、データの取得と再生成をさらに細かく制御できます。
Revalidate について
実際に体験してみましょう。
WordPress に記事を新しく投稿してみてください。
- 投稿した瞬間(
revalidate
で設定した秒数(10 秒)よりも早く)リロードした場合、画面が変わりません。 -
revalidate
で設定した秒数(10 秒)が立ったのちに、アクセスしても画面は変わりません。 - もう一度リロードすると、画面が切り替わります。
2 のタイミングで build が行われ、次のアクセスでその結果が表示されることがわかります。ISR と同じ仕組みですね。
おまけ fetch URL
fetch URL が http://wordpress:80/graphql
になっています。
直接 Nextjs を立ち上げた場合(npm run dev
)、fetch URL は、http://localhost:8000/graphql
になります。
docker で立ち上げている時に何か不具合が出て、原因がはっきり掴めないときは、まずは、
docker-compose logs app
にてログをチェックしてみましょう。先ほどの fetch URL 関係だと
-
http://localhost:8000/graphql
を使った場合TypeError: fetch failed at Object.fetch (node:internal/deps/undici/undici:13220:11) at process.processTicksAndRejections (node:internal/process/task_queues:95:5) { cause: Error: connect ECONNREFUSED 127.0.0.1:8000 at TCPConnectWrap.afterConnect [as oncomplete] (node:net:1595:16) at TCPConnectWrap.callbackTrampoline (node:internal/async_hooks:130:17) { errno: -111, code: 'ECONNREFUSED', syscall: 'connect', address: '127.0.0.1', port: 8000 } }
-
http://wordpress:8000/graphql
を使った場合TypeError: fetch failed at Object.fetch (node:internal/deps/undici/undici:13220:11) at process.processTicksAndRejections (node:internal/process/task_queues:95:5) { cause: Error: connect ECONNREFUSED 172.18.0.4:8000 at TCPConnectWrap.afterConnect [as oncomplete] (node:net:1595:16) at TCPConnectWrap.callbackTrampoline (node:internal/async_hooks:130:17) { errno: -111, code: 'ECONNREFUSED', syscall: 'connect', address: '172.18.0.4', port: 8000 } }
こんな感じでエラーを捕捉することができます。
もし記事があなたのお役に立ったなら、ぜひ「いいね!」ボタンをクリックしてくださいね。
Discussion