Hugo is a great static site generator, but it can be a bit inscrutable in some of the decisions it makes. It’s default RSS template is fairly opinionated in what it decides to include/exclude, but it can be easily overridden to match what you want your RSS feed to contain.
All the below tips involve overriding Hugo’s default RSS template.
To get started:
- Grab a copy of
that template,
and paste it into your site at
layouts/_default/rss.xml
. - We’ll be making updates to the line that originally reads as
{{ range $pages }}
. As of writing, it’s line 23.
Include all pages in the main RSS feed
By default, the root index.rss
only contains content directly under the root
directory. If your blog lives under a subsection (as it likely does), then by
default your posts won’t show up in your site’s root RSS feed.
Supposed your site looks something like this:
site
about.md
blog/
my_post.md
Then, index.rss
will only contain a reference to the generated about.html
and blog/index.html
– but not blog/my_post.html
.
If you want all your pages to appear in the root RSS feed, you can change the
template to loop over all .Site.Pages
:
<!-- Change the original range expression to the following: -->
{{ range .Site.Pages }}
Include only pages for a certain section
For my site, the only content that I want to have included in my RSS is pages under the “blog” section. We can use a where filter to only include pages that are in a certain section:
<!-- Change the original range expression to the following: -->
{{ range (where .Site.Pages ".Section" "blog") }}
Note: Some themes use “posts” as the section name for blog posts, so adjust your template accordingly.
Exclude “section” indices from RSS feeds
Additionally, Hugo includes a bunch of non-post pages in your RSS. For example, if you have an “About” page, or a landing page for your blog section, these pages may get included in your RSS.
The only pages that I want to have show up in my RSS feed are actual blog posts. Fortunately we can easily exclude anything that isn’t a page (i.e. a blog post).
<!-- Change the original range expression to the following: -->
{{ range where $pages "Kind" "page" }}
Putting it all together
Hugo allows you to chain “where” filters, so you can combine all the above tips into a single expression:
{{ range where (where .Site.Pages ".Section" "blog") "Kind" "page" }}
This changes the RSS template so that it displays all posts under the “blog” section, but doesn’t include the base “blog/index.html” section page or any other taxonomy/section pages.
For completeness, this is what my final RSS template looks like:
<!-- /layouts/_default/rss.xml -->
<rss version="2.0"
xmlns:atom="http://www.w3.org/2005/Atom">
<channel>
<title>{{ if eq .Title .Site.Title }}{{ .Site.Title }}{{ else }}{{ with .Title }}{{.}} on {{ end }}{{ .Site.Title }}{{ end }}</title>
<link>{{ .Permalink }}</link>
<description>Recent content {{ if ne .Title .Site.Title }}{{ with .Title }}in {{.}} {{ end }}{{ end }}on {{ .Site.Title }}</description>
<generator>Hugo -- gohugo.io</generator>{{ with .Site.LanguageCode }}
<language>{{.}}</language>{{end}}{{ with .Site.Author.email }}
<managingEditor>{{.}}{{ with $.Site.Author.name }} ({{.}}){{end}}</managingEditor>{{end}}{{ with .Site.Author.email }}
<webMaster>{{.}}{{ with $.Site.Author.name }} ({{.}}){{end}}</webMaster>{{end}}{{ with .Site.Copyright }}
<copyright>{{.}}</copyright>{{end}}{{ if not .Date.IsZero }}
<lastBuildDate>{{ .Date.Format "Mon, 02 Jan 2006 15:04:05 -0700" | safeHTML }}</lastBuildDate>{{ end }}
{{ with .OutputFormats.Get "RSS" }}
{{ printf "<atom:link href=%q rel=\"self\" type=%q />" .Permalink .MediaType | safeHTML }}
{{ end }}
{{ range where (where .Site.Pages ".Section" "blog") "Kind" "page" }}
<item>
<title>{{ .Title }}</title>
<link>{{ .Permalink }}</link>
<pubDate>{{ .Date.Format "Mon, 02 Jan 2006 15:04:05 -0700" | safeHTML }}</pubDate>
{{ with .Site.Author.email }}<author>{{.}}{{ with $.Site.Author.name }} ({{.}}){{end}}</author>{{end}}
<guid>{{ .Permalink }}</guid>
<description>{{- .Content | html -}}</description>
</item>
{{ end }}
</channel>
</rss>