Hugoテンプレートとショートコード

最終更新: 2025-10-30 09:45:02 +0800 +0800
tags: Hugo | Go
原文は英語で書かれています。あなたはAI翻訳版を読んでいます。

Hugoのテンプレートは、Goのテンプレート言語にHugoの関数とページ オブジェクトを組み合わせたものです。ショートコードも同じ言語を使用しますが、 コンテンツ作成者はMarkdownから呼び出し、Hugoが.Contentを構築します。

Goテンプレートのコンテキストとスコープに従う #

テンプレートアクションは{{と}}の内側に記述します。パイプラインは各コマンドの 結果を次のコマンドの最後の引数に渡します。

go-html-template
{{ .Title | strings.TrimSpace | htmlEscape }}

ドット(.)は現在のコンテキストです。with、range、テンプレート呼び出しでは ドットを再束縛できるため、より狭いスコープに入る前に外側のオブジェクトを捕捉します。

go-html-template
{{ $page := . }}
{{ range .Pages }}
  <a href="{{ .RelPermalink }}">{{ .LinkTitle }}</a>
  <span>{{ $page.Site.Title }}</span>
{{ end }}

変数は$で始まり、宣言されたスコープ内で参照できます。特殊なルート変数$は 初期状態ではテンプレートに渡されたコンテキストを参照しますが、明示的に名前を付けた 変数を使うと、ネストしたコードをレビューしやすくなります。

Goテンプレート関数は、パイプラインで変換できる値を返します。関数によっては最後の 戻り値としてエラーも返し、nilではないエラーが発生するとテンプレートの実行は停止します。 任意の値にはwithを使い、値がないことがコンテンツの契約違反になる場合は、不完全な マークアップを黙って出力するのではなくerrorfを使います。

コンテキストに応じたエスケープを維持する #

HTMLレイアウトはGoのhtml/templateを通じて実行されます。値がテキスト、属性、URL、 CSS、JavaScriptのいずれに現れるかに応じてエスケープされます。

go-html-template
<a href="{{ .Params.target }}">{{ .Params.label }}</a>

safeHTML、safeCSS、safeJS、safeURLなどの関数は、あるコンテキストに対して 値を信頼済みとして扱います。これらは信頼できない入力をサニタイズしません。サイトで 生成または検証したコンテンツにだけ適用してください。誤ったsafe型を使うと、 クロスサイトスクリプティングの経路を作る可能性があります。

Hugoのtemplate.HTMLに類似したsafe値は、パーシャルの境界も越えます。したがって パーシャルでは、プレーンテキスト、URL、ページオブジェクト、信頼済みマークアップの どれを期待するかを文書化する必要があります。

パーシャルには明示的なデータを渡す #

layouts/_partials/以下のパーシャルは、再利用可能なテンプレート断片を レンダリングします。呼び出し側がドットを選択します。

go-html-template
{{ partial "card.html" (dict
  "page" .
  "compact" true
) }}

card.html内では.pageと.compactを利用できますが、元のページが暗黙的に 復元されることはありません。明示的な辞書を使うと、パーシャルが呼び出し箇所で たまたま有効だったドットに依存することを防げます。

partialCachedはビルド中にパーシャルの結果を保存します。

go-html-template
{{ partialCached "menu.html" . .Language.Lang .Section }}

キャッシュのバリアントには、出力を変更し得るすべての入力を含める必要があります。 バリアントキーがないと、ページ固有のコンテンツが無関係なページで再利用される可能性があります。

ショートコードのテンプレートとリソースを特定する #

現在のHugoでは、プロジェクトのショートコードテンプレートはlayouts/_shortcodes/に 配置されます。モジュールやテーマは、より低い優先順位の定義を提供できます。 サブディレクトリはショートコード名の一部になります。docs/noteの呼び出しは、次のような テンプレートに解決されます。

text
layouts/_shortcodes/docs/note.html

呼び出しはコンテンツページに記述します。そのページは通常のファイルでも、バンドルの index.mdでも構いません。アセットはレイアウトディレクトリには配置しません。 リーフバンドルで使用するショートコードは、.Page.Resources.Getを通じて兄弟リソースを 解決できます。一方、サイト全体で使うアセットはグローバルリソースパイプラインから取得します。

ショートコードには、周囲のページをドットとするのではなく、ショートコードコンテキストが 渡されます。一般的なメンバーには.Page、.Params、.Get、.Inner、 .InnerDeindent、.Ordinal、.Parentがあります。名前付き引数と位置引数は、曖昧に 混在させないでください。

go-html-template
{{ $src := .Get "src" }}
{{ with .Page.Resources.Get $src }}
  <img src="{{ .RelPermalink }}" alt="{{ $.Get "alt" }}">
{{ else }}
  {{ errorf "shortcode image %q not found in %s" $src $.Page.Path }}
{{ end }}

Markdownの境界を選択する #

Hugoには2種類の区切り形式があります。

  • {{< note >}}はショートコードテンプレートの出力を挿入しますが、その出力を Markdownレンダラーには渡しません。
  • {{% note %}}はショートコードテンプレートの出力をMarkdownレンダリングに渡します。

ショートコードがMarkdownを生成する場合はパーセント形式が適しています。テンプレートが 最終HTMLを担当する場合は山括弧形式が適しています。Markdown形式ではインデントも重要です。 4つのスペースによって生成コンテンツがコードブロックになる可能性があるためです。 Goldmarkのunsafe-HTML設定も、Markdown経路に入る生HTMLに影響します。

ペア形式のショートコードでは、Hugoがネストしたショートコード呼び出しを解決した後の 内部コンテンツが.Innerに格納されます。ショートコードテンプレートは、その値を直接 レンダリングするか、.Page.RenderStringを通して渡すかを決定します。すでにレンダリング された値を二重にレンダリングしないでください。

リテラルの区切り文字を安全に出力する #

ショートコードに見えるテキストは、Markdownレンダラーがフェンスを処理する前に ショートコード展開が行われるため、Markdownのコードフェンスでは保護されません。 Hugoのコメントエスケープを使うと、検索を試みずにリテラルの例を出力できます。

text
{{< note >}}
{{% note %}}

レンダリングされたページで区切り文字を表示するだけなら、HTMLエンティティも選択肢になります。 レンダリング結果からリテラルのショートコード構文を読者がコピーできる必要がある場合は、 コメントエスケープを使います。

検索と実行の失敗を診断する #

不明なショートコードがあると、通常はコンテンツファイルとショートコード名が報告されます。 次の順序で確認します。

  1. 呼び出し箇所で使用している名前と大文字・小文字。
  2. _shortcodesディレクトリと、名前に含まれるサブディレクトリ。
  3. 有効なモジュールマウントとテーマの優先順位。
  4. プロジェクトのバージョンが現在のレイアウト名前空間を想定しているかどうか。
  5. 検索後にテンプレート実行が失敗していないか。引数またはリソースが存在しない可能性があります。

続行可能なアクション可能な診断にはwarnfを使い、ビルドを失敗させる必要がある 不変条件の破れにはerrorfを使います。テンプレートはサイト構造を提供し、 パーシャルは構造を再利用し、ショートコードは作成者が制御するコンテンツと 意図的に制限されたテンプレートAPIを橋渡しします。

コメント

GitHub で閲覧・コメントする(投稿にはログインが必要です)