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 的安全值也会跨越 partial 边界。因此,partial 应说明它 期望的是纯文本、URL、页面对象还是可信标记。

向 partial 传递显式数据 #

layouts/_partials/下的 partial 会渲染可复用的模板片段。调用方选择其点号上下文:

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

在card.html中可以使用.page和.compact,但原始页面不会被隐式恢复。显式字典可以 防止 partial 依赖调用位置当时恰好处于活动状态的点号上下文。

partialCached会在构建期间缓存 partial 的结果:

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

缓存变体必须包含所有可能改变输出的输入。没有变体键时,特定页面的内容可能会在无关页面 上被重复使用。

定位短代码模板和资源 #

在当前版本的 Hugo 中,项目短代码模板位于layouts/_shortcodes/下;模块或主题可以提供 优先级更低的定义。子目录属于短代码名称的一部分。调用docs/note时,会解析到如下模板:

text
layouts/_shortcodes/docs/note.html

调用应写在内容页面中,该页面可以是普通文件,也可以是 bundle 的index.md。资源不应 放在 layout 目录中。leaf bundle 使用的短代码可以通过.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 提供两种分隔符形式:

  • {{< note >}}插入短代码模板输出,但不会将该输出交给 Markdown 渲染器。
  • {{% note %}}会将短代码模板输出交给 Markdown 渲染。

当短代码生成 Markdown 时,应使用百分号形式。当模板负责生成最终 HTML 时,应使用尖括号 形式。在 Markdown 形式中,缩进仍然重要,因为四个空格可能会将生成的内容转换为代码块。 Goldmark 的 unsafe-HTML 设置也会影响进入 Markdown 路径的原始 HTML。

对于成对短代码,Hugo 解析嵌套的短代码调用后,其内部内容会存放在.Inner中。短代码 模板决定是直接渲染该值,还是通过.Page.RenderString传递它;不要对已经渲染过的值 再次渲染。

安全输出字面分隔符 #

看起来像短代码的 Markdown 文本无法通过 Markdown 代码围栏得到保护,因为短代码展开会在 Markdown 渲染器处理围栏之前发生。Hugo 的注释转义可以输出字面示例,而不会尝试查找模板:

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

如果渲染后的页面只需要显示分隔符,也可以使用 HTML 实体。当读者需要从渲染结果中复制 字面短代码语法时,应使用注释转义。

诊断查找和执行失败 #

未知短代码通常会报告内容文件和短代码名称。按以下顺序检查:

  1. 调用位置使用的名称及大小写。
  2. _shortcodes目录,以及名称中的任何子目录。
  3. 当前生效的模块挂载和主题优先级。
  4. 项目版本是否要求使用当前的 layout 命名空间。
  5. 查找成功后模板执行是否失败,原因可能是参数或资源缺失。

对于可以继续构建的可操作诊断,使用warnf;对于必须使构建失败的破坏性不变量, 使用errorf。模板提供站点结构,partial 复用结构,短代码则将作者控制的内容与 有意限定范围的模板 API 连接起来。

评论

在 GitHub 上阅读或评论(发表评论需要登录)