Pedicularis groenlandica

Wetlands and landscapes

Data science, water, isotopes, and ecosystems

Jason Mercer

24 minutes read

Introduction

This is the third blog/site I’ve built in the last few years. Knowing very little about web development, but wanting to develop some kind of curated web presence, I’ve moved from Blogger to Jekyll (hosted on GitHub) and now to Hugo (which I’m hoping to host on GitLab using a custom domain) via the blogdown package in R. It’s really my comfort with R, Rstudio, and knitr/rmarkdown that has prompted this move, because I want to take advantage of all the features I’m used to in the R/RStudio universe of packages and products, and in particular the integration of html widgets that can be produced using .Rmd files.

But one thing I’ve learned from building my sites is that I need to take notes regarding what steps I’ve taken to get where I’m at. Otherwise I forget and then don’t know how my own site even works.

So, this post is mostly for me, as a record of how I setup my site and how to do things with blogdown and Hugo.

Reminder: How to make new posts

  1. RStudio -> Addins -> BLOGDOWN: New Post
    • Brings up a nice dialog box for filling out typical information.
  2. blogdown::new_post()
    • This version of the workflow will require filling out some arguments to properly execute the function.

New post information

Both of the workflows above allow me to fill out some basic information about the post and how it should be integrated into the structure of the site.

  • Title: Title of the post.
  • Author: Author of the post.
  • Date: Date of the post.
  • Subdirectory: Where the post should be saved. Save to post for the sake of consistency.
  • Categories: Metadata about a post to help people search for content.
  • Tags: Similar to categories.
  • Archetype: A file containing a “template” of what front matter should be populated when making content.
    • It appears that the Hugo Future Imperfect Slim theme has two archetypes in themes\hugo-future-imperfect-slim\archetypes:
      • blog.md
      • default.md
  • Filename: Name of the file to be created. Automatically generated, but can be edited.
  • Slug: A short title for the post, appended to the date. Ex “this-is-a-slug”
  • Language: The language the post is in. My default is english.
  • Format: .md vs .Rmd vs .Rmarkdown

Reminder: How to “preview” the site

Once I’ve made a post I can preview the site two ways:

  1. RStudio -> Addins -> BLOGDOWN: Serve Site
  2. blogdown::serve_site()

This will activate the site in the Viewer tab. Usually it’s worth hitting the “Show in new window” button and viewing in an actual web browser.

Getting started

The main resource I’m using for setting up this site is the blogdown book written by Xie, Thomas, and Hill: https://bookdown.org/yihui/blogdown/.

Installation and theme selection

I’m using blogdown and RStudio to manage my Hugo site. Along those lines, the first thing I did was install blogdown and then used blogdown to install Hugo via blogdown::install_hugo().

In the future, if I want to update Hugo I can use the command blogdown::update_hugo.

Since Hugo is it’s own program, it is worth to know that I can access Hugo’s command line with the command: blogdown::hugo_cmd(). This is useful for some troubleshooting that sometimes needs to happen.

More about Hugo: https://gohugo.io/

Site creation and theme selection

To generate my site I used an R project: Open Rstudio -> click the projects drop down -> New Project… -> New Directory (I don’t think you can make a Hugo site in an existing directory) -> Website using blogdown

At this point a dialog popped-up with some additional information for me to fill out. Specifically, I included the directory name (wetlandscapes) and the location of the site on my computer.

Here, though I had to play around a bit and ended up making multiple sites as I developed understanding of both blogdown and Hugo.

First site

The first site I installed used the default options, including the Hugo theme from Yihui’s site, Lithium. This was a good first step because it let me see the folder structure of a Hugo site and how some of the different options and meta files (e.g., config.toml) changed the site.

Current site(s)

However, I didn’t ultimately like the Lithium theme. So, I went looking for some templates at: https://themes.gohugo.io/

After looking around a bit I came across the theme Hugo Future Imperfect Slim (HFIS), which had some nice built-in features, such as social media sharing, and icon links from Font Awesome places like GitLab, ORCiD, Research Gate, etc. This being an academic blog, I thought that was nice.

Initially I tried changing the theme of my first site using blogdown::install_theme(), but I quickly became disoriented, as I didn’t really know what the `config.toml file was telling me.

To help me understand what was going on with the theme, I ended up building two more sites. Turns out when you build a site in blogdown you have the option of populating the site with sample blog posts and the example site from the theme. So what I did was I build a “skeleton” site with HFIS, where I populated nothing, and then I built the example site in another folder. This allowed me to see how the two sites differed and slowly build the site I wanted around my understanding of the example site.

Configuration

Global

config.toml

Like Jekyll, Hugo appears to use a config file for a lot of site functionality: config.toml. My file has different “sections” and “subsections” enclosed in square brackets:

  • (header): The top of the toml file seems to have some global options
  • [params]
    • mainSections: Seems to be the order in which pages are displayed on the home and blog/ pages. For that reason I have “post” first, because I want my blog posts to display first.
    • [params.meta]
    • [params.header]
    • [params.intro]
      • [params.intro.pic]
    • [params.sidebar]
    • [params.footer]
    • [[menu.main]]
      • name: The name of the page.
      • identifier: Seems to be the name of the folder the content will go into.
      • url: Relative path of the page. Note the “/page/” syntax.
      • pre: A symbol representing the page, from Font Awesome.
      • weight: I think this is display importance for when the display windo changes.
  • [Languages]
    • [Languages.en]
  • [social]

blogdown

.Rprofile

There are a bunch options that can be modified. To ensure those options are preserved from session to session I need to make a .Rprofile file.

To setup the .Rprofile for the site I used the terminal in RStudio, which I’ve setup to used to Ubuntu for Windows Subsystem for Linux. List of commands I used:

touch .Rprofile
nano .Rprofile
#Once inside nano
options(blogdown.ext = ".Rmd",
  blogdown.author = "Jason Mercer",
  blogdown.subdir = "blog")

#Note the blank line -- R ignores the last line, so need make sure a trailing
# line is included.
#Exit nano and check that the edits occurred
cat .Rprofile

The reason I’ve set my default blogdown extension as .Rmd (as opposed to .md) is because, in the context of knitr and blogdown, .Rmd files are more flexible in their capabilities. For example, Table 1.2 of https://bookdown.org/yihui/blogdown/output-format.html illustrates that .Rmd files automatically include MathJax and HTML widgets, the later of which was severly lacking when I was using my Jekyll site (not that it is impossible with Jekyll, there’s just more tinkering on the backend that I don’t really want to deal with).

The reason the default subdirectory is blog/ is because the HFIS theme expects blog posts in that folder and not post/.

_output.yml

I can also add some standard output options by making and using a _output.yml file. For example, I used the following code to get a standard output.

touch _output.yml
nano _output.yml
#Inside nano
blogdown::html_page:
  out.width: '100%'
  dev: 'svg'

Post

Hugo front matter (yaml/toml/json header information)

Front matter is the stuff that goes at the top of a post or other content. This is similar to Jekyll. Basically, the front matter is metadata about the post or content. For more about front matter: https://www.youtube.com/watch?v=Yh2xKRJGff4

Here is a list of front matter variables that Hugo is aware of: https://gohugo.io/content-management/front-matter/

Note: My site is setup to use yaml front matter variables. This was an option (check box) when I made the site: “Convert all metadata to YAML”. I didn’t know what this meant at the time, but apparently you can supply front matter to Hugo as yaml, toml, or json. I think by converting all metadata to yaml it makes the interface more consistent, but I don’t know that for sure.

Some useful predefined variables (that all Hugo sites know):

  • date
  • description
  • images
  • linktitle: I think this can be used as an alternative to the title, if the title is really long.
  • slug
  • summary
  • title
  • type: For blog posts on my site I always need to set this to “post” for the blog entry to register properly.
  • weight

Some variables that I think are defined by my theme:

  • author
  • categories
  • featured
  • featuredpath

blogdown front matter

The yaml used in a typical knitr .Rmd file also applies to blogdown posts. For example, take the yaml header used to create this document. In this case the output variable uses blogdown’s html_page, which can then take arguments, like toc, that I’m used to dealing with from knitr.

---
title: Notes on setting up my new blogdown/Hugo site
author: Jason Mercer
date: '2019-11-08'
slug: notes-on-setting-up-my-new-blogdown-hugo-site
categories:
  - meta
tags: []
description: ''
images:
  - ''
linktitle: ''
output:
  blogdown::html_page:
    toc: true
---

Pages

About

For this page, I more or less just copied over the about page from my Jekyll blog. At first I had some problems with the images not displaying properly, but I found out that my custom html/css just needed some “div” tags around them.

<!-- This works -->
<div>
  <figure-right>
    <img src="/img/about/about-viking.jpg">
    <figcaption>
      Packrafting the Anaktuvuk River, North Slope, Alaska.
    </figcaption>
  </figure-right>
</div>

<!-- This doesn't work; my captions wondered off -->
<figure-right>
  <img src="/img/about/about-viking.jpg">
  <figcaption>
    Packrafting the Anaktuvuk River, North Slope, Alaska.
  </figcaption>
</figure-right>

Research

Using the lesson from the about page, translating this page from Jekyll to Hugo was smooth.

CV

For this page I’m trying to replicate some functionality developed by Noam Ross, who developed an R script for downloading and populating his CV from ORCiD. Pretty neat! His script is located here.

The first issue I ran into was automatically downloading my ORCiD information. It appears I need use OAuth with the ORCID API. To get that information I performed the folllowing steps:

  1. Ran rorcid::orcid_auth()

  2. Logged into ORCiD and authorized the use of OAuth

    library(rorcid)
    orcid_credentials <- orcid_auth()
  3. I then copied the key into my .Rprofile file

    options(blogdown.ext = ".Rmd",
      blogdown.author = "Jason Mercer",
      blogdown.subdir = "blog",
      orcid_token = "XXXXXXX...")
  4. Then I added .Rprofile to my .gitignore file so my information wouldn’t be exposed.

To test if this solution worked I restarted R (ctrl + shift + f10) and re-ran the rorcid code for downloading data and it worked!

However, not all of the DOIs associated with my works seem to be registering with CrossRef (though the actual DOIs do properly link to the underlying material), so I’ll have to figure that out at some point.

It looks Noam also included some manual publication information. I may end up using that to fix my problem, but for the time being I’m ignoring the manual publication stuff.

The result of the script are 4 yaml files in the data/ directory:

  • education.yaml
  • employment.yaml
  • papers.yaml
  • papers_orcid.yaml

I had a bit of trouble with the education yaml, so I ended up modifying Noam’s code a bit. For example, I ended up hardcoding “(Excpected) 2020” for my graduation date, as Hugo didn’t know what to do with the empy file. I also added an “order” element to the education lists, to help with getting my education in the right order. These changes are refelected in both the script and the file layouts/cv/cv.html (which I’ll talk about later).

The next big issue was figuring out how to put all that yaml information together as there wasn’t an obvious way to use it in the context of markdown. This took a bit and I had to learn about “sections” in Hugo.

Basically, I:

  1. Added a cv/ directory to content/.
  2. In cv/ I added an _index.md file (a convention in Hugo) with a single line of YAML: the title (“Curriculum Vitae”). This file basically “initializes” the layout I want, which aggregates all the yaml I made earlier.
  3. I then made the file layouts/cv/cv.html. This file is basically just themes\hugo-future-imperfect-slim/layouts/_default/single.html, except that I replace the “{{ .Content }}” code with some code from Noam.
  4. The code I used come’s from Noam’s layouts/section/vitae.html. He had a lot of extra stuff in there, so I just used some of the information from the eduction, professional experience, and publications sections. It wasn’t crazy hard to figure out, but is definitely weird looking.
  5. Last, to get the professional experience code to work, I had to borrow a partial from Noam’s site: layouts/partials/work.html. This file I did not edit, but put straight into my own layout folder.
  6. Other than that I just made some aesthetic edits that matched my own theme a bit more, compared to Noam’s site.

Tags

To generate the tags page I took advantage of some default behavior used by Hugo related to “taxonomies”. The Mike Dane video on taxonomies was helpful in understanding how to deal with this.

Basically, the theme I’m using comes with a “categories” page, but not a “tags” page – despite tags being common front matter. However, I wanted a way to be able to see and access tags the same way as the categories. The way I did this was by more or less copying the categories info in the menu table (menu.main) of the config.toml file. Then I just changed “categories” to “tags”.

This is possible because Hugo automatically makes tags list sites, it’s just that it wasn’t accessed by default from the theme I’m using.

Also, as an FYI, I can make customizable taxonomies (e.g., something besides “categories” and “tags”), if I want to. Maybe later.

About Hugo

Page strategy

There are basically two kinds of pages in Hugo:

  • List pages
  • Single pages

List pages

List pages are basically aggregator pages. For example, my home page is a list page, because it’s listing all the blog posts on the page (or some of them). The categories and tags pages are also list pages.

Single pages

Single pages are one off pages. So, for example, my about and research pages are sinlge pages. Also, all the individual blog posts are single pages.

Folder structure

The following folders and files make-up the core structure of Hugo:

  • config.toml
  • content/
  • themes/
  • static/

TOML

The primary building block of toml is the key/value pair. For example:

key = "value"

Boolean’s in toml are represented as “true” and “false”

This is super detailed, but the time standard used by toml can be found here.

Arrays can be passed to toml using brackets (and brackets in brackets for multi-dimensional arrays). It seems that arrays don’t need to be the same type. Example:

colors = ["red", "white", "blue"]
nested_colors = [["red", "fuscha", "pink"], ["blue", "cyan"]]
Tables

toml also includes tables/hash tables/dictionaries. They are encolsed by square brackets.

Types of tables:

  • Table
  • Inline table
  • Array of tables

For example, a table (top line in the example below) with multiple keys and values might look like:

[table]
key1 = "value1"
key2 = "value2"

Related tables are generally given similar names that build on some theme. For example:

[table]
key = "value"
[something.else]
key = "another value"
[something.other]
key = "yet another"
  [something.other.thing] # This is really part of an array of tables
  color = "red"
  shape = "round"

An inline table is a bit more compact:

name = { first = "Tom", last = "Preston-Werner" }
point = { x = 1, y = 2 }
animal = { type.name = "pug" }

That is equivalent to:

[name]
first = "Tom"
last = "Preston-Werner"

[point]
x = 1
y = 2

[animal]
type.name = "pug"

An array of tables looks like:

[[menu.main]]
    name              = "Home"
    identifier        = "home"
    url               = "/"
    pre               = "<i class='fa fa-home'></i>"
    weight            = 1

Note that the indexing above is not necessary, but does help visually parse the code. Array elements (what’s in the double brackets) are inserted in the order they are encountered. That is why the menu in the config.toml files is in the order it is in, to ensure those elements, in that order show up in the header of the website.

config.toml

toml: Tom’s Obvious, Minimal Language

All the elements wrapped with “[]” and “[[]]” are related to specific structural elements listed above. It seems that some of these tables are associated with standard behavior in Hugo. For example:

  • baseURL
  • menu
  • paginate

For a full list of the standard key and table values, check out (note that values in parentheses are the defaults): https://gohugo.io/getting-started/configuration/

Based on my understanding of this stuff, and a recommendation in the blogdown book, I added the following code to my config.toml file:

ignoreFiles = ["\\.Rmd$", "\\.Rmarkdown$", "_files$", "_cache$"]

[permalinks]
    post = "/:year/:month/:day/:slug/"

Site setup

My expected site structure: * content/ * about.md * blog/ * … * curriculum-vitae/ * research.md * data/ * .yaml (related to the curriculum-vitae section) r/ * layouts/ * curriculum-vitae/ * partials/ * public/ * scripts/ * get-orcid-data.R * static/ * blog/ * … * img/ * about/ * blog/ * main/ * research/ * themes/

content/

This contains the main content for the site. Specifically, this is where the blog posts (html), and their underlying .Rmd/.md/.Rmarkdown files will live. So, when I make a new post in RStudio (Addins -> BLOGDOWN -> New Post), I’ve configured blogdown to put the files in content/blog/, as is expected by the theme.

Most everything in this folder uses the “single” template (in the themes folder: layouts/_default/single.html), which means they are formatted a specific way. The one exception to this are the files in the curriculum-vitae folder, which is it’s own section, according to how Hugo sets up its file tree. In this respect, I’m controlling the look of the CURRICULUM VITAE page by including a special layouts html that corresponds the the _index.md in content/curriculum-vitae/. Basically, the index file acts as an indicator that I want a special section dedicated to my CV. I had to do things this way to get my links to work properly, otherwise I had this weird link set of ./cv/curriculum-vitae.html, which isn’t terrible, but not as clean as ./cv/. I probably could have made this less complicated, but this is what I came up with based on my limited understanding of Hugo.

The files about.md and research.md get processed like normal “single” pages, and have their own links due to the way Hugo processes files like this in the content folder.

data/

This folder is intended to host data that the site can use. I’m using if for two purposes.

  1. Hosting site data. Specifically the yaml files I use to build my CV from ORCiD.
  2. Hosting R data for blog posts that take a long time to build. Basically, I’m using it as a cache. I could probably avoid this kind of thing by better figuring out blogdown and knitr’s caching behavior, but one step at a time.

For the second purpose, I’ve made the folder data/r/. I’ve also added "\\.Rdata$" to the array of the ignoreFiles variable in config.toml.

I also found out that other data types (like a tiffs) are not respected by Hugo (they will cause Hugo to throw and error). To get around this, in the context of the data file, I added the following to the ignoreFiles array: "data/r/.*". Now it ignores everyhing in the that folder. Pretty neat.

layouts/

This folder contains files that control the look of the site. Specifically, I’m using this folder to:

  1. Control the look of special sections of the site. Specifically, the page with my CV.
  2. Add files not included in the theme layouts folder. In particular Noam Ross’s work.html partial.
  3. Provide alternative files to the theme layout that take precedence over the theme layout. I’m not actually using this functionality at the moment, but I could in the future.
public/

This is where Hugo builds the actual site. I don’t really need to do anything here.

scripts/

Right now this is just hosting a single file: get-orcid-data.R. This file is used to download my ORCiD information for the CV page. I have to run this script manually, though I may be able to automate it with a different continuous integration setup on GitLab. Something to think about.

I’m not sure if I needed to, but I added "\\.R$" to the ignoreFiles array in the config file.

static/

This is where static files live. All contents in this file will be copied to public/ for use with the site.

The blog/ folder is built by blogdown and contains all the supplemental files (mostly images) used by the blog posts. I should not have to interact with this folder much, except when I want to set a featured image.

The img/ folder contains images I’m using for specific pages, sections, and blog posts. Note that the main/ folder is for the home page.

themes/

This folder contains all the aesthetic information (except for what is in my layouts/ folder) and code used to build the website. I’m not going to try to get very deep into this stuff until I actually want to start customizing my site, though I did have to get a little into it with the CV page.

About my theme

I was having a hard time getting the right bit of text to display in a header. I finally figured out that there was a partial I needed to update. Specifically in the theme that prioritizes section titles over page titles. I was able to reverse that priority. The correct bit of code, in layouts/partials/site-header.html takes precedence over what is in the theme directory, so I should be okay, even if I update the theme later.

Turns out the above solution didn’t work; I ended up reverting back to the original partial file. Instead, I changed all section references from “cv” to “curriculum-vitae” in the file tree:

  • layouts/curriculum-vitae/curriculum-vitae.html
  • content/curriculum-vitae/

It seems that the site-header.html partial also parses the name of the section from the file tree, so the “-” is not included and everything gets capitalized. I’m still not sure where this logic gets implemented, but it seems to work, so there you go.

Font awesome

I was able to update the fonts associated with the different sections in the config.toml file. That is, each section (in [menu] -> [[menu.main]]) has a variable pre that is associated with some fonts. I can change those fonts. W3Schools has a huge visual list of all the free Font Awesome fonts I can use.

Tweaks

Blog titles

For some reason the behavior of blog titles was set to break words, rather than wrap them to the next line, like normal. I was able to find the css associated with this choice deep in main.scss. That is, it was in .post -> header -> word-break, which I changed from break-all to normal.

Also, it turns out I need to re-render the site everytime I make a change to the css otherwise the changes will not be updated in the public file, which is what I’m really viewing when the site is being served to my local host.

Tips and tricks

If you are working on a .Rmd file, but don’t want blogdown to render it, temporarily change the extension (e.g., .Rmdt) to something blogdown will not recognize.

If you don’t want a .Rmd (or equivalent) file to be rendered, you can set draft: true in the yaml metadata. This will make the file available for local preview, but not part of the site build.

You can use “shortcode” as a quick way to write code. Here is an example of using shortcode in blogdown:

For more on Hugo shortcode: https://gohugo.io/content-management/shortcodes/

Useful resources

Example websites:

Things I’m still trying to figure out

  • ~~What is going on with the config.toml file? Are these options universal (determined by Hugo), or determined by the theme? Which are which?
    • A: https://gohugo.io/getting-started/configuration/~~
    • Solution: A lot of options are theme-specific in the sense that the data associated with variables is accessed by code in the theme. Basically, there is a lot of flexibility built into Hugo.
  • ~~What about the yaml header at the beginning of every post?
    • Some seem to be predefined by Hugo and some seem to be defined by the theme.
    • I’m not sure where the theme-specific variables are defined, so I can figure out what my options are and what those options mean.~~
  • What is the difference between post and blog?
    • Solution: For the theme I’m using, posts go in the blog folder, but are still call posts. For that reason, the front matter of all blog posts must include the line type: post for the theme to work properly.
  • How can I add a picture from my .Rmd file as the “featured” image without having to specify the location or re-rendering the file?
  • How can I add Twitter activity to my site?
  • Custom domain on GitLab
  • ~~How do can I automatically download and format my publications from ORCiD?
  • How can I add a search bar?

Recent posts

See more

Categories

About

I am a PhD candidate at the University of Wyoming, studying mountain wetlandscapes.