How to customise Hugo sections
Do you want to supercharge your Hugo sections? There are several great tips here for you.
Updated March 9, 2020
Tested with Hugo version 0.74.3
Hugo sections overview
Let’s go over how Hugo sections work before customising them.
Hugo automatically generates sections if you have subfolders in your content folder
If you use subfolders to organise your posts, Hugo will automatically create sections for this content for you.
For example, let’s say you have content on Mars, as well as content on Venus.
And let’s say you organise your Hugo content like this:
📁 content
📁 mars
is-there-life-on-mars.md
red-planet.md
📁 venus
second-brightest.md
Given the above, you’d end up with the following URIs:
/mars/
/mars/is-there-life-on-mars/
/mars/red-planet/
/venus/
/venus/second-brightest/
The first two URIs in each group above—/mars/
and /venus/
—are our section indexes; the rest of the URIs are blog posts.
Sections appear in Hugo blog post urls by default
As you can see above, whatever you name your section folder will appear in blog post URLs from that section.
For example, the blog post /venus/second-brightest/
contains the /venus/
subfolder.
You can eliminate the section subfolder from Hugo blog post urls
In Hugo, you can overwrite the url to eliminate the subfolder.
However, in this tutorial we’ll be using the default URL setting we’ve been exploring, i.e. where section subfolder names appear in blog post URLs.
Hugo also generates section index pages by default
Hugo also automatically generates index pages for each section. These are the /mars/
and /venus/
pages we discussed above.
However, if your theme doesn’t have a customised layout file for sections, then it will likely look quite boring.
I’ll now show you how to make these section index pages more interesting.
How to customise section indexes to make them more interesting
What if we wanted a custom h1
heading of “Destination Mars”? And what if we wanted some custom intro text before the list of Mars blog posts?
The way to do that is below. There are two parts.
Part 1: Store custom headings, descriptions, and images in an _index.md file
We’ll need to keep our custom h1
heading (“Destination Mars”) and our custom intro text in a special file named _index.md
, which we’ll need to store in the root (top level) of our Mars section.
In other words, the file will need to live at /content/mars/_index.md
.
Code for playing along
First, create a (blank) new file under /content/mars/
and name it _index.md
. Don’t forget the leading underscore in the filename.
Secondly, copy and paste in the following text into your _index.md
file and save it:
title: "Destination Mars"
summary: "When will we land on the Red Planet?"
Part 2: Create a custom layout named section.html
OK, so we’ve stored our custom text in the right place, now we need to create a layout file to call that custom text.
Code for playing along
Create a blank new file named section.html
in the /layouts/_default/
subfolder that’s included automatically in each Hugo site.
Inside this /layouts/_default/section.html
file, copy and paste the below:
<h1>{{ .Title }}</h1>
<p>{{ .Summary }}</p>
<div>
{{ range .Pages }}
{{ .Render "li" }}
{{ end }}
</div>
Note that you’ll also need to include any header or footer partials that you use elsewhere on your site. You can learn more about partials by scrolling down about a screen’s worth.
HTML output
So now our rendered /mars/
section homepage will contain this HTML:
<h1>Destination Mars</h1>
<p>When will we land on the Red Planet?</p>
<!-- Blog posts below -->
Pretty cool right?
Example of a customised Hugo section homepage
You can see a live example of a customised section homepage right here on this site.
How to get different email signup forms on posts from different sections
What if you want to allow people to sign up for email updates just for Mars posts, or just for Venus posts?
You’d need a custom email signup form for each section. I do that on this site, by the way.
I’ll show you how to do that, but first, you need to know about a Hugo feature called “partials”.
OK, so let’s say we have a subscribe
partial in our single
blog post template. In this subscribe
partial we’ll put our email signup forms.
Code for playing along
Our single
blog post template, /layouts/_default/single.html
, might look like this:
{{ partial "header.html" . }}
<h1>{{ .Title }}</h1>
{{ .Content }}
{{ partial "subscribe.html" . }}
{{ partial "footer.html" . }}
So there are three partials in there: the header, the footer, and the email signup forms.
All pretty straightforward.
However, what if you want a different signup form for each section? One for Venus, one for Mars?
You do it in the subscribe
partial itself, using Hugo’s if
and else if
statements:
Code for playing along
In our subscribe
partial, /layouts/partials/subscribe.html
, we see:
{{ if eq .Section "mars" }}
<!-- Mars signup form goes here -->
{{ else if eq .Section "venus" }}
<!-- Venus signup form goes here-->
{{ end }}
Nested partials (Hugo partials inside partials)
You can also use nested partials (partials inside other partials) in Hugo.
So rather than putting the two sets of email signup forms (one for Mars, one for Venus) directly in the subscribe
partial like we did above … (draws breath) … you could first put each form in its own partial, then use them in the conditional logic:
{{ if eq .Section "mars" }}
{{ partial "subscribe-mars.html" . }}
{{ else if eq .Section "venus" }}
{{ partial "subscribe-venus.html" . }}
{{ end }}
That way, you’d be free to use just the Mars email signup form elsewhere on the site, by calling {{ partial "subscribe-mars.html" . }}
How to get different RSS feeds in different Hugo sections
In a similar way to the section-specific email signup form work we did above, what if you wanted a different RSS feed for each section?
Hugo does most of the work for us, but not all. Read on to find out how to do this.
How does RSS work in Hugo by default?
Even if you don’t alter any RSS-related code, Hugo will create a bunch of different RSS feeds for you, right out of the box.
To start, there’ll be one for each section; that is, one for each folder in the root of your Hugo /content
folder.
So let’s say we had the same file structure as we saw earlier in this tutorial:
📁 content
📁 mars
is-there-life-on-mars.md
red-planet.md
📁 venus
second-brightest.md
You can see that we have two sections, one for Mars, the other for Venus.
Hugo will automatically generate RSS feeds at:
/mars/index.xml
/venus/index.xml
It will also generate a top-level RSS feed at:
/index.xml
which will contain content on both Mars and Venus.
How to eliminate the top-level RSS feed and just use the section-specific RSS feeds
I’m not sure if there’s an easy way to suppress publication of the top-level RSS feed (i.e. /index.xml
), but I can show you how to encourage feed readers to only present your section-specific RSS feeds to readers.
OK, here’s how to do that:
Code for playing along
In the <head>
section of your homepage, include this code:
{{ range .Site.Sections }}
<link rel="alternate" type="application/rss+xml"
title="{{ .Site.Title }} {{ title .Section }} Articles"
href="{{ .Site.BaseURL }}{{ .Section }}/index.xml">
{{ end }}
As usual, I’ve broken up the code over a few lines so you can read this tutorial more easily on your mobile device. However, your production code should keep the link
element all on one line.
Now let’s go through the code, line by line.
{{ range .Site.Sections }}
starts a loop over each site section. In our case, that’smars
andvenus
.
<link rel="alternate" type="application/rss+xml"
starts our RSS link. This is all standard, nothing to customise here.
title="{{ .Site.Title }} {{ title .Section }} Articles"
generates the title of the RSS link. We’re using two variables here.The first variable is
{{ .Site.Title }}
. This is the name of your site, and it’s pulled from yourconfig.toml
file, specifically thetitle
field.The second variable is
{{ title .Section }}
. The.Section
part pulls the name of section subfolders (e.g.mars
orvenus
), whiletitle
turns them into Title Case (Mars
andVenus
).Note that I’ve also hardcoded
Articles
to the end of the link title, so it will read, for example, “MoonBooth Mars Articles”.
href="{{ .Site.BaseURL }}{{ .Section }}/index.xml">
generates the actual link itself. There are two variables in here, one that we saw a second ago.The first variable is
{{ .Site.BaseURL }}
, and this also looks in yourconfig.toml
file, but this time, it’s looking for thebaseURL
field. For example:baseURL = "https://example.com/"
.And the second variable we saw a second ago, it’s
{{ .Section }}
, and it will fetchmars
andvenus
as the names of the subfolders under your Hugo/content/
folder.I’ve hardcoded
/index.xml
to the end of the link, so we’ll end up with, for example,https://example.com/mars/index.xml
as the value ofhref
.
{{ end }}
closes the loop we opened a few lines above.
OK, let’s see how it looks!
HTML output
Putting that together, you end up with this output in your rendered homepage’s HTML:
<link rel="alternate"
type="application/rss+xml"
title="MoonBooth Mars Articles"
href="https://example.com/mars/index.xml">
<link rel="alternate"
type="application/rss+xml"
title="MoonBooth Venus Articles"
href="https://example.com/venus/index.xml">
Note that Hugo pulls the sections in alphabetical order, which is why we see Mars before Venus.