W3Techsによれば、WordPressは20年以上前に誕生し、現在もインターネット上の42.7%のサイトを支えています。また、サイトのバックエンドとなるコンテンツ管理システム(CMS)の市場シェアも62.5%を占める人気ぶりです。

しかし今日では、WordPressをどれほど最適化しても、WordPressよりもはるかに高速で、ユーザーフレンドリーかつ高性能なサイト構築可能言語やフレームワークが多数存在します。多くの支持を集めるReactフレームワークのNext.jsがその良い例です。

今回は、WordPressをヘッドレスCMSとして使用し、Next.jsアプリケーションにデータを渡す方法をご紹介。また、Next.jsコードを静的サイトとしてKinstaの無料静的サイトホスティングにデプロイする手順も見ていきます。

ヘッドレスWordPressサイトとは

ヘッドレスWordPressサイトとは、WordPressのバックエンド機能(コンテンツの管理と保存)を使用して、フロントエンドの表示にはNext.jsのような別のシステムを使用するサイトを意味します。

このフロントエンドとバックエンドを切り離す仕組みにより、WordPressの堅牢なコンテンツ管理機能を活かしながら、Next.jsのサーバーサイドレンダリングや静的サイト生成といった最新のフロントエンド開発機能をフル活用することができます。

WordPressサイトの準備

Next.jsでの開発を始める前に、WordPressサイトをヘッドレス化するちょっとした準備が必要になります。

まだWordPressサイトをお持ちでない場合は、Kinstaで簡単に作成可能です。以下3つの方法があります。

  1. Kinstaにサイトを移行する前にローカルマシンでサイトを作成する(ローカル開発ツールのDevKinstaが便利)
  2. MyKinstaを利用してリモートでサイトを作成する
  3. Kinsta APIを使用してリモートでサイトを作成する

WordPressサイトを準備したら、WPGraphQLまたはREST APIでWordPressからフロントエンドフレームワークにデータを渡します。

REST APIは、Fetch APIAxiosライブラリのようなJavaScriptのアプローチを用いて、JSON形式でデータ取得を行います。REST APIは、WordPress 4.7から組み込まれているため、プラグインは不要です。ただし、GraphQLクエリでWordPressのデータと対話するWPGraphQLを使う場合は、WPGraphQLプラグインのインストールが必要になります。

今回は、例としてREST APIを使用していきます。WordPressのデータをJSON形式で取得するには、以下のように、WordPressサイトのURLの末尾に/wp-json/wp/v2を追加します。

http://yoursite.com/wp-json/wp/v2

デフォルトでhttp://yoursite.com/wp-json、JSON APIが有効になっていない場合は、WordPress管理画面の「設定」>「パーマリンク設定」に移動し、「投稿名」または「基本」以外のものを選択すると、有効化されます。

JSONデータにアクセスするためにWordPress REST APIを設定
JSONデータにアクセスするためにWordPress REST APIを設定

この設定は、ローカルおよび公開済みWordPressサイトに適用され、投稿固定ページコメントメディアを含むコンテンツのエンドポイントが提供されます。REST APIの詳細はこちらをご覧ください。

Next.js環境をセットアップする

Next.jsはウェブアプリケーションの構築が簡単で、パフォーマンスにも優れ、開発体験に最適化されています。ファイルベースのルーティングは、Next.jsの主な機能のひとつ。

パフォーマンスが重視されているため、各ページに必要なJavaScriptだけを読み込むことで表示速度を大幅に改善する自動コード分割などの機能も組み込まれています。

Next.jsプロジェクトをセットアップするには、次のコマンドを実行し、デフォルトのレスポンスを使用します。

npx create-next-app@latest nextjs-wp-demo

以下の手順でGitのスターターテンプレートを入手可能です。

  1. 本プロジェクトのGitHubリポジトリにアクセス。
  2. Use this template」>「Create a new repository」を選択し、スターターコードをGitHubアカウント内のリポジトリにコピー(「Include all branches」にチェックをいれる)。
  3. リポジトリをローカルコンピューターにプルし、コマンドgit checkout starter-filesを使ってstarter-filesブランチに切り替える。
  1. コマンドnpm installを実行し、必要な依存関係をインストールする。

インストールが完了したら、npm run devを使ってローカルコンピュータ上でプロジェクトを起動します。これで、「http://localhost:3000/」からプロジェクトを利用できるようになります。

Next.jsでビルドしたスタータープロジェクト
Next.jsでビルドしたスタータープロジェクト

プロジェクトを理解する

Next.js 13以降は、既存のpagesディレクトリに代わってApp Routerがルーティングを行います。App Routerのルーティングでは、appディレクトリ内にフォルダが作成され、それから適切なフォルダにpage.jsファイルがネストされ、ルートが定義されます。

このプロジェクトでは、appがコアディレクトリになり、以下のようなファイル構造を持ちます。

/
|-- /app
    |-- /blog
        |-- /[postId]
        	|-- page.js
        |-- page.js
    |-- globals.css
    |-- layout.js
    |-- navbar.js
    |-- page.js

基本的な情報を表示するトップページ、WordPressのすべての投稿を表示するブログページ、そして個々の投稿をレンダリングするための動的なページ([postId]/page.js)です。

また、navbar.jsコンポーネントは、プロジェクトのレイアウトを作成するためのもので、layout.jsファイルにインポートされます。

WordPressからNext.jsにデータを渡す

WordPressのREST APIでは、特定のエンドポイントにHTTPリクエストを送信し、投稿、固定ページ、カスタム投稿タイプを取得します。

以下、blog/page.jsファイルで、WordPress内のすべての投稿を取得するリクエストを送信して、最後に渡されたidパラメータに基づき、blog/[postId]/page.jsで各投稿を動的に取得するリクエストを行ってみます。

なお、これらのリクエストを行う前に、JSON APIのアドレスを環境変数に追加しておくことをお勧めします。APIのベースURLが環境変数に格納されるため設定が簡単になり、複数のファイルにハードコーディングされることもなくなります。

Next.jsプロジェクトのルートに.envファイルを作成して、以下を貼り付けましょう。

NEXT_PUBLIC_WORDPRESS_API_URL=https://yoursite.kinsta.cloud/wp-json/wp/v2

URLは、サイトのJSON APIに置き換えてください。また、.env.gitignoreファイルに追加し、Gitサービスにファイルをプッシュしないようにしましょう。

WordPressからすべての投稿を取得する

WordPressサイトからすべての投稿を取得するには、blog/page.jsファイルにgetPostsという名前の非同期関数を作成します。この関数がFetch APIを使用して、REST APIの/postsエンドポイントにGETリクエストを送信します。

async function getPosts() {
    const response = await fetch(
        `${process.env.NEXT_PUBLIC_WORDPRESS_API_URL}/posts`
    );
    const posts = await response.json();
    return posts;
}

レスポンスを受け取ると、レスポンスをJSONに変換し、投稿オブジェクトの配列を作成します。これらのpostsは、Next.jsアプリケーションでレンダリング可能で、WordPressから直接取得したブログ記事の動的なリストを提供します。

const BlogPage = async () => {
    const posts = await getPosts();
    return (
        <div className="blog-page">
            <h2>すべてのブログ記事</h2>
            <p>すべてのブログ記事は、WP REST APIを介してWordPressから取得されます</p>
            <div className="posts">
                {posts.map((post) => {
                    return (
                        <Link href={`/blog/${post.id}`} className="post" key={post.id}>
                            <h3>{post.title.rendered}</h3>
                            <p
                                dangerouslySetInnerHTML={{ __html: post.excerpt.rendered }}
                            ></p>
                        </Link>
                    );
                })}
            </div>
        </div>
    );
};

Next.jsのページコンポーネント内で、getPostsを非同期に呼び出して投稿を取得します。それから、postsの配列に対してmapを呼び出し、<Link>コンポーネント内で各投稿のtitleexcerptをレンダリングします。

これにより、投稿が表示されるだけでなく、投稿の詳細ビューにナビゲートするリンクで各投稿がラップされます。これはNext.jsのファイルベースのルーティングを使用することで実行され、投稿IDがURLパスを動的に生成するために使用されます。

WordPressからNext.jsへ動的な投稿を取得する

上のコードでは、各投稿が投稿の詳細ビューにナビゲートするためのリンクでラップされています。

各投稿ページに関しては、Next.jsの動的ルーティングを利用して、IDに基づき単一の投稿を取得して表示するページを作成します。動的ページ[postID]/page.jsは、stater-filesコード内にすでに生成されている状態です。

パラメータとして渡された投稿IDを使って単一の投稿を取得するため、getPostsと同様のgetSinglePost 関数を作成します。

async function getSinglePost(postId) {
    const response = await fetch(
        `${process.env.NEXT_PUBLIC_WORDPRESS_API_URL}/posts/${postId}`
    );
    const post = await response.json();
    return post;
}

動的ページのコンポーネントでは、URLパラメータから投稿IDを抽出してgetSinglePostdを呼び出し、投稿内容をレンダリングします。

const page = async ({ params }) => {
    const post = await getSinglePost(params.postId);
    // 残りのページコード
};

取得したデータをページに埋め込みます。

const page = async ({ params }) => {
    const post = await getSinglePost(params.postId);
    if (!post) {
        return <div>読み込み中...</div>;
    }
    return (
        <div className="single-blog-page">
            <h2>{post.title.rendered}</h2>
            <div className="blog-post">
                <p> dangerouslySetInnerHTML={{ __html: post.content.rendered }}></p>
            </div>
        </div>
    );
};

コードの全貌は、GitHubリポジトリでご覧いただけます。

Next.jsアプリケーションをKinstaに無料でデプロイする

Kinstaの静的サイトホスティングサービスでは、最大100の静的サイトを無料でホストすることができます。

ホストできるのは静的ファイルのみで、Next.jsのような静的サイトジェネレーターを使用する場合は、GitHubからプロジェクトをビルドし、静的ファイルをKinstaにデプロイする設定を行うことも可能です。

Next.jsでの静的レンダリング

Next.js 13以上で静的HTMLのエクスポートを有効にするには、next.config.js内のoutputモードを変更します。

const nextConfig = {
    output: 'export',
};

これでプロジェクトのビルド時に、Next.jsはアプリケーションのHTMLCSSJavaScriptアセットを含むoutフォルダが生成されるように。

Next.js 13以降から、静的サイトとしてプロジェクトを起動することができ、その後オプションでアップグレードすることで、サーバーを必要とする機能を使用できるようになっています。サーバー機能を使用する場合は、ページをビルドしても静的ページは生成されません。

例えば、動的ルートではこれらのデータを動的に取得します。すべての投稿を静的に生成できるようにするため、generateStaticParams関数を使用します。

この関数は、動的なルートセグメントと組み合わせて使用され、リクエスト時にオンデマンドでルートを生成するのではなく、ビルド時に静的にルートを生成します。ビルド時には、対応するレイアウトやページが生成される前にgenerateStaticParamsが実行されます。

postID]/page.jsで、すべての投稿のルートを取得するには、generateStaticParams関数を使います。

export async function generateStaticParams() {
    const response = await fetch(
        `${process.env.NEXT_PUBLIC_WORDPRESS_API_URL}/posts`
    );
    const posts = await response.json();

    return posts.map((post) => ({
        postId: post.id.toString(),
    }));
}

ビルドコマンドを実行すると、Next.jsプロジェクトは静的ファイルを含むoutディレクトリを生成します。

Kinstaの静的サイトホスティングにNext.jsをデプロイする

任意のGitサービス(BitbucketGitHub、またはGitLab)にコードをプッシュし、以下の手順に従うことで、Next.js静的サイトをKinstaにデプロイすることができます。

  1. ログイン、またはアカウントを作成してMyKinstaを開く
  2. GitサービスでKinstaを認証
  3. 左サイドバーの「静的サイト」を選択して「サイトの追加」をクリック
  4. デプロイしたいリポジトリとブランチを選択
  5. サイトに一意の名前を割り当てる
  6. 次の形式でビルド設定を追加
    • ビルドコマンドnpm run build
    • Nodeバージョン18.16.0
    • 公開ディレクトリout
  1. サイトを作成」をクリック

これで、数秒以内にサイトのデプロイが完了し、デプロイされたバージョンにアクセスするためのリンクが表示されます。必要に応じて、独自ドメインSSL証明書を追加することもできます。

また、Kinstaのアプリケーションホスティングで静的サイトをデプロイすることも可能です。より優れた柔軟性とスケーラビリティ、Dockerfileを使ったデプロイメントのカスタマイズ、およびリアルタイムおよび過去のデータを網羅する包括的な分析機能など、数々のメリットがあります。また、静的レンダリング用にNext.jsプロジェクトを設定する必要もありません。

まとめ

今回は、Next.jsプロジェクトでヘッドレスCMSとしてWordPressを活用し、投稿を動的に取得して表示する方法をご紹介しました。これにより、Next.jsアプリケーションにWordPressコンテンツをシームレスに統合し、モダンで動的なウェブ体験を実現することができます。

ヘッドレスCMSのAPIの可能性は投稿だけにとどまらず、固定ページ、コメント、メディアなどの取得と管理にも活用可能です。

Kinstaなら、フロントエンドフレームワークとWordPressのホスティングはとてもシンプル。専用コントロールパネルのMyKinstaで、WordPressサイトアプリケーションデータベース、静的サイトを一元管理することができます。ぜひお試しください。

Joel Olawanle Kinsta

Joel is a Frontend developer working at Kinsta as a Technical Editor. He is a passionate teacher with love for open source and has written over 200 technical articles majorly around JavaScript and it's frameworks.