Hugoで階層型カテゴリーを実現する

こんにちはnasustです。

今回はHugoで階層カテゴリー実現するテンプレートを紹介します。

Hugoはカテゴリーには対応していますが階層型ではありません。 taxonomiesという機能でタグと同じ様な感じで対応しています。

そこで階層型に対応するにはセクションとサブセクションのディレクトリ構造を利用して、階層型カテゴリーに対応します。

要するにセクション = カテゴリーの様に扱います。

例えば、post/generalというサブセクションがあればgeneralカテゴリーとして扱うようにします。post/general/sub/とあれば、generalカテゴリーの下のsubはサブカテゴリーとして扱います。

このテンプレートが表示するカテゴリーの例:

- 雑記 ( 10 )
    - 映画 (3)
    - 旅行 (4)
  
- 開発 (7)
    - Go (3)
    - JavaScript (4)
bash

さらにカテゴリーの記事数は、サブカテゴリーの記事数と自身の記事数を合計したものになります。

雑記(3)+ 映画(3)+ 旅行(4)= 雑記(10)

これを実現するには複数の以下の部分テンプレートを作成します。

  1. Sectionの階層を変数に格納する集計用テンプレート
  2. 階層構造をHTMLにレンダリングするテンプレート

集計用テンプレート

{{ $section := . }}
{{ $scratch := newScratch }}
{{ $scratch.Set "all_child_pages" $section.CurrentSection.Pages }}

{{ if len $section.Sections  }}
    {{ range .Sections }}
        {{ $current_section := . }}
        {{ $child_section_category_data := partial "function/get_all_category_pages" $current_section }}
        {{ $scratch.Add "list" (slice $child_section_category_data )  }}
    {{ end }}
    {{ if ($scratch.Get "list") }}
        {{ range ($scratch.Get "list") }}
            {{ $scratch.Add "all_child_pages" .all_child_pages }}
        {{ end }}
    {{ end }}
{{ end }}

{{ return dict "section" $section "all_child_pages" ($scratch.Get "all_child_pages")  "child_section_category_data_list" ($scratch.Get "list")  }}
html

これの引数はセクションページを渡します。 .Sectionsをrangeでループして、自分自身のテンプレートに再帰で読んでSectionの構造を変数に格納して行ってます。

変数の構造をGo言語で表すと以下の通りになります。

type section_category_data struct{
    section Page 
    all_child_pages Pages 
    child_section_category_data_list []section_category_data 
}
go

Node構造でSectionの構造になります。

HTMLレンダリングテンプレート

{{ $root_section_page := .Site.GetPage .Section }}
{{ if eq $root_section_page.Kind "section" }}
    {{ $section_category_data := partial "function/get_all_category_pages" $root_section_page }}
    {{ if $section_category_data.child_section_category_data_list }}
        <div class="m-aside-widget__category">
            {{ template "category" $section_category_data.child_section_category_data_list }}
        </div>
    {{ end }}
{{ end }}
{{ define "category" }}
    <ul class="m-aside-widget__category-list" >
        {{ range . }}
            <li class="m-aside-widget__category-list-item">
                <a class="m-aside-widget__category-list-item-link" href="{{ .section.Permalink }}">
                    <span class="m-aside-widget__category-list-link-title" >{{ .section.Title }}
                    <span class="m-aside-widget__category-list-link-count"> ({{ len .all_child_pages }}) </span>
                </a>
                {{ if .child_section_category_data_list }}
                    {{ template "category" .child_section_category_data_list }}
                {{ end }}
            </li>
        {{ end }}
    </ul>
{{ end }}
html

partial “function/get_all_category_pages”が集計用テンプレートを呼び出してSectionの構造を得ています。

後は同じ様に再帰で、リストのHTMLをレンダリングするテンプレートを記述すれば階層型カテゴリーを実現出来ます。

prevnext