Hugo tutorial looking at page bundles and shortcodes to improve managing content on you pages.
About page bundles and shortcodes
How to set up page bundles
How to use shortcodes
How to create your own shortcodes
# Starting repo
git clone https://github.com/CloudCannon/hugo-learn-blog-template.git
# Starting branch:
git checkout shortcode-bundles-intro-start
# Finished branch:
git checkout shortcode-bundles-intro-finish
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.
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:
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._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.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:
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!
Please note that Hugo shortcodes are not currently supported within CloudCannon’s Visual Editor.
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.
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:
## 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 >}}
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:
shortcodes
inside layouts
.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.
content/gallery/index.md
:## 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!
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.