Files
hugoDocs/content/templates/go-templates.md
T

16 KiB

title, linktitle, description, godocref, date, publishdate, lastmod, categories, tags, weight, draft, aliases, toc, wip
title linktitle description godocref date publishdate lastmod categories tags weight draft aliases toc wip
Go Template Primer Go Template Primer Hugo uses Go html/template library, an extremely lightweight and performant, engine as the basis for all Hugo templating. https://golang.org/pkg/html/template/ 2017-02-01 2017-02-01 2017-02-25
templates
go
fundamentals
10 false
/templates/go-template-primer/
/layouts/go-templates/
/layout/go-templates/
true true

Hugo uses the excellent Go html/template library, an extremely lightweight engine that provides just the right amount of logic to be able to create any style of static website. If you have used other template systems from different languages or frameworks, you will find a lot of similarities in Go templates.

{{% note "Go Deep with the Go Docs" %}} This document is only designed as a brief primer. For an in-depth look into Go templates, check the official Go docs. {{% /note %}}

Introduction to Go Templates

Go templates provide an extremely simple template language that adheres to the belief that only the most basic of logic belongs in the template or view layer. As a positive consequence of this simplicity, Go templates parse very quickly.

A unique characteristic of Go templates is that they are content aware. Variables and content will be sanitized depending on the context of where they are used.

Basic Syntax

Golang templates are HTML files with the addition of variables and functions. Golang template variables and functions are accessible within {{ }}.

Accessing a Predefined Variable

{{ foo }}

Parameters for functions are separated using spaces. The following example calls the add function with inputs of 1 and 2:

{{ add 1 2 }}

Methods and Fields are Accessed via dot Notation

Accessing the Page Parameter "bar"

{{ .Params.bar }}

Parentheses can be Used to Group Items Together

{{ if or (isset .Params "alt") (isset .Params "caption") }} Caption {{ end }}

Variables

Each Go template has a struct (object) made available to it. In Hugo, each template is passed page struct. More details are available in the [variables and params section][variablesparams].

A variable is accessed by referencing the variable name.

<title>{{ .Title }}</title>

Variables can also be defined and referenced.

{{ $address := "123 Main St."}}
{{ $address }}

Functions

Go template ships with a few functions that provide basic functionality. The Go template system also provides a mechanism for applications to extend the set of available functions. Hugo template functions provide additional functionality we believe us useful for building websites. Functions are called by using their name followed by the required parameters separated by spaces. Template functions cannot be added without recompiling Hugo.

Example 1: Adding Numbers

{{ add 1 2 }}
=> 3

Example 2: Comparing Numbers

{{ lt 1 2 }}
=> true (i.e., since 1 is less than 2)

Note that both examples make us of Go template's math functions.

{{% note "Additional Boolean Operators" %}} There are more boolean operators than those listed in the Hugo docs in the Golang template documentation. {{% /note %}}

Includes

When including another template, you will pass to it the data it will be able to access. To pass along the current context, please remember to include a trailing dot. The templates location will always be starting at the /layout/ directory within Hugo.

Template and Partial Examples

{{ template "partials/header.html" . }}

Starting with Hugo v0.12, you may also use the partial call for partial templates:

{{ partial "header.html" . }}

Logic

Go templates provide the most basic iteration and conditional logic.

Iteration

Just like in Go, the Go templates make heavy use of range to iterate over a map, array or slice. The following are different examples of how to use range.

Example 1: Using Context**

{{ range array }}
    {{ . }}
{{ end }}

Example 2: Declaring Value=>Variable name

{{range $element := array}}
    {{ $element }}
{{ end }}

Example 3: Declaring Key-Value Variable Name

{{range $index, $element := array}}
   {{ $index }}
   {{ $element }}
{{ end }}

Conditionals

if, else, with, or & and provide the framework for handling conditional logic in Go Templates. Like range, each statement is closed with an {{end}}.

Go Templates treat the following values as false:

  • false
  • 0
  • any array, slice, map, or string of length zero

Example 1: if

{{ if isset .Params "title" }}<h4>{{ index .Params "title" }}</h4>{{ end }}

Example 2: ifelse

{{ if isset .Params "alt" }}
    {{ index .Params "alt" }}
{{else}}
    {{ index .Params "caption" }}
{{ end }}

Example 3: and & or

{{ if and (or (isset .Params "title") (isset .Params "caption")) (isset .Params "attr")}}

Example 4: with

An alternative way of writing "if" and then referencing the same value is to use "with" instead. with rebinds the context . within its scope, and skips the block if the variable is absent.

The first example above could be simplified as:

{{ with .Params.title }}<h4>{{ . }}</h4>{{ end }}

Example 5: ifelse if

{{ if isset .Params "alt" }}
    {{ index .Params "alt" }}
{{ else if isset .Params "caption" }}
    {{ index .Params "caption" }}
{{ end }}

Pipes

One of the most powerful components of Go templates is the ability to stack actions one after another. This is done by using pipes. Borrowed from Unix pipes, the concept is simple, each pipeline's output becomes the input of the following pipe.

Because of the very simple syntax of Go templates, the pipe is essential to being able to chain together function calls. One limitation of the pipes is that they only can work with a single value and that value becomes the last parameter of the next pipeline.

A few simple examples should help convey how to use the pipe.

Example 1: shuffle

{{ shuffle (seq 1 5) }}

is the same as

{{ (seq 1 5) | shuffle }}

Example 2: index

{{ index .Params "disqus_url" | html }}

Access the page parameter called "disqus_url" and escape the HTML.

The index function is built in to [Go][]. You can read more about index in the Godocs. The Godocs have the following to say aboutindex:

...returns the result of indexing its first argument by the following arguments. Thus "index x 1 2 3" is, in Go syntax, x[1][2][3]. Each indexed item must be a map, slice, or array.

Example 3: or with isset

{{ if or (or (isset .Params "title") (isset .Params "caption")) (isset .Params "attr") }}
Stuff Here
{{ end }}

Could be rewritten as

```golang
{{ if isset .Params "caption" | or isset .Params "title" | or isset .Params "attr" }}
Stuff Here
{{ end }}

### Example $: Internet Explorer Conditional Comments

By default, Go Templates remove HTML comments from output. This has the unfortunate side effect of removing Internet Explorer conditional comments. As a workaround, use something like this:

```golang
{{ "<!--[if lt IE 9]>" | safeHTML }}
  <script src="html5shiv.js"></script>
{{ "<![endif]-->" | safeHTML }}

Alternatively, you can use the backtick (`) to quote the IE conditional comments, avoiding the tedious task of escaping every double quotes (") inside, as demonstrated in the examples in the Go text/template documentation:

{{ `<!--[if lt IE 7]><html class="no-js lt-ie9 lt-ie8 lt-ie7"><![endif]-->` | safeHTML }}

Context (aka "the dot")

The most easily overlooked concept to understand about Go templates is that {{ . }} always refers to the current context. In the top level of your template, this will be the data set made available to it. Inside of a iteration, however, it will have the value of the current item. When inside of a loop, the context has changed: {{ . }} will no longer refer to the data available to the entire page. If you need to access this from within the loop, you will likely want to do one of the following:

Define a Variable Independent of Context

The following shows how to define a variable independent of the context.

{{% code file="range-through-tags-w-variable.html" %}}

{{ $title := .Site.Title }}
{{ $base := .Site.BaseURL }}
<ul class="tags">
{{ range .Params.tags }}
    <li>
        <a href="{{ $base }}tags/{{ . | urlize }}">{{ . }}</a>
        - {{ $title }}
    </li>
{{ end }}
</ul>

{{% /code %}}

{{% note %}} Notice how once we have entered the loop (i.e. range), the value of {{ . }} has changed. We have defined a variable outside of the loop ({{$title}}) that we've assigned a value so that we have access to the value from within the loop as well. {{% /note %}}

Use $. to Access the Global Context

$ has special significance in your templates. $ is set to the starting value of . ("the dot") by default. This is a documented feature of Go text/template. This means you have access to the global context from anywhere. Here is an equivalent example of the preceding code block where we defined $title and $base for the same desired output, but now using $:

{{% code file="range-through-tags-w-global.html" %}}

{{ $base := .Site.BaseURL }}
<ul class="tags">
{{ range .Params.tags }}
  <li>
    <a href="{{$base}}tags/{{ . | urlize }}">{{ . }}</a>
            - {{ $.Site.Title }}
  </li>
{{ end }}
</ul>

{{% /code %}}

{{% warning "Don't Redefine the Dot" %}} The built-in magic of $ would cease to work if someone were to mischievously redefine the special character; e.g. {{ $ := .Site }}. Don't do it. You may, of course, recover from this mischief by using {{ $ := . }} in a global context to reset $ to its default value. {{% /warning %}}

Whitespace

Go 1.6 includes the ability to trim the whitespace from either side of a Go tag by including a hyphen (-) and space immediately beside the corresponding {{ or }} delimiter.

For instance, the following Go template will include the newlines and horizontal tab in its HTML output:

{{% code file="with-whitespace.html" %}}

<div>
  {{ .Title }}
</div>

{{% /code %}}

{{% output file="with-whitespace-output.html" %}}

<div>
  Hello, World!
</div>

{{% /output %}}

Leveraging the - in the following example will remove the extra white space surrounding the .Title variable and remove the newline:

{{% code file="without-whitespace-input.html" %}}

<div>
  {{- .Title -}}
</div>

{{% /code %}}

{{% output file="without-whitespace-input.html" %}}

<div>Hello, World!</div>

{{% /output %}}

Go considers the following characters whitespace:

  • space
  • horizontal tab
  • carriage return
  • newline

Hugo Parameters

Hugo provides the option of passing values to the template language through the site configuration (i.e. for site-wide values), or through the metadata of each specific piece of content (i.e. the front matter). You can define any values of any type---as long as they are supported by the front matter format specified via metaDataFormat in your configuration file---and use them however you want in your templates.

Using Content (Page) Parameters

You can provide variables to be used by templates in individual content's front matter.

An example of this is used in this documentation site and specifically on the page you're currently reading. Most of the pages benefit from having the table of contents provided, but sometimes the table of contents doesn't make a lot of sense. We've defined a variable in our front matter that will prevent a table of contents from rendering when specifically set to false.

Here is the example front matter:

---
title: Go Template Primer
lastmod: 2017-02-21
date: 2013-11-18
toc: true
---

Here is the corresponding code inside the table-of-contents.html partial template:

{{% code file="table-of-contents.html" %}}

{{if ne .Params.toc false}}
<aside id="toc">
  <header class="toc-header">
    <a href="#{{.Title | urlize}}">
    <h3 class="{{.Section}}">{{.Title}}</h3>
    </a>
  </header>
  {{.TableOfContents}}
</aside>
<a href="#" id="toc-toggle"></a>
{{end}}

{{% /code %}}

We want the default behavior to be for pages to include a TOC unless otherwise specified. This template checks to make sure that the toc: field in this page's front matter does not equal (i.e. ne) false.

Using Site Configuration Parameters

In your site's configuration file (e.g., config.yaml), you can define site-level parameters that are available to you as variables throughout your templates.

For instance, you might declare:

{{% code file="config.yaml" %}}

params:
  CopyrightHTML: "Copyright &#xA9; 2013 John Doe. All Rights Reserved."
  TwitterUser: "spf13"
  SidebarRecentLimit: 5

{{% /code %}}

Within a footer layout, you might then declare a <footer> which is only provided if the CopyrightHTML parameter is provided, and if it is given, you would declare it to be HTML-safe, so that the HTML entity is not escaped again. This would let you easily update just your top-level config file each January 1st, instead of hunting through your templates.

{{% code file="layouts/partials/sample-footer.html" %}}

{{if .Site.Params.CopyrightHTML}}<footer>
<div class="text-center">{{.Site.Params.CopyrightHTML | safeHTML}}</div>
</footer>{{end}}

{{% /code %}}

An alternative way of writing the "if" and then referencing the same value is to use with instead. with rebinds the context (.) within its scope and skips the block if the variable is absent:

{{% code file="layouts/partials/twitter.html" %}}

{{with .Site.Params.TwitterUser}}<span class="twitter">
<a href="https://twitter.com/{{.}}" rel="author">
<img src="/images/twitter.png" width="48" height="48" title="Twitter: {{.}}"
 alt="Twitter"></a>
</span>{{end}}

{{% /code %}}

Finally, you can pull "magic constants" out of your layouts as well. The following uses the first and .RelPermalink functions as well as the .Site.Pages variable.

<nav class="recent">
  <h1>Recent Posts</h1>
  <ul>{{range first .Site.Params.SidebarRecentLimit .Site.Pages}}
    <li><a href="{{.RelPermalink}}">{{.Title}}</a></li>
  {{end}}</ul>
</nav>

Example: Show Only Upcoming Events

Go allows you to do more than what's shown here. Using Hugo's where function and Go built-ins, we can list only the items from content/events/ whose date (set in a content file's front matter) is in the future. The following is an example partial template:

{{% code file="layouts/partials/upcoming-events.html" download="upcoming-events.html" %}}

<h4>Upcoming Events</h4>
<ul class="upcoming-events">
{{ range where .Data.Pages.ByDate "Section" "events" }}
  {{ if ge .Date.Unix .Now.Unix }}
    <li><span class="event-type">{{ .Type | title }} —</span>
      {{ .Title }}
      on <span class="event-date">
      {{ .Date.Format "2 January at 3:04pm" }}</span>
      at {{ .Params.place }}
    </li>
  {{ end }}
{{ end }}
</ul>

{{% /code %}}