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/