Some notes on hugo templates and taxonomies #16

Open
opened 2026-04-09 21:02:55 +00:00 by jsheunis · 1 comment
Member

While working on supporting custom searching and filtering functionality on the /publications page, I took some time to figure out the differences between the following:

  • taxonomy page template (kind=taxonomy)
  • section page template (kind=section)
  • term page template (kind=term)
  • list page template

because all of them work from the _index.md source.

So what I determined (because I finally read the docs thoroughly... but perhaps not even enough yet):

  1. if we use index.md it is a regular page and has kind=page and will be rendered by the page.html template (or single.html if the former does not exist)
  2. if we use _index.md it is either:
    • a section page, if there is no relevant taxonomy configured for the current section (e.g. content/books/_index.md), and this will be rendered by the section.html template ; or
    • a taxonomy page, if there is a taxonomy configured for the current section (e.g. content/projects/_index.md), and this will be rendered by the taxonomy.html template ; or
    • a term page, if the term (i.e. the parent directory of the _index.md), is part of a configured taxonomy (e.g. taxonomy could be persons and stephan-heunis would be the term), and this would then be rendered by the term.html template, or

Some further important notes:

  • the list.html template is the fallback for all of: section.html, taxonomy.html, term.html
  • even if no _index.md source is available (for either a section or a taxonomy), Hugo will still use the relevant template to render a section or taxonomy page at the relevant path (e.g. if persons is a taxonomy, Hugo will render the taxonomy.html template for <website-domain>/persons/ even if no content/persons/_index.md exists)

I needed to figure all of this out for the filtering/searching functionality on the /publications page because:

  • whether publications is a configured taxonomy or not will influence which template, section.html or taxonomy.html, should be customized
  • the customized code needs to fetch front matter from specific pages in order to build up publication data (this is a shift from the current approach where a separate workflow generates a json data file), and we need to know whether we are working with regular pages or term pages in order to customize that template correctly

So, after working through all of the above, my approach going forward will be:

  • configure publications as a taxonomy (already done)
  • remove the update_publications_data.yaml workflow that currently generates a data/publications.json file used by the current filtering/searching functionality
  • add a new update_publication_pages.yaml wofklow that generates individual publication pages, same as persons, projects etc. These will be content/publications/<pid>/_index.md pages, and their front matter will contain information about the publication.
  • customize the layouts/publications/taxonomy.html page to contain the functionality for filtering/searching publications; this includes code to fetch all front matter from all publication term pages (i.e. pages at content/publications/<pid>/_index.md) and put that into a json object for the page to use further
While working on supporting custom searching and filtering functionality on the `/publications` page, I took some time to figure out the differences between the following: - taxonomy page template (`kind=taxonomy`) - section page template (`kind=section`) - term page template (`kind=term`) - list page template because all of them work from the `_index.md` source. So what I determined (because I finally read the docs thoroughly... but perhaps not even enough yet): 1. if we use `index.md` it is a regular page and has `kind=page` and will be rendered by the `page.html` template (or `single.html` if the former does not exist) 2. if we use `_index.md` it is either: - a section page, if there is no relevant taxonomy configured for the current section (e.g. `content/books/_index.md`), and this will be rendered by the `section.html` template ; or - a taxonomy page, if there is a taxonomy configured for the current section (e.g. `content/projects/_index.md`), and this will be rendered by the `taxonomy.html` template ; or - a term page, if the term (i.e. the parent directory of the `_index.md`), is part of a configured taxonomy (e.g. taxonomy could be `persons` and `stephan-heunis` would be the term), and this would then be rendered by the `term.html` template, or Some further important notes: - the `list.html` template is the fallback for all of: `section.html`, `taxonomy.html`, `term.html` - even if no `_index.md` source is available (for either a section or a taxonomy), Hugo will still use the relevant template to render a section or taxonomy page at the relevant path (e.g. if `persons` is a taxonomy, Hugo will render the `taxonomy.html` template for `<website-domain>/persons/` even if no `content/persons/_index.md` exists) I needed to figure all of this out for the filtering/searching functionality on the `/publications` page because: - whether `publications` is a configured taxonomy or not will influence which template, `section.html` or `taxonomy.html`, should be customized - the customized code needs to fetch front matter from specific pages in order to build up publication data (this is a shift from the current approach where a separate workflow generates a `json` data file), and we need to know whether we are working with regular pages or term pages in order to customize that template correctly So, after working through all of the above, my approach going forward will be: - configure `publications` as a taxonomy (already done) - remove the `update_publications_data.yaml` workflow that currently generates a `data/publications.json` file used by the current filtering/searching functionality - add a new `update_publication_pages.yaml` wofklow that generates individual publication pages, same as persons, projects etc. These will be `content/publications/<pid>/_index.md` pages, and their front matter will contain information about the publication. - customize the `layouts/publications/taxonomy.html` page to contain the functionality for filtering/searching publications; this includes code to fetch all front matter from all publication term pages (i.e. pages at `content/publications/<pid>/_index.md`) and put that into a json object for the page to use further
jsheunis changed title from Spme notes on hugo templates and taxonomies to Some notes on hugo templates and taxonomies 2026-04-10 08:00:47 +00:00
Author
Member

Regarding:

still figure out how to use a partial (or something else) to render a custom individual element of the taxonomy list page

The challenge here is: I currently use javascript for injecting html elements on the fly based on the result after searching/filtering. However, this is a convoluted way to structure html. I rather want to use hugo templating for the layout of a single publication element in the list. But the problem is that hugo templating renders once on build, not at runtime.

How I think I will approach this is to use a hugo partial to render every publication on build, and then use the javascript just to handle publication element visibility based on the results of searching/filtering at runtime.

This keeps the components separated and every tool does what it is good at.

This might become a problem for very large data arrays, but I don't want to optimise for that prematurely. What we could consider when we need to do this is to extend the current approach:

    <!-- Data -->
    {{ $pubPages := where .Site.Pages "Section" "publications" }}
    {{ $pubPagesTerms := where $pubPages "Kind" "term" }}
    <script id="pub-data" type="application/json">
    [
    {{- $first := true -}}
    {{- range $i, $p := $pubPagesTerms }}
      {{- if not $first }},{{ end }}
      {{- $first = false }}
      {
        "title": {{ $p.Title }},
        "permalink": {{ $p.RelPermalink }},
        "doi": {{ $p.Params.doi }},
        "date": {{ $p.Params.date }},
        "kind": {{ $p.Params.kind }},
        "author": {{ $p.Params.author }},
        "topic": {{ $p.Params.topic }}
        "html": {{ partial "publication-element.html" $p | jsonify }}
      }
    {{- end }}
    ]
    </script>

I.e. can use the partial to return the html for a given element, and add that into the json. And then let the javascript do filtering and inject the html of the element back into the DOM.

Regarding: > still figure out how to use a partial (or something else) to render a custom individual element of the taxonomy list page The challenge here is: I currently use javascript for injecting html elements on the fly based on the result after searching/filtering. However, this is a convoluted way to structure html. I rather want to use hugo templating for the layout of a single publication element in the list. But the problem is that hugo templating renders once on build, not at runtime. How I think I will approach this is to use a hugo partial to render every publication on build, and then use the javascript just to handle publication element visibility based on the results of searching/filtering at runtime. This keeps the components separated and every tool does what it is good at. This might become a problem for very large data arrays, but I don't want to optimise for that prematurely. What we could consider when we need to do this is to extend the current approach: ```html <!-- Data --> {{ $pubPages := where .Site.Pages "Section" "publications" }} {{ $pubPagesTerms := where $pubPages "Kind" "term" }} <script id="pub-data" type="application/json"> [ {{- $first := true -}} {{- range $i, $p := $pubPagesTerms }} {{- if not $first }},{{ end }} {{- $first = false }} { "title": {{ $p.Title }}, "permalink": {{ $p.RelPermalink }}, "doi": {{ $p.Params.doi }}, "date": {{ $p.Params.date }}, "kind": {{ $p.Params.kind }}, "author": {{ $p.Params.author }}, "topic": {{ $p.Params.topic }} "html": {{ partial "publication-element.html" $p | jsonify }} } {{- end }} ] </script> ``` I.e. can use the partial to return the html for a given element, and add that into the json. And then let the javascript do filtering and inject the html of the element back into the DOM.
Sign in to join this conversation.
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
www/www-from-model#16
No description provided.