Documentation for the MoonBooth SEO Theme for Hugo
How to use the MoonBooth SEO Theme for Hugo.
Updated October 15, 2023
About this theme
Here’s more about the MoonBooth SEO Theme for Hugo and all its SEO advantages.
Demo
This site (moonbooth.com) uses the theme, as does its sister site, Julia School, where I publish Julia language tutorials.
Installation
Step 1
After purchase, download the .zip
of the theme folder. Extract it, then drop it into your /themes/
folder.
Step 2
In your config file (usually /hugo.toml
), add these lines without any indents:
theme = "moonbooth-seo-theme"
disableKinds = ['taxonomy', 'term']
enableRobotsTXT = true
The first line will tell Hugo to go ahead and actually use the theme.
The second line tells Hugo that we’re not using any taxonomies. If you want to use this theme with Hugo taxonomies, feel free to add the relevant code to your site (including updating this part of hugo.toml
).
The third line activates the creation and publication of a robots.txt
file at the root of your site.
Step 3
Also in your config file, add these lines and fill in the values between the double quotes:
[params]
blogFooterLinkText = ""
# Sets anchor text of footer link to the blog
blogSection = ""
# Enter your blog folder's name [1]
color = ""
# Sets theme colour [2] & Safari mask icon colour [3]
description = ""
# Sets homepage meta description (for SEO)
rssTitle = ""
# Sets RSS feed title (for RSS readers)
seoTitle = ""
# Sets homepage <title> (for SEO)
Notes for code above:
[1] If you haven’t renamed your blog folder, the value you should enter here is Hugo’s default of posts
. I customise the name of my blog folder, making it more specific to help Google and humans infer what my content is about. For example, on my Julia language training site, I called it julia
.
[2] Theme colour documentation
[3] Safari mask icon documentation
Step 4
N.B. This step is required from v1.0.2 of the theme—released on March 17th, 2022—onwards. It is not necessary for earlier versions.
In the root of your /content/
folder, ensure you have an _index.md
file (note the leading underscore in the filename). It can be totally blank; mine is.
This file is needed to make the theme’s footer link logic work correctly on your site’s homepage.
Using the theme’s SEO features
Before we get into the theme’s SEO features, here’s a quick primer on the most important text fields for SEO:
Homepage
To set the <title>
and meta description of the homepage, fill in the value of seoTitle
and description
respectively in hugo.toml
, as discussed above.
The homepage is essentially just a subscribe form, and as such there is no <h1>
, only a form label
. The font size of this label
is the same as the <h1>
headings elsewhere on the site, though.
Blog index
SEO fields for the blog index are populated using the _index.md
approach outlined in the official Hugo documentation. In short, you’ll need to create a file named _index.md
at the root of your blog directory. If you’re using the default posts
as your blog folder, this file will live at /content/posts/_index.md
.
The theme will be looking for three text fields in this _index.md
file:
title
seoTitle
description
Each populates the relevant area of the blog index: title
populates the <h1>
heading, seoTitle
populates the document <title>
in the <head>
section, and description
populates two fields: the meta description in the <head>
and an italicised summary just below the <h1>
. You can see an example on my Julia language training site.
Blog posts
The way to populate the SEO (and other) fields in a blog post is with the following YAML front matter:
---
title:
date: 2021-01-19 13:04:46+11:00
seoTitle:
description:
authors: ["Firstname Lastname"]
tableOfContents: true
---
Let’s go over each.
title
populates the <h1>
on the blog post itself, and also the anchor text of the link from the blog index back to the post.
date
populates the following: 1) the date in the byline on the blog post itself; 2) the <lastmod>
date in the XML sitemap—this tells Google when the post was last modified; and 3) the <pubDate>
in the RSS feed, which provides the date to RSS readers.
seoTitle
populates the document <title>
in the <head>
section.
description
populates two fields: the meta description in the <head>
and an italicised summary just below the <h1>
. You can see an example on my Julia language training site.
authors: ["Firstname Lastname"]
populates the byline (author) field near the top of the blog post. Note that the value is an array of strings, which allows Hugo to do things such as build a page of all your authors.
tableOfContents
is an optional YAML field, which, if set to true
, builds a table of contents for the page, like the one at the top of this article.
Keeping pages out of Google’s index
There are likely a few pages on your site you want to keep out of Google’s index. Your “thank you for signing up” page, your unsubscribe page, and your 404 page, for example.
The reason you want to keep these pages out of Google’s index is because you don’t want to waste Google’s time crawling pages which will never bring you SEO traffic.
Instead, you want to direct Google’s attention to pages that will bring you SEO traffic, such as useful blog posts and product pages.
The easiest way to keep necessary but non-SEO-worthy pages out of Google’s index is to put a noindex
tag in the <head>
section of the relevant page.
Specifically, a tag that looks like this:
<meta name="robots" content="noindex" />
That will tell Google and other reputable search engines not to index (list) the page in search results.
You can add the noindex
tag easily with this theme, by adding a parameter to your YAML front matter—for posts and pages—that looks like this:
noindex: true
Sitemap for search engines
One of the parts of this theme I’m most proud of is that when you noindex
a page, it also withholds it from the SEO (XML) sitemap and the RSS feed. I’ll explain why.
If you noindex
a page but simultaneously list it in your XML sitemap, Google considers that an error, or at least, suboptimal.
It’s kind of like driving a car with the handbrake on.
On the one hand, you’re telling Google to go look at Page X (by listing it in the XML sitemap), but on the other, you’re telling it to stop by including the noindex
tag.
Generally speaking, you don’t want to direct Google’s attention to pages which have a noindex
tag.
robots.txt
Another theme feature I’m proud of is making the location of the XML sitemap (see above section) easy for Google to discover.
To do that, I use an SEO feature called robots.txt
.
This theme will automatically include the location of your XML sitemap in your robots.txt
file. All you have to do is include the line:
enableRobotsTXT = true
in your hugo.toml
file.
CSS
Broadly, there are three ways to customise styles using this theme; I cover each below. Note that you can use these methods in tandem; they’re not mutually exclusive.
Method 1: Change the value of SCSS variables
The MoonBooth SEO Theme for Hugo uses SCSS—a superset of CSS3—to generate its CSS style sheet.
I’ve designed it this way so that you can change the theme colours in just two lines, rather than doing a potentially messy “find and replace”.
How? SCSS uses variables—something CSS really needs—to keep your styles DRY ("Don’t Repeat Yourself").
All the style variables live in an “SCSS partial” at /themes/assets/scss/_variables.scss
.
The variables in the _variables.scss
partial look like this:
$color-accent: red;
$color-background: black;
$color-gray: #ccc;
$color-text: white;
$increment: 10px;
$wrapper-max-width: 700px;
Going through each in turn:
$color-accent
sets the accent colour. Namely: links and buttons in hovered state, block quote decoration, form input fill, button and table borders. It defaults to red because I had to pick a colour that would stand out.
$color-background
sets the background colour. It defaults to black because the theme defaults to dark mode, but you can easily change it (as all variables) by following the steps outlined below.
$color-gray
specifies which shade of grey should be used when appropriate. At the moment it only sets the colour of visited links, but may be used for more elements in the future. I made it a variable mainly so that all colours can be specified in one place (the SCSS variables partial).
$color-text
sets the colour of paragraphs, links, lists, headings (in non-visited, non-hovered state). It defaults to white because the theme defaults to dark mode (white text on a black background).
$increment
sets the rhythm for font sizes. Its default value is 10px, but your fonts will never be that small. In the main stylesheet, paragraphs are $increment * 2
or 20px (did you know you can do maths in SCSS?), <h3>
headings are $increment * 2.5
(25px), <h2>
headings are $increment * 4
(40px), and <h1>
headings are $increment * 6
(60px). If you want to change these multiples, you can learn how to do that in the section on adding custom styles, which is lower down on this page.
$wrapper-max-width
sets the maximum width of the content column, and defaults to 700px. This theme is responsive, and uses a single column on both mobile and desktop devices. However, given most phone screens are narrower than 700px, this setting will really only affect desktop and tablet devices. I chose 700px as the default as it makes for easy reading when combined with the default paragraph font size (20px) and the default font family.
Here are all the variables in table form:
Design element | SCSS variable | Default value |
---|---|---|
Accent colour | $color-accent | red |
Background color | $color-background | black |
Light gray | $color-gray | #ccc |
Text color | $color-text | white |
Font size increment | $increment | 10px |
Content width | $wrapper-max-width | 700px |
To change the value of any of these variables:
Step 1
Duplicate /themes/assets/scss/_variables.scss
into your repo (e.g. outside the /themes
folder) at /themes/assets/scss/_variables.scss
. You may need to create the /assets/
and/or /scss/
folders. Note the leading underscore in the filename of _variables.scss
. The reason you want to duplicate the file into your repo is so that your changes won’t be overwritten if/when you pull theme changes.
Step 2
Copy in all six variables, not just the one(s) you want to change. The master theme.scss
file will be expecting to see all six variables filled out in your copy of /assets/scss/_variables.scss
(if it exists).
Step 3
Change some/all values as you desire. For example, if you wanted to switch from the default dark theme to a light theme, and from the default red accent colour to blue, the complete contents of your <YOUR_REPO>/assets/scss/_variables.scss
file could look like this:
$color-accent: blue;
$color-background: white;
$color-gray: #ccc;
$color-text: black;
$increment: 10px;
$wrapper-max-width: 700px;
Method 2: Add custom CSS or SCSS
If you want to make style changes that go beyond altering the theme colours or otherwise editing the SCSS variable values, you can do that too.
For example, if you want a different hover effect on the email signup button, you would do that by using the process outlined in this section.
The way to add custom styles is to use an SCSS partial I’ve called _custom.scss
. Here, you can overwrite style rules that ship with the theme and/or add your own style rules.
Your custom style rules can be in plain CSS, or you can use SCSS.
Here’s how to make CSS changes to the theme without having to clone its SCSS file.
Step 1
Duplicate /themes/assets/scss/_custom.scss
into your repo (e.g. outside the /themes
folder) at /themes/assets/scss/_custom.scss
. You may need to create the /assets/
and/or /scss/
folders. Note the leading underscore in the filename of _custom.scss
. The reason you want to duplicate the file into your repo is so that your changes won’t be overwritten if/when you upgrade the theme.
Step 2
Add your CSS or SCSS style rules to the file you just created in Step 1. That’s it!
Method 3: Major style overhaul
If you want to change a lot of styles, you’ll probably be better off duplicating the theme stylesheet into your repo and editing it there. That way, you won’t have to “swim against the tide” of the existing style rules that ship with the theme, constantly overwriting them as you would if you used Method 2, above. You’ll probably also have a more efficient style sheet from the browser’s perspective.
Here’s how to use this method:
Step 1
Create a blank SCSS file—don’t worry, you can use just CSS—at <YOUR_REPO>/assets/scss/theme.scss
Step 2
Add your CSS or SCSS style rules to the file you just created in Step 1. Again, you can use just plain old CSS if you like, you don’t even have to know SCSS. This will completely bypass (ignore) the default MoonBooth CSS styles.
[Optional] JavaScript
Custom JS
To add custom JS to your Hugo site using this theme, you don’t have to create your own head.html
partial.
Instead, simply create a file at /static/scripts/custom.js
and put all your custom JS in that file.
The theme will notice the presence of the custom.js
file and create a link to it in the <head>
section. If no custom.js
file exists (the default state), then no link is created. Simple!
External JS files
If you want to add third-party Javascript—from Stripe, for example—to your site with this theme, simply add the link to the script in hugo.toml
, like this:
[params]
scripts = ["https://js.stripe.com/v3/"]
This will appear in the <head>
section of all your web pages like this:
<script src="https://js.stripe.com/v3/"></script>
Note that the theme is expecting an array—hence the square brackets surrounding the value above—even if you only have one third-party script to add.
To add more scripts, simply comma-separate them inside the array, like this:
[params]
scripts = ["https://js.stripe.com/v3/", "https://js.example.com/v1/"]
NB: Read on for an easy way to implement Google Analytics.
[Optional] Google Analytics
If you want to add Google Analytics to your site, the MoonBooth SEO Theme for Hugo makes this easy.
You can use the new version of Google Analytics (GA4), or the sunsetting version, (GA3 a.k.a. Universal Analytics), or neither!
Opt-in if desired; do nothing if you don’t want Google Analytics
This feature is opt-in; if you don’t use Google Analytics, simply do nothing. You won’t end up with any extraneous code on your site. (That’s what I do on my own sites, including this one—no GA in sight!)
No inflated pageviews from localhost
I particularly like the fact that with the MoonBooth SEO Theme for Hugo, you won’t get any inflated pageviews or other GA metrics when using localhost.
This is because I’ve added conditional logic which requires the Hugo environment to be set to production
for the GA code to be inserted. Hugo automatically sets the environment to production
when running the hugo
command to build your site.
Conversely, when you run hugo server
to view your site locally via localhost, Hugo automatically sets the environment to development
. As mentioned earlier, because of the conditional logic I’ve included in the MoonBooth SEO Theme for Hugo, this means your GA code won’t be inserted for localhost pageviews.
How to implement Google Analytics for Hugo
To add Google Analytics (GA4 or GA3) when using the MoonBooth SEO Theme for Hugo, simply follow the instructions below.
In hugo.toml
, under the [params]
section, add a parameter named ga_id
and set the value as a string containing your Google Analytics id.
For example, for Google Analytics 3 (a.k.a. Universal Analytics; IDs start with UA-
), you’d have something like this:
[params]
ga_id = "UA-123456789-1"
(Obviously you’d use your own UA-
ID.)
Whereas for Google Analytics 4 (GA4), you’d have something like this in your Hugo site’s hugo.toml
:
[params]
ga_id = "G-A1B2C3D4E5"
(Obviously you’d use your own G-
ID.)
[Optional] Social media markup
The MoonBooth SEO Theme for Hugo also includes optional automatic markup in the form of meta tags for Facebook and Twitter. This is an opt-in feature; if you don’t want the markup, simply do nothing. However, I do recommend enabling this feature; read on to see why.
The theme uses an approved combination of Open Graph markup (for both Facebook and Twitter) and Twitter card markup (to add extra information for Twitter cards).
If you enable this opt-in feature—more on that below—the theme will generate meta tags to ensure your pages look great when shared on Facebook and Twitter. Note that even if you have no personal social media presence, others may share your content, so it’s worth having the preview of your content look as good as possible.
The social media meta tags are super-lightweight, and are not “like”, “share” or “tweet” buttons, so they have no ability to track users on your site—there’s zero Javascript involved.
If you don’t want the social media tags, simply do nothing—you won’t get any extraneous social media code on your site. However, again, if you choose not to enable this feature, your articles and homepage will probably not look their best when shared on Facebook and Twitter.
If you do want these meta tags—again, I recommend enabling this feature—read on to see how. There’s only one step!
How to enable social media tags for Hugo
There’s only one step—simply create a .png
image of your site logo or brand (here’s mine) that’s 1200px wide and 630px high. Add it to your Hugo site’s /static/
folder, and you’re done!
After publishing (or in localhost mode), you should be able to see it at /opengraph.png
(again, see my example above).
Note that if you don’t add this .png
image, you won’t get any social media tags. This is because the image tag is required for Open Graph.
At the risk of sounding repetitive, do note that the theme is looking specifically for a .png
image named opengraph.png
. PNGs are the best image type for logos (other than SVGs, which unfortunately aren’t accepted by Facebook and Twitter as preview images).
Read on to see which social media tags you’ll get, and which data populates them.
Which Open Graph tags will appear?
The following Open Graph tags will appear when you enable social media tags in the theme (again, how to enable is covered above).
og:title
This is pulled from thetitle
field in the YAML front matter of posts and pages, or from thetitle
inhugo.toml
for the homepage.
og:description
This is pulled from thedescription
field in the YAML front matter of posts and pages, or from thedescription
inhugo.toml
for the homepage.
og:type
This is set toarticle
for blog posts (such as the one you’re reading right now) and pages (such as the About page) and towebsite
for all other content types (including the home page and blog indexes).
og:site_name
This is populated by the sitetitle
inhugo.toml
.
og:image
This will be hardcoded to/opengraph.png
, which is the image you’ll need to create in order to enable social media markup. See above section for details.
og:image:secure_url
This will also be hardcoded to/opengraph.png
.
og:image:type
This will be hardcoded toimage/png
.
og:image:width
This will be hardcoded to1200
(1200 pixels; Facebook’s recommended width).
og:image:height
This will be hardcoded to630
(630 pixels; Facebook’s recommended width).
og:image:alt
This will be populated by the sitetitle
inhugo.toml
plus the wordlogo
. For example, the value of this field for my site isMoonBooth logo
.
Which Twitter tags will appear?
Just one Twitter-specific tag will appear:
twitter:card
This will be hardcoded tosummary_large_image
.
All other Twitter metadata reuses the Open Graph tags discussed above. This is a Twitter-approved solution.
[Optional] Netlify CMS
Do you have a content team or person who wants a WYSIWYG editor to add and update content on a Hugo site? The free and mostly excellent Netlify CMS provides this functionality.
This is an opt-in feature of the MoonBooth SEO Theme for Hugo; if you don’t want the Netlify CMS, simply do nothing. You won’t get any extraneous code clogging up your site!
You don’t need to be hosted on Netlify to use the Netlify CMS
You don’t need to be hosted on Netlify to use the Netlify CMS. From the official site linked above:
Not all Netlify sites use Netlify CMS, and not all sites using Netlify CMS are on Netlify … Netlify CMS … has never been locked to the Netlify platform (despite the name).
How to implement the Netlify CMS for Hugo
To enable Netlify CMS on the MoonBooth SEO Theme for Hugo, simply create a parameter named netlify_cms
set to true
under [params]
in hugo.toml
.
The relevant part of your hugo.toml
will look something like this:
[params]
netlify_cms = true
Once done, all the necessary Netlify CMS code will be added. Again, this is an opt-in feature of the MoonBooth SEO Theme for Hugo, so if you don’t want the Netlify CMS added, simply do nothing, and no extraneous code will clog up your pages.
How to purchase
You can purchase the MoonBooth SEO Theme for Hugo here:
You can also read the benefits page here.
Feedback
I’d love feedback on this theme—I’m on ron dot erdos at [the site you’re on], or on Twitter (DMs open).