Hugoには、1つのソースコードを使い回すパーシャルテンプレート機能があります。
この記事ではパーシャルテンプレート機能について解説します。

パーシャルテンプレートとは?

Hugoでテーマを開発していると、同じソースコードが複数箇所に何回も現れます。
このソースコードを1つにまとめて管理をしやすくするという考えが「パーシャルテンプレート機能」です。
プログラミングの言葉を借りると「関数」や「メソッド」です。

Hugoは、一切のパーシャルテンプレートを使用することなくテーマを開発することが可能です。
ですが、DRYの原則(=Don’t Repeat Yourself)の観点から、パーシャルテンプレートを使用しないことはおすすめしません。

パーシャルテンプレートの保存場所

パーシャルテンプレートは、layouts/partialsディレクトリに保存したHTMLファイルがパーシャルテンプレートとしてみなされます。
また、テーマのパーシャルテンプレートはサイトディレクトリから上書きできます。

従って、パーシャルテンプレートの検索順序は次の通りです。

  1. サイトディレクトリ/layouts/partials/
  2. サイトディレクトリ/テーマフォルダー/テーマ名/layouts/partials/

パーシャルテンプレートの使い方

パーシャルテンプレートの概要が終わったので、次は使い方です。
パーシャルテンプレートの使い方は非常に簡単で、まさに関数やメソッドと同じ感覚で使うことができます。

パーシャルテンプレートの定義

先ほど解説したlayouts/partialsディレクトリにHTMLファイルを作成します。
これが自動的にパーシャルテンプレートとして使用されます。
HTMLファイルには、呼び出されたときに実行したい処理を書いておきます。

後々解説しますが、パーシャルテンプレートには引数が使用できます。
また、パーシャルテンプレートから呼び出し元に返り値を返すことができます。

パーシャルテンプレートを呼び出す

パーシャルテンプレートは、定義しただけでは機能しません。 呼び出されて初めてテンプレートとして機能します。

{{ partial "<PATH>/<TEMPLATE-NAME>.html" . }}
  • <PATH>には、layouts/partialsディレクトリからの絶対パスを指定します。
  • <TEMPLATE-NAME>には、呼び出したいテンプレート名を指定します。

パーシャルテンプレートの引数機能

パーシャルテンプレートには引数機能があります。
<TEMPLATE-NAME>の後ろに渡したい引数を1つだけ指定することができます。
なお、渡せる引数は1つだけですが、渡せる引数に制限は無いため何でも渡すことができる

現在のページ情報(Page構造体)を渡す
{{ partial "<PATH>/<TEMPLATE-NAME>.html" . }}

文字列Veilnuiを引数として渡す
{{ partial "<PATH>/<TEMPLATE-NAME>.html" "Veilnui" }}

浮動小数点数3.14を引数として渡す
{{ partial "<PATH>/<TEMPLATE-NAME>.html" 3.14 }}

スライスを引数として渡す
{{ partial "<PATH>/<TEMPLATE-NAME>.html" (slice "one" "two") }}

マップを引数として渡す
{{ partial "<PATH>/<TEMPLATE-NAME>.html" (dict "one" 1 "two" 2) }}

パーシャルテンプレート内では、デフォルトでPage変数やSite変数を参照できません。
そのためパーシャルテンプレート内で、Page変数やSite変数を参照したい場合は、現在のPage構造体を渡してあげる必要があります。

現在のページ情報(Page構造体)を渡す(再掲)
{{ partial "<PATH>/<TEMPLATE-NAME>.html" . }}

パーシャルテンプレート側で渡された引数を使用する

パーシャルテンプレートで、渡された引数を使用したいときは、ドットで取得できます。

引数を使用したいときは、ドットで取得する
{{ . }}

パーシャルテンプレートに複数の値を渡すには?

パーシャルテンプレートに指定できる引数は1つだけです。
ですが、スライスまたはマップを使用することで複数の引数を渡すことができます。

スライスとして2つの値を渡す(再掲)
{{ partial "<PATH>/<TEMPLATE-NAME>.html" (slice "one" "two") }}

マップとして2つの値を渡す(再掲)
{{ partial "<PATH>/<TEMPLATE-NAME>.html" (dict "one" 1 "two" 2) }}

パーシャルテンプレート側で引数を使用するときは、少しコツが必要です。
これは、渡された引数がスライスやマップだから、ドットを参照するとスライスやマップ自体を取得してしまうからです。

ドットだと渡されたスライスやマップ自体を取得してしまう
{{ . }}

マップの場合は、キーを指定すると各値を取得できます。

呼び出し側
{{ partial "<PATH>/<TEMPLATE-NAME>.html" (dict "one" 1 "two" 2) }}

パーシャルテンプレート側

ドットでマップ自体を取得する
{{ . }}    => map[ one: 1, two: 2 ]
キーを指定すると、個別の値を取得する
{{ .one }} => 1
{{ .two }} => 2

スライスの場合は少し面倒です。
キーが無いため、index関数を使用して各値を取得します。

呼び出し側
{{ partial "<PATH>/<TEMPLATE-NAME>.html" (slice "one" "two") }}

パーシャルテンプレート側

ドットでスライス自体を取得する
{{ . }}    => slice[ "one" "two" ]
index関数で個別の値を取得する
{{ index . 1 }} => 1
{{ index . 2 }} => 2

パーシャルテンプレートから値を返す

パーシャルテンプレートから呼び出し元に値を返すことができます。

{{ return <VALUE> }}
  • <VALUE>には、返したい値を指定します。
  • return関数は1つのテンプレートにつき1つだけです。
文字列Veilnuiを返り値として返す
{{ return "Veilnui" }}

浮動小数点数3.14を返り値として返す
{{ return 3.14 }}

スライスを返り値として返す
{{ return (slice "one" "two") }}

マップを返り値として返す
{{ return (dict "one" 1 "two" 2) }}

呼び出し元では、テンプレートの呼び出し部分をそのまま返り値として使用できます。

変数に代入する
{{ $value := partial "<PATH>/<TEMPLATE>.html" . }}

そのまま演算に使用する
{{ print 10 (partial "<PATH>/<TEMPLATE>.html" . ) }}

return関数の注意点

返り値を返せるreturn関数ですが、1つだけ注意点があります。
それは1つのパーシャルテンプレートで使用できるreturn関数は1つだけということです。
そのため、条件分岐などと併用する際は注意が必要です。

return関数が2つあるため、エラーになる。
{{ if $value }}
  {{ return "真です" }}
{{ else }}
  {{ return "偽です" }}
{{ end }}
変数を媒介してreturn関数を1つにすれば、エラーにはならない
{{ $result := "" }}
{{ if $value }}
  {{ $result = "真です" }}
{{ else }}
  {{ $result = "偽です" }}
{{ end }}
{{ return $result}}

インラインパーシャルテンプレート機能

Hugoには、テンプレートファイル内で定義できる「インラインパーシャルテンプレート機能」があります。
通常のパーシャルテンプレートはlayouts/partialsディレクトリ内に定義しますが、こちらは、テンプレートファイル内で定義をします。
定義する場所が違うことを除けば、他は通常のパーシャルテンプレートと同一です。

インラインパーシャルテンプレートを定義する

テンプレートファイル内に定義します。 もちろん、パーシャルテンプレート内に定義することもできます。

{{ define "partials/<TEMPLATE-NAME>" }}
呼び出したときの処理
{{ end }}
  • <TEMPLATE-NAME>には、パーシャルテンプレート名を指定します。
  • 通常のパーシャルテンプレートと名前が衝突しないようにしてください。

インラインパーシャルテンプレートを呼び出す

呼び出しは、通常のパーシャルテンプレート呼び出しと同一です。

{{ partial "<PATH>/<TEMPLATE-NAME>.html" . }}
  • <PATH>には、layouts/partialsディレクトリからの絶対パスを指定します。
  • <TEMPLATE-NAME>には、呼び出したいテンプレート名を指定します。

引数の指定、返り値の指定もパーシャルテンプレートと同一です。

定義場所がlayouts/partialsディレクトリであるか、他のテンプレートファイル内であるかの違いだけです。
それ以外はすべて同じです。