HUGO

Loop through all occurrences of a certain shortcode and access it's ".Inner" content

Hello everyone,

I couldn’t find anything online, but I’m wondering how I could loop through all occurrences of a certain shortcode in a markdown file and access it’s “.Inner” content to display it in my HTML. I’m not quite sure how I would solve this.
So I want to access the content of all “title” shortcodes in a loop, so I can build a list out of it in my single.html file for example:

Some text. This shouldn't be considered.

{< title >}
This is a title.
{< /title >}

Something else. This shouldn't be considered of course.

{< title >}
Another title
{< /title >}

Thank you already in advance, the support here is awesome!

You can’t really access the shortcode in single.html as far as I know.

While looping through all shortcodes is probably not possible, what you can do instead is just create one shortcode and add all the values as parameters to it. Then you can use it (untested):

{{- range .Params -}}
  {{- . -}}
{{- end -}}

markdown

{{< capture >}}
Frankly, my dear, I don't _give_ a damn.
{{< /capture >}}

{{< capture show >}}
Toto, I've a _feeling_ we're not in **Kansas** anymore.
{{< /capture >}}

{{< capture hide >}}
I'm gonna make him an **offer** he can't refuse.
{{< /capture >}}

layouts/shortcodes/capture.html

{{- $show := false -}}
{{- with .Get 0 -}}
  {{- if eq . "show" -}}
    {{- $show = true -}}
  {{- else if eq . "hide" -}}
    {{- $show = false -}}
  {{- else -}}
    {{- errorf "The %s shortcode accepts a single positional parameter with a value of either 'show' or 'hide'. See %s" $.Name $.Position -}}
  {{- end -}}
{{- end -}}

{{- with .Inner -}}
  {{- $.Page.Scratch.SetInMap $.Name (printf "%04d" $.Ordinal) . -}}
  {{- if $show -}}
    {{- . | $.Page.RenderString (dict "display" "block") -}}
  {{- end -}}
{{- else -}}
  {{- errorf "The %s shortcode requires 'Inner' content. See %s" .Name .Position -}}
{{- end -}}

layouts/_default/single.html

{{ define "main" }}
  <h1>{{ .Title }}</h1>

  {{ $noop := .Content }}
  {{ $shortcode := "capture" }}
  <p>Titles:</p>
  <ul>
    {{ range $k, $v := .Scratch.GetSortedMapValues $shortcode }}
      <li id="{{ printf `%s-%d` $shortcode (add 1 $k) }}" class="{{ $shortcode }}">
        {{ $v | $.Page.RenderString }}
      </li>
    {{ end }}
  </ul>

  {{ .Content }}
{{ end }}

Notes

  1. By default, the captured text will be hidden. If you want to capture and show, set the optional positional parameter to show.
  2. The {{ $noop := .Content }} statement in layouts/_default/single.html is critical. We need to render the content before we can capture it.
  3. If you make changes to the template or the shortcode while runnning hugo server, you will probably have to restart the server after each change.
  4. This was not my idea. See https://github.com/gohugoio/hugo/issues/4560.
2 Likes

Thank you a lot for your answer. That is fantastic. It works perfectly fine, thank you!

There is one last thing I wanted to mention though. Everything worked fine, until I added a new shortcode with content. It is at the very bottom of the markdown file, but in the ordered list, it’s at the second place, right below the first entry. I expect it to be added as the last element of the list.

How many instances are on the page?

Sorry about that. With 11 or more captures the sorting failed due to alphabetical instead of numeric sorting. I’ve revised my earlier post with two changes:

1) layouts/shortcodes/capture.html

I changed this:

{{- $.Page.Scratch.SetInMap $.Name (string $.Ordinal) . -}}

To this:

{{- $.Page.Scratch.SetInMap $.Name (printf "%04d" $.Ordinal) . -}}

Now you can have 10,000 captures on a page before you run into sorting problems.

2) layouts/_default/single.html

I changed this:

<li id="{{ printf `%s-%d` $shortcode $k }}" class="{{ $shortcode }}">

To this:

<li id="{{ printf `%s-%d` $shortcode (add 1 $k) }}" class="{{ $shortcode }}">

Now the <li> element id’s start with 1 instead of zero.

1 Like

Thank you very very much! I had only 4 instances, but the new changes fixed this issue.

I really appreciate your help, thank you a lot!

This concerns me. I understand why it would have happened with 11 or more, but it should not have happened with only 4. Please let me know if you are able to reproduce the problem.

I’ll definitely let you know once I’m able to reproduce the issue. I will fiddle around with the solution and different counts of instances.

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