This post is more of a story about how I used Hugo and its features. ðŸ¤
I’m creating a website for something related to my research (I’ll share it here soon) where I need to generate multiple pages from JSON files for a static site. I’ve been using Hugo on this blog since 2018, and although there are other great options out there, I always end up trying to do things with it.
An alternative for a similar problem is Data Templates, and I’ve already ventured into it myself, using Google Sheets as a backend. But instead of creating just one page, I wanted to create several. For this, I found a solution with Content Adapters.
Content adapters allow you to create content dynamically, either by adding a page or a resource. My problem was: I have a large JSON with a list of things (definitions
) that I want to turn into individual pages, based on a pre-established markdown.
The documentation covers basic cases, but since I had to struggle until it worked, I thought it was worth sharing the step-by-step process. Let’s go!
Prepare your template
I created the page (markdown) the way I wanted it, since they all have the same structure, and placed it in assets/definitions.md
with placeholders where the JSON information would go. For example:
# TITLE
By ORGANIZATION - AUTHORS
## Purpose
DESCRIPTION
Tip: you don’t include that header here; it will be inserted later.
Prepare the data
To have accessible data, I created a small folder data/definitions.json
with a list of JSONs that I would like to use. But you can also use a remote address to access this JSON. It should be a list of JSONs.
Finally, the adapter
In content/
, I created a folder for definitions
and inside it a _content.gotmpl
. You also need an _index.md
(don’t forget to check the official documentation!).
content/
└── definitions
├── _content.gotmpl
└── _index.md
The _content.gotmpl
holds the secret sauce: I load my definitions.md
and iterate over them, replacing the placeholders in the page with the data from the JSON. When running hugo server
, all pages are created.
{{ with resources.Get "definitions.md" }}
{{ $definitionTemplate := .Content }}
{{ range $.Site.Data.definitions }}
{{ $publishedAt := dict }}
{{ if .published_at }}
{{ $publishedAt := dict "date" (time.AsTime .published_at) }}
{{ end }}
{{ $dates := dict "date" now.UTC }}
{{ $processedContent := replace $definitionTemplate "TITLE" .title }}
{{ if .authors }}
{{ $processedContent = replace $processedContent "AUTHORS" (delimit .authors ", ") }}
{{ else }}
{{ $processedContent = replace $processedContent " - AUTHORS" "" }}
{{ end }}
{{ $processedContent = replace $processedContent "ORGANIZATION" .organization }}
{{ $processedContent = replace $processedContent "DESCRIPTION" .description }}
{{ $processedContent = replace $processedContent "DEFINITION" ( . | jsonify (dict "prefix" " " "indent" " ")) }}
{{ $content := dict
"mediaType" "text/markdown"
"value" $processedContent
}}
{{ $page := dict
"content" $content
"kind" "page"
"path" .title
"title" .title
"dates" $dates
"publishDate" .publishedAt
"draft" false
}}
{{ $.AddPage $page }}
{{ end }}
{{ end }}
But wait, there’s no new markdown in the folder.
That’s right. It generates the files (content) only based on the template you provided.
I hope this little recipe helps you!
Links that helped me: https://gohugo.io/content-management/content-adapters/ https://github.com/gohugoio/hugo/issues/12427 https://www.thenewdynamic.com/article/toward-using-a-headless-cms-with-hugo-part-2-building-from-remote-api/