Use shortcode within markdown to inject contents in arbitrary location on page

I’d like to have a shortcode for hero content which allows the post author to place the content within the body of the markdown, but allow me to place the inner content in a different location (in this specific case, the <heading> tag for the article.

I attempted doing this via the following method, but it did not work. Is this achievable by some other means?

layouts/single.html

...
<heading>
  {{ block "hero" . }}
  {{ end }}
</heading>
...

shortcodes/hero.html

{{ define "hero" }}
  {{ .Inner }}
{{ end }}

content/myPost.md

...
{{% hero %}}
## My hero subheading
Lorem ipsum dolor sit amet consectetur adipisicing elit. Delectus repellendus aliquam mollitia quod non distinctio ipsam voluptates officia! Maiores, similique dolores amet inventore reiciendis aliquid assumenda nemo corrupti praesentium expedita?
{{% /hero %}}
...

I think I would handle this with .Page.Store.

markdown

{{< hero >}}
A **bold** word.
{{< /hero >}}

layouts/shortcodes/hero.html

{{ .Page.Store.Set "hero_content" .Inner }}

layouts/_default/baseof.html

{{ $noop := .WordCount }}    <-- force .Content to be rendered first
{{ with .Store.Get "hero_content" }}
  <header>
    {{ . | $.RenderString }}
  </header>
{{ end }}

This is helpful, and makes a lot of sense.

A few questions:

  1. Would .Scratch work just as well here, or is there a reason why .Store is ideal for this scenario?
  2. Why is it necessary to force .Content to be rendered first?
  3. How would I allow footnotes to be included within the hero shortcode?

I’ve started using .Page.Store instead:
https://gohugo.io/functions/store/

In contrast to the .Scratch method, this Scratch is not reset on server rebuilds.

The .Store value is initialized when the content is rendered, but we need the value before the content is rendered. Instead of trying to remember the rendering sequence and the nuances of concurrency, I always force content to be rendered to a “no-op” variable if I need a .Scratch or .Store value before calling .Content in a template.

See this post for a list of methods that cause content rendering.

I’m not sure I’ve seen a problem when building a site, but I’ve definitely seen a problem when editing templates while running hugo server.

You can obviously create a footnote that appears immediately below the .Inner content, but I can’t think of a way to place that footnote at the bottom of the page; you’re rendering the shortcode content outside of page rendering.

1 Like

Thank you, @jmooring!

Well, I thought of one, but it’s a bit of a cheat. Let me know if your’re interested.

I’m interested!

markdown

{{% hero %}}
A **bold** word with a footnote[^1].

[^1]: Some footnote
{{% /hero %}}

shortcode

{{ .Page.Store.Set "hero_content" .Inner }}
<div class="hidden">
{{ .Inner }}
</div>

baseof.html

{{ $noop := .WordCount }}
{{ with .Store.Get "hero_content" }}
  <div class="hide-footnotes">
    {{ . | $.RenderString }}
  </div>
{{ end }}

css

.hidden {
  display: none;
}
.hide-footnotes div.footnotes {
  display:none;
}

Try it…

git clone --single-branch -b hugo-forum-topic-46317 https://github.com/jmooring/hugo-testing hugo-forum-topic-46317
cd hugo-forum-topic-46317
hugo server

This topic was automatically closed 2 days after the last reply. New replies are no longer allowed.