作ったものとか » Hugo テーマ

Hugo テーマ 4. layouts/page.html をいじる

2026-06-15 00:11:30 Hugo
最終更新日から %s 以上が経過しています。
内容が古くなっている可能性があるのでご注意ください。

コンテンツに対応するページのレイアウトを編集します。

どのように進めるか

このサイト向けのテーマとしての実装を題材にして、レイアウト定義の内容を掲載しながら解説します。 その中で使った情報源へのリンクも適宜、掲載します。

Go 言語のテンプレートの詳細には触れませんが、あまり慣れていない方が見たときにつまづきそうなところには補足説明を入れます。

このレイアウトの方針

layouts/page.html は、コンテンツページのレイアウトを定義します。

このサイトでは以下の要素を組み込みます。

page.html

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
{{ define "main" }}
  <h1>{{ .Title }}</h1>

  {{/* コンテンツの最終更新日時とタグ */}}
  <span class="lastmod">{{ .Lastmod.Format "2006-01-02 15:04:05" }}</span>
  {{ with .GetTerms "tags" }}
    {{ range . }}
      <span class="tag"><a href="{{ .RelPermalink  }}">{{ .LinkTitle }}</a></span>
    {{ end }}
  {{ end }}

  {{/* 表示期限切れの警告 */}}
  {{/* あらかじめプロジェクトの [params.derty] 内に以下の if で使っているパラメーターを設定しておく */}}
  {{ if and .Site.Params.derty.outdatedUnit .Site.Params.derty.outdatedLimit }}
    {{/* 最終的な表示は js にまかせる */}}
    <div class="may_be_outdated" derty-outdated-since="{{ .Lastmod.Format "2006-01-02T15:04:05Z07:00" }}" derty-outdated-limit="{{ .Site.Params.derty.outdatedLimit }}" derty-outdated-limit-unit="{{ .Site.Params.derty.outdatedUnit }}">{{ .Site.Params.derty.outdatedMessageHTML | default  "最終更新日から %s 以上が経過しています。<br/>内容が古くなっている可能性があるのでご注意ください。" | safeHTML }}</div>
  {{ end }}

  {{ .Content }}

  {{ partial "pagenav.html" . }}
{{ end }}
{{/* vim: set et ft=html sts=2 sw=2 ts=2 : */}}

現在注目している対象 … コンテキスト

{{ .Lastmod.Format ... }} の部分ですが、. から始まる記述は「現在注目している対象が持っている情報を取得する」ということを意味しています。
page.html はコンテンツのページをひとつピックアップしてそれを HTML に変換する際のレイアウト定義をしているので、現在注目している対象というのは、コンテンツのページです。

Note

「現在注目している対象」などと表現していますが、これはコンテキスト (Introduction to templating / Context ) と呼ばれる概念です。

ちなみに、取得できる情報については、Page に説明があります。

たとえば Lastmod は “Returns the last modification date of the given page.” となっています。
該当のページ Lastmod には、レイアウト定義内での記述の仕方に加えて、設定ファイルやコンテンツのフロントマター (いずれもこのテーマを利用するプロジェクト側) の説明があります。

with や range の中では現在注目している対象 (コンテキスト) が変わる

どういうことかというと、上のように {{ .Lastmod ... }} で情報を取得しようとしている対象と、{{ .RelParmalink }} で情報を取得している対象は別物、ということです。

{{ with .GetTerms "tags" }} から、同じインデントの {{ end }} までの間で、2回、現在注目している対象が切り替わっています。

現在注目している対象が切り替わっているため、. から始まる記述で取得できる情報の種類が変わります。
具体的には、上記の切り替わりに応じて以下のようになります。

Tip

{{ range . }} の中でコンテンツページの情報が欲しくなった場合は {{ $.Title }} のように記述します。
ほかには、外側で変数を定義してそれに格納しておくというやり方もあります。

表示期限切れの警告

普段は表示しないものの、コンテンツの最終更新日時が一定の期間を過ぎた場合に「この記事は古いのでご注意ください」といった表示をしようとしています。

コード (見かえしたい場合はここをクリックして、見たらまた戻ってきてください)

if and A B という記述について

複数のパラメーターに値が設定されている場合の判断分岐を {{ if and ... }} の部分でしています。

if のシンプルな記述は {{ if CONDITION }} ... {{ end }} です。 (CONDITION には真偽値になるような式が来る)

and はテンプレートの文法 (レイアウト定義として記述できるもの) としては関数という扱いです。
関数は 関数名 引数1 引数2 ... という記述で呼び出すことになります。
そのため、複数の結果をもとに if で判断する場合の記述は if and A B となります。

サイトの設定からパラメーターを取得する方法

まず、テーマ作成側としては…これは上記のコード のとおりです。

{{ .Site.Params.derty.outdatedUnit }} と記述した場合、このテーマを利用するプロジェクトの設定ファイル (config.toml 等) には以下のように記述します。

[params]
  [params.derty]
    outdatedUnit = (省略)

テーマの README には設定について説明しておきましょう

利用に対し、そのような機能があることを伝達しましょう。

partial を使った layouts/_partials 内の定義の利用

{{ partial "pagenav.html" . }} という記述について。

"pagenav.html" の部分で、layouts/_partials/pagenav.html を参照しています。

おしりの . は、上で触れた「現在注目している対象」を意味します。
ここはコンテンツページでしたね。
pagenav.html ではコンテンツページに応じた内容を出力したいので、引数2として . を渡しているわけです。

_partials/pagenav.html

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
{{/* セクション内の前後のコンテンツページ */}}
{{/* <前ページ  次ページ> */}}

{{ if or .PrevInSection .NextInSection }}
  {{ $prev := .PrevInSection }}
  {{ $next := .NextInSection }}

  {{/*
    シリーズものを扱うセクションの場合、セクションでの一覧と同じ基準で前後のページを決める。
    section.html も参照のこと。

    通常: <過去のページ  未来のページ>
    シリーズ: <最初の方のページ  最新の方のページ>
  */}}
  {{ if .CurrentSection.Params.series }}
    {{ $pages := .CurrentSection.Pages.ByTitle }}
    {{ $prev = $pages.Next . }}
    {{ $next = $pages.Prev . }}
  {{ end }}

  <div class="pagenav">
    <div class="pagenav_prev">
      {{ if $prev }}
        <a href="{{ $prev.Permalink }}">&laquo; {{ $prev.Title }} &laquo;</a>
      {{ end }}
    </div>
    <div class="pagenav_next">
      {{ if $next }}
        <a href="{{ $next.Permalink }}">&raquo; {{ $next.Title }} &raquo;</a>
      {{ end }}
    </div>
  </div>
{{ end }}
{{/* vim: set et ft=html sts=2 sw=2 ts=2 : */}}

ここでの . は、参照元の . と同じ

page.htmlpagenav.html の呼び出しをしていることについて解説しましたが、そこでの引数2 (.) がこのレイアウト定義にも引き継がれます。

セクション内の前後のコンテンツへのナビゲーション

このサイトはセクションごとに独立した話題のコンテンツを公開するサイトといえるので、関連するコンテンツとして、特にセクション内のコンテンツから前後にくるものを指定して表示するようにしています。

変数の利用

前後それぞれのコンテンツページを取得し変数に代入しています。場合に応じてナビゲーションの内容を変えるためです。
HTML の部分を複雑にすることを避けるため、その手前で条件分岐し変数に代入し、 HTML の部分では適切に代入されている変数の値を参照する形にしました。

変数に代入する場合も参照する場合も、$prev のように変数名の頭に $ を付けます。

出力結果の比較 (画像)

もともと変更後