Hugo で schema.org (JSON-LD) を自動生成するスクリプト
Google の検索結果をリッチにするためのマークアップについて、FAQpage 形式のリッチリザルトを JavaScript で動的に生成する方法として以下の記事を執筆しました。
この記事では、以下の記事の技術情報を前提に Hugo で実装する場合の手法について補足説明します。
派生元の記事。Hugo を使わずに JSON-LD を生成する場合はこちら。構造化データについても説明しています。
解決策のコード
// HTML ドキュメントの読み込みを待つトリガー
window.addEventListener("DOMContentLoaded", () => {
// JSON-LD 形式の Schema を生成する処理の開始
createFaqSchema();
});
function createFaqSchema() {
// 質問情報のあるセクションを抽出
let questions = document.querySelectorAll(".question-section");
if (!questions.length) {
// 質問に関するコンテンツがなかった場合は処理を終了
return false;
}
// 質問と回答のセットを格納するための変数。つまりセットはいくつあってもよい。
const entities = [];
questions.forEach((section) => {
// 質問そのものの抽出
let question = section.querySelector(".question").innerText;
// 回答そのものの抽出
let answer = section.querySelector(".answer").innerHTML.trim();
entities.push(createQuestionEntity(question, answer));
});
const schemaBody = {
"@context": "https://schema.org",
"@type": "FAQPage",
mainEntity: entities,
};
createSchemaElement(JSON.stringify(schemaBody));
}
// <head> タグ内に <script> タグを生成する
function createSchemaElement(structuredDataText) {
const script = document.createElement("script");
script.setAttribute("type", "application/ld+json");
script.textContent = structuredDataText;
document.head.appendChild(script);
}
function createQuestionEntity(question, answer) {
if (!question) {
return false;
}
if (!answer) {
return false;
}
return {
"@type": "Question",
name: `${question}`,
acceptedAnswer: {
"@type": "Answer",
text: `${answer}`,
},
};
}
layouts/shortcodes/faq.html
として保存していること。
{{- $title := .Get "title" -}}
<div class="question-section">
<span class="question">{{ $title }}</span>
<div class="answer">
{{ .Inner | markdownify }}
</div>
</div>
呼び出し方
{{<faq title="インターネットとはなんですか?">}}
インターネットは、世界中のコンピュータなどの情報機器を接続するネットワークです。
{{</faq>}}
<!-- 注!カッコは全角になっているので利用の際は半角にすること -->
Hugo におけるFAQ形式の構造化表現の悩み
Hugo は静的サイトジェネレーターですので、記事にあたるマークダウンファイルの中身はただのテキストにすぎません。そのため、記事の本文からFAQ部分を抽出して慈善にJSON-LDを生成することは難しそうでした。
Data template を使えば他にもやりようはありそうですが、記事そのものとFAQのファイルが分離されてしまうのは管理上面倒くさいです。
他にも、Front Matter に書いてしまう方法も議論されています(下記リンク)。これなら同一ファイルでコンテンツとFAQを集約できるものの、Front Matter にコンテンツのテキスト(場合によっては長文)を記載するのも、いまいち直感的ではありませんでした。
- How to use front matter parameter that contains markdown or HTML and turn it into HTML in partials? - support - HUGO
- https://discourse.gohugo.io/t/how-to-use-front-matter-parameter-that-contains-markdown-or-html-and-turn-it-into-html-in-partials/36020/15
確かに、この方法でも動かすことはできました。
このコンテンツ管理で特にに違和感がない場合は、確実に静的ページとして慈善ビルドが行えるこの方法の方がよいかと思います。ただしその場合、Front Matter に記載したFAQコンテンツを記事本文に表示するための partial テンプレートが別途必要になるかと思います。
今回の選択においては、「マークダウンファイルに記事を書いている形そのままでHTMLを生成したい」という要件に主軸をおいたため、JavaScript での動的生成の方式に落ち着きました。