Featured image of post Hugoのサイトを構造化データ(JSON-LD)に対応させる

Hugoのサイトを構造化データ(JSON-LD)に対応させる

これはなに Link to this heading

Hugoで作ったサイトをJSON-LD方式の構造化データに対応するためしたことのまとめ。

構造化データとは Link to this heading

構造化データとは、簡単に言うとウェブページの詳細をGoogleなどの検索エンジンに教えるためのデータである。 データには、たとえばタイトル、日付、記事の種類などが含まれる。

Google検索セントラルの「構造化データのマークアップの仕組み概要」 によると、構造化データの追加はGoogleに対するSEOの1つでもあるようだ。 少なくともGoogleでは、Google検索でリッチリザルトとして表示されるために、構造化データが必要である。

構造化データの形式 Link to this heading

構造化データには複数の形式がある。 Google検索セントラル によると、Googleでは下記3種類の形式がサポートされている。

  • JSON-LD(Google推奨)
  • microdata
  • RDFa

また、構造化データの中にも種類がある。 Google 検索セントラルの「Google 検索がサポートする構造化データ マークアップ」 あたりが参考になるだろう。 今回は 「Article 」 「パンくずリスト(BreadcrumbList) 」 「WebSite 」 の3つを利用する。

HugoのサイトをJSON-LD方式の構造化データに対応させる方法 Link to this heading

本記事では、Googleが推奨しているJSON-LDの形式で、Hugoのサイトを構造化データに対応させる。 流れは下記のとおりである。

  1. schema.htmlを作成する
  2. schema.htmlをサイトに埋め込む
  3. 構造化データが正常に作成されているか確認する

schema.htmlを作成する Link to this heading

layouts/partials/下にschema.htmlを作成する。

このschema.htmlに、<script type="application/ld+json">で始まる構造化データスクリプト記述を記述する。 たとえば、Google検索セントラル によると、 サイトの記事(Article)には下記の構造化データが推奨されている。

<script type="application/ld+json">
{
  "@context": "https://schema.org",
  "@type": "NewsArticle",
  "headline": "Title of a News Article",
  "image": [
    "https://example.com/photos/1x1/photo.jpg",
    "https://example.com/photos/4x3/photo.jpg",
    "https://example.com/photos/16x9/photo.jpg"
  ],
  "datePublished": "2015-02-05T08:00:00+08:00",
  "dateModified": "2015-02-05T09:20:00+08:00",
  "author": [{
    "@type": "Person",
    "name": "Jane Doe",
    "url": "https://example.com/profile/janedoe123"
  },{
    "@type": "Person",
    "name": "John Doe",
    "url": "https://example.com/profile/johndoe123"
  }]
}
</script>

これをHugoの変数 を用いて 各記事に適応できるように変更すると、次のようになる。

<script type="application/ld+json">
{
  "@context": "https://schema.org",
  "@type": "BlogPosting",
  "headline": {{ .Title }},
  "image": {{ .Page.Params.image | absURL }},
  "datePublished": {{ .PublishDate }},
  "dateModified": {{ .Lastmod }},
  "author": {
    "@type": "Person",
    "name": {{ .Site.Author.name }},
    "url": {{ .Site.Author.url }}
  }
}
</script>

ただし、下記のように記事のfront matterにtitledateimageが定義されているものとする1

記事のfront matterの例
---
title: Example
date: 2022-12-28T09:58:07+09:00
image: test/sample.webp
---

## タイトル

記事の内容

また、config.yamlに、次のようにauthorが定義されているものとする2

config.yamlの例
author:
  name: NakuRei
  url: https://twitter.com/nakurei7901

ここでさらに、記事のページにパンくずリスト(BreadcrumbList) の構造化データを加える。 Google検索セントラル によると、 パンくずリストで推奨されている構造化データは次のとおりである。

<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>

これをHugoの変数 を用いて 各記事に適応できるように変更すると、次のようになる。

<script type="application/ld+json">
{{ if .Page.Params.categories }}
{
  "@context": "https://schema.org",
  "@type": "BreadcrumbList",
  "itemListElement": [{
    "@type": "ListItem",
    "position": 1,
    "name": {{ index .Page.Params.categories 0 }},
    "item": {{ path.Join (.Site.BaseURL) ("/categories/" | relLangURL) (index .Page.Params.categories 0 | urlize) }}
  }]
}
{{ end }}
</script>

{{ if .Page.Params.categories }}で囲むことで、このパンくずリストの記述は、記事のfront matterにcategoriesが定義されているときだけ反映される。 また、下記のように複数カテゴリが記述されている場合、最初の1つだけが利用されるようにしている。

記事のfront matterの例
---
categories: [Example1, Example2]
---

これら2つの構造化データ記述をまとめると下記のようになる。

<script type="application/ld+json">
  [
    {
      "@context": "https://schema.org",
      "@type": "BlogPosting",
      "headline": {{ .Title }},
      "image": {{ .Page.Params.image | absURL }},
      "datePublished": {{ .PublishDate }},
      "dateModified": {{ .Lastmod }},
      "author": {
        "@type": "Person",
        "name": {{ .Site.Author.name }},
        "url": {{ .Site.Author.url }}
      },
    },
    {{ if .Page.Params.categories }}
    {
      "@context": "https://schema.org",
      "@type": "BreadcrumbList",
      "itemListElement": [{
        "@type": "ListItem",
        "position": 1,
        "name": {{ index .Page.Params.categories 0 }},
        "item": {{ path.Join (.Site.BaseURL) ("/categories/" | relLangURL) (index .Page.Params.categories 0 | urlize) }}
      }]
    }
    {{ end }}
  ]
</script>

ところで、上記<script>タグのままだと、記事以外のページもBlogPosting扱いになってしまう。 そのため、記事にだけBlogPostingの構造化データが適用されるように、Hugoの変数IsPageを利用する。

<script type="application/ld+json">
  [
+   {{ if .IsPage }}
    {
      "@context": "https://schema.org",
      "@type": "BlogPosting",
      "headline": {{ .Title }},
      "image": {{ .Page.Params.image | absURL }},
      "datePublished": {{ .PublishDate }},
      "dateModified": {{ .Lastmod }},
      "author": {
        "@type": "Person",
        "name": {{ .Site.Author.name }},
        "url": {{ .Site.Author.url }}
      },
    },
    {{ if .Page.Params.categories }}
    {
      "@context": "https://schema.org",
      "@type": "BreadcrumbList",
      "itemListElement": [{
        "@type": "ListItem",
        "position": 1,
        "name": {{ index .Page.Params.categories 0 }},
        "item": {{ path.Join (.Site.BaseURL) ("/categories/" | relLangURL) (index .Page.Params.categories 0 | urlize) }}
      }]
    }
    {{ end }}
+   {{ end }}
  ]
</script>

記事以外のページには、WebSite の構造化データを適用する。 Google検索セントラル によると、 WebSiteで推奨されている構造化データは下記のとおりである。

<script type="application/ld+json">
  {
    "@context" : "https://schema.org",
    "@type" : "WebSite",
    "name" : "Example",
    "url" : "https://example.com/"
  }
</script>

これをHugoの変数 を用いて 各記事に適応できるように変更すると、次のようになる。

<script type="application/ld+json">
  {
    "@context": "https://schema.org",
    "@type": "WebSite",
    "name": {{ .Site.Title }},
    "url": {{ .Site.BaseURL }},
  }
</script>

ただし、config.yamlに、次のようにtitlebaseurlが定義されているものとする3

config.yamlの例
title: Examole Site Title
baseurl: https://example.com

以上すべての構造化データをまとめると、layouts/partials/schema.htmlには下記を記述することになる。

layouts/partials/schema.html
<script type="application/ld+json">
  [
    {{ if .IsPage }}
    {
      "@context": "https://schema.org",
      "@type": "BlogPosting",
      "headline": {{ .Title }},
      "image": {{ .Page.Params.image | absURL }},
      "datePublished": {{ .PublishDate }},
      "dateModified": {{ .Lastmod }},
      "author": {
        "@type": "Person",
        "name": {{ .Site.Author.name }},
        "url": {{ .Site.Author.url }}
      }
    },
    {{ if .Page.Params.categories }}
    {
      "@context": "https://schema.org",
      "@type": "BreadcrumbList",
      "itemListElement": [{
        "@type": "ListItem",
        "position": 1,
        "name": {{ index .Page.Params.categories 0 }},
        "item": {{ path.Join (.Site.BaseURL) ("/categories/" | relLangURL) (index .Page.Params.categories 0 | urlize) }}
      }]
    },
    {{ end }}
    {{ else }}
    {
      "@context": "https://schema.org",
      "@type": "WebSite",
      "name": {{ .Site.Title }},
      "url": {{ .Site.BaseURL }}
    }
    {{ end }}
  ]
</script>

schema.htmlをサイトに埋め込む Link to this heading

つくったschema.htmlをサイトに埋め込む。 <head>タグ内か、<body>タグの下部に埋め込めばよい。

<head>
 ...
 ...
<!-- json-ld -->
    {{- partial "schema.html" . -}}
<!-- json-ld -->
</head>

筆者の使っているHugoのテーマStack では、layouts/partials/head/custom.htmlに追加したい内容を記述すれば、 <head>タグ内に自動で追記してくれる。 よって、layouts/partials/head/custom.htmlにschema.htmlを読み込む記述を書く。

layouts/partials/head/custom.html
{{- partial "schema.html" . -}}

構造化データが正常に作成されているか確認する Link to this heading

構造化データが作成されているかは、 Google 検索セントラルの構造化データ マークアップテストサイト で確認できる。

参考文献・URL Link to this heading


  1. .Title.PublishDate.Lastmod.Page.Params.imageのため。 ↩︎

  2. .Site.Author.name.Site.Author.urlのため。 ↩︎

  3. .Site.Title.Site.BaseURLのため。 ↩︎

Licensed under CC BY-NC-SA 4.0
Hugo で構築されています。
テーマ StackJimmy によって設計されています。