Hugoでmicrodata形式のパンくずリストを出力する

Hugoでパンくずリストをmicrodata形式で出力するpartialテンプレートを作成しました。

はじめに

パンくずリストはサイトの利用者のために現在のページの位置を分かりやすくするため設置するものと考えていましたが、構造化されたデータ形式で記述することでクローラなどのプログラムにとっても理解できるようにすることができると知りました。

このブログに設定していたパンくずリストは構造化されたデータ形式ではなかったので、構造化データ形式で出力するように変更しました。

microdata形式について

まず構造化データ形式について調べたことを記載します。

構造化データを追加することでクローラがそのページを理解ための情報をページに追加することができます。

たとえば構造化されたパンくずリストをページに追加した場合、Google検索の検索結果にそのページがサイト階層内のどこに位置するかを示すリストが表示されます。

Google検索結果のパンくずリスト

その他のGoogleの検索結果で表示される構造化されたデータはGoogle Developersの構造化データの仕組みについてに一覧があります。

以下に構造化データ形式についての概要をまとめました。

JSON-LD形式(推奨)
JSON形式でtype属性にapplication/ld+jsonを指定した<script>要素に記述します。HTMLの要素に属性などで記述する他の形式よりも表現できることが多く推奨されている形式です。
RDFa形式
HTMLの要素の属性を利用して構造化データを定義します。構造化データのマークアップにはitemscopeitempropなどの属性を使用します。オープンコミュニティのHTML仕様です。
microdata形式
HTMLの要素の属性を利用して構造化データを定義します。構造化データのマークアップにはvocabtypeofpropertyresourceprefixの属性を使用します。HTML5の拡張機能です。

それぞれの仕様の公式のページは以下です。

JSON-LD形式が推奨となっていますが、今回は以下のようなmicrodata形式の構造化データのパンくずリストを作成します。

<ol itemscope
    itemtype="https://schema.org/BreadcrumbList">
  <li itemprop="itemListElement" itemscope
      itemtype="https://schema.org/ListItem">
    <a itemprop="item" href="https://example.com/">
      <span itemprop="name">トップ</span>
    </a>
    <meta itemprop="position" content="1" />
  </li>
  <li itemprop="itemListElement" itemscope
      itemtype="https://schema.org/ListItem">
    <a itemprop="item" href="https://example.com/section1/">
      <span itemprop="name">セクション1</span>
    </a>
    <meta itemprop="position" content="2" />
  </li>
  ...
</ol>

microdata形式ではitemscope属性を指定した要素が1つのアイテムの範囲になりitemtype属性にその構造化データのタイプを指定します。

パンくずリストの構造化データのルートはitemtypeBreadcrumbListのスキーマを指定した要素になります。その中でパンくずリストのアイテムとなるページをそれぞれ定義していきます。

パンくずリストの構造化されたデータのイメージは以下になります。

  • BreadcrumbList
    • ListItem
      • item = https://example.com/
      • name = トップ
      • position = 1
    • ListItem
      • item = https://example.com/section1/
      • name = セクション1
      • position = 2

パンくずリストの構造化データのスキーマの定義はBreadcrumbList - Schema.org Typeにあります。

microdata形式のパンくずリストを出力

それではmicrodata形式のパンくずリストを出力するpartialテンプレートを作成します。

今回は以下のルールでパンくずリストを作成します。

  • パンくずリストにリンクが1つしかない場合はパンくずリスト自体を出力しない
  • パンくずリストには一覧やセクションのページのリンクのみを表示する

microdata形式のパンくずリストでは上位の階層のページから順番にそのページの位置をposition属性に設定します。そのためトップページから現在のページまでのパンくずリストとなるページの一覧を取得してからリストのページを出力するようにしました。

layouts/partials/breadcrumb.html
{{- $pages := partial "partials/breadcrumb/__fn__pages" . -}}
{{- if ge (len $pages) 2 -}}
<nav id="breadcrumb">
  <ul itemscope itemtype="https://schema.org/BreadcrumbList">
    {{- range $i, $page := $pages }}
    <li itemprop="itemListElement"
        itemscope itemtype="https://schema.org/ListItem">
      <a itemprop="item"
         href="{{ $page.Permalink | relURL }}"
         title="{{ $page.LinkTitle }}">
        <span itemprop="name">{{- $page.LinkTitle -}}</span>
      </a>
      <meta itemprop="position" content="{{ add $i 1 }}" />
    </li>
    {{- end }}
  </ul>
</nav>
{{- end -}}

{{/*
  関数として利用するインラインのpartial
  トップページからのページ一覧を取得(レギュラーページは除外)
*/}}
{{- define "partials/breadcrumb/__fn__pages" -}}
  {{- $pages := slice -}} 
  {{- with .Parent -}}
    {{- $pages = partial "partials/breadcrumb/__fn__pages" . -}}
  {{- end -}}
  {{/* レギュラーページは除外 */}}
  {{- if .IsNode -}}
    {{- $pages = $pages | append . -}} 
  {{- end -}}
  {{- return $pages -}}
{{- end -}}

このパンくずリストを出力するpartialテンプレートは以下のように利用します。

{{- partial "breadcrumb" . -}}

つづいてpartialテンプレートの内容について説明していきます。

パンくずリストのページの一覧はインラインで定義しているpartials/breadcrumb/__fn__pagesから関数のように値を返すことで取得しています。

{{- define "partials/breadcrumb/__fn__pages" -}}
  {{/* ページの一覧を取得 ... */}}
  {{- return $pages -}}
{{- end -}}

引数のページにParentがある場合は自分自身にPatentを渡して呼び出すことで1つ上の階層までのページの一覧を取得して、そのページの一覧の末尾に引数のページを追加しています。

またパンくずリストには一覧やセクションのページのリンクのみを表示するようにするため、引数のページがIsNodeの場合にのみページ一覧に追加するようにしました。

{{- with .Parent -}}
  {{- $pages = partial "partials/breadcrumb/__fn__pages" . -}}
{{- end -}}
{{- if .IsNode -}}
  {{- $pages = $pages | append . -}} 
{{- end -}}

パンくずリストを出力するpartialテンプレートの本体側ではこのインラインで定義したpartials/breadcrumb/__fn__pagesに現在のページを渡して実行することでページの一覧を取得します。

{{- $pages := partial "partials/breadcrumb/__fn__pages" . -}}
{{- if ge (len $pages) 2 -}}
  {{/* パンくずリストを出力する処理 ... */}
{{- end -}}

ページの一覧の件数のチェックを行っているのは、パンくずリストにリンクが1つしかない場合はパンくずリスト自体を出力しないようにするためです。

構造化データのマークアップのテスト

正しく構造化データのマークアップができているかの検証はGoogleのリッチリザルト テストのページで行うことができます。

「コード」を選択すると表示されるテキストエリアにパンくずリストのHTMLを貼り付けて「コードをテスト」ボタンをクリックします。

リッチリザルトテストにコードを貼り付け

正しく構造化データのマークアップができている場合、テスト結果に「有効なアイテムを検出しました」が表示されます。

リッチリザルトテストの結果(成功時)

テスト結果がエラーとなった場合はエラーの詳細を確認することができるので修正もしやすいです。

リッチリザルトテストの結果(エラー時)

おわりに

ページに構造化データを追加することでクローラなどにそのページの追加の情報を伝えることができます。

Hugoのテンプレートではpartialから関数のように値を返すことができます。これはとても便利なので使わない手は無いと思います。

microdata形式の構造化データの場合はページの表示に必要ではないタグを追加する必要があるので、推奨されているJSON-LD形式を採用するほうがいいと思います。