published on 03.08.2020

In this post, I aim to explain this website. Template by template… The main purpose here is to create a document to myself for future reference. Templates are complicated and not easy to read. That’s why I’ll probably forget what I did and why I coded this way.

Taxonomies

We are using the default taxonomy called tags. Hugo provides 2 taxonomies by default: tags and categories. You don’t need to specify them anywhere. I’ve added the configuration below to config.yaml file to use only tagsand disable categories taxonomy.

1
2
[taxonomies]
  tag = "tags"

Templates

Hugo templates are stored in /layouts folder. There are 2 types of templates: list templates and single templates. List templates are for listing content while single templates are for displaying the content itself. For example, /tags, /categories, /posts use “list templates”; while /post/foo.html, /about pages use “single page templates”.

Home Page

Home page is a stand-alone page created impilicty by hugo. I’ve used layouts/home.html template to separate home page from others. If we want to add content to home page we should use /content/_index.md file.

baseof.html & Hugo Blocks

Every other template is using baseof.html. I had similar layout in jekyll called default.html

Here is an example of Hugo blocks. This block indicates where “footer” block will be placed. What’s defined inside this block is the default for the block. Default lines will be used if it’s not overwritten by some other template.

1
2
3
    {{ block "footer" . }}
        <footer>{{ partial "footer.html" . }}</footer>
    {{ end }}

In another template, let’s say, list.html , we define “footer” block. So, all the content in the footer block be placed in that part of baseof.html. If there is no “footer” block defined in child template (list.html) then hugo will use the original lines from the baseof.html. Which is <footer>{{ partial "footer.html" . }}</footer> in this example.

In this site, footer is not variable but content is. I have content block in baseof.html and it has no lines of code inside which means if it’s not defined then it’ll be empty.

1
    {{ block "content" . }}{{ end }}

And here is the definition of content from list.html

1
2
3
4
{{  define "content" }}
  {{ partial "generate_button.html" (dict "href" "/series" "name" "Remove Filters")}}
  {{ partial "list_pages_episodes.html" . }}
{{ end }}

Listing Content

In my setup there are 3 ways of listing blog posts.

  • Tags (group by tags)
  • Series (group by sections)
  • Archives (group by date).

Filter All Blog Posts & Ordinary Pages

To display all pages across sections, we need to gather all the pages in the site. To do this I’ve used the following code.

1
{{ $pages := where $.Site.RegularPages ".Type" "!=" "ordinary" }}

Site.Pages will gather all the pages including “index pages”, “term pages” and home pages for each section. Site.RegularPages will filter out those pages still it will include pages like about.md. To gather only the blog posts, either we should add a meta-data in blog-posts or the pages we don’t want to display. Since it’s easier to tag the pages I don’t want to display, I added type: ordinary line in their front-matter.

There is one more way to filter those pages, I call ‘ordinary’. We can check if file contains date in it’s front-matter. This will work since I won’t enter a date for ordinary pages. Yet, it’s not obvious to understand. I find setting a meta-data in the front-matter more clean and intuitive instead of using magic variables.

1
{{ where $.Site.RegularPages ".Params.date" "!=" "" }}

Also, we may need to check a single page to see if the page fits our criteria. To do that, we’ll not use RegularPages but (eq .Kind "page"). RegularPages is a shortcut for us. It checks if .Kind is equal to "page" for all pages and returns an array of pages.

In order to control if a single page is a post or not I use the following mechanism:

1
{{ if and (eq .Kind "page") (ne .Type "ordinary") }}

Tags View

1
2
/layouts/tags/list.html
/layouts/tags/term.html

These files overwrites the default list html /layouts/_defaults/list.html for tag section.

list.html is for creating the /tags page and term.html is for /tags/foo where foo is a tag. In Hugo terminology; each tag is called as a “term” in “tags” taxonomy.

Layouts above also using these partials:

  • generate_button
  • tag_cloud
  • get_post_infocard
  • pagination
  • list_pages

Archives View

  • Layout: /layouts/_default/archives.html
  • Page: /content/archives.md

Unlike tags, “series” and “archives” pages are custom pages and these are not taxonomies. Just single - ordinary pages. So, by default these pages use /_default/single.html However, I’ve added layout information in the front-matter.

1
2
3
4
5
---
title: Archives
layout: archive
type: ordinary
---

Archives view, is simply displays all blog posts in the website ordered by date and grouped by year-month.

Series View

  • Layout: /layouts/_default/series.html
  • Page: /content/series.md

Similarly with the archives view, series view has layout meta-data in it’s front-matter.

1
2
3
4
5
---
title: Archives
layout: series
type: ordinary
---

Hugo calls, each sub-folder in the /content directory as sections. In this site, all blog posts will be there and each blog-post series will have their sub-directory. For example, I’ll create three blog-post series called “linear-programming”, “jekyll” and “hugo”. Each blog-post of a series, as hugo called them sections, will have meta-data called “episode”.

Basically, series view do: group posts by sections then order by episode. Also, check “section.html” which can be considered as a term if we take series (sections) as a taxonomy.

Other Templates

I’ve two more templates, called list.html and section.html.

list.html

/layouts/_default/list.html In my design, this template is not used by any of the pages. Because, tags are overwritten by their own files and I’ve created a separate section.html for section pages.

section.html

As I said before, section.html can be considered as a term for series view. This template is used by section pages (home pages for sections) which are "/hugo", "/jekyll", "/linear-programming" or "/foo". If I delete this template, section pages will start using /layouts/_default/list.html.

What if I don’t want to use any template?

Well, you don’t have to. When we use templates, we define parts inside blocks. If you don’t use any block, then the template won’t be related with baseof.html. You can create a separate <html> file, 404 page is a good example.

Blog Posts vs Series vs Projects

In my site, series are blog posts with episode parameter in their front-matter. I’ve seen many blogs using the name “tutorials” where I use the name “series” instead. I am not sure if they created different taxonomy but I didn’t. Also there are projects which is again just another section.

I considered to create different taxonomies called “series” and “projects” to separate those from others. Then I realised I had to add category taxonomy too and not use sections. As far as I understand, most people alredy don’t use sections. Taxonomies can even make somethings easier, like templating and filtering since Hugo provides built-in functions. However, I found using sections is easier, it requires less templates and folders. I don’t need to make things complicated since all these 3 are basically the same thing. Also, I don’t want to make front-matter longer.

I’ve customized projects section’s list template and single template by creating a separate folder for them /layouts/projects. So, Hugo will use these templates instead of /layouts/_default for projects section. Template Lookup Order is important here.

You are reading the 3rd of 19 episodes in Hugo.
Published on 03.08.2020 by Mert Bakır with commit 3a172e2.
hugo
#hugo #web-dev #workflow
Next episode:
Overwrite Default Landing Page For Hugo Taxonomies
published on 21.08.2020

“Overwriting default landing page for Hugo taxonomies”. What do I mean by that? By default, Hugo will create a home page or a landing page for your taxonomies. /tags/ or /categories are good examples. If you don’t have any specific templates for tags /layouts/tags/list.html Hugo …

published on 05.08.2020

This post will be very short and precise. In Jekyll, we had to create an .xml file using liquid templates to tell Jekyll that we want an rss.xml or similarly sitemap.xml. Luckily, Hugo creates these files for us under the hood. You can check them by going to /index.xml and /sitemap.xml pages in your …

published on 06.08.2020

Search engine bots or crawlers, use two files to crawl a website more intelligently. These are robots.txt and sitemap.xml. A robots.txt file tells search engine crawlers which pages or files the crawler can or can’t request from the site. This is used mainly to avoid overloading your site with …

published on 24.01.2021
edited on 11.06.2021

Some time ago, I wanted to display image galleries on my Hugo website and searched for Hugo themes for photography and gallery. I can’t say I find much. Then, I met with a javascript library called nanogallery2 which is using another javascript library as an image viewer lightbox2. In this …

published on 23.01.2021
edited on 11.06.2021

Image processing may seem complicated at first but it’s actually easy and definitely worth implementing since it’ll help you decrease page load times. As you probably know, we don’t want to load raw images with huge sizes for small thumbnails or blog-posts. We want to load a small …

published on 31.12.2020
edited on 26.06.2021

I’ve, recently, published a blog post called Perfect Workflow for Publishing Python Notebooks. I talked about some of the benefits of using Rmarkdown and reticulate. In this post, I’ll try HTML widgets and explain how we can embed those in our blog post using nothing but R. […] 1 …

published on 05.12.2020

Resume A4 is a side project of mine. It’s one page Hugo Theme that allows you to write your resume in YAML format and keep track of it using git. Also, you can publish it online as a static site using GitLab, GitHub Pages, Netlify, or some other service you are familiar with. A few months …