rOpenSci | An even better rOpenSci website with Hugo

An even better rOpenSci website with Hugo

A bit more than one year ago, rOpenSci launched its new website design, by the designer Maru Lango. Not only did the website appearance change (for the better!), but the underlying framework too. is powered by Hugo, like blogdown! Over the last few months, we’ve made the best of this framework, hopefully improving your browsing experience (and trapping you into binge reading). In this note, we’ll go over the main developments, as well as give some Hugo tips.

🔗 Our website and its source

Skip this section if you just want to know what’s become better on our website!

Our website is located at Its source lives on GitHub in the ropensci/roweb2 repo. The website is built on Netlify from the master branch, and each pull request gets a Netlify preview link too, which is quite handy when reviewing new blog posts.

Nearly all the changes mentioned in this post were made to the theme of our website which you can find at this folder of the GitHub repo. When modifying Hugo templates, reading Hugo docs is very helpful. When things go wrong (why doesn’t this partial know about the author list?!) head to the debugging template docs. And if you can’t figure out a way out, Hugo has got a Discourse forum like all the cool kids these days. Needless to say, another useful tip when learning Hugo templating is to start small, with either a minimal theme and tiny website, or small updates, then your skills will improve.

In this note, we will mention both templates and partials. A template for a page is the map of what’s going to be included in this page. A partial is a partial template. Partials are to Hugo templating what functions are to R development. If you’re going to use a template part several times, e.g. the template for the footer, to not repeat yourself pack it to a partial template and call it from other templates! To continue the R functions analogy, partial templates have their own environment so if you want them to use variables, e.g. authors’ names in a template for authors listing, you need to pass them. Read more about Hugo partials. If you now wonder what the Hugo equivalent of an R package would be, Locke Data’s Hugo utility belt comes to mind: it’s “a theme consisting of partials that can be added as a theme component for any Hugo site”, since one can use several themes for a single site nowadays.

Other changes were adjustments to content such as YAML reformatting. Fear not, we rarely had to manually update metadata, we wrote scripts using the yaml R package. Find such a script.

🔗 More entry points to content

On top of a few general pages, our website is the home of many blog posts, tech notes and community calls. We’ve created and improved pages referencing content over all these categories, so that you might more easily bounce from say one software peer review post to the next, read all posts by our community manager, or simply find all the things we ever published.

🔗 Tags and authors pages

We now have a tags page referencing all tags along with the number of posts associated to them. The tags of a blog post, tech note or community call are shown at the bottom, so that after reading you can choose to check out more content on the topic. After tags became even more valuable, to make the process of adding or editing them smoother, we’ve created a Shiny app to update tags more easily over many posts, blogyaml. It’s worked well for us, and if you notice something wrong, well it has an issue tracker!

We also have added an authors page that’s very similar to the tags page. On each author’s page, you’ll find their title for rOpenSci staff members, their online home, possibly their Twitter handle, and all the content they’ve authored on our website. See for instance the author pages of rOpenSci community members Nick Tierney and Kelly O’Briant. These pages are linked from authors’ names. Thanks to Angela Li for suggesting we add authors pages.

Technically, getting tag(s) and author(s) pages is quite straightforward with Hugo thanks to taxonomies. To switch them on, we added these lines to the website config.toml

  tag = "tags"
  author = "authors"

We added this option as well

preserveTaxonomyNames = true

to not mess up authors’ names capitalization when listing them.

For authors, a challenge was moving metadata around, from storing authors’ information (online home, Twitter username) inside the YAML of posts to having separate authors metadata files under content/authors, see this example. Thankfully, as mentioned earlier, with the yaml package you can edit hundreds of Markdown files at once, granted you check the edits carefully. We found this guidance about authors page very thorough.

Read more about Hugo taxonomies, how to write templates for taxonomy pages and where to save them so Hugo finds them. In our case, the tags and authors pages have different templates: tags page i.e. the list of tags, tag pages i.e. the list of posts associated to one tag, authors templates

🔗 Archive

With precious content scattered over three categories (blog, tech notes, community calls), getting an overview can be tricky, hence our adding an archive page featuring all our website content from our very first blog post. Behind the scenes, we list pages by publication date and feed them to an archive partial that we use for the tech notes page and authors pages as well for consistent presentation.

And should you ever get lost, we’ve now got a cool 404 page, although mentioning it probably lessens its coolness. Here is its source.

🔗 More content

In the previous section we mention the community calls living in They used to have their own source and subdomain, but we’ve transferred them which has several advantages:

  • When reading about community calls, you’re looking at the same design as when reading tech notes which makes us happy since we like our website. Besides, thanks to the footer and header, you’re more likely to bounce over to another part of the website, rather than leave.

  • The community calls list list and individual pages use partials from the rest of the website. Community calls are now more similar to blog posts and tech notes, and are cross-listed via their tags and authors so that they’re more easy to find.

  • We knew more about Hugo possibilities: in each community call page, the video recording is for instance embedded!

🔗 Feed updates

If you want to keep up with our production, you can subscribe to different feeds (or our newsletter since it includes mentions of recent posts!).

🔗 All the feeds

Our website has both RSS and JSON feeds. We added a JSON feed, format introduced in May last year, because we could and because some people might like that.

  • RSS feeds /blog/index.xml, /technotes/index.xml.

  • JSON feeds /blog/index.json, /technotes/index.json.

Here’s how we added the JSON feeds.

🔗 Not too much content for R-Bloggers

Our website has an R-Bloggers specific feed. For this, we created an R-Bloggers page which only outputs XML, with an XML template ensuring this RSS feed is a full RSS feed contrary to the rest of our website that uses Hugo default RSS feeds with excerpts. We do not filter posts by category which means this not-so-R post (but still a bit R, thanks to our explaining how to browse our R stuff ;o) will appear in R-Bloggers, but we might do that later on.

🔗 Twitter friendliness

While Twitter is not the only platform on which our content is shared, it is an important player so we’ve upped our Twitter game with two edits.

We’ve worked on adding Twitter metadata to our head partial so when tweeting links from the website you get a pretty card (see above). Thanks to Marie-Helene Burle for this suggestion! We’ve used resources listed in this GitHub issue and Twitter card validator on Netlify preview links. Whilst updating the head partial we realized not all our pages used it so we homogeneized all pages. Some of our pages like about have fancy stuff that’s not Markdown based, but we now handle that with partials listed in YAML and then called from the single.html default template. Here is the source of our about page.

We put a bird on it, in Mara Averick’s words, i.e. we now add a Twitter icon near authors’ names when their metadata contains a Twitter username (have you noticed the bird near my name at the top of this post?). That happens in the authors.html partial. Authors pages also link to Twitter accounts. By the way, if you’re ever authored a post for us feel free to open a pull request updating your metadata, e.g. if you were Ignasi Bartomeus you’d update this file.

🔗 A calendar automatically up-to-date

Have you noticed our calendar of events? It has its own page but is also displayed from several other places of the website. We used to have a clunky calendar update workflow. Now, events information are stored as YAML in content/events, see this example, and the calendar partial creates an HTML table from all events and community calls between now (Hugo now function) and one year from now. We trigger one website build per day thanks to a Zapier Netlify integration.

Each event also gets its own page which allows displaying more information than in the calendar table, e.g. read more about what Karthik Ram and Jeroen Ooms will be up to at rstudio::conf.

🔗 Conclusion

In the last months, our website has gained more pages, lists of pages and cross-references, JSON feeds, and Twitter metadata. It should have gotten nicer for you to browse and we hope you’ll never leave it! You can now in particular find content by authors, by tag and by date, better share our content on Twitter, subscribe via XML or JSON feeds. We’re open to more suggestions of improvements, in the comments below or in roweb2 issue tracker.