Keith misner h0 vxgz5ty xa unsplash

Hugo partial: Sharing and inheritance of Hugo page resources

A Hugo partial that vastly improves resource management in Hugo sites by avoiding duplicate images in your content based on Page Bundles and Headless Bundles

This partial is designed for retrieving resources from a page bundle in Hugo, where resources refer to files like images, or data files. The partial is used for obtaining resources from Page Bundles, with a unique feature of traversing upwards to parent page bundles if the resource isn’t found in the current page’s bundle. This is especially useful for managing resources that are inherited on child pages or shared across multiple sections.

Let’s consider the following example of a directory structure:

 1content:
 2  articles:
 3    _index.md
 4    my-article:
 5      index.md
 6      images:
 7        feature-image.jpg
 8    images:
 9      index.md
10      share-image.jpg
11assets:
12  images:
13    logo.png

If you now use this partial in the file content/articles/my-article/index.md, you can access the three images by their relative paths.

As the feature image is specific to the article, it exists in the page bundle of the article my-article. We can access it using the following code:

1{{ $featureImage := partial "claris/_functions/resources/get" (dict 
2        "Page" .
3        "resource" "images/feature-image"
4) }}

Now the share image might also be specific to the article, but in my case, I use the same share image for all articles. The share image hence only exists in the branch bundle of the articles section articles.

Note

Ensure to turn images directory into a headless bundle: Add a file named index.md with the following content into every images directory that is part of a branch bundle (see below for an explanation what a branch bundle is)

1---
2headless: true
3---

If we have properly set up the images directory under articles as a headless bundle, we can access the share image share-image.jpg from the page bundle my-article using the following code:

1{{ $shareImage := partial "claris/_functions/resources/get" (dict 
2        "Page" .
3        "resource" "images/share-image"
4) }}

Perhaps surprisingly, the call to the resources partial is almost the same, even though we will get an image from a headless bundle one level up.

Finally, the site’s logo image will be the same for all articles. Hence, it makes sense to either put it into a headless bundle at the top of the content directory, or into the assets directory.

To access the share image, we use the following invocation of the resources partial:

1{{ $logoImage := partial "claris/_functions/resources/get" (dict 
2        "Page" .
3        "resource" "images/logo"
4) }}

Again, the call to the resources partial is almost the same, even though we will get an image from the global assets directory.

This partial accepts a dictionary with two key-value pairs: Page refers to the current page, while $resourcePath is the path of the resource. The path is treated as the prefix of the resource to be found, unless it ends with a file extension.

1{{ $resourcePath := "images/feature-image" }}
2{{ $resourceArgs := (dict
3"Page" .
4"resource" $resourcePath
5) }}
6
7{{- $image := partial "claris/_functions/resources/get" $resourceArgs }}

Hugo categorizes Page Bundles into Leaf Bundles and Branch Bundles. Leaf Bundles are directories containing an index.md file and can include a variety of content and attachments for single pages. Branch Bundles, represented by _index.md, need to be used for sections and typically only contain non-page resources (source: Hugo Page Bundles).

For Branch Bundles, the partial employs a workaround using Headless Bundles. By adding headless: true to the front matter of an index.md file within a directory, the directory can host resources similarly to a Leaf Bundle (detailed at Hugo Headless Bundles).

The partial uses the current page and the resource path as parameters, returning a Hugo resource object or false if not found.

Preference is given to page resources, with a fallback to site resources if the desired resource isn’t found in the current page or its ancestors (source: Hugo Page Resources).

A $debug variable can be set to true for insights into the operational flow, aiding in troubleshooting and enhancements.

This partial is part of my Hugo module claris-resources and hosted on GitHub. To use it in your Hugo website, add the following to your config/_default/hugo.yaml (or hugo.toml) file:

1module:
2  imports:
3    - path: github.com/simonheimlicher/claris-resources

This custom Hugo partial offers enhanced resource management, ensuring efficient resource utilization in Hugo websites. Its ability to navigate through different types of Page Bundles and leverage Headless Bundles for Branch Bundles is particularly valuable.

This partial is the result of my continuous experimentation and adaptation to my own use case. Please let me know about [Personal information, requires JavaScript] . I would be happy to further improve it to handle additional use cases.