Hugo を使った個人サイトの作り方 10 タグ、カテゴリ用ページの作成 List TemplateとTerms Templage、Paging

Hugo アイキャッチ画像

前回はHugoの分類機能(Taxonomy)を解説し、個別の記事ページにタグ、カテゴリ、シリーズを設定しました。今回はこれらを概観するためのリストページなどの体裁を整えていくことにします。

Taxonomy Terms Template

ようするにタグ一覧、カテゴリ一覧のページです。当サイトの例は何も特別なことをしておらず、リンク切れよりマシという有様ですが、リンク切れよりはマシなので体裁を整えたいと思います。タグ一覧、カテゴリ一覧のページはTerms Templateとして特別扱いされています。

./themes/Museum/layouts/_default/terms.html
 1<!DOCTYPE html>
 2<html lang="{{.Site.LanguageCode}}">
 3    {{- partial "head.html" . -}}
 4    <body>
 5    {{- partial "header.html" . -}}
 6    <main>
 7{{ if eq .Title "Tags"}}
 8    <h1>タグ一覧</h1>
 9    <ul class="terms">
10        {{ range .Site.Taxonomies.tags.ByCount }}
11        <li><a href="{{ "./tags/" | relURL }}{{ .Name | urlize }}">{{ .Name }}({{ .Count }})</a></li>
12        {{ end }}
13    </ul>
14{{ else if eq .Title "Categories"}}
15    <h1>カテゴリ</h1>
16    <ul class="terms">
17        {{ range .Site.Taxonomies.categories.ByCount }}
18        <li><a href="{{ "./categories/" | relURL }}{{ .Name | urlize }}">{{ .Name }}({{ .Count }})</a></li>
19        {{ end }}
20    </ul>
21{{- end }}
22    </main>
23     <div class="local_navi">
24      <ol class="breadcrumb">
25       {{- template "breadcrumb" (dict "node" . "start" .) }}
26      </ol>
27     </div><!-- div.local_navi end -->
28{{- partial "footer.html" . -}}
29    </body>
30</html>

やっていることは.Title変数でカテゴリとタグを読み分け、リスト出力しているだけです。ただし、このページは検索エンジンに引っかかってほしくないので、普段は入れていないメタタグを組み込むため、Head要素を規定しているpartialテンプレートに記述を追加します。

{{ if eq .Type "tags" }}
 <meta name="robots" content="noindex,nofollow">
 <meta name="robots" content="noarchive">
 {{ end }}

出たー! 同人腐女子の宗教、検索避けのまじないだぞーーーー!大文字がいいとか違うとかルートでなくてもrobot.txtを置くのがいいとか本当におまじないじみたところがありましたね。今は表示してほしくても拾われなくなってたりしますがw トラブルを避けるという意味では有用でしょうか。

Taxonomy List Template

タグやカテゴリに紐づけられた中身のページのリストは、List Templateで表示されます。分かりづらいですね~。一体どの部分だ?と思う方もいらっしゃるので例をあげると

これらをそれぞれ場合分けしてテンプレートを作成することも可能です(HUGO のテンプレートファイルの優先順位を理解する - ひよこまめ)が、当サイトでは一括したデザインで手抜きしています。

第六回で固定ページを作成する際に、List Templateの条件分けを行いました。今回はリスト表示部分の詳細を見ていこうと思います。

 1<main>
 2<h1>{{ .Title }}</h1>
 3{{ range .Paginator.Pages }}
 4 <article class="listingarticles">
 5  <h2><a href="{{- .Permalink }}">{{.Title}}</a></h2>
 6  <div class="post-meta">
 7   <p>
 8   <time pubdate="{{ .Date.Format "2006-01-02" }}">{{ .Date.Format "2006-01-02" }}</time>
 9    {{- partial "coloredcategories.html" . }}
10   {{- if .Params.tags }}
11    {{ with .Params.tags }}<i class="fa-solid fa-tag"></i>{{ range . }} <a href="/tags/{{ lower . }}/" class="tags tag-{{ . }}">#{{ . }}</a>{{ end }}{{ end }}
12   {{- end }}
13   </p>
14{{- $readTime := mul (div (countwords .Content) 540.0) 60 -}}
15{{- $minutes := math.Floor (div $readTime 60) -}}
16{{- $seconds := mod $readTime 60 -}}
17   <p>
18{{ countwords .Content -}}字:読了まで約
19{{- if gt $minutes 0 -}}{{ $minutes }}{{- end -}}
20{{- if gt $seconds 0 -}}{{ $seconds }}{{- end -}}
21   </p>
22  </div><!-- post-meta -->
23  <p>{{ .Summary | plainify | htmlUnescape }}{{ if .Truncated }}...{{ end }}</p
24</article>
25{{ end }}
26 <nav id="Paging">
27{{ template "_internal/pagination.html" . }}
28 </nav>
29 </main>

ここでの注意点はタグ一覧のリンクURLを{{ lower . }}としていることでしょうか。Hugoはタグには小文字でしかアクセスできないので丸めています。そしてリンクにはタグ名のクラスを付加し、装飾できるようにしています。

ページング

リストページですので、ページングが必要です。Hugoにはページ送り機能が自動で備わっています。自前で実装することもできるようですが、そんなにこだわりがないので、標準機能を利用しようと思います。

具体的な手順は

  1. サイト設定ファイル(hugo.toml)でページ送りの件数を設定する
  2. ページ送りしたい部分を定義する
  3. ページ送りナビゲーションを挿入する

となります。

1.ページ送りの件数を設定する

hugo.tomlにて、以下のように設定できます。

paginate
ページ送りする場合、1ページあたりの表示件数。デフォルトは10
paginatePath
ページネーションの際に使われるパス要素 (https://example.com/page/2) デフォルトはpage

デフォルトで構わないのでとくに記述しませんでした。

2.ページ送りしたい部分を定義する

.Paginator.Pages で呼び出してやればいいです。現在のページを含んで、設定ファイルで指定された件数分の要素を繰り返し、自動でページ送り用に分割されます。

上記の例の場合、<article class="listingarticles"> の内部を10件ずつ繰り返していきます。 繰り返し部分については、タイトルから記事にリンクできるようにし、投稿日を出力、色分けカテゴリとタグを列挙して、読了時間もつけたのちに、概要を出力しています。これだけあれば情報は充分かな。

3.ページ送りナビゲーションを挿入する

Hugoの内部組み込みテンプレートを読み込みます。該当箇所に{{ template "_internal/pagination.html" . }} と書けばOK。ただし、出力HTMLなどをカスタマイズする場合は自前で実装しなければなりません。

出力HTMLは以下のようになっています! Pagination - Bootstrap 4.5 - 日本語リファレンスの様式らしいので、Bootstrapを参考にすればCSSの装飾もはかどりそうです。

 1<ul class="pagination pagination-default">
 2  <li class="page-item disabled">
 3  <a aria-disabled="true" aria-label="First" class="page-link" role="button" tabindex="-1"><span aria-hidden="true">&laquo;&laquo;</span></a>
 4  </li>
 5  <li class="page-item disabled">
 6   <a aria-disabled="true" aria-label="Previous" class="page-link" role="button" tabindex="-1"><span aria-hidden="true">&laquo;</span></a>
 7  </li>
 8  <li class="page-item active">
 9   <a aria-current="page" aria-label="Page 1" class="page-link" role="button">1</a>
10  </li>
11  <li class="page-item">
12   <a href="../essay/page/2/" aria-label="Page 2" class="page-link" role="button">2</a>
13  </li>
14  <li class="page-item">
15   <a href="../essay/page/2/" aria-label="Next" class="page-link" role="button"><span aria-hidden="true">&raquo;</span></a>
16    </li>
17  <li class="page-item">
18   <a href="../essay/page/2/" aria-label="Last" class="page-link" role="button"><span aria-hidden="true">&raquo;&raquo;</span></a>
19   </li>
20</ul>

追記のCSSでのデザインは次のようになります。

ページャーのデザイン[paginglistpreview.png(4281byte)]

CSSはほとんど参考サイトと同じですが以下です。長いね……

 1------------------------------------
 2 Pagination
 3------------------------------------ */
 4.pagination {
 5  display: inline-block;
 6  padding-left: 0;
 7  margin: 20px 0;
 8  border-radius: 4px;
 9}
10.pagination > li {
11  display: inline;
12}
13.pagination > li > a,
14.pagination > li > span {
15  position: relative;
16  float: left;
17  padding: 6px 12px;
18  margin-left: -1px;
19  line-height: 1.42857143;
20  color: #337ab7;
21  text-decoration: none;
22  background-color: #fff;
23  border: 1px solid #ddd;
24}
25.pagination > li:first-child > a,
26.pagination > li:first-child > span {
27  margin-left: 0;
28  border-top-left-radius: 4px;
29  border-bottom-left-radius: 4px;
30}
31.pagination > li:last-child > a,
32.pagination > li:last-child > span {
33  border-top-right-radius: 4px;
34  border-bottom-right-radius: 4px;
35}
36.pagination > li > a:hover,
37.pagination > li > span:hover,
38.pagination > li > a:focus,
39.pagination > li > span:focus {
40  z-index: 2;
41  color: #23527c;
42  background-color: #eee;
43  border-color: #ddd;
44}
45.pagination > .active > a,
46.pagination > .active > span,
47.pagination > .active > a:hover,
48.pagination > .active > span:hover,
49.pagination > .active > a:focus,
50.pagination > .active > span:focus {
51  z-index: 3;
52  color: #fff;
53  cursor: default;
54  background-color: #e37560;
55  border-color: #e37560;
56}
57.pagination > .disabled > span,
58.pagination > .disabled > span:hover,
59.pagination > .disabled > span:focus,
60.pagination > .disabled > a,
61.pagination > .disabled > a:hover,
62.pagination > .disabled > a:focus {
63  color: #777;
64  cursor: not-allowed;
65  background-color: #fff;
66  border-color: #ddd;
67}

次回はOGP、ツイッターカード、faviconなどの外部へのアピール機能の設定を行います。