Expand shortcodes (or partials) within custom shortcodes

Hello folks,

How can you get shortcodes (or partials) to expand shortcodes within them?

I want to build a shortcode (or partial) for a Disclaimer – to be cited in all posts. The disclaimer uses the admonition shortcode offered in theme uBlogger.

The final partial to display is:

{{< admonition type=warning >}}**Disclaimer**: All information on this page is my opinon and for information purposes only [snip].{{< /admonition >}}

As soon as I excise that into an own partial (or shortcode), hugo fails to run, with error:

Process: loading templates: "/Users/mij/mysite/layouts/partials/disclaimer.html:1:1": parse failed: template: partials/disclaimer.html:1: unexpected "<" in command

The same applies if I use syntax {{% %}} instead.

Thank you!

Outer Inner Allowed
partial partial :white_check_mark:
shortcode partial :white_check_mark:
partial shortcode :x:
shortcode shortcode :white_check_mark:

Nesting a shortcode within a shortcode can be tricky—it depends on what each one is doing. You will need to provide code for both if you have further questions.

3 Likes

Thank you @jmooring .

Here’s the code for the outer shortcode (defining my disclaimer):

{{< admonition type=warning >}}**Disclaimer**: All information on this page ...{{< /admonition >}}

And here’s the code for the inner shortcode (defining admonition):

{{- $inner := .Inner | .Page.RenderString -}}

{{- $iconMap := dict "note" "admonition-icon icon-note" -}}
{{- $iconMap  = dict "abstract" "admonition-icon icon-abstract" | merge $iconMap -}}
{{- $iconMap  = dict "info" "admonition-icon icon-info" | merge $iconMap -}}
{{- $iconMap  = dict "tip" "admonition-icon icon-tip" | merge $iconMap -}}
{{- $iconMap  = dict "success" "admonition-icon icon-success" | merge $iconMap -}}
{{- $iconMap  = dict "question" "admonition-icon icon-question" | merge $iconMap -}}
{{- $iconMap  = dict "warning" "admonition-icon icon-warning" | merge $iconMap -}}
{{- $iconMap  = dict "failure" "admonition-icon icon-failure" | merge $iconMap -}}
{{- $iconMap  = dict "danger" "admonition-icon icon-danger" | merge $iconMap -}}
{{- $iconMap  = dict "bug" "admonition-icon icon-bug" | merge $iconMap -}}
{{- $iconMap  = dict "example" "admonition-icon icon-example" | merge $iconMap -}}
{{- $iconMap  = dict "quote" "admonition-icon icon-quote" | merge $iconMap -}}
{{- $iconDetails := "admonition-icon admonition-icon-arrow-right" -}}
{{- $aside := (.Get `aside`) | default false }}


{{- if $aside -}}<aside>{{- end -}}
{{- if .IsNamedParams -}}
    {{- $type := .Get "type" | default "note" -}}
    <div class="details admonition {{ $type }}{{ if .Get `open` | ne false }} open{{ end }}">
        <div class="details-summary admonition-title {{ if not (.Get `title`) }}admonition-title-none{{ end }}">
            {{- with (.Get "title") -}}
            <i class="icon {{ index $iconMap $type | default (index $iconMap "note") }}"></i>{{ . | default (T $type) }}<i class="details-icon  {{ $iconDetails }}"></i>
            {{- end -}}
        </div>
        <div class="details-content">
            <div class="admonition-content">
                {{- $inner  -}}
            </div>
        </div>
    </div>
{{- else -}}
    {{- $type := .Get 0 | default "note" -}}
    <div class="details admonition {{ $type }}{{ if .Get 2 | ne false }} open{{ end }}">
        <div class="details-summary admonition-title" style="display: none">
            <i class="icon {{ index $iconMap $type | default (index $iconMap "note") }}"></i>{{ .Get 1 | default (T $type) }}<i class="details-icon {{ $iconDetails }}"></i>
        </div>
        <div class="details-content">
            <div class="admonition-content">
                {{- $inner -}}
            </div>
        </div>
    </div>
{{- end -}}
{{- if $aside -}}</aside>{{- end -}}

You may find interesting bits there: Hugo: add custom infoboxes - roneo.org

When I described inner and outer shortcodes, I was referring to nested shortcodes. For example:

config.toml

[markup.goldmark.renderer]
unsafe = true

layouts/shortcodes/disclaimer.html

This is *bold* text before the admonition.
{{ .Inner }}
This is *bold* text after the admonition.

markdown

{{% disclaimer %}}
{{< admonition type="warning" title="Foo" aside=true >}}
**Disclaimer**: All information on this page ...
{{< /admonition >}}
{{% /disclaimer %}}

You cannot call a shortcode from a shortcode.

You cannot call a shortcode from a shortcode.

Ok, this answers it.

The table you showed at the beginning pushed me to show code for shortcode and shortcode, as partials → shortcode showed “x”.

It’s a painful limitation if shortcodes can be used neither within shortcodes nor partials. I have other cases where I’d like to recycle graphs between blog posts.

Each graph is drown using echarts, for which my theme has a echarts shortcode available. That would basically require to repeat the charts in every post, and multiply edits whenever a change must be done.

Any workaround you could think of for that, which I can further look into?

Thanks.

@iaeiou That gets you to rebuild the raw HTML for infoblocks in the partial, if I understand you right. I’d like to avoid that if possible.

First create a partial that does what you need. Then create a shortcode to wrap the partial. Here’s a silly example that:

  • Scrambles the page’s title, month, and weekday
  • Renders the desired number of words, in lowercase, in the color you specify
layouts/partials/scramble.html
{{ $page := .page }}
{{ $count := .count }}
{{ $color := .color }}
{{ $dateWords := split ($page.Date.Format "January Monday") " " }}
{{ $titleWords := split $page.Title " " }}
{{ $shuffled := append $dateWords $titleWords | shuffle | first $count }}
<span style="color: {{ $color }}">{{ delimit $shuffled " " | lower }}</span>

layouts/shortcodes/scramble.html
{{ $msg := "The %q shortcode requires a %q parameter. See %s" }}
{{ with $count := .Get "count" }}
  {{ with $color := $.Get "color" }}
    {{ partial "scramble" (dict "page" $.Page "count" $count "color" $color) }}
  {{ else }}
    {{ errorf $msg $.Name "color" $.Position }}
  {{ end }}
{{ else }}
  {{ errorf $msg .Name "count" .Position }}
{{ end }}

To call the shortcode from markdown:

{{< scramble count=6 color=green >}}

To call the partial from a shortcode, template, or from another partial:

{{ partial "scramble" (dict "page" .Page "count" $count "color" $color) }}

Notes:

  1. The shortcode has 10 lines of code. One line calls the partial, the rest is for data validation.
  2. When calling the partial, the value of the “page” map element must be the .Page context. The syntax of the call will depend on the… context.

Thanks for the suggestion.

The problem I mentioned in the initial post persists – so it might be that we’re talking away from each other.

As soon as I prepare a file for the partial, even before I can create the shortcode for it, Hugo fails with error:

Process: loading templates: "/Users/myname/gitlab/mypath/layouts/partials/graph_cpi.html:1:1": parse failed: template: partials/graph_cpi.html:1: unexpected "<" in command

To avoid any unnecessary ping-pong, here’s the process I use:

  1. I create file layouts/partials/graph_cpi.html
  2. I fill the file with the graph code. This code contains the {{< echarts >}} shortcode provided by my theme (as I linked in my previous answer).
  3. I save the file. At this point already, hugo fails with Process: loading templates "[snip]: parse failed: template: partials/graph_cpi.html:1: unexpected "<" in command
  4. At this point, I would proceed to create a shortcode that wraps the partial – but given the error, I can no longer proceed.

Now, here’s the (minimized) code of that partial:

{{< echarts >}}
{
    "backgroundColor": "transparent",
    "title": {
        "text": "Inflation in Switzerland",
        "subtext": "Consumer Price Index [CHF], 1928 to 2018. Source: Swiss Federal Statistical Office."
    }
}
{{< /echarts >}}

What did I misunderstand of your proposal?

Using the echarts shortcode within the template is useful to avoid building myself the logic to load-once the respective JS dependency and graph loading code.

Thank you for the help

You can’t do that.

image

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