diff --git a/.cspell.json b/.cspell.json index 755c77b88..62c2576e3 100644 --- a/.cspell.json +++ b/.cspell.json @@ -114,6 +114,7 @@ "# ----------------------------------------------------------------------", "# cspell: ignore names", "# ----------------------------------------------------------------------", + "Atishay", "Eliott", "Furet", "Gregor", @@ -132,6 +133,7 @@ "cifs", "corejs", "disqus", + "docutils", "dpkg", "doas", "eopkg", @@ -161,6 +163,7 @@ "rsmith", "tdewolff", "tjones", + "wcag", "xfeff" ] } diff --git a/assets/images/examples/zion-national-park-grayscale.jpg b/assets/images/examples/zion-national-park-grayscale.jpg deleted file mode 100644 index 908bd88c6..000000000 Binary files a/assets/images/examples/zion-national-park-grayscale.jpg and /dev/null differ diff --git a/content/en/content-management/content-adapters.md b/content/en/content-management/content-adapters.md new file mode 100644 index 000000000..42285b7a5 --- /dev/null +++ b/content/en/content-management/content-adapters.md @@ -0,0 +1,339 @@ +--- +title: Content adapters +description: Create content adapters to dynamically add content when building your site. +categories: [content management] +keywords: [] +menu: + docs: + parent: content-management + weight: 280 +weight: 280 +toc: true +--- + +{{< new-in 0.126.0 >}} + +## Overview + +A content adapter is a template that dynamically creates pages when building a site. For example, use a content adapter to create pages from a remote data source such as JSON, TOML, YAML, or XML. + +Unlike templates that reside in the layouts directory, content adapters reside in the content directory, no more than one per directory per language. When a content adapter creates a page, the page's [logical path] will be relative to the content adapter. + +```text +content/ +├── articles/ +│ ├── _index.md +│ ├── article-1.md +│ └── article-2.md +├── books/ +│ ├── _content.gotmpl <-- content adapter +│ └── _index.md +└── films/ + ├── _content.gotmpl <-- content adapter + └── _index.md +``` + +Each content adapter is named _content.gotmpl and uses the same [syntax] as templates in the layouts directory. You can use any of the [template functions] within a content adapter, as well as the methods described below. + +## Methods + +Use these methods within a content adapter. + +###### AddPage + +Adds a page to the site. + +{{< code file=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 }} +{{< /code >}} + +###### AddResource + +Adds a page resource to the site. + +{{< code file=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 }} +{{< /code >}} + +Then retrieve the new page resource with something like: + +{{< code file=layouts/_default/single.html >}} +{{ with .Resources.Get "cover.jpg" }} + +{{ end }} +{{< /code >}} + +###### Site + +Returns the `Site` to which the pages will be added. + +{{< code file=content/books/_content.gotmpl >}} +{{ .Site.Title }} +{{< /code >}} + +###### Store + +Creates a persistent “scratch pad” to store and manipulate data. See [examples](/methods/page/store/). + +{{< code file=content/books/_content.gotmpl >}} +{{ .Store.Set "key" "value" }} +{{ .Store.Get "key" }} +{{< /code >}} + +###### EnableAllLanguages + +By default, Hugo executes the content adapter for the language defined by the _content.gotmpl file . Use this method to activate the content adapter for all languages. + +{{< code file=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 }} +{{< /code >}} + +## Page map + +Set any [front matter field] in the map passed to the [`AddPage`](#addpage) method, excluding `markup`. Instead of setting the `markup` field, specify the `content.mediaType` as described below. + +This table describes the fields most commonly passed to the `AddPage` method. + +Key|Descripion|Required +:--|:--|:-: +`content.mediaType`|The content [media type]. Default is `text/markdown`. See [content formats] for examples.|  +`content.value`|The content value as a string.|  +`dates.date`|The page creation date as a `time.Time` value.|  +`dates.expiryDate`|The page expiry date as a `time.Time` value.|  +`dates.lastmod`|The page last modification date as a `time.Time` value.|  +`dates.publishDate`|The page publication date as a `time.Time` value.|  +`kind`|The [page kind]. Default is `page`.|  +`params`|A map of page parameters.|  +`path`|The page's [logical path] relative to the content adapter. Do not include a leading slash.|:heavy_check_mark: +`title`|The page title.|  + +{{% note %}} +While `path` is the only required field, we recommend setting `title` as well. + +When setting the `path`, Hugo transforms the given string to a logical path. For example, setting `path` to `A B C` produces a logical path of `/section/a-b-c`. +{{% /note %}} + +## Resource map + +Construct the map passed to the [`AddResource`](#addresource) method using the fields below. + +Key|Descripion|Required +:--|:--|:-: +`content.mediaType`|The content [media type].|:heavy_check_mark: +`content.value`|The content value as a string or resource.|:heavy_check_mark: +`name`|The resource name.|  +`params`|A map of resource parameters.|  +`path`|The resources's [logical path] relative to the content adapter. Do not include a leading slash.|:heavy_check_mark: +`title`|The resource title.|  + +{{% note %}} +If the `content.value` is a string Hugo creates a new resource. If the `content.value` is a resource, Hugo obtains the value from the existing resource. + +When setting the `path`, Hugo transforms the given string to a logical path. For example, setting `path` to `A B C/cover.jpg` produces a logical path of `/section/a-b-c/cover.jpg`. +{{% /note %}} + +## Example + +Create pages from remote data, where each page represents a book review. + +Step 1 +: Create the content structure. + +```text +content/ +└── books/ + ├── _content.gotmpl <-- content adapter + └── _index.md +``` + +Step 2 +: Inspect the remote data to determine how to map key-value pairs to front matter fields. + +: + +Step 3 +: Create the content adapter. + +{{< code file=content/books/_content.gotmpl copy=true >}} +{{/* Get remote data. */}} +{{ $data := dict }} +{{ $url := "https://gohugo.io/shared/examples/data/books.json" }} +{{ with resources.GetRemote $url }} + {{ with .Err }} + {{ errorf "Unable to get remote resource %s: %s" $url . }} + {{ else }} + {{ $data = . | transform.Unmarshal }} + {{ end }} +{{ else }} + {{ errorf "Unable to get remote resource %s" $url }} +{{ 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 resources.GetRemote $url }} + {{ with .Err }} + {{ errorf "Unable to get remote resource %s: %s" $url . }} + {{ else }} + {{ $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 }} + {{ end }} + {{ else }} + {{ errorf "Unable to get remote resource %s" $url }} + {{ end }} + {{ end }} + +{{ end }} +{{< /code >}} + +Step 4 +: Create a single page template to render each book review. + +{{< code file=layouts/books/single.html copy=true >}} +{{ define "main" }} +

{{ .Title }}

+ + {{ with .Resources.GetMatch "cover.*" }} + {{ .Params.alt }} + {{ end }} + +

Author: {{ .Params.author }}

+ +

+ ISBN: {{ .Params.isbn }}
+ Rating: {{ .Params.rating }}
+ Review date: {{ .Date | time.Format ":date_long" }} +

+ + {{ with .GetTerms "tags" }} +

Tags:

+ + {{ end }} + + {{ .Content }} +{{ end }} +{{< /code >}} + +## Multilingual sites + +With multilingual sites you can: + +1. Create one content adapter for all languages using the [`EnableAllLanguages`](#enablealllanguages) method as described above. +2. Create content adapters unique to each language. See the examples below. + +### Translations by file name + +With this site configuration: + +{{< code-toggle file=hugo >}} +[languages.en] +weight = 1 + +[languages.de] +weight = 2 +{{< /code-toggle >}} + +Include a language designator in the content adapter's file name. + +```text +content/ +└── books/ + ├── _content.de.gotmpl + ├── _content.en.gotmpl + ├── _index.de.md + └── _index.en.md +``` + +### Translations by content directory + +With this site configuration: + +{{< code-toggle file=hugo >}} +[languages.en] +contentDir = 'content/en' +weight = 1 + +[languages.de] +contentDir = 'content/de' +weight = 2 +{{< /code-toggle >}} + +Create a single content adapter in each directory: + +```text +content/ +├── de/ +│ └── books/ +│ ├── _content.gotmpl +│ └── _index.md +└── en/ + └── books/ + ├── _content.gotmpl + └── _index.md +``` + +[content formats]: /content-management/formats/#classification +[front matter field]: /content-management/front-matter/#fields +[logical path]: /getting-started/glossary/#logical-path +[media type]: https://en.wikipedia.org/wiki/Media_type +[page kind]: /getting-started/glossary/#page-kind +[syntax]: /templates/introduction/ +[template functions]: /functions/ diff --git a/content/en/content-management/formats.md b/content/en/content-management/formats.md index 305679b21..7b141593c 100644 --- a/content/en/content-management/formats.md +++ b/content/en/content-management/formats.md @@ -29,7 +29,7 @@ content/ Regardless of content format, all content must have [front matter], preferably including both `title` and `date`. -Hugo selects the content renderer based on the `markup` identifier in front matter, falling back to the file extension. See the [comparison table](#comparison) table below for a list of markup identifiers and recognized file extensions. +Hugo selects the content renderer based on the `markup` identifier in front matter, falling back to the file extension. See the [classification](#classification) table below for a list of markup identifiers and recognized file extensions. ## Formats @@ -99,16 +99,16 @@ Hugo passes these CLI flags when calling the rst2html executable: --leave-comments --initial-header-level=2 ``` -## Comparison +## Classification -Content format|Identifier|Identifier aliases|File extensions +Content format|Media type|Identifier|File extensions :--|:--|:--|:-- -Markdown|`goldmark`|`md`, `mdown`, `markdown`|`md`, `mdown`, `markdown` -HTML|`html`|`htm`|`html`, `htm` -Emacs Org Mode|`org`||`org` -AsciiDoc|`asciidocext`|`adoc`, `ad`|`adoc`, `ad` -Pandoc|`pandoc`|`pdc`|`pandoc`, `pdc` -reStructuredText|`rst`||`rst` +Markdown|`text/markdown`|`markdown`|`markdown`,`md`, `mdown` +HTML|`text/html`|`html`|`htm`, `html` +Emacs Org Mode|`text/org`|`org`|`org` +AsciiDoc|`text/asciidoc`|`asciidoc`|`ad`, `adoc`, `asciidoc` +Pandoc|`text/pandoc`|`pandoc`|`pandoc`, `pdc` +reStructuredText|`text/rst`|`rst`|`rst` When converting content to HTML, Hugo uses: diff --git a/content/en/content-management/front-matter.md b/content/en/content-management/front-matter.md index 8ea41487d..2c01f7854 100644 --- a/content/en/content-management/front-matter.md +++ b/content/en/content-management/front-matter.md @@ -163,7 +163,7 @@ lang (`string`) An identifier corresponding to one of the supported [content formats]. If not provided, Hugo determines the content renderer based on the file extension. -[content formats]: /content-management/formats/#comparison +[content formats]: /content-management/formats/#classification ###### menus diff --git a/content/en/getting-started/glossary.md b/content/en/getting-started/glossary.md index e31f45187..bbc35906e 100644 --- a/content/en/getting-started/glossary.md +++ b/content/en/getting-started/glossary.md @@ -90,6 +90,10 @@ Command line interface. An [array](#array), [slice](#slice), or [map](#map). +###### content adapter + +A template that dynamically creates pages when building a site. For example, use a content adapter to create pages from a remote data source such as JSON, TOML, YAML, or XML. See [details](/content-management/content-adapters/). + ###### content format A markup language for creating content. Typically Markdown, but may also be HTML, AsciiDoc, Org, Pandoc, or reStructuredText. See [details](/content-management/formats/). diff --git a/content/en/methods/page/File.md b/content/en/methods/page/File.md index 310404cb8..d59171577 100644 --- a/content/en/methods/page/File.md +++ b/content/en/methods/page/File.md @@ -82,6 +82,20 @@ The path separators (slash or backslash) in `Path`, `Dir`, and `Filename` depend {{ end }} ``` +###### IsContentAdapter + +{{< new-in 0.126.0 >}} + +(`bool`) Reports whether the file is a [content adapter]. + +[content adapter]: /content-management/content-adapters/ + +```go-html-template +{{ with .File }} + {{ .IsContentAdapter }} +{{ end }} +``` + ###### LogicalName (`string`) The file name. @@ -159,6 +173,7 @@ ContentBaseName|a|b|news Dir|news/|news/b/|news/ Ext|md|md|md Filename|/home/user/...|/home/user/...|/home/user/... +IsContentAdapter|false|false|false LogicalName|a.en.md|index.en.md|_index.en.md Path|news/a.en.md|news/b/index.en.md|news/_index.en.md Section|news|news|news diff --git a/content/en/methods/page/RenderString.md b/content/en/methods/page/RenderString.md index 0f2df111f..1a92c78c6 100644 --- a/content/en/methods/page/RenderString.md +++ b/content/en/methods/page/RenderString.md @@ -47,5 +47,5 @@ Render with [Pandoc]: {{ .RenderString $opts $s }} →

H2O

``` -[markup identifier]: /content-management/formats/#formats +[markup identifier]: /content-management/formats/#classification [pandoc]: https://www.pandoc.org/