Hugoで記事中に目次を挿入する方法です。方法としてはJekyllで記事中にGoogle AdSenseなどの広告コードを挿入する方法と同じで、最初のh2タグに挿入したいデータを追加して、記事内に差し込みます。

環境

  • Hugo 0.53

目次用のhtmlファイルを用意する

目次用の部分テンプレートをlayouts/partialsに作成します。

<section class="toc">
  <h2>目次</h2>
  {{ .TableOfContents }}
</section>

テンプレートファイル(single.html)の変更

テンプレートファイルの記事を表示している部分({{ .Content }}の部分)を以下のように変更します。

{{ $first_h2 := index (findRE "<h2 id.*?>" .Content 1) 0 }}
{{ .Scratch.Set "first_h2" $first_h2}}
{{ if and (.Params.toc) (.Scratch.Get "first_h2") }}
  {{ $toc_and_h2 := printf "%s\n%s" (partial "toc.html" . ) (.Scratch.Get "first_h2")}}
  {{ replace .Content (.Scratch.Get "first_h2") $toc_and_h2 | safeHTML }}
{{ else }}
  {{ .Content }}
{{ end }}

順番に説明していくとfindREで最初の見出しの開始タグを取得。findREは配列を返すので、その中から1つ目の要素を取得しています。 Hugoではif内から外の変数を参照できないので、.Scratchを使って取得したh2タグを格納します。
次に、用意しておいた目次用のhtmlファイルと最初のh2タグを結合、replaceで結合した文字列と最初のh2タグを置換して、記事の内容を出力しています。
if文では.Params.tocを条件に記述して、mdファイルのFront-matterで目次の挿入要否を切り替えれるようにしています。