Learning to Hugo Part 2: Content Organisation

Learning to Hugo Part 2: Content Organisation

  • hugo
  • 2021-05-02
  • 10 minutes to read

This post is over 12 months old and Hugo is evolving. Please be mindful of that when reading this post as it could be outdated. I try to keep on top of changes where possible. I try to keep things up to date, but if you think something needs updating, please let me know in the comments.

Intro

This is the second part of the learning to Hugo series detailing my journey to getting this site up and running! I'm also using Hugo to configure my business website. In typical dev style, I just installed Hugo and got going. I have learnt a few things along the way that have improved my development time and hopefully these things will help you.

In this section I'm going to walk through fundamentals of directory structure and content organisation.

Health & safety warning

I'm no web dev! My world is data and so this stuff is outside my area of expertise. I'm learning as I go and so the info I'm sharing is my interpretation of that in a way that makes sense for me as a data-person-doing-web-dev. Some of the technical aspects might be a little misunderstood and I'd love to hear from you in the comments if you think there's a better way or if I've misunderstood a concept. Hopefully outlining my understanding of it might make it easier for someone wanting to give it a go. If you want advanced CSS understanding or web development skills though these are not the posts you're looking for!

obi wan kenobi saying these are not the posts you're looking for

obi wan says these might not be the posts you're looking for

Directory Structure

Once you have run the command “Hugo New Site” your folder structure will look similar to this;

six folders called archetypes, content, data, layouts, static & themes

Archetypes

Is used to store preconfigured file structures, I liken these to post templates, but Hugo uses the term templates for something else. If you want all your posts to have a specific look or feel, you can create an archetype to set that structure for all future posts created using the “hugo new” command. This is great for creating a standard structure for your posts or even for designing multiple formats for different post styles. For example, for this series of posts I have created a specific file to give me a head start with some of the repeated content. I will go through this in more detail in a future post.

Content

Is where you create all your site content. Each subfolder is considered a content section. For example, if you have a folder called content/blog your site will present [site url]/blog and all content within that folder will by default be considered of type blog. This pattern is used to apply layouts to your page type. Hugo will look for a file called blog.html in the layouts folder. If no blog.html is found it will revert to default.html. By creating a specific file for a specific file / folder you can set the formatting of that directly. You can override the type by setting a specific type in the front matter of the post. Where this might come in handy is when for a specific post you want to apply a different layout. You can override the type in the front matter and then create a new layout for that type. More on that in a future post.

Data

Appears to be used differently based on your choice of theme. I use the keepit theme for https://justinjbird.me which doesn’t make use of this folder. In other themes, YAML files have been used to structure the page layout. I have not explored this in too much detail yet.

Layouts

Holds content that is used to build your static pages. Hugo refers to these as templates. There are a number of different template types. The ones I have adjusted so far are partials & shortcodes. A full Hugo page might refer to any number of partials to create the entire page, such as a header partial, or a footer partial. Shortcodes on the other hand are used within a post to speed up your development and provide you with repeatable code or code snippets. Hugo has a few built in shortcodes and you can create your own shortcodes too. Supposing you wanted to end every post with the same thank you message, you can turn that into a shortcode and add it to your post archetype. This is really powerful as it gives you the ability to amend a shortcode in future and thus propagate that change to all posts referencing that shortcode! I will go through this in more detail in a future post.

Static

Is where all static content is stored such as images, css, javascript. This content is used during build. All content within the static folder is placed in the root of the built site directory.

Themes

Is where all themes are to be stored by default. If you open a theme folder you will notice that some of the above listed folders will also appear in there. This is because Hugo has a content lookup order which starts from the site folders and then looks inside the relevant theme folder. This is important to understand for two reasons;

  • if you are trying to find why a certain widget is behaving in a certain way it may be in the site’s version of that folder or it may be in the theme folder of the same name.
  • if you want to override a certain widget, it is better to copy that file to the respective folder in the site and adjust it there. That way you effectively override the version in the theme rather than directly changing the theme. This means you can keep the theme clean for future updates whilst still managing your changed versions.

Build folders

The folders above are the fundamental building blocks of your site. As you develop and build your site, more folders will be generated. It’s also possible to add your own folders for notes etc. Here is mine for this site;

more folders have been created, which are explained below

Here is a brief explanation of the extra folders;

  • .github is used by github to automatically build my site when I push it to the remote repository.
  • #notes and #upcoming are my working folders and since they aren’t native to Hugo, Hugo just ignores them.
  • Assets is built once your site is built, in here you’ll find a file called _custom.scss where you can add your own css.
  • Resources and Public are created and used as part of the build process. These appear to be good candidates for your .gitignore file.

Organisation

You have a few options when organising your content. For a single post it is possible to create a single markdown file or a folder containing a markdown file called index.md.

one markdown file, one index.md inside a subfolder

When built, both posts will appear with consistent URLs;

If Hugo finds a file called index.md it considers this to be a single post and uses the name of the folder it is found in as the post name. If a file is called by any other name, that becomes the post name. Examples of this;

content/posts/getting-started-part-one/index.md > [site url]/posts/getting-started-part-one
content/posts/getting-started-part-two.md > [site url]/posts/getting-started-part-two
content/posts/getting-started-part-one/foobar.md > [site url]/posts/foobar #oops

The filename index.md is recognised as a single page. Consideration should go into how or where you wish to store supporting content such as images. For the post called part one, it is possible to store images inside that very folder or even create a subfolder for images however, for the post called part two you don’t have a folder to store them in. You might consider storing them in the root folder alongside the file or storing them in the static/images folder. In the image below I have created part three and shown a few options;

shows images stored in the post folder, in the root folder or in the static folder

Because part 2 doesn’t have a folder you will very quickly find yourself having to start giving images associated names in order to understand which post an image is used in. This is equally a consideration when making use of the static/images folder. In the image above I have called the file 001.webp but three months down the line that isn’t going to be very obvious to anyone. So it’s advisable to also consider a suitable folder structure inside of the static/images folder.

My structure

The structure I have settled on after exploring various options is this;

  • ALL of my posts get a folder, this just means everything looks consistent and appeals to my OCD. But in all seriousness…you never know when you might want to add a supporting file.
  • Images specific to the post will be stored in the post’s folder. Because of this, the names don’t need to be meaningful, they will simply be called 001.webp, 002.webp etc and in terms of naming files, writing the markdown, less I have to type, the more time I have to procrastinate over the post itself.
  • Images that will be used by more than one post (e.g. the Hugo logo) will be stored in the static/images folder with a meaningful name. I have subfolders to help with sorting.

Here is an example;

shows one image in the post folder and one reusable image in the static folder

In the image above you can see a post I wrote about being retained as a Friend of Redgate (yay!). The post has an image specific to the post and also makes use of my friends of Redgate badge, but because I might use that badge more than once I have placed it in the shared folder.

Referencing these images

The only other thing of note when using this folder structure is how to reference the images. For an image in the same folder as the index.md file, you can simply use the filename;

![this is my hugo logo alongside the image.md file](thumb.webp)

If you stored your images in a subfolder then you would use a relative path reference;

![this is my hugo logo from subfolder](./images/thumb.webp)

If you stored your images in the static folder, then you need to provide the full path but note that when built the contents of the static folder are placed at the root of the site so the “static” folder is removed from the filepath;

![this is my hugo logo from static folder](/images/logos/hugo.webp)

Flattening URLs

One other aspect of this which has been really useful is how my site manages the construction of post URLs. In my config.toml file, there is an entry under permalinks;

[Permalinks]
 posts = "/:year/:filename/"

This configuration setting is telling Hugo to adjust the URL of any file it generates from the posts folder. It acquires the date from the front matter of the post and the filename and applies that as the URL. This means I can store my posts in any folder structure I wish (so long as it is inside the posts folder) but once presented at the site they will conform to this setting.

This example will also get the month from the front matter and add that to the URL. See link to info on other values that can be used.

[Permalinks]
 posts = "/:year/:month/:filename/"

I have used this behaviour to split some of my posts into different folders allowing me to control which posts get shared with another site. I will cover this off in a future post.

What else did I learn

Out of the box functionality

Out of the box, Hugo has a few addressable URLs that are pretty useful to be aware of;

  • [site url]/categories will return a list of all your categories.
  • [site url]/tags will return a list of all your post tags.
  • [site url]/index.xml is essentially your RSS feed, you can target any section of your site by changing the URL. So for instance [site url]/posts/index.html is an RSS feed for your posts folder.

Filename behaviour

  • A file called _index.md is considered the index of a section/kind, and so uses the list.html template.
  • A file called index.md is considered the index of a page/post, and so uses the single.html template.

ref: https://laurakalbag.com/processing-responsive-images-with-hugo/

Further reading

Any comments?

I'd love to hear from you in the comments. If you think something needs more explanation or I've not quite understood a concept, if you have a question or just want to say hi please drop me a message in the comments!>

#mtfbwy



Recent Posts

How to Search for a Lost File in the Git Log

How to Search for a Lost File in the Git Log

  • 2024-04-27
  • 4 minutes to read

I have lost a file in my Git repository. How can I find it by searching the git log?

Read More
No Such Shell Function 'Zle Line Init' in Zsh

No Such Shell Function 'Zle Line Init' in Zsh

  • 2024-04-25
  • 3 minutes to read

Troubleshooting the error message "no such shell function 'zle line init'" in zsh when using OhMyPosh.

Read More
Getting Started With Python in Vscode

Getting Started With Python in Vscode

  • 2024-04-05
  • 2 minutes to read

This post will help you get started with Python in Vscode and identify some of the useful extensions to install.

Read More