Page bundles and Hugo shortcodes

Page bundles and shortcodes are great ways to improve managing content on your Hugo pages.

Farrel Burns, Developer Evangelist
Duration: 2 hours
Expertise level: Beginner
On this page:

Loading...

Code

Clone: git clone https://github.com/CloudCannon/hugo-learn-blog-template.git

Starter branch: git checkout shortcode-bundles-intro-start

Finished lesson: git checkout shortcode-bundles-intro-finish

What you’ll learn here:

  • About page bundles and shortcodes

  • How to set up page bundles

  • How to use shortcodes

  • How to create your own shortcodes

What are page bundles and shortcodes?

Page bundles and shortcodes are great ways to manage your content pages. Both are reasonably simple to use at a basic level and can work well together, so we’ll use both of them in this lesson.

Page bundles

A great feature of Hugo is the ability to group together any resources related to your content pages. Normally, we would add, for example, all images to the static or assets folder (depending on processing needs). But with page bundles, we can add images or other files to the same folder (or as a subfolder) as our content pages, which can make management easier and more convenient.

In Hugo, there are two types of page bundle. The difference is whether you add an index.md or _index.md (note the underscore) file:

  • An index.md means that our content is a “leaf”. This means the content isn’t a section of its own and doesn’t have more content sections below it.
  • An _index.md means this content is a “branch” (i.e., more content directories below it), and lets Hugo know this is a section. This file can also have metadata - note the content/_index.md file with metadata for our index page.

Shortcodes

A shortcode is a bit like a partial, except you can only use them in your content (and partials can only be used in your layouts). They are great for two reasons:

  • They can help you keep your layouts clean, so that you can use a generic template for multiple content types.
  • They can help you when you need to use custom HTML/CSS areas in your specific content pages, without putting HTML/CSS into your Markdown.

Better still, Hugo even has many built-in shortcodes, such as for Twitter and YouTube content, so you might not even have to create your own!

Practical work: creating page bundles and shortcodes

Create a page bundle

As usual, feel free to clone the code for this lesson.

In a previous lesson, we created some basic blog posts for displaying, using files in the static folder as resources. These are fine as is, but we can also group content as page bundles, where images and other resources are local to the content.

Why is this useful? It makes it easier to manage/keep track of resources specific to a page, and you can also add metadata about the page/content, such as description and alt text.

For an example bundle, we’ll create a gallery page showing some of our native birds. To begin creating a bundle, use the Hugo CLI to create a new gallery folder with an index.md:

hugo new gallery/index.md

Next, move the images folder from static to content/gallery, and then add this front matter to gallery/index.md, with metadata such as references to our local images folder.

---
# ^ rest of front matter 
resources:
- alt: Kea on a snowy mountain
  src: images/kea.jpg
- alt: Kaka in profile
  src: images/kaka.jpg
- alt: Kereru in a tree
  src: images/kereru.jpg
- alt: Hoiho with eyes closed
  src: images/hoiho.jpg
- alt: Pukeko on a wooden deck
  src: images/pukeko.jpg
- alt: Tui in a harakeke/NZ flax bush
  src: images/tui.jpg
---

With page bundles, you can also directly use page resources in a template, without needing to add this front matter metadata. However, this metadata gives us the flexibility to create shortcodes using alt/description text along with the relative URL of the image.

Adding shortcodes to content

Using shortcodes in Hugo is very easy.

In most cases, all you need to do is use the name of the shortcode inside of your content, with any necessary parameters and slightly different syntax than usual. Feel free to add these examples to content/gallery/index.md to see how they turn out:

# Gallery - with shortcodes
## Built-in shortcodes

### YouTube
{{< youtube 7W7hEUGtv4U >}}  
{{< youtube E3a88_SjJR0 >}}

### Figure
{{< figure src="./images/kea.jpg" title="Kea on a mountain" >}}

Some shortcodes, such as highlight, also allow nesting of content to be parsed/rendered:

HTML:
{{< highlight html >}}
<div>
  <p>Lorem ipsum.</p>
</div>
{{< /highlight >}}  

JavaScript:
{{< highlight js >}}
// All highlighting options:
// https://gohugo.io/content-management/syntax-highlighting/#list-of-chroma-highlighting-languages
const add = (a, b) => (a + b);
console.log(add(1, 2));
{{< /highlight >}}

Creating a custom shortcode

We’ve set up a page bundle with a folder of images and metadata about the images to our index.md front matter. While we could use Go templating inside a layout (gallery/index.md will default to using _default/single.html) to display these images, this is a good opportunity to create our own (very basic) shortcode that could be set up in any similar page bundle.

Because we have a group of images, let’s create a flexible (but slightly contrived) gallery shortcode:

  • Create the folder shortcodes inside layouts.
  • Add shortcodes/gallery.html with the following content:
<div class="gallery">
	{{ range .Page.Params.resources }}
		{{if $.Get "figures" }}
			<figure>
				<img src="{{.src}}" alt="{{.alt}}" />
				<figcaption>
					<p>{{.alt}}</p>
				</figcaption>
			</figure>
		{{else}}
			<img src="{{.src}}" alt="{{.alt}}">
		{{end}}
	{{end}}
</div>

We are using a new function called .Get, which is specific to shortcodes and allows us to get parameter data from our shortcode (either as numbered or named parameters). We are looking for a “figures” parameter in our shortcode, so if it’s true/exists, we’ll render our page bundle images as figures with captions; if not, we’ll just render them as images.

  • Now, to use this shortcode, simply add this to content/gallery/index.md:
## Custom shortcode
### With figures
{{< gallery figures=true >}}
### Without figures
<!-- Leaving out "figures" will also be considered "false" -->
{{< gallery figures=false >}}
## Custom shortcode
### With figures
{{< gallery figures=true >}}
### Without figures
<!-- Leaving out "figures" will also be considered "false" -->
{{< gallery figures=false >}}

If we navigate to our /gallery page, we should see two galleries rendered on our page - one containing figures, and another without.

There’s a lot more you can do with your own shortcodes, such as nesting content, error handling, and more, but that is beyond the scope of this lesson. See Hugo’s docs for custom shortcodes for more!

What's next?

With page bundles and shortcodes, we have more options for managing and displaying our page content.

For this and other pages, we’ve used front matter, which gives us access to local data for a page. However, there are times when we might want to reuse data throughout the site, like you might expect from a database. Fortunately, Hugo allows this, so global data files is our next subject.