TOSAKAFUNK

Loading...

脱・本文直書き!Next.jsとACFで「サマリー」「要約リスト」を構造化し、柔軟に管理する方法

脱・本文直書き!Next.jsとACFで「サマリー」「要約リスト」を構造化し、柔軟に管理する方法 のビジュアル

Next.jsとヘッドレスWordPress(ACF)でブログを運用する際、「サマリー」や「要約リスト」の管理に悩んでいませんか?
この記事では、ACFのカスタムフィールド(リピーター含む)を使ってこれらを本文と分離し、構造化する方法を解説。
WPGraphQL経由でNext.jsからデータを取得し、柔軟に表示する具体的な手順とコード例を紹介します。

  • ACFによる課題解決標準の抜粋機能や本文への直書きの課題を、ACFの専用フィールドで解決します。
  • WordPress側の設定「サマリー」用のテキストエリアと、「要約リスト」用のリピーターフィールドの具体的な設定方法を解説します。
  • Next.jsでの取得方法WPGraphQL(またはREST API)を使い、定義したカスタムフィールドのデータをNext.js側で取得・表示するコード例を紹介します。
  • コンテンツ構造化の利点本文とメタ情報(要約など)を分離することで、CMSの運用性とフロントエンドの柔軟性が向上します。

Next.jsとヘッドレスWordPress運用における「サマリー」管理の課題

Next.jsによる高速なフロントエンドと、WordPressの柔軟な編集体験を組み合わせたヘッドレスCMS構成は、現代のWeb制作において非常に強力な選択肢です。しかし、この構成特有の「コンテンツ管理の悩み」に直面している方も少なくありません。

特に、「記事一覧ページに表示するサマリー(抜粋)」と「記事詳細ページの冒頭に置く要約リスト」の扱いは、多くの開発者が悩むポイントです。

課題1: 標準「抜粋」機能の限界と一覧ページでの表示問題

WordPressには標準で「抜粋(excerpt)」機能が備わっています。しかし、このフィールドはデフォルトでプレーンテキストしか受け付けず、HTMLタグが許可されていません。そのため、「サマリー内の一部を強調したい」「改行を入れたい」といったデザイン上の要求に応えにくいという問題があります。

かといって、抜粋欄が空の場合に適用される「本文の先頭から自動抜粋(`the_excerpt()`の挙動)」に頼ると、意図しない箇所で文章が途切れたり、本文冒頭の画像やコードブロックが中途半端に含まれてしまい、一覧ページのデザイン崩れを引き起こす原因となります。

課題2: 本文冒頭に「要約リスト」を含めることのデメリット

SEOやCRO(コンバージョン率最適化)の観点から、記事の冒頭に「この記事のポイント」や「要約リスト」を設置することは非常に有効です。読者は記事全体を読まずとも、概要を素早く把握できます。

しかし、この要約リストをWordPressの本文(`the_content` / Gutenbergエディタ)の先頭に直接書き込んでしまうと、前述の「本文の自動抜粋」機能が作動した際に、この要約リストがそのまま一覧ページのサマリーとして表示されてしまいます。

私たちが一覧ページで見せたいのは「記事全体を要約したサマリー」であり、「記事のポイントを箇条書きにしたリスト」ではありません。このように、本文(content)にメタ的な情報(サマリーや要約)が混在することは、コンテンツの再利用性を著しく低下させます。


解決策はACFカスタムフィールドによる「コンテンツの構造化」

これらの課題を根本的に解決するアプローチが、「コンテンツの構造化」です。

具体的には、WordPressの本文(content)エリアは純粋な「記事本文」だけを管理するものと割り切り、「サマリー」や「要約リスト」といったメタ的な情報は、専用の入力欄(カスタムフィールド)として分離・管理します。

なぜACF(Advanced Custom Fields)が最適なのか

この「カスタムフィールド」を直感的かつ柔軟に作成・管理できるのが、Advanced Custom Fields (ACF) プラグインです。

ACFを使えば、以下のような対応が容易になります。

  • サマリー用フィールド: HTMLタグの使用を許可できる「テキストエリア」フィールドを作成できます。
  • 要約リスト用フィールド: 「見出し」と「説明」のセットを動的に追加・削除・並べ替えできる「リピーター(繰り返し)フィールド」を作成できます。

このようにコンテンツを構造化することで、Next.js側(フロントエンド)は、必要なデータをAPI経由でピンポイントに取得し、デザイナーが意図した通りの場所に正確に配置できるようになります。


【手順1】WordPress (ACF) でカスタムフィールドを定義する

まず、WordPress側でACFプラグインをインストールし、有効化していることを前提とします(※リピーターフィールドはACF Pro版の機能ですが、必須級の投資です)。

「カスタムフィールド」メニューから新規フィールドグループを作成し、投稿タイプ「投稿」に関連付けます。

「サマリー(summary)」フィールドの作成(テキストエリア)

記事一覧ページで使いたい、HTMLを許容するサマリー用のフィールドを作成します。

フィールド ラベル:

サマリー

フィールド名:

summary

フィールドタイプ:

テキストエリア

改行:

自動的に <br> を追加する(または、WYSIWYGエディタを選択しても良いでしょう)

これで、投稿編集画面に「サマリー」という専用の入力欄が表示されます。

「要約リスト(point_list)」フィールドの作成(リピーター)

次に、記事詳細ページの冒頭に表示する「要約リスト」用のフィールドを作成します。これは、複数の「見出し」と「説明」のペアを管理できるリピーターフィールドとして定義します。

フィールド ラベル:

要約リスト

フィールド名:

point_list

フィールドタイプ:

リピーター

リピーターフィールドの内部構造(サブフィールド)

「要約リスト(point_list)」フィールドの中に、以下の2つのサブフィールドを作成します。

  1. ポイント見出し
    • フィールド ラベル: ポイント見出し
    • フィールド名: point_title
    • フィールドタイプ: テキスト
  2. ポイント説明
    • フィールド ラベル: ポイント説明
    • フィールド名: point_description
    • フィールドタイプ: テキストエリア(改行を許可)

これにより、編集者は「行を追加」ボタンを押すだけで、要約の項目を好きなだけ追加できるようになります。


【手順2】API (WPGraphQL / REST) へのフィールド登録

作成したACFフィールドをNext.jsから取得できるように、APIで公開(エクスポーズ)する必要があります。ヘッドレス構成では、WPGraphQLを使用する方法が最も推奨されます。

(推奨) WPGraphQL ACFアドオンを使ったGraphQLスキーマへの登録

WPGraphQL for Advanced Custom Fields というアドオン(無料プラグイン)をインストールして有効化します。

その後、先ほど作成したACFのフィールドグループ設定に戻り、「GraphQL で表示」という設定項目を「はい」に変更します。また、各フィールド(`summary`, point_list)の設定内にも「GraphQL で表示」のトグルがある場合は、それもオンにします。

WPGraphQL ACFアドオンでスキーマに登録

これだけで、WordPressのGraphQLスキーマ(GraphiQL IDEなどで確認可能)に、`summary` や pointList といったフィールドが自動的に追加されます。

(参考) REST API への登録方法

もしREST APIを使用している場合、ACF Pro版であればフィールドグループの設定で「REST API で表示」を「はい」にするだけで公開されます。無料版の場合は、`functions.php` などで register_rest_field を使った追加実装が必要になる場合があります。


【手順3】Next.js側でのデータ取得と表示(GraphQL例)

最後に、Next.js側(`getStaticProps` や getServerSideProps、またはApp Routerのfetch)で、WPGraphQLエンドポイントからデータを取得し、コンポーネントに渡して表示します。

記事一覧ページ(アーカイブ)での「サマリー」取得

一覧ページでは、各投稿のID、タイトル、スラッグなどに加えて、カスタムフィールドの summary を取得します。

クエリ例 (GraphQL)


query GetPostArchives {
  posts(first: 10) {
    nodes {
      id
      title
      slug
      # ACFで追加したフィールド(フィールドグループ名が 'postFields' の場合)
      postFields {
        summary
      }
    }
  }
}
    

※フィールドグループ名(例: postFields)は、ACFのフィールドグループ設定で指定した「GraphQL フィールド名」に応じて変わります。

実装コード例 (React / JSX)

取得したデータを ArchivePage コンポーネントなどで展開します。`summary` フィールドはHTMLを含む可能性があるため、`dangerouslySetInnerHTML` を使用してレンダリングします。


// pages/blog/index.js (Pages Router例)

export default function ArchivePage({ posts }) {
  return (
    <div>
      <h1>ブログ一覧</h1>
      <ul>
        {posts.map((post) => (
          <li key={post.id}>
            <h2>{post.title}</h2>
            {/* ACFのサマリーフィールドを表示 */}
            {post.postFields?.summary && (
              <div
                className="post-summary"
                dangerouslySetInnerHTML={{ __html: post.postFields.summary }}
              />
            )}
            <a href={`/blog/${post.slug}`}>続きを読む</a>
          </li>
        ))}
      </ul>
    </div>
  );
}
    

セキュリティノート: dangerouslySetInnerHTML を使用する際は、入力ソースが信頼できること(CMS管理画面からの入力であること)を確認してください。ACFのテキストエリアはXSSのリスクを軽減するサニタイズ機能を持っていますが、万全を期す場合は dompurify などのライブラリを併用することも検討してください。

記事詳細ページでの「要約リスト」取得と表示

詳細ページでは、本文(`content`)に加えて、リピーターフィールドの pointList を取得します。`pointList` はオブジェクトの配列として返されます。

クエリ例 (GraphQL)


query GetPostDetails($slug: ID!) {
  post(id: $slug, idType: SLUG) {
    id
    title
    content # 本文
    # ACFフィールド
    postFields {
      # リピーターフィールド(サブフィールドも指定)
      pointList {
        pointTitle
        pointDescription
      }
    }
  }
}
    

実装コード例 (React / JSX)

pointList は配列なので、`map()` メソッドでループ処理してリスト(`dl` タグや ul タグなど)としてレンダリングします。


// pages/blog/[slug].js (Pages Router例)

// (getStaticProps/Paths ... 省略)

export default function PostPage({ post }) {
  const points = post.postFields?.pointList;

  return (
    <article>
      <h1>{post.title}</h1>

      {/* --- 要約リスト --- */}
      {points && points.length > 0 && (
        <div className="summary-box">
          <h2>この記事のポイント</h2>
          <dl>
            {points.map((item, index) => (
              <React.Fragment key={index}>
                <dt>{item.pointTitle}</dt>
                {/* 説明文(改行を <br> に変換する場合など) */}
                <dd dangerouslySetInnerHTML={{ __html: item.pointDescription.replace(/\n/g, '<br />') }} />
              </React.Fragment>
            ))}
          </dl>
        </div>
      )}
      {/* --- /要約リスト --- */}


      {/* --- 本文 --- */}
      <div
        className="post-content"
        dangerouslySetInnerHTML={{ __html: post.content }}
      />
      {/* --- /本文 --- */}

    </article>
  );
}
    

まとめ: ACFによる構造化でNext.jsとWordPressの連携を強化しよう

今回は、Next.jsとヘッドレスWordPressの構成において、ACF(Advanced Custom Fields)を活用して「サマリー」と「要約リスト」を管理・表示する方法を解説しました。

最大のポイントは、「本文(content)」と「メタ的な情報(summary, point_list)」を明確に分離することです。

  1. WordPress側で、ACFを使いコンテンツを構造化されたフィールドとして定義する。
  2. WPGraphQL(またはREST API)経由で、必要なデータをピンポイントで取得する。
  3. Next.js側で、取得したデータを意図したレイアウトに組み込む。

このアプローチにより、編集者は直感的にコンテンツを入稿でき、開発者はフロントエンドの柔軟性とパフォーマンスを最大限に高めることができます。ぜひ、貴社のヘッドレスCMS運用にお役立てください。


Next.jsでのヘッドレスCMS構築にお悩みですか?

「Next.jsとWordPressの連携がうまくいかない」
「パフォーマンスと編集体験を両立させたい」
「ACFのより高度な活用法を知りたい」

当社は、Next.jsとヘッドレスCMS(WordPress, microCMSなど)を用いた高パフォーマンスなWebサイト構築を得意としています。現状の課題ヒアリングから最適な構成のご提案まで、まずはお気軽にご相談ください。