Shortcode templates
Introduction
Hugo provides embedded shortcodes for many common tasks, but you’ll likely need to create your own for more specific needs. Some examples of custom shortcodes you might develop include:
- Audio players
- Video players
- Image galleries
- Diagrams
- Maps
- Tables
- And many other custom elements
Directory structure
Create shortcode templates within the layouts/shortcodes
directory, either at its root or organized into subdirectories.
layouts/
└── shortcodes/
├── diagrams/
│ ├── kroki.html
│ └── plotly.html
├── media/
│ ├── audio.html
│ ├── gallery.html
│ └── video.html
├── capture.html
├── column.html
├── include.html
└── row.html
When calling a shortcode in a subdirectory, specify its path relative to the shortcode
directory, excluding the file extension.
{{< media/audio path=/audio/podcast/episode-42.mp3 >}}
Lookup order
Hugo selects shortcode templates based on the shortcode name, the current output format, and the current language. The examples below are sorted by specificity in descending order. The least specific path is at the bottom of the list.
Shortcode name | Output format | Language | Template path |
---|---|---|---|
foo | html | en | layouts/shortcodes/foo.en.html |
foo | html | en | layouts/shortcodes/foo.html.html |
foo | html | en | layouts/shortcodes/foo.html |
foo | html | en | layouts/shortcodes/foo.html.en.html |
Shortcode name | Output format | Language | Template path |
---|---|---|---|
foo | json | en | layouts/shortcodes/foo.en.json |
foo | json | en | layouts/shortcodes/foo.json |
foo | json | en | layouts/shortcodes/foo.json.json |
foo | json | en | layouts/shortcodes/foo.json.en.json |
Methods
Use these methods in your shortcode templates. Refer to each methods’s documentation for details and examples.
- Get
- Returns the value of the given argument.
- Inner
- Returns the content between opening and closing shortcode tags, applicable when the shortcode call includes a closing tag.
- InnerDeindent
- Returns the content between opening and closing shortcode tags, with indentation removed, applicable when the shortcode call includes a closing tag.
- IsNamedParams
- Reports whether the shortcode call uses named arguments.
- Name
- Returns the shortcode file name, excluding the file extension.
- Ordinal
- Returns the zero-based ordinal of the shortcode in relation to its parent.
- Page
- Returns the Page object from which the shortcode was called.
- Params
- Returns a collection of the shortcode arguments.
- Parent
- Returns the parent shortcode context in nested shortcodes.
- Position
- Returns the filename and position from which the shortcode was called.
- Ref
- Returns the absolute URL of the page with the given path, language, and output format.
- RelRef
- Returns the relative URL of the page with the given path, language, and output format.
- Scratch
- Returns a “scratch pad” to store and manipulate data, scoped to the current shortcode.
- Site
- Returns the Site object.
- Store
- Returns a “scratch pad” to store and manipulate data, scoped to the current shortcode.
Examples
These examples range in complexity from simple to moderately advanced, with some simplified for clarity.
Insert year
Create a shortcode to insert the current year:
{{- now.Format "2006" -}}
Then call the shortcode from within your markup:
This is {{< year >}}, and look at how far we've come.
This shortcode can be used inline or as a block on its own line. If a shortcode might be used inline, remove the surrounding whitespace by using template action delimiters with hyphens.
Insert image
This example assumes the following content structure, where content/example/index.md
is a page bundle containing one or more page resources.
content/
├── example/
│ ├── a.jpg
│ └── index.md
└── _index.md
Create a shortcode to capture an image as a page resource, resize it to the given width, convert it to the WebP format, and add an alt
attribute:
{{- with .Page.Resources.Get (.Get "path") }}
{{- with .Process (printf "resize %dx wepb" ($.Get "width")) }}
<img src="{{ .RelPermalink }}" width="{{ .Width }}" height="{{ .Height }}" alt="{{ $.Get "alt" }}">
{{- end }}
{{- end -}}
Then call the shortcode from within your markup:
{{< image path=a.jpg width=300 alt="A white kitten" >}}
The example above uses:
- The
with
statement to rebind the context after each successful operation - The
Get
method to retrieve arguments by name - The
$
to access the template context
Insert image with error handling
The previous example, while functional, silently fails if the image is missing, and does not gracefully exit if a required argument is missing. We’ll add error handling to address these issues:
{{ with .Get "path" }}
{{- with $r := $.Page.Resources.Get ($.Get "path") }}
{{- with $.Get "width" }}
{{- with $r.Process (printf "resize %dx wepb" ($.Get "width" )) }}
{{- $alt := or ($.Get "alt") "" }}
<img src="{{ .RelPermalink }}" width="{{ .Width }}" height="{{ .Height }}" alt="{{ $alt }}">
{{- end }}
{{- else }}
{{- errorf "The %q shortcode requires a 'width' argument: see %s" $.Name $.Position }}
{{- end }}
{{- else }}
{{ warnf "The %q shortcode was unable to find %s: see %s" $.Name ($.Get "path") $.Position }}
{{- end }}
{{- else }}
{{ errorf "The %q shortcode requires a 'path' argument: see %s" .Name .Position }}
{{- end -}}
This template throws an error and gracefully fails the build if the author neglected to provide a path
or width
argument, and it emits a warning if it cannot find the image at the specified path. If the author does not provide an alt
argument, the alt
attribute is set to an empty string.
The Name
and Position
methods provide helpful context for errors and warnings. For example, a missing width
argument causes the shortcode to throw this error:
ERROR The "image" shortcode requires a 'width' argument: see "/home/user/project/content/example/index.md:7:1"
Positional arguments
Shortcode arguments can be named or positional. We used named arguments previously; let’s explore positional arguments. Here’s the named argument version of our example:
{{< image path=a.jpg width=300 alt="A white kitten" >}}
Here’s how to call it with positional arguments:
{{< image a.jpg 300 "A white kitten" >}}
Using the Get
method with zero-indexed keys, we’ll initialize variables with descriptive names in our template:
{{- $path := .Get 0 }}
{{- $width := .Get 1 }}
{{- $alt := .Get 2 }}
Named and positional arguments
You can create a shortcode that will accept both named and positional arguments, but not at the same time. Use the IsNamedParams
method to determine whether the shortcode call used named or positional arguments:
{{- $path := cond (.IsNamedParams) (.Get "path") (.Get 0) }}
{{- $width := cond (.IsNamedParams) (.Get "width") (.Get 1) }}
{{- $alt := cond (.IsNamedParams) (.Get "alt") (.Get 2) }}
This example uses the cond
alias for the compare.Conditional
function to get the argument by name if IsNamedParams
returns true
, otherwise get the argument by position.
Argument collection
Use the Params
method to access the arguments as a collection.
When using named arguments, the Params
method returns a map:
{{< image path=a.jpg width=300 alt="A white kitten" >}}
{{- .Params.path }} → a.jpg
{{- .Params.width }} → 300
{{- .Params.alt }} → A white kitten
When using positional arguments, the Params
method returns a slice:
{{< image a.jpg 300 "A white kitten" >}}
{{- index .Params 0 }} → a.jpg
{{- index .Params 1 }} → 300
{{- index .Params 1 }} → A white kitten
Combine the Params
method with the collections.IsSet
function to determine if a parameter is set, even if its value is falsy.
Inner content
Extract the content enclosed within shortcode tags using the Inner
method. This example demonstrates how to pass both content and a title to a shortcode. The shortcode then generates a div
element containing an h2
element (displaying the title) and the provided content.
{{< contrived title="A Contrived Example" >}}
This is a **bold** word, and this is an _emphasized_ word.
{{< /contrived >}}
<div class="contrived">
<h2>{{ .Get "title" }}</h2>
{{ .Inner | .Page.RenderString }}
</div>
The preceding example called the shortcode using standard notation, requiring us to process the inner content with the RenderString
method to convert the Markdown to HTML. This conversion is unnecessary when calling a shortcode using Markdown notation.
Nesting
The Parent
method provides access to the parent shortcode context when the shortcode in question is called within the context of a parent shortcode. This provides an inheritance model.
The following example is contrived but demonstrates the concept. Assume you have a gallery
shortcode that expects one named class
argument:
<div class="{{ .Get "class" }}">
{{ .Inner }}
</div>
You also have an img
shortcode with a single named src
argument that you want to call inside of gallery
and other shortcodes, so that the parent defines the context of each img
:
{{ $src := .Get "src" }}
{{ with .Parent }}
<img src="{{ $src }}" class="{{ .Get "class" }}-image">
{{ else }}
<img src="{{ $src }}">
{{ end }}
You can then call your shortcode in your content as follows:
{{< gallery class="content-gallery" >}}
{{< img src="/images/one.jpg" >}}
{{< img src="/images/two.jpg" >}}
{{< /gallery >}}
{{< img src="/images/three.jpg" >}}
This will output the following HTML. Note how the first two img
shortcodes inherit the class
value of content-gallery
set with the call to the parent gallery
, whereas the third img
only uses src
:
<div class="content-gallery">
<img src="/images/one.jpg" class="content-gallery-image">
<img src="/images/two.jpg" class="content-gallery-image">
</div>
<img src="/images/three.jpg">
Other examples
For guidance, consider examining Hugo’s embedded shortcodes. The source code, available on GitHub, can provide a useful model.
Detection
The HasShortcode
method allows you to check if a specific shortcode has been called on a page. For example, consider a custom audio shortcode:
{{< audio src=/audio/test.mp3 >}}
You can use the HasShortcode
method in your base template to conditionally load CSS if the audio shortcode was used on the page:
<head>
...
{{ if .HasShortcode "audio" }}
<link rel="stylesheet" src="/css/audio.css">
{{ end }}
...
</head>