Is it possible to send a field through the Hugo parser?

I’m wondering if it’s possible to dynamically send fields through the Hugo parser. An example:

layouts/my-service/single.html

{{ with $.Page.Params.summaryoverride }}
  {{ . | HUGO }}
{{ else }}
  {{ .Summary }}
{{ end }}

content/my-service/normal.md

+++
title = "My normal service
+++
This is my normal service

content/my-service/overridden.md

+++
title = "I override summary"
summaryoverride = "Overridden: {{ .title }}"
+++
This is my overridden service

With the ideal output being:
my-service/normal

This is my normal service

my-service/overridden

Overridden: I override summary

My usecase being I’d like individual pages to be able to override sections of the page without needing to check if we’re on that page. ie I want to avoid:

{{ if and (eq .Title "this_page") (eq $.Page.Params.overridesummary true) }}
  {{ partial "this_page.html" . }}
{{ end }}
{{ if and (eq .Title "other_page") (eq $.Page.Params.overridesummary true) }}
  {{ partial "other_page.html" . }}
{{ end }}

First there’s the inline shortcodes feature.

If you have just a few different layouts you want to choose from, you can use the layout front-matter parameter and define a different template per layout.

If you have a few fields and a few variants per field you want to define in front-matter you can just use plain strings in the markdown file:

title = "hello world"
summary_style = "expanded"
sidebar_style = "compact"

… and map them to partials in layout:

{{ with $.Page.Param "summary_style" | default "default" }}
  <div class="summary">{{ partial (printf "summary_style__%s.html" .) $.Page }}</div>
{{ end }}

… which would reference a file named partials/summary_style__expanded.html.
Or you could map them to template snippets directly:

{{ with $.Page.Param "sidebar_style" | default "compact" }}
  {{ if eq . "compact" }}
    <aside class="sidebar--compact">...</aside>
  {{ end }}
  {{ if eq . "expanded" }}
    <div class="sidebar-wrapper">
      <aside class="sidebar--expanded">...</aside>
    </div>
  {{ end }}
{{ end }}

If you really want to define templates inline, there’s a method of (ab)using resources:

{{ with $.Page.Params.summaryoverride }}
  {{ $resource := resources.FromString $.Page.File.UniqueID . }}
  {{ $parsedResource := resources.ExecuteAsTemplate $.Page.File.UniqueID $.Page $resource }}
  {{ $parsedResource.Content }}
{{ else }}
  {{ .Summary }}
{{ end }}

It reads your string into a resource and then executes it as template, giving page as context. UniqueID references are “file paths” - in this case basically cache keys. These should be made unique per per page and field. Otherwise Hugo would cache the first invocation (first page or first field in page) and reuse it everywhere else.

EDIT: for multiple fields you can ensure uniqueness by concatenating with a string, like field name:

  {{ $fieldName := "summaryoverride" }}
  {{ $templateCacheKey :=  printf "%s::%s" $.Page.File.UniqueID $fieldName }}
  {{ $parsedResource := resources.ExecuteAsTemplate $templateCacheKey $.Page $resource }}

In case of giving $.Page as context, like in the example, you would use this in front-matter:

summaryoverride = "Overridden: {{ .Title }}"

And it would display the page’s title in the placeholder

This way of creating and parsing resources might affect performance. I haven’t tested it on anything large.

1 Like

Just a follow-up in case anyone lands here. $.Page.File.UniqueID is only unique to the page and not the field as thought above. The second solution with resources.ExecuteAsTemplate works for one field. I unfortunately ran into a situation where I needed to run this against multiple front-matter fields and Hugo had cached the output and ended up only showing the first field it had parsed.

I expressed myself incorrectly in the answer. Indeed you would need to make the cache key unique.

  {{ $fieldName := "summaryoverride" }}
  {{ $templateCacheKey :=  printf "%s-%s" $.Page.File.UniqueID $fieldName }}
  {{ $parsedResource := resources.ExecuteAsTemplate $templateCacheKey $.Page $resource }}

Edited answer accordingly