Arbitrarily Nested Shortcodes

In a few different cases, I’d like to be able to enable users of my theme to write markdown with arbitrary shortcodes nested inside of others. I have three shortcodes currently implemented: detail, icon, and rolltable.

For example, I have a detail shortcode, which should be able to render the inner markdown (and all of its shortcodes) inside of the detail block - but I have no way of knowing (and prefer not to hand code handling for) each of the potential shortcodes a user might include - if they want both an icon in the detail body and a rolltable, for example. Or if they want to include an icon in the tabledata of the rolltable.

The detail shortcode definition:

{{- $type := .Get 0 -}}
{{- $title := .Get 1 -}}
{{- $anchor := urlize $title -}}

<details class="{{ $type }}">
  <summary id="{{ $anchor }}">{{ $title }}</summary>
  {{ .Inner | markdownify }}
</details>

The Icon shortcode definition:

{{- $icon   := .Get 0 -}}
<img src="/icons/{{$icon}}.svg" alt="{{$icon}}" class="icons"/>

All of the examples I’ve seen for nested shortcodes (and the docs) seem to be for shortcodes designed to be relatively tightly coupled. Maybe I’m not fully understanding? I saw some (closed) issues on GitHub for adding a new hugo function that would combine markdownify with parsing nested shortcodes, which seems to be what I’m looking for.

I think there is an open issue about adding support for shortcodes in markdownify, but I don’t think that would solve your particular problem.

I’m guessing you’re writing something like this:

{{< details >}}
{{< icon >}
{{< /details >}}
{{< details >}}
{{< icon >}
{{< rolltable >}
{{< /details >}}

Etc.

Im the above:

  • The outer shortcode knows nothing about the inner shortcodes
  • The inner shortcodes have a .Parent which can be used to pass information upwards

So, if you’re details shortcode can contain “anything”, I would suggest you more any formatting (incl. markdownify) up to each shortcode and just print the resulting HTML, e.g.:

<details class="{{ $type }}">
  <summary id="{{ $anchor }}">{{ $title }}</summary>
  {{ .Inner }}
</details>

Correct me if I’m wrong, but that will then display the icon but not the markdownified text in the detail, right?

So a detail like:

{{< detail example "Determining Characteristics for Taryn Carozza" >}}
To determine Taryn's characteristics, we roll a dz and get a ☀️️️️️️️:

- {{< icon iron >}} **29**
- {{< icon flax >}} **39**
- {{< icon bone >}} **49**

At the beginning of play Taryn has a bit less personal power than most people, has an average education and knowledge-base, and is stronger, tougher, and more agile than most people.
{{< /detail >}}

With {{ .Inner }} we get:

<details class="example" open="">
  <summary id="determining-characteristics-for-taryn-carozza">Determining Characteristics for Taryn Carozza</summary>
  
To determine Taryn's characteristics, we roll a dz and get a ☀️️️️️️️:

- <img src="/icons/iron.svg" alt="iron" class="icons">
 **29**
- <img src="/icons/flax.svg" alt="flax" class="icons">
 **39**
- <img src="/icons/bone.svg" alt="bone" class="icons">
 **49**

At the beginning of play Taryn has a bit less personal power than most people, has an average education and knowledge-base, and is stronger, tougher, and more agile than most people.

</details>

and with {{ .Inner | markdownify }}

<details class="example" open="">
  <summary id="determining-characteristics-for-taryn-carozza">Determining Characteristics for Taryn Carozza</summary>
  <p>To determine Taryn’s characteristics, we roll a dz and get a ☀️️️️️️️:</p>
<ul>
<li>
<!-- raw HTML omitted -->
</li>
</ul>
<p><strong>29</strong></p>
<ul>
<li>
<!-- raw HTML omitted -->
</li>
</ul>
<p><strong>39</strong></p>
<ul>
<li>
<!-- raw HTML omitted -->
</li>
</ul>
<p><strong>49</strong></p>
<p>At the beginning of play Taryn has a bit less personal power than most people, has an average education and knowledge-base, and is stronger, tougher, and more agile than most people.</p>

</details>