HUGO
Menu
GitHub 87548 stars Mastodon

Hugo 内容适配器

创建内容适配器以在构建站点时动态添加内容。
New in v0.126.0

概述

内容适配器是一种模板,在构建站点时动态创建页面。例如,使用内容适配器从远程数据源(如 JSON、TOML、YAML 或 XML)创建页面。

与驻留在 layouts 目录中的模板不同,内容适配器驻留在 content 目录中,每种语言每个目录不超过一个。当内容适配器创建页面时,页面的 逻辑路径 将相对于内容适配器。

content/
├── articles/
│   ├── _index.md
│   ├── article-1.md
│   └── article-2.md
├── books/
│   ├── _content.gotmpl  <-- 内容适配器
│   └── _index.md
└── films/
    ├── _content.gotmpl  <-- 内容适配器
    └── _index.md

每个内容适配器命名为 _content.gotmpl,使用与 layouts 目录中模板相同的 语法。你可以在内容适配器中使用任何 模板函数,以及下面描述的方法。

方法

在内容适配器中使用这些方法。

AddPage

向站点添加页面。

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

向站点添加页面资源。

content/books/_content.gotmpl
{{ 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

content/books/_content.gotmpl
{{ .Site.Title }}

请注意,从内容适配器调用时返回的 Site 尚未完全构建;如果你尝试调用依赖于页面的方法,例如 .Site.Pages,你会收到错误提示"this method cannot be called before the site is fully initialized"。

Store

返回一个持久的"scratch pad"来存储和操作数据。这的主要用例是在 EnableAllLanguages 设置时在多次执行之间传输值。参见 示例

content/books/_content.gotmpl
{{ .Store.Set "key" "value" }}
{{ .Store.Get "key" }}

EnableAllLanguages

默认情况下,Hugo 只为 sites matrix 中第一个匹配的站点执行内容适配器一次。使用此方法将执行扩展到所有语言,同时保持当前角色和版本。

对于更细粒度的控制,在 front matter 或内容挂载中定义 sites.matrix

content/books/_content.gotmpl
{{ .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

默认情况下,Hugo 只为 sites matrix 中第一个匹配的站点执行内容适配器一次。使用此方法将执行扩展到语言、角色和版本的每种可能组合。

对于更细粒度的控制,在 front matter 或内容挂载中定义 sites.matrix

New in v0.153.0

页面映射

在传递给 AddPage 方法的映射中设置任何 front matter 字段,不包括 markup。代替设置 markup 字段,如下所述指定 content.mediaType

此表描述了最常传递给 AddPage 方法的字段。

Key 描述 必需
content.mediaType 内容 media type。默认是 text/markdown。参见 内容格式 示例。  
content.value 内容值为字符串。  
dates.date 页面创建日期,为 time.Time 值。  
dates.expiryDate 页面失效日期,为 time.Time 值。  
dates.lastmod 页面最后修改日期,为 time.Time 值。  
dates.publishDate 页面发布日期,为 time.Time 值。  
params 页面参数映射。  
path 页面相对于内容适配器的 逻辑路径。不要包含前导斜杠或文件扩展名。 ✔️
title 页面标题。  

虽然 path 是唯一必需字段,但我们也建议设置 title

设置 path 时,Hugo 将给定字符串转换为逻辑路径。例如,将 path 设置为 A B C 会产生逻辑路径 /section/a-b-c

资源映射

使用以下字段构建传递给 AddResource 方法的映射。

Key 描述 必需
content.mediaType 内容 media type ✔️
content.value 内容值为字符串或资源。 ✔️
name 资源名称。  
params 资源参数映射。  
path 资源相对于内容适配器的 逻辑路径。不要包含前导斜杠。 ✔️
title 资源标题。  

content.value 是字符串时,Hugo 生成一个相对于页面的发布路径的新资源。但是,如果 content.value 已经是资源,Hugo 直接使用其值并将其相对于站点根目录发布。后一种方法更高效。

设置 path 时,Hugo 将给定字符串转换为逻辑路径。例如,将 path 设置为 A B C/cover.jpg 会产生逻辑路径 /section/a-b-c/cover.jpg

示例

从远程数据创建页面,每个页面代表一篇书评。

Step 1
创建内容结构。
content/
└── books/
    ├── _content.gotmpl  <-- 内容适配器
    └── _index.md
Step 2
检查远程数据以确定如何将键值对映射到 front matter 字段。
https://www.hugodoc.com/shared/examples/data/books.json
Step 3
创建内容适配器。
content/books/_content.gotmpl
{{/* 获取远程数据。*/}}
{{ $data := dict }}
{{ $url := "https://www.hugodoc.com/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" $url }}
  {{ end }}
{{ end }}

{{/* 添加页面和页面资源。*/}}
{{ range $data }}

  {{/* 添加页面。*/}}
  {{ $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 }}

  {{/* 添加页面资源。*/}}
  {{ $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" $url }}
      {{ end }}
    {{ end }}
  {{ end }}

{{ end }}
Step 4
创建 page 模板来渲染每篇书评。
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>作者:{{ .Params.author }}</p>

  <p>
    ISBN: {{ .Params.isbn }}<br>
    评分:{{ .Params.rating }}<br>
    评论日期:{{ .Date | time.Format ":date_long" }}
  </p>

  {{ with .GetTerms "tags" }}
    <p>标签:</p>
    <ul>
      {{ range . }}
        <li><a href="{{ .RelPermalink }}">{{ .LinkTitle }}</a></li>
      {{ end }}
    </ul>
  {{ end }}

  {{ .Content }}
{{ end }}

多语言站点

使用多语言站点,你可以:

  1. 使用上面的 EnableAllLanguages 方法为所有语言创建一个内容适配器。
  2. 为每种语言创建独特的内容适配器。参见下面的示例。

按文件名翻译

使用此站点配置:

languages:
  de:
    weight: 2
  en:
    weight: 1
[languages]
  [languages.de]
    weight = 2
  [languages.en]
    weight = 1
{
   "languages": {
      "de": {
         "weight": 2
      },
      "en": {
         "weight": 1
      }
   }
}

在内容适配器的文件名中包含语言标识符。

content/
└── books/
    ├── _content.de.gotmpl
    ├── _content.en.gotmpl
    ├── _index.de.md
    └── _index.en.md

按内容目录翻译

使用此站点配置:

languages:
  de:
    contentDir: content/de
    weight: 2
  en:
    contentDir: content/en
    weight: 1
[languages]
  [languages.de]
    contentDir = 'content/de'
    weight = 2
  [languages.en]
    contentDir = 'content/en'
    weight = 1
{
   "languages": {
      "de": {
         "contentDir": "content/de",
         "weight": 2
      },
      "en": {
         "contentDir": "content/en",
         "weight": 1
      }
   }
}

在每个目录中创建单个内容适配器:

content/
├── de/
│   └── books/
│       ├── _content.gotmpl
│       └── _index.md
└── en/
    └── books/
        ├── _content.gotmpl
        └── _index.md

页面冲突

当两个或多个页面具有相同的发布路径时会发生冲突。由于并发,已发布页面的内容是不确定的。考虑以下示例:

content/
└── books/
    ├── _content.gotmpl  <-- 内容适配器
    ├── _index.md
    └── the-hunchback-of-notre-dame.md

如果内容适配器也创建 books/the-hunchback-of-notre-dame,则已发布页面的内容是不确定的。你无法定义处理顺序。

要检测页面冲突,在构建站点时使用 --printPathWarnings 标志。


Last updated: January 1, 0001
Improve this page