09 – Partials and shortcodes
In the past couple of chapters, we’ve learned how we can use base templates, code blocks, and Hugo’s template lookup rules to build a site with templates that are efficient and eliminate redundant code. This will help make our code more maintainable and prevent you from having to pull out all your hair as your site grows larger and more complex.
Code reuse is an important mantra for any software developer. Thankfully, Hugo provides a few other tools that can help you avoid code duplication and keep your templates organized.
Partials and shortcodes are two features that allow you to create reusable snippets of code that you can use in your site.
While they serve similar functions, they differ in where they are used. Shortcodes can only be used in content files, while partials are used in templates. You can’t use a partial in a content file, and you can’t use a shortcode in a template.
Using shortcodes
You can think of shortcodes as a way to embed content that requires specific HTML markup or Javascript. Embedding a tweet or Youtube video are some common examples.
In fact, Hugo comes out-of-the-box with shortcodes for embedding Twitter, Youtube, Instagram, Vimeo, and other content.
The syntax for embedding a shortcode is similar to a normal code block, except that angle brackets are included inside the double braces. A shortcode can also take one or more parameters. Here’s an example that will display a tweet:
A new 1LP version of Rick’s career-spanning compilation ‘The Best of Me’ will be released on September 2nd! Order your copy now: https://t.co/HHaPWYdi3P - Team Rick pic.twitter.com/OVxiTxBzJS
— Rick Astley (@rickastley) August 8, 2022
If you insert this into your Markdown, the shortcode will be replaced in the rendered output with the HTML to display the tweet.
You’ll notice that this shortcode takes two parameters. Parameters are optional in shortcodes, and if there’s only one it doesn’t need to be named.
For example, here’s a shortcode for a Youtube video:
With this shortcode, the parameter is the id of the video (the v
parameter in the URL of a Youtube video).
Here’s the code that this shortcode outputs:
<div style="position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;">
<iframe src="https://www.youtube.com/embed/dQw4w9WgXcQ" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;" allowfullscreen title="YouTube Video"></iframe>
</div>
A list of all the built-in shortcodes can be found in the official Hugo documentation.
With built-in shortcodes, the code is supplied by Hugo and not your templates. You can’t modify it directly. If you need to make your own shortcode, it’s easy to do.
Creating your own shortcodes
Shortcodes are templates that live in the /layouts/shortcodes/
directory and have a .html
extension.
Let’s create a simple shortcode for our pets website. It will simply display a gif of a sad cat.
First, create a directory for your shortcodes:
mkdir layouts/shortcodes
Next, create a file named sad-cat.html
:
vim layouts/shortcodes/sad-cat.html
Insert this code into your file:
<iframe src="https://giphy.com/embed/qA9BnxUPmgWgU" width="480" height="235" frameBorder="0" class="giphy-embed" allowFullScreen></iframe><p><a href="https://giphy.com/gifs/puss-prewedding-summerbird-qA9BnxUPmgWgU">via GIPHY</a></p>
Now, any time that you want to drop a picture of a sad cat into an article, you can use this code:
{{< sad-cat >}}
Note that the name of the shortcode is simply its file name without the file extension.
Now, when you view your page, sad-cat
should be replaced with the image of a sad cat.
Shortcode parameters
There’s one problem with our sad-cat example: it’s only good for displaying one gif. That’s not very useful, so let’s create a new shortcode that will display any image from Giphy.
Create a file named giphy.html
:
vim layouts/shortcodes/giphy.html
… then insert this code into your file:
<iframe src="https://giphy.com/embed/{{ .Get "id" }}" frameBorder="0" class="giphy-embed" allowFullScreen></iframe><p><a href="{{ .Get "url" }}">via GIPHY</a></p>
Now you can embed any Giphy image in your content file. Here’s one of a happy dog:
{{< giphy id="3ndAvMC5LFPNMCzq7m" url="https://giphy.com/gifs/cute-aww-eyebleach-3ndAvMC5LFPNMCzq7m" >}}
You’ll notice that this shortcode has two named parameters. These are accessed in the shortcode template by using {{ .Get "id" }}
and {{ .Get "url" }}
.
If you wanted to access these parameters by position instead, you could use {{ .Get 0}}
and {{ .Get 1 }}
. However, this is only a good practice if your shortcode takes only one parameter. Shortcodes that accept multiple parameters will be easier to understand if you use named parameters.
There’s more details about creating custom shortcodes that you can learn about in the official documentation.
Using partials
Shortcodes are reusable code snippets that you embed in your content files. Partials, on the other hand, are code snippets you use in template files.
You create partials in a way very similar to shortcodes. Partials live in the layouts/partials
directory by default, so let’s create that for our example:
mkdir layouts/partials
One example of where you might want to use a partial is to create an ad tag. Google Adsense is a common ad platform, so let’s create an example partial to display an Adsense tag:
vim layouts/partials/adsense.html
The code for that might look like this:
<script async src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-123456"
crossorigin="anonymous"></script>
<ins class="adsbygoogle"
style="display:block; text-align:center;"
data-ad-layout="in-article"
data-ad-format="fluid"
data-ad-client="ca-pub-123456"
data-ad-slot="7890"></ins>
<script>
(adsbygoogle = window.adsbygoogle || []).push({});
</script>
(You’ll notice that we’ve used fake values for data-ad-client and data-ad-slot, so this won’t actually render an ad for you, but the HTML will be visible in the page output.)
To use this partial, you would place this code snippet anywhere in one of your templates (such as single.html
):
{{ partial "adsense.html" }}
This will display our ad code wherever we place this partial in a template.
Partials parameters
However, much like our Giphy shortcode example, this partial would be more useful if we could pass some parameters in. One convention is to pass in the entire site context with a dot, like this:
{{ partial "adsense.html" . }}
This would give the partial template access to all of the variables in the parent template. That’s a common practice, but we’re going to do something a little different. Our Adsense code needs two parameters, so we’re going to pass them in like this:
{{ partial "adsense.html" (dict "adClient" "ca-pub-123456" "adSlot" "123456") }}
Our layout/partials/adsense.html
code can then be modified to access these variables:
<script async src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client={{ .adClient }}"
crossorigin="anonymous"></script>
<ins class="adsbygoogle"
style="display:block; text-align:center;"
data-ad-layout="in-article"
data-ad-format="fluid"
data-ad-client="ca-pub-{{ .adClient }}"
data-ad-slot="{{ .adSlot }}"></ins>
<script>
(adsbygoogle = window.adsbygoogle || []).push({});
</script>
This makes our partial much more useful because the same component can be used to display any ad slot you need.
You’ll notice that we’re using a dict
to pass our two parameters as name-value pairs. You can read more about the dict function in the official Hugo docs.
Recap: when to use partials and shortcodes
You can think of both shortcodes and partials as two ways of implementing reusable components in your Hugo site.
While they work in similar ways, shortcodes are intended for components that are content-focused, such as embedded videos and other HTML widgets, while partials can be used to eliminate duplication in your template code. That’s why shortcodes are used in content files and partials are for templates.
However, for many instances where we need to reduce code duplication, base templates and code blocks already provide the functionality we need. For example, page headers and footers are often same across pages of a site, so you should try to implement those in your base template if possible.
What is the use case for partials then? Our advertising code example is a pretty good example. You might not want to show ads on every page, or you might have multiple ads, each of which would have a different ad-slot identifier. Because this piece of code isn’t inherited into every page from the base template, it’s better suited for a partial that can be dropped onto any page.