Contentful Content Preview 機能チュートリアル実践 - Next.js での実装例

Contentful Content Preview 機能チュートリアル実践 - Next.js での実装例

Contentful の Content Preview 機能を使用して、下書き記事をリアルタイムでプレビューする方法を解説します。編集者が公開前にコンテンツの見た目を確認できるこの機能の設定方法と、Next.js を使った実装例を最小構成で紹介します。

はじめに

本記事では、Contentful の Content Preview 機能を使用し、下書き記事をプレビューできるアプリを構築します。

Contentful とは

Contentful は、API ファーストのヘッドレス CMS です。コンテンツの作成・管理と表示を分離することで、様々なプラットフォームやデバイスに対して柔軟にコンテンツを配信できます。

Contentful の Content Preview 機能とは

Content Preview 機能は、Contentful で作成したコンテンツを公開前にプレビューできる機能です。この機能により、編集者は下書き状態のコンテンツを実際のウェブサイトやアプリの見た目で確認できます。

Preview の例

対象読者

  • Content Preview 機能の導入を検討している方
  • Contentful を使用したヘッドレス CMS の実装経験がある方
  • Next.js の基本的な知識を持つ開発者

参考

全体の構成

本記事では Preview 用アプリの例として Next.js を使用します。

全体構成

Contentful 側の準備

本記事では、 Preview 機能を適用する Content model として BlogPost を作成済みであるとします。

Content model: BlogPost

  1. Contentful コンソール にアクセス

  2. Settings menu (画面上部の歯車マーク) > General settings > Space ID を控える
    Space ID 取得

  3. Settings menu > API keys から Content Preview API - access token を控える
    Content Preview API 取得

  4. Settings menu > Content preview で Start setup をクリック
    Content preview メニュー

  5. 以下の設定を入力

    • Name: 任意 (例: Local Development)
    • Description: 任意 (例: ローカル開発環境)
    • Content types: BlogPost
    • Preview URL for BlogPost: http://localhost:3000/api/preview?secret=YOUR_PREVIEW_SECRET&id={entry.sys.id}
      Preview Setting

ローカルでの実装

プロジェクトのセットアップ

プロジェクトディレクトリを作成し、必要なライブラリをインストールします。Next.js プロジェクトの初期設定では app router を選択し作成します。

npx create-next-app@latest contentful-preview-demo
cd contentful-preview-demo
npm install contentful @contentful/rich-text-react-renderer @contentful/rich-text-types

環境変数の設定

Contentful へのアクセスのため .env.local ファイルを作成し認証情報を入力します。

CONTENTFUL_SPACE_ID=your_space_id
CONTENTFUL_PREVIEW_ACCESS_TOKEN=your_preview_api_token
CONTENTFUL_PREVIEW_SECRET=YOUR_PREVIEW_SECRET

Contentful クライアントの設定

Contentful とのやり取りを行う lib/contentful.js を作成します。

import { createClient } from 'contentful'

/**
 * Contentful Preview API 専用クライアントの作成
 * 
 * Preview API を使用することで、下書き状態のコンテンツも取得可能
 * 通常の Delivery API では公開済みコンテンツのみ取得できる
 */
export const previewClient = createClient({
    space: process.env.CONTENTFUL_SPACE_ID,                    // Contentful スペース ID
    accessToken: process.env.CONTENTFUL_PREVIEW_ACCESS_TOKEN,  // Preview API 用のアクセストークン
    host: 'preview.contentful.com',                           // Preview API のエンドポイント
})

Preview API エンドポイントの実装

Preview API エンドポイントとして app/api/preview/route.js を作成します。

import { redirect } from 'next/navigation'

/**
 * Contentful からのプレビューリクエストを処理する API エンドポイント
 * 
 * Contentful の管理画面でプレビューボタンをクリックした際に呼び出される
 * 認証後、該当するブログ記事ページにリダイレクトする
 */
export async function GET(request) {
    // URL パラメータから secret と entry ID を取得
    const { searchParams } = new URL(request.url)
    const secret = searchParams.get('secret')  // 認証用のシークレットキー
    const id = searchParams.get('id')          // プレビュー対象のエントリ ID

    // 認証チェック: シークレットキーの検証とエントリ ID の存在確認
    if (secret !== process.env.CONTENTFUL_PREVIEW_SECRET || !id) {
        return new Response('Invalid token', { status: 401 })
    }

    // 認証成功時、該当するブログ記事ページにリダイレクト
    redirect(`/blog/${id}`)
}

ブログ記事表示ページの実装

プレビュー機能の本体である app/blog/[id]/page.js を作成します。

import { previewClient } from '../../../lib/contentful'
import { documentToReactComponents } from '@contentful/rich-text-react-renderer'

/**
 * ブログ記事のプレビューページコンポーネント
 * 
 * Contentful の Preview API を使用して、下書きを含むすべてのエントリを表示
 * Rich Text フィールドを適切にレンダリングする
 */
export default async function BlogPost({ params }) {
    // Next.js 15 では params を await で取得する必要がある
    const resolvedParams = await params

    try {
        // Preview API を使用してエントリを取得
        // これにより下書き状態のコンテンツも取得可能
        const entry = await previewClient.getEntry(resolvedParams.id)

        return (
            <div style={{ padding: '2rem', maxWidth: '800px', margin: '0 auto' }}>
                {/* プレビューモードであることを示すバナー */}
                <div style={{
                    background: '#f0f8ff',
                    padding: '1rem',
                    marginBottom: '2rem',
                    border: '1px solid #0066cc'
                }}>
                    🔍 Preview Mode - Entry ID: {resolvedParams.id}
                </div>

                {/* 記事タイトルの表示 */}
                <h1>{entry.fields.title || 'No Title'}</h1>

                {/* Rich Text 本文の表示 */}
                {entry.fields.body && (
                    <div>
                        {/* 
                         * documentToReactComponents を使用して Rich Text をレンダリング
                         * Contentful の Rich Text 形式を React コンポーネントに変換
                         */}
                        {documentToReactComponents(entry.fields.body)}
                    </div>
                )}

                {/* 本文が存在しない場合のフォールバック表示 */}
                {!entry.fields.body && (
                    <p style={{ color: '#666', fontStyle: 'italic' }}>
                        本文が設定されていません
                    </p>
                )}
            </div>
        )
    } catch (error) {
        // エラーハンドリング: エントリが見つからない場合やAPI エラーの処理
        return (
            <div style={{ padding: '2rem' }}>
                <h1>記事が見つかりません</h1>
                <p>Entry ID: {resolvedParams.id}</p>
                <p>Error: {error.message}</p>
            </div>
        )
    }
}

動作確認

開発サーバーの起動

下記のコマンドでローカルにサーバーを起動し、動作を確認します。

npm run dev

表示されている URL をブラウザで開き、 Next.js のテンプレート画面が表示されれば正常に起動が行われています。

Next.js テンプレート画面

プレビューの確認手順

Contentful コンソールの Content > Add entry から BlogPost を選択し、記事の内容を入力してから Open Live Preview を選択します。

Open Live Preview ボタン

プレビューが表示されることを確認します。

Preview 結果

まとめ

本記事では、Next.js を使用した Contentful Content Preview の最小構成実装を紹介しました。この機能は、リアルタイムで出力結果を確認しながら編集を行いたいというユースケースにおいて非常に有効です。

Share this article

facebook logohatena logotwitter logo

© Classmethod, Inc. All rights reserved.