Passing Scratch flags between shortcodes

Hi

I am (like many before and many to follow) confused about scoping of Scratch and variables in general.

What I’m trying to do is make a shortcode test behave differently if it is called inside another shortcode testwrap, by setting a Scratch flag, but I can’t get it to work. I did some experiments to try and figure out what is going on:

###/layouts/shortcodes/testwrap.html:

{{ .Scratch.Add "flag" "A" }}
{{ $.Scratch.Add "flag" "a" }}
{{ .Page.Scratch.Add "flag" "B" }}
{{ $.Page.Scratch.Add "flag" "b" }}

<p>testwrap .Scratch.Get "flag" = {{ .Scratch.Get "flag" }}</p>
<p>testwrap $.Scratch.Get "flag" = {{ $.Scratch.Get "flag" }}</p>
<p>testwrap .Page.Scratch.Get "flag" = {{ .Page.Scratch.Get "flag" }}</p>
<p>testwrap $.Page.Scratch.Get "flag" = {{ $.Page.Scratch.Get "flag" }}</p>

{{ .Inner }}

<!-- clear flags here if they are only supposed to be visible within .Inner -->

###/layouts/shortcodes/test.html:

{{ .Scratch.Add "flag" "C" }}
{{ $.Scratch.Add "flag" "c" }}
{{ .Page.Scratch.Add "flag" "D" }}
{{ $.Page.Scratch.Add "flag" "d" }}

<p>test .Scratch.Get "flag" = {{ .Scratch.Get "flag" }}</p>
<p>test $.Scratch.Get "flag" = {{ $.Scratch.Get "flag" }}</p>
<p>test .Page.Scratch.Get "flag" = {{ .Page.Scratch.Get "flag" }}</p>
<p>test $.Page.Scratch.Get "flag" = {{ $.Page.Scratch.Get "flag" }}</p>

###/content/test.md:

testwrap:
{{< testwrap >}}
test inside testwrap:
  {{< test >}}
{{< /testwrap >}}
test outside testwrap:
{{< test >}}

###Result:

testwrap:
testwrap .Scratch.Get "flag" = Aa
testwrap $.Scratch.Get "flag" = Aa
testwrap .Page.Scratch.Get "flag" = DdBb
testwrap $.Page.Scratch.Get "flag" = DdBb

test inside testwrap:
test .Scratch.Get "flag" = Cc
test $.Scratch.Get "flag" = Cc
test .Page.Scratch.Get "flag" = Dd
test $.Page.Scratch.Get "flag" = Dd

test outside testwrap:
test .Scratch.Get "flag" = Cc
test $.Scratch.Get "flag" = Cc
test .Page.Scratch.Get "flag" = DdBbDd
test $.Page.Scratch.Get "flag" = DdBbDd

So as far as I can tell:

  • .Scratch = $.Scratch and .Page.Scratch = $.Page.Scratch (I put the .Scratch.Add statements inside an if block - it made no difference)
  • $.Scratch is the shortcode-scoped Scratch
  • $.Page.Scratch is shared between shortcodes called from the same scope (e.g. between testwrap and the “outside” test) - can use this to pass flags between shortcodes called from the same scope
  • You can pass flags from an inner shortcode to an outer shortcode (e.g. from the “inner” test to testwrap) but the behaviour is very strange:
    • The “inner” test is parsed in its entirety before any of testwrap is parsed (I would have expected $.Page.Scratch.Get "flag" = Bb before {{.Inner}} is called and $.Page.Scratch.Get "flag" = BbDd after {{.Inner}} is called.)
    • Within the inner test, $.Page.Scratch.Get appears to point to the local Scratch only, but $.Page.Scratch.Add appears to point to the local Scratch AND the page-scoped Scratch.
  • It doesn’t seem to be possible to pass a flag from testwrap to test

Is all of this the correct behaviour?

This was a long and puzzling post …

In general:

  • .Page.Scratch is Page scoped, ie. available for all shortcodes in the same page.
  • Shortcodes are rendered inside out, so you cannot get a scratch var from the outer shortcode before it is executed … If that made sense in an Einsteinian way …

There is also this:

{{ with .Parent }}
{{ .Scratch ... }}
{{ end

I’m not sure that covers all your questions, but $.Page.Scratch.Add will never point to a shortcode’s scratch.

But in general, I think you use scratch where you should really use shortocde parameters.

Aaah the penny just dropped for me. I had figured out the shortcodes are rendered inside out but hadn’t deduced that that is why you can’t pass a scratch flag from the outer shortcode to the inner one. This all makes perfect sense now. /doh

Thanks :slight_smile: and apologies for the longness and confusingness (I know longness isn’t a word but I can’t adjective today)

@liwenyip This is how I get shortcode parent parameters dynamically.

Works like a charm