Hugo 内容适配器(Content adapters)#
内容适配器用于在构建站点时动态创建页面。常用于从远程 JSON/TOML/YAML/XML 等数据源生成页面(新增于 v0.126.0)。
概览#
- 内容适配器是模板类型的一种,但它们位于
content目录,而不是layouts。 - 每个目录(每种语言)最多一个内容适配器,命名为
_content.gotmpl(或带语言后缀的_content.<lang>.gotmpl)。 - 内容适配器创建的页面的逻辑路径(logical path)相对于内容适配器所在目录。
示例目录结构:
content/
├── articles/
│ ├── _index.md
│ ├── article-1.md
│ └── article-2.md
├── books/
│ ├── _content.gotmpl <-- content adapter
│ └── _index.md
└── films/
├── _content.gotmpl <-- content adapter
└── _index.md内容适配器使用与 layouts 模板相同的语法和函数,可在模板内调用下列方法来创建页面和资源。
注意:EnableAllDimensions 方法为 v0.153.0 新增。
方法(Methods)#
在内容适配器中常用的方法:AddPage、AddResource、Site、Store、EnableAllLanguages、EnableAllDimensions。
AddPage#
向站点添加页面。最小需要设置 path 字段,建议同时设置 title。
示例(content/books/_content.gotmpl):
{{ $content := dict
"mediaType" "text/markdown"
"value" "The _Hunchback of Notre Dame_ was written by Victor Hugo."
}}
{{ $page := dict
"content" $content
"kind" "page"
"path" "the-hunchback-of-notre-dame"
"title" "The Hunchback of Notre Dame"
}}
{{ .AddPage $page }}AddResource#
向站点添加页面资源(例如封面图片)。示例:
{{ with resources.Get "images/a.jpg" }}
{{ $content := dict
"mediaType" .MediaType.Type
"value" .
}}
{{ $resource := dict
"content" $content
"path" "the-hunchback-of-notre-dame/cover.jpg"
}}
{{ $.AddResource $resource }}
{{ end }}在页面模板中使用资源示例(layouts/page.html):
{{ with .Resources.Get "cover.jpg" }}
<img src="{{ .RelPermalink }}" width="{{ .Width }}" height="{{ .Height }}" alt="">
{{ end }}Site#
返回要将页面添加到的 Site 对象。
{{ .Site.Title }}注意:从内容适配器内调用时,Site 尚未完全构建,像 .Site.Pages 这类依赖已构建页面集合的方法会报错。
Store#
返回一个持久化的“便签”(scratch pad),可在多次执行间存取数据。主要用于在启用多语言(EnableAllLanguages)时在不同执行之间传递值。
{{ .Store.Set "key" "value" }}
{{ .Store.Get "key" }}EnableAllLanguages#
默认情况下,Hugo 只为站点矩阵(sites matrix)中第一个匹配的站点执行内容适配器一次。调用此方法可扩展到所有语言(保持当前 role 与 version)。
{{ .EnableAllLanguages }}
{{ $content := dict
"mediaType" "text/markdown"
"value" "The _Hunchback of Notre Dame_ was written by Victor Hugo."
}}
{{ $page := dict
"content" $content
"kind" "page"
"path" "the-hunchback-of-notre-dame"
"title" "The Hunchback of Notre Dame"
}}
{{ .AddPage $page }}EnableAllDimensions (v0.153.0)#
默认情况下内容适配器仅为 sites matrix 的第一个匹配项执行。EnableAllDimensions 用于扩展执行到语言、role、version 的所有可能组合(更细粒度控制可通过 front matter 中的 sites.matrix 或 content mount 定义)。
页面映射(Page map)#
调用 AddPage 时传入的 map 可设置任意 front matter 字段(不包括 markup),若要指定标记类型请设置 content.mediaType。下表列出常用字段:
| Key | 描述 | 必需 |
|---|---|---|
content.mediaType | 内容的媒体类型,默认 text/markdown。 | |
content.value | 内容字符串值。 | |
dates.date | 创建日期(time.Time)。 | |
dates.expiryDate | 过期日期(time.Time)。 | |
dates.lastmod | 最后修改时间(time.Time)。 | |
dates.publishDate | 发布时间(time.Time)。 | |
params | 页面参数 map。 | |
path | 相对于内容适配器的页面逻辑路径(不要带前导斜杠或扩展名)。 | ✔️ |
title | 页面标题。 |
提示:虽然 path 是唯一必需字段,但建议同时设定 title。Hugo 会将 path 自动规范化(例如 A B C -> /section/a-b-c)。
资源映射(Resource map)#
AddResource 使用的 map 字段说明:
| Key | 描述 | 必需 |
|---|---|---|
content.mediaType | 资源的媒体类型。 | ✔️ |
content.value | 字符串或资源对象(string 或 resource)。 | ✔️ |
name | 资源名称。 | |
params | 资源参数 map。 | |
path | 相对于内容适配器的资源逻辑路径(不要带前导斜杠)。 | ✔️ |
title | 资源标题。 |
说明:
- 当
content.value为字符串时,Hugo 会为页面生成一个新资源,其发布路径相对于页面。 - 当
content.value已经是一个 resource(比如通过 resources.GetRemote 得到的资源),Hugo 会直接使用该资源并按站点根发布,这种方式更高效。 - 路径会被规范化,例如
A B C/cover.jpg->/section/a-b-c/cover.jpg。
示例:从远程数据生成书评页面#
目标:从远程 JSON 创建每本书的页面,并为每本书添加封面资源。
步骤 1 — 创建内容结构:
content/
└── books/
├── _content.gotmpl <-- content adapter
└── _index.md步骤 2 — 查看远程数据结构(示例):
步骤 3 — 创建内容适配器(content/books/_content.gotmpl):
{{/* Get remote data. */}}
{{ $data := dict }}
{{ $url := "<https://gohugo.io/shared/examples/data/books.json>" }}
{{ with try (resources.GetRemote $url) }}
{{ with .Err }}
{{ errorf "Unable to get remote resource %s: %s" $url . }}
{{ else with .Value }}
{{ $data = . | transform.Unmarshal }}
{{ else }}
{{ errorf "Unable to get remote resource %s: %s" $url }}
{{ end }}
{{ end }}
{{/* Add pages and page resources. */}}
{{ range $data }}
{{/* Add page. */}}
{{ $content := dict "mediaType" "text/markdown" "value" .summary }}
{{ $dates := dict "date" (time.AsTime .date) }}
{{ $params := dict "author" .author "isbn" .isbn "rating" .rating "tags" .tags }}
{{ $page := dict
"content" $content
"dates" $dates
"kind" "page"
"params" $params
"path" .title
"title" .title
}}
{{ $.AddPage $page }}
{{/* Add page resource. */}}
{{ $item := . }}
{{ with $url := $item.cover }}
{{ with try (resources.GetRemote $url) }}
{{ with .Err }}
{{ errorf "Unable to get remote resource %s: %s" $url . }}
{{ else with .Value }}
{{ $content := dict "mediaType" .MediaType.Type "value" .Content }}
{{ $params := dict "alt" $item.title }}
{{ $resource := dict
"content" $content
"params" $params
"path" (printf "%s/cover.%s" $item.title .MediaType.SubType)
}}
{{ $.AddResource $resource }}
{{ else }}
{{ errorf "Unable to get remote resource %s: %s" $url }}
{{ end }}
{{ end }}
{{ end }}
{{ end }}步骤 4 — 创建页面模板(layouts/books/page.html):
{{ define "main" }}
<h1>{{ .Title }}</h1>
{{ with .Resources.GetMatch "cover.*" }}
<img src="{{ .RelPermalink }}" width="{{ .Width }}" height="{{ .Height }}" alt="{{ .Params.alt }}">
{{ end }}
<p>Author: {{ .Params.author }}</p>
<p>
ISBN: {{ .Params.isbn }}<br>
Rating: {{ .Params.rating }}<br>
Review date: {{ .Date | time.Format ":date_long" }}
</p>
{{ with .GetTerms "tags" }}
<p>Tags:</p>
<ul>
{{ range . }}
<li><a href="{{ .RelPermalink }}">{{ .LinkTitle }}</a></li>
{{ end }}
</ul>
{{ end }}
{{ .Content }}
{{ end }}多语言站点支持#
有两种常见方法处理多语言内容适配器:
- 在一个内容适配器中使用
EnableAllLanguages为所有语言生成内容。 - 为每种语言创建独立的内容适配器(按文件名或按目录)。
通过文件名区分语言#
示例站点配置(按语言权重):
YAML / TOML / JSON 示例均可。然后在 content/books/ 下放置:
content/
└── books/
├── _content.de.gotmpl
├── _content.en.gotmpl
├── _index.de.md
└── _index.en.md通过内容目录区分语言#
在配置中指定每个语言的 contentDir,例如:
示例目录结构:
content/
├── de/
│ └── books/
│ ├── _content.gotmpl
│ └── _index.md
└── en/
└── books/
├── _content.gotmpl
└── _index.md页面冲突(Page collisions)#
当两个或更多页面具有相同发布路径时会发生冲突(例如内容适配器生成的页面与目录中已有的 .md 文件路径相同)。由于构建过程是并发的,被发布页面的内容将不确定,无法控制处理顺序。
示例:
content/
└── books/
├── _content.gotmpl <-- content adapter
├── _index.md
└── the-hunchback-of-notre-dame.md如果内容适配器也创建 books/the-hunchback-of-notre-dame,则该路径会冲突。构建时可使用 --printPathWarnings 标志来检测此类冲突。
参考与最后更新#
- 文档来源:Hugo 官方文档 - Content adapters(含示例与方法说明)
