Hugoテンプレートのカスタマイズで工夫したこと — noindex・構造化データ・minifyハック

HugoのDocsyテーマを使いながら、SEOやテンプレートまわりで工夫した点の記録です。

テーマを直接編集しない

Docsyテーマを使っていましたが、テーマのファイルを直接編集するのは避けていました。バージョンアップのたびに手動マージが発生するからです。Docsyは更新頻度が高く、partialの構成がバージョンで変わることもあるので、直接触ると面倒が増えます。

HugoにはLookup Orderがあり、layouts/ に置いたファイルが themes/ より優先されます。上書きしたい部分だけ layouts/ に配置すれば、テーマ本体は触らなくて済みます。

この方針でやっていたカスタマイズをいくつか紹介します。

noindexの設計判断

Docsyのデフォルトでは、本番ビルド時にすべてのページに <meta name="robots" content="index, follow"> が付きます。タグ一覧やセクションページまでインデックスされるのは気持ち悪かったので、制御を入れました。

layouts/partials/head.html を上書きし、robotsのロジックだけを layouts/partials/noindex.html に分離しました。

{{ if or (eq .Params.Noindex true) (eq .Kind "section") (eq .Section "tags") }}
  <meta name="robots" content="noindex, nofollow">
{{ else }}
  {{ if hugo.IsProduction }}
  <meta name="robots" content="index, follow">
  {{ end }}
{{ end }}

ポイントは3つです。

  • FrontMatterでの個別制御: 記事単位で noindex: true を指定できる
  • セクションページの一括noindex: 記事一覧はインデックス不要と判断
  • タグページのnoindex: 自動生成のタグ一覧は内容が薄い

head.html 全体をコピーせず、robotsのロジックだけpartialに切り出しています。テーマのhead.htmlが更新されても影響を受けにくいです。

構造化データ

JSON-LD形式の構造化データを入れました。Google検索結果に公開日・更新日を出すためです。

{
  "@type": "BlogPosting",
  "datePublished": "2022-11-06T00:00:00+09:00",
  "dateModified": "2022-11-06T00:00:00+09:00"
}

Goの日付フォーマットは独特で、参照日時 2006-01-02T15:04:05 をテンプレートとして使います。最初は少し戸惑いました。

Google検索セントラルには「1つの日付要素だけに依存すると問題が生じやすい」とあるので、JSON-LDに加えて記事本文にも「YYYY年MM月DD日公開」を入れています。

minifyハック — IE Conditional Commentsの目的外利用

これは正直、ハックと呼ぶしかない対応でした。

Googleのモバイル検索結果にサムネイル画像を表示するために、PageMapデータをHTMLに埋め込む必要がありました。問題は、PageMapデータはHTMLコメント内に記述する仕様だということです。

<!--
  <PageMap>
    <DataObject type="thumbnail">
      <Attribute name="src" value="https://example.com/image.jpg"/>
    </DataObject>
  </PageMap>
-->

ところが hugo --minify を使うとHTMLコメントがすべて消えます。minify全体を無効にするのも嫌なので、別の方法を探しました。

Hugoが内部で使っているminifyライブラリ(tdewolff/minify)に keepConditionalComments: true というオプションがありました。IE Conditional Commentsだけは残す設定です。

IE Conditional Commentsの [if true](常にtrue)を使えば、minify有効のままコメントを残せます。

{{"<!--[if true]>" | safeHTML}}
  <PageMap>
    <DataObject type="thumbnail">
      <Attribute name="src" value="{{ $metaThumbnailImage | absURL }}"/>
    </DataObject>
  </PageMap>
{{"<![endif]-->" | safeHTML}}

IEのサポートは終了しているので実害はありません。ただ、Googleのクローラーがこの形式を正しく解釈する保証もないので、 <meta name="thumbnail"> タグとの併用を前提にしています。

まとめ

Lookup Orderを使ってテーマ本体に手を入れない方針にしておくと、テーマ更新が楽です。minifyハックは力技でしたが、ライブラリの実装を読んで回避策を逆引きするアプローチ自体は割と汎用的でした。

Related Posts