How I used blogdown and Hugo to set up a personal static site

Goodbye WordPress, Hello blogdown

I have had a WordPress website for about a year now. I have nothing against it. It does what I want it to do. It’s okay-looking. It might be working great for you!

But, I wanted to switch from WordPress to my own static site. I have three main reasons for this. First, WordPress has ads, and they really clunk up your pages. To remove them, you have to upgrade your site, but I didn’t want to do that (I’m a broke grad student, after all). Secondly, it was buggy. The theme that I chose used widgets to display social icons which linked to Twitter, LinkedIn, GitHub, and all that. The problem was that this widget sometimes didn’t show up on desktop or mobile browsers; there was no rhyme or reason to it not working at all. But thirdly, and I think most importantly, learning a new thing is fun. For about a week, I was waiting to hear back on news about fieldwork while I was locked inside during the COVID-19 pandemic. I wanted a challenge (spoiler alert: I was challenged).

I used the R package blogdown, developed by Yihui Xie, Amber Thomas, Alison Presmanes Hill (all very big names in the R world). It allows users to generate a static website using R markdown files. As a graduate student, I do a lot of data analyses on RStudio already, so I am familiar with R code, and I love the functionality of it. I picked the Hugo Academic theme for my site (an immensely popular one for academics, hence the name). Here goes.

Steps

There are so many really good articles of step-by-step instructions on how to create your own website. Since I wanted to use the Academic theme, I Googled iterations of “Hugo”, “Academic”, and “blogdown” for an entire weekend while getting my homepage set up, and I had no less than 20 open tabs from different people who all did something differently. The end result is (mostly) the same. So, I guess this post doesn’t really add anything new per se but I think it is still useful to document my process and what I’ve learned from this endeavor for myself. Maybe this will become obsolete in five years when another package comes out that makes the whole process even simpler. Who knows. At least I learned something from it.

My process largely followed the Git and RStudio methods that Academic has, in great detail, on their Install page. However, any of their other methods do the same job, and it really depends on what you, the user, are most comfortable with. (Side note: by no means am I “comfortable” with Git, but after all of this, I can now use 3 Git commands without having to Google what they are anymore.)

I’m not going to comprehensively document how I did everything because I replicated a lot of great follow-along blog posts, videos, and tips already posted (also, here is the official blogdown book aka user guide aka holy grail). Instead, I’m going to document the changes I made and personalization steps I took because although the Hugo Academic theme is great and all it’s not what I prefer. Also, in the unlikely chance that this post has readers, then I’m going to go ahead and assume that you’re already familiar with the likes of RStudio, Git, editing markdown files, etc..

To avoid confusion, all code and file names are denoted like this, and folders end on a slash like this/.

1. Fork Academic Kickstart and download it locally

Here’s the Academic Kickstart repo. Fork it. I also renamed it to “vmzhang-academic”; I don’t remember why but probably because I am still scared of Git Bash.

Clone your fork using Git, following the instructions in the Install with Git page. On my computer, my local repo is also named vmzhang-academic/.

Next, open RStudio and install blogdown and hugo, following the instructions in the Install with RStudio page. Open the local folder that you just downloaded (vmzhang-academic/ for me), and open the R Project named academic. Anytime you want to make edits, just open up this project.

Serve your site!

Note that step 4 suggests you move a file into the project root in order to work around a bug; I didn’t do this and I haven’t had any problems (yet).

2. Edit away!

I am trying to induce excitement! Hold on to that excitement because it is a slippery slope to frustration! I don’t understand how you all could “build a website in under 10 minutes” because it took me 5 days!!!

(Also, I’m a stubborn perfectionist and I knew exactly what I wanted this site to look like. Conceivably, it was harder than I expected to implement my visions. Why am I like this.)

Specifically, I wanted:

  • multiple separate pages
  • a way to filter by tags (especially for research and posts)

Also, some other tips and tricks that helped me:

Run locally to see how your website looks

On RStudio, your site can be built locally so that any changes you make can take effect in real time. This was super helpful. I found that running blogdown:::serve_site() and viewing my site in the “Viewer” pane on RStudio was slightly laggy, so I opened the local URL (http://127.0.0.1:4321/) on my browser, and the site still reloaded every time I ran blogdown:::serve_site(). However, sometimes it opened up a new page; I didn’t realize this at first, until I saw that many previous iterations of my homepage were taking up all my tab space. I ctrl + w’d for days.

Making new separate widget pages

This was by far the most important thing to me, but also the most challenging to implement. A lot of other static sites only had two pages: one page with all of the info placed inside “widgets”, and another page for just blog posts. Widgets are basically sections on your page, and there are a lot of widgets that are very nice to look at and can really spruce up your site. This one-page format works well for some people, but I knew I wanted separated pages with only a couple widgets instead of one page with a lot of widgets. There are two reasons for this: I dislike scrolling up and down on a seemingly endless page (because I am easily distracted), and I wanted to categorize all the facets of my life into separate pages (because I am notoriously organized to a fault).

There really wasn’t a lot of documentation on how to do this, apart from a short section in the Academic documents on how to create a new widget page. It honestly was easier said than done, because the way the folders in your repo have to be organized and named is important. So, here goes.

In your root/ folder, navigate to the folder titled content/. These subfolders inside are the bones of your site. The contents that go into the widgets are all organized as subfolders within the content/ folder. This needs to be shouted from the rooftops for how much trouble it caused me, so let me reiterate: the subfolders in the content/ folder do not correlate specifically with different pages. Instead, subfolders, like project/, publication/, and post/, are referenced by different widgets which may be on different pages on your site, but all of these subfolders have to be in the top level in your content/ folder.

To make new pages, make new folders! Do not change any of the other folders (or do, if you know what you’re doing. I’m not your keeper. Just saying, I wish someone told me not to change the other folders).

For example, here is how I made new page for “Research”:

  1. In the content/ folder, make a new folder called research/
  2. Move the markdown file called _index from content/project/to content/research/ folder and rename it to index
    • don’t ask me why because I don’t know why; it works for Allison Hill and it works for me
    • in index, add YAML front matter as documented here
  3. Add widgets into the research/ folder
    • more on widgets below!
  4. To link these new widget pages to your menu bar, navigate to the config/_default/ folder and open the menus TOML file.
    • see how the url for all the pages start with a hash #? That means that it is looking in your homepage folder content/home/
    • in order to link to another page, delete the # and add a / at the end, e.g., url = research/
  5. Repeat for other pages. Make sure new folders that are created have an index file, populate the folder with all the widgets you want on the page, and edit the menus file

Great! Cool! New pages!!

Okay. Now, adding widgets to your new page. This part stumped me for the better part of an afternoon.

Using the “Research” page as an example again, let’s say that you want to have a “Portfolio” widget that showcases your projects. For each individual project:

  1. Inside the now-empty project/ folder, create a further newproject/ subfolder that reference a project
  2. Within this newproject/ subfolder, create another index file.
  3. Add some YAML front matter (title, summary, tags)
    • of importance is the tags front matter: use informative tags and remember what they are!
  4. Write about your project!
    • you can also add a featured JPG or PNG
  5. Then, create a “Portfolio” widget within the content/research/ folder
    • the easiest way to do this is by copying the projects markdown file from the content/home/ folder
    • make sure that your pages are rearranged in the order you want using weight
    • the projects file can be renamed to anything
  6. In the projects file, under [[content.filter_button]], rename the tags, and change the tag = to refer to the tags you used earlier
  7. Edit your widget to your heart’s desire!

One page down, one more to go! I basically repeated this process to create my “Outreach” page, except using other widgets that I wanted. Learning to create a separate page was definitely an uphill battle, but after figuring that out (and become familiar with blogdown and my repo), it was smoother sailing to create more pages. I say “smoother” because the next challenge was creating a “Posts” page. More on that below.

Filtering posts by tags/categories

I was able to make my research projects filterable by tags and my publications filterable by publication type in a drop-down menu. I still cannot figure out how to achieve the same thing with posts; I’m envisioning a drop-down menu where I can select “Month/Year” or “Category” and then only posts that match the date or category will pop up. Perhaps the “Posts” page for blog posts is inherently different than “Projects”, but also this makes no sense because static pages are static pages are static pages, right? Please contact me if you have any insights.

In any case, I created a “Journal” page where I have all of my posts. In this page, I linked all the tags and categories by referencing to the tags and categories path. To keep track of the dates which I published posts, I assigned each month to another tag. For example, I added “2020-May” as a tag to denote posts published during the month of May in 2020. Then, I linked a reference to tags and categories.

The Markdown code to reference something (e.g., blog post) within your site is {{< ref "/post/blog-post" >}}. The part in quotes is the permalink, or slug, to your blog post. As long as one of your blogs has that URL, then you are able to reference it anywhere in your site. You can link this by using the syntax [linked text](link). However (and this part is annoying): this doesn’t work for R Markdown. For blog posts, which are written in R Markdown, I just link the URL of whatever I want to reference.

So, putting it all together, I reference blog categories and tags in 2 ways:

  • [category]({{< ref "/categories" >}}) and [tags]({{< ref "/tags" >}}).
  • [category](vickimzhang.rbind.io/categories}) and [tags](vickimzhang.rbind.io/tags).

This isn’t the most optimal solution yet for me, since I think filtering using a drop-down menu would be much more elegant and intuitive. However, it works.

3. Pushing to GitHub using git

I’m not going to get into the merits of GitHub and version control because I’ll be preaching to the choir (if you code, you should have a version control system). This section was written to myself for the sole purpose of delineating the git commands that are needed to push a local folder (or repo) to GitHub.

Set Up

You only need to do this once!! (You need the git command line downloaded.)

  1. Open git bash

  2. cd Documents/vmzhang-academic

    Change your working directory to the root/ folder.

  3. git init

    Initialize that folder (basically making that the local folder that is linked to your GitHub repo).

  4. git add .

    Add all the files in the local folder (telling git which files you want to add; by default, it adds all of them).

  5. git commit -m "initial commit"

    Commit the files that you just added (confirming the files you just added and prepping them to be pushed).

  6. git remote add origin https://github.com/vmzhang/vmzhang-academic.git

    git remote -v

    Set and verify your remote (replace the URL with the URL of your GitHub repo - this links your local folder to your remote GitHub repo).

  7. git push origin master

    Push upstream from origin to master (aka push all the files that you just added and confirmed from your computer to GitHub).

Subsequent changes

Only 3 lines of code!!!

  1. cd Documents/vmzhang-academic

    Locate your local folder directory.

  2. git commit -a -m "new additions/changes"

    Here, you are combining a bunch of steps together in one line of code: -a means that you are adding all the file changes that were made, the code after -m is a message stating what was changed, and you are committing everything.

  3. git push origin master

    Push all committed changes.

For every change and every new blog post, I just open git bash and run those three lines. More git commands can be found here, but I probably won’t need them within my workflow. Git and GitHub are important, crucial, useful, etc., but it doesn’t mean that I am good at using git command line (yet!).

Speaking of GitHub, here’s another tip that really helped me: I found static sites using Hugo Academic that I liked, then tried to find that person’s GitHub and subsequently tried to find their website repo. Just clicking through their repo files really helped me organize my folders locally. Just Google the name of the person’s website plus “GitHub”. Not going to lie, I was lurking on so many people’s GitHub accounts.

4. Deploy using Netlify instead of GitHub Pages

The final stretch! This was the easiest and most fun part of the whole process. Make sure you have a Netlify account, and make sure all your changes have been pushed to GitHub.

After you have created a Netlify account, link the repo with your site’s static files. Then, follow this guide, starting with “easily edit your site…”. You will be assigned a dummy-url.netlify.com, but you can change that to a more-professional-url.netlify.com. You can also use a subdomain .rbind.io, which is explained here (basically tell them what domain name you want, and they will speedily assign you your-subdomain-name.rbind.io). Or, if you have a custom domain name already, you can use that! The world is your oyster!

Why Netlify instead of GitHub Pages? Well, Netlify does have a bunch of other features that GitHub doesn’t have. My main reason for switching (besides being told by Yihui, who is very convincing), is that GitHub Pages primarily uses Jekyll, another static site generator like Hugo. However, Jekyll is slower and more difficult to set up, an opinion that is shared among many science bloggers. Letting Netlify deploy my site ensures that I do not have to worry about deployment, and I get to see the changes I make within minutes after pushing to GitHub.

Final thoughts

I am still very much a newbie when it comes to coding and computers and web design. I’m as green as it gets. I bet someone else could easily have done what I did here in less than an hour, and I’m sure someone has. But (as I keep reminding myself), that is not the point. The point is that I learned something, and I got my site up and running through a lot of trial and error, and the next time I need to create A Beautiful Website (or at least A Passable Website), I might be able to do it faster and with a lot less frustration. Yay me.

If it wasn’t clear throughout this post, it wasn’t easy. Even though I did minimal amounts of coding, and zero programming, generating your own static site is on par in terms of level of difficulty. You follow a guide (or two, or ten), and you put out something that you hope your computer will pick up, and when it doesn’t, you try to figure out why. I had to wrap my brain around the file structure, which was especially frustrating because it isn’t intuitive.

Here are five incredibly useful links that helped me (out of countless opened tabs):

One final lesson I learned: document everything. Everything. It has been so useful during this entire process, because I don’t want to forget what I learned, and it has greatly increased my familiarity with using Hugo and blogdown. It may also be useful for someone else; if any part of all of my rambling above helped even one other person, I will be so pleased.

Vicki M. Zhang
Vicki M. Zhang
PhD Candidate

I am a PhD Candidate at UofT studying invasive species in the subarctic, and am passionate about science communication and outreach.