Next.jsでパンくずリストを構造化マークアップで実装する方法

  • #開発
  • #nextJS
  • #breadcrumb

こんにちは。CURUCURUエンジニアの水谷です。 先日にNext.jsでパンくずリストを実装しました。 今回はそこでの実装方法も踏まえて解説していきます。


パンくずリストとは?

パンくずリストとは、Webサイトの階層構造を示したものです。

TOP > カテゴリー一覧 > トップス > ポロシャツ

上記のような形をしたものです。

パンくずリストを構造化マークアップするとは?

パンくずリストはWebサイトのユーザーだけでなく、検索エンジンもチェックしています。 しかし、普通にUIとして書くだけでは検索エンジンは認識できません。

そこで、検索エンジンでもわかる形式で書く必要があり、その形式に合わせて書くことを構造化マークアップと言います。

構造化マークアップの種類

構造化マークアップにもいくつか種類がありますが、主に下記が使用されています。

  • JSON-LD
  • microdata
  • RDFa

Googleが推奨しているのがJSON-LDであり、CURUCURUでもJSON-LDを採用しました。

ちなみに、microdataやRDFaはHTMLに埋め込む形式ですが、JSON-LDはJavaScript形式で記載できるためUIに依存せずに書くことができるのもメリットです。

Next.jsでパンくずリストを実装する

まず、基本となる形を書いておきます。

<html>
  <head>
    <title>Award Winners</title>
    <script type="application/ld+json">
    {
      "@context": "https://schema.org",
      "@type": "BreadcrumbList",
      "itemListElement": [{
        "@type": "ListItem",
        "position": 1,
        "name": "Books",
        "item": "https://example.com/books"
      },{
        "@type": "ListItem",
        "position": 2,
        "name": "Science Fiction",
        "item": "https://example.com/books/sciencefiction"
      },{
        "@type": "ListItem",
        "position": 3,
        "name": "Award Winners"
      }]
    }
    </script>
  </head>
  <body>
  </body>
</html>

このコードはこちらから見ることができます。

パンくずリストの項目について

@contextや@contextは固定です。

皇族化マークアップ、パンくずリストであることを書いています。

itemListElement

itemListElementに階層構造を作るページを入れていきます。

@typeはListItemで共通です。 @positionは階層のどの位置にいるかを書きます。 @nameはページの名前を書きます。 @itemはページのURLを書きます。

最後の要素に@itemがないですが、ここはあってもなくてもOKです。 ない場合は現在のページのURLが自動で入ります。

Next.jsで実装する

まずは、上記のコードを生成する関数を作ります。

export interface List {
    label: string;
    path: string;
}

export const Markup = (list: List[]) => {
    let jsonLd = '';
    jsonLd += `
    {
        "@context": "https://schema.org",
        "@type": "BreadcrumbList",
        "itemListElement": [`;
        list.forEach((l, i, array) => {
            jsonLd += `{
                "@type": "ListItem",
                "position": ${i+1},
                "name": "${l.label}",
                "item": "${l.path}"
            }`;
            if(i !== (array.length - 1)) {
                jsonLd += ',';
            }
        });
    jsonLd += `
        ]
    }`;
    return jsonLd;
};

細かいところですが、「,」のある、なしも大事です。 例えば、最後の要素に「,」は不要ですが、点があるだけでエラーが出ます。

そして、この関数で生成したJSON-LDをコンポーネントとして実装します。

interface Props {
    jsonLd: string;
}

export const BreadCrumbMarkup = (props: Props)=> {
    return(
        <Head>
            {props.jsonLd && (
                <script
                    type="application/ld+json"
                    dangerouslySetInnerHTML={{__html: props.jsonLd}}
                />
            )}
        </Head>
    );
};

ポイントはHeadコンポーネントでラップするところです。 headタグ内で書いておくのはもちろんですが、もう1つ役割があります。 検索エンジンのクローラーがパンくずリストを検出できるようにSSGで生成しておく必要があります。 それをHeadコンポーネントでラップすることで実現できるので、Headコンポーネントで括っています。

ちなみに、このHeadコンポーネントはコンポーネントを括るとheadタグに入れてくれません。

なので、HeadコンポーネントでBreadCrumbMarkupコンポーネントをラップするのではなく、 BreadCrumbMarkupコンポーネントの中でHeadコンポーネントを使用しています。

まとめ

今回はパンくずリストをNext.jsで実装する方法を紹介しました。 パンくずリストの理解と、Next.jsの理解がまた一歩深まりました。 何度も先輩にプルリク出して見てもらったので、毎月知識が身についている実感があります。自分も忙しいのに良い先輩です。

メンバー募集

CURUCURUでは開発メンバーを募集中です。 CURUCURUの開発に興味があったり、モダンな開発環境で挑戦してみたいという方がいましたら、ぜひこちらも覗いてみてください!