• Pricing

Content and blogging in Hugo

Farrel Burns, Developer Evangelist
Duration: 2 hours
Expertise level: Beginner
On this page:

Loading...

Code

Clone: git clone https://github.com/CloudCannon/hugo-learn-blog-template.git

Starter branch: git checkout content-intro-start

Finished lesson: git checkout content-intro-finish

What you’ll learn here:

  • How to create a blog with Hugo content and layouts

  • The difference between a section and type

  • Understand archetypes and front matter for content pages

  • Create an archetype for your specific content

  • Create layouts for list pages and content

What is "content" for Hugo?

As previously mentioned, Hugo takes an unambiguous stance on content and structure - they need to be separate:

  • Content is anything that you want to put on a page (generally in Markdown format for written content), without considering the design.
  • Layouts take care of displaying your content, and can be as specialized as you need for each content area.

In Hugo, the content folder holds your pieces of documentation, blog posts, etc. Top-level folders are considered sections of your site.

Hugo will also automatically use the top-level folder’s name as a type behind the scenes. Unless otherwise specified, it will first look for a layout with the same naming convention (i.e. type) as your content: e.g., content/bloglayouts/blog

Content concepts

Sections vs. types

The difference between Hugo’s sections and types might not be immediately obvious.

In simple terms, a section is generally a top-level folder in your content folder (e.g. /blog, /products, /customer-stories). Hugo keeps track of your sections in a tree structure, giving you access to data that you can use for navigation purposes (parent directory, next article, previous article, etc.). This is all automatic, and you cannot set the section in your front matter.

A type will also be implicitly applied to your sections, with the same name as your section (e.g., content/blog is type: blog). This type is used to match content with layouts, and unlike a section, you can override the type in front matter. This is useful where you haven’t created specific layouts for a section of content, but you want to explicitly use another one. For example, setting type: page in content/blog front matter will let Hugo know to use the page layout and ignore a standard, implicit lookup order of blog_default.

Oversimplification:

- section: a navigable part of your site, generally a top-level folder. Section cannot be changed in front matter.

- type: a name, generally the same as a section, used to link content to layouts. Type can be changed in front matter.

You can also add an _index.md file to a folder (with optional front matter) to let Hugo know it should be considered a section. This has already been done in the root of layouts, so that index.html has access to metadata.

Front matter and archetypes

If you’re unfamiliar with front matter, it’s simply a great way to make your content more powerful by putting a special section at the top of files. With front matter, you can create and modify variables and data specific to each piece of content, which can be used more “dynamically” in your layouts.

However, a Hugo-specific concept for front matter is an archetype. An archetype is a front matter template for content. This is Hugo’s _default.md archetype:

---
title: "{{ replace .Name "-" " " | title }}"
date: {{ .Date }}
draft: true
---

With this example, you can simply run hugo new a-test-article.md and Hugo will create a file with front matter like this:

---
title: "A test article"
date: 2021-02-05T13:03:42+13:00
draft: true
---

While it’s purely optional, an archetype is a great way to keep front matter regular when creating new content. An archetype is (generally) a Markdown file in the archetypes folder, with the same name as your content section (e.g., content/blogarchetypes/blog.md), along with the front matter you’d like that content type to have.

Important notes:

By convention, unlike in Jekyll, front matter should always live in content pages, not in layouts.

Archetypes can include Go templating, but ordinary front matter cannot. It is also possible to use TOML and JSON in archetypes/front matter, but YAML is the most common.

Practical work: creating a basic blog

Let’s get to the action and create an archetype, content, and a specific layout. As usual, feel free to clone the Hugo project we’ve created for you.

A new archetype

  • Create an archetype for posts by creating a copy of archetypes/default.md. Rename it blog.md
  • In a real blog, we can imagine that users would like to navigate content by tags and/or categories, so change the content of the blog archetype to this:
---
title: "{{ replace .Name "-" " " | title }}"
date: {{ .Date }}
draft: true
image: 
author:
tags:
categories:
---

Add a blog section and posts

We’re following a convention now. Create the folder content/blog. Because we have a blog.md archetype, we can now auto-generate some files with front matter. Use Hugo’s CLI to create an _index.md and 3 new posts:

hugo new blog/_index.md
hugo new blog/first-post.md
hugo new blog/bird-of-the-year.md
hugo new blog/endangered-gulls.md

Now we have three empty posts, ready for content, as well as an _index.md. This is helpful for adding metadata to our section which our browser will display, such as the section title when we are viewing the blog landing page.

For the individual content, you’ll find a posts.txt file in the content folder to help you fill these out.

Now for the "blog" layouts

We have some default layouts in our project, but we probably want more specific layouts for showing posts. Create the folder layouts/blog, and add a list.html and a single.html. Add this to list.html:

{{ define "main" }}
    <h1 class="col-header dark-orange">All blog posts</h1>
    {{ range (.Site.GetPage "section" "blog").Pages }}
        <div class="post-preview">
            <img class="post-preview__left" src="{{ .Params.image }}">
            <div class="post-preview__right">
                <a class="preview-title" href="{{ .Permalink }}">{{ .Title }}</a>
                <span>{{ .Date.Format "January 2, 2006" }}</span>
            </div>
        </div>
    {{ end }}
{{ end }}

There is more than one way to request the blog pages, for example .Site.Pages (which would get all of our current pages) and where .Site.RegularPages "Type" "blog".

The great thing about Hugo is how much work it does for us. In a list.html layout under blog, we can simply loop through all the blog post pages in our blog section. Hugo knows which content belongs in this section, so it takes over the rest.

Next, for the layout for a single post (single.html), we can reference the post’s title and author and get its main content (.Content is anything below front matter). Note that .Title works normally, but author from front matter comes through .Params.

{{ define "main" }}
        <div class="b-hero">
            <img class="b-hero__image" src="{{ .Params.image }}">
            <div class="b-hero__info">
                <h1 class="b-hero__title">{{ .Title }}</h1>
                <div class="b-hero__author-date">
                    <span>Written by: {{ .Params.author }}</span>
                    <span>{{ .Date.Format "January 2, 2006" }}</span>
         <!-- Tag navigation can be added later -->
                </div>
            </div>
        </div>
        {{ .Content }}
{{ end }}

In both cases, because we have _defaults/baseof.html with a “main” block, Hugo will find and use this. Now, all we need to do is make the posts listing page available on our site. That’s just one small change in layouts/partials/nav.html:

<a href="/blog">Blog</a>

And just like that, Hugo uses its magic to create the pages and make them available for navigation. Check out the result by running the server and opening localhost:1313!

Layout alternative: section.html

Because our blog is also a section of our site, you can also use a more generic section layout in_default/section.html with more generic listing logic. This would be used to display all section content consistently, which can be useful when your site grows. However, because we won’t have many sections here and want to get accustomed to ordinary lookup rules and specific logic, our blog layout is fine and can be changed later if need be.

What's next?

We now know the basics of how to use the content folder to create sections that help Hugo navigate your corresponding layouts, as well as what purpose archetypes fulfill. Feel free to experiment with your own content types and layouts. Next, we will look at how to make it easy to navigate between related content with taxonomies.

Comments