Lego2012
8/14/2017 - 9:35 AM

Explanation of rendering order

Explanation of rendering order

1. Shortcodes are rendered inside out

If you have nested shortcodes, the child shortcodes are rendered before their respective parents.

This means:

You can't use .Page.Scratch to pass variables from a parent to a child shortcode. Instead, use .Parent to access the parent shortcode's scope from the child shortcode, e.g. use .Parent.Params or .Parent.Get to inherit parameters from the parent shortcode.

You can use .Page.Scratch (or .Parent.Scratch) to pass information from the child to the parent shortcode, e.g. if you wanted to count the number of child shortcodes.

Example:

/layouts/shortcodes/child.html:

{{ .Page.Scratch.Add "count" 1 }}
Running Count: {{ .Page.Scratch.Get "count" }}

/layouts/shortcodes/parent.html:

Total Count: {{ .Page.Scratch.Get "count" }}
{{ .Inner }}

/content/test.md:

{{< parent >}}
  {{< child >}}
  {{< child >}}
  {{< child >}}
{{< /parent >}}

Output:

Total Count: 3
  Running Count: 1
  Running Count: 2
  Running Count: 3

2. Shortcodes called from the page scope are rendered in random order

If you call the same shortcode several times, Hugo will render a random one first, then render the subsequent ones in order (when it reaches the last shortcode it will loop back to the first one.)

Example:

/content/test.md:

{{< child >}}
{{< child >}}
{{< child >}}
{{< child >}}
{{< child >}}

Output (varies at random):

Running Count: 3
Running Count: 4
Running Count: 5
Running Count: 1
Running Count: 2

If you call two different shortcodes on the same page, the rendering order is completely random.

Example:

/content/test.md: (child2 is a copy of child)

{{< child >}}
{{< child >}}
{{< child >}}
{{< child >}}
{{< child >}}
{{< child2 >}}
{{< child2 >}}
{{< child2 >}}
{{< child2 >}}
{{< child2 >}}

Output (varies at random):

Running Count: 1
Running Count: 8
Running Count: 3
Running Count: 4
Running Count: 5
Running Count: 9
Running Count: 6
Running Count: 7
Running Count: 10
Running Count: 2

This means:

  • You generally can't use .Page.Scratch to pass variables between shortcodes, unless you don't care which order they are rendered in.
  • For example, you could use {{ $.Page.Scratch.Add "count" 1 }} to count the number of times a shortcode is used (as long as you're only using this information in a template file, NOT in another shortcode), or to give each shortcode a unique number (as long as the numbers don't need to be in order).

3. Shortcodes nested within another shortcode ARE rendered in order

Example:

/content/test.md: (child2 is a copy of child)

{{< parent >}}
  {{< child >}}
  {{< child >}}
  {{< child >}}
  {{< child >}}
  {{< child >}}
  {{< child2 >}}
  {{< child2 >}}
  {{< child2 >}}
  {{< child2 >}}
  {{< child2 >}}
{{< /parent >}}

Output (consistent):

Total Count: 10
  Running Count: 1
  Running Count: 2
  Running Count: 3
  Running Count: 4
  Running Count: 5
  Running Count: 6
  Running Count: 7
  Running Count: 8
  Running Count: 9
  Running Count: 10

This means:

If you do need a bunch of shortcodes to render in order (e.g. because you want to give each one a consecutive number), you can achieve this by wrapping them in a dummy parent shortcode.

4. Shortcodes are rendered before anything else

Example:

/layouts/partials/header.html:

... <title>I have {{ .Page.Scratch.Get "count" }} children</title> ...

/content/test.md: (as above)

Output:

... <title>I have 10 children</title> ...

Note this works even though in terms of page order, <title> appears before the content which contains the shortcodes.

This means:

  • You can use .Page.Scratch to pass variables from a shortcode to a template file, e.g. if you have some bulky css/js files that you want to load in /layouts/partials/header.html iff a shortcode has been used.

5. Templates are rendered in order of appearance

Example:

/layouts/index.html:

... {{ .Page.Scratch.Add "count" 1 }}
index.html: {{ .Page.Scratch.Get "count" }}
{{ partial "head.html" . }} ...

/layouts/partials/head.html:

... {{ .Page.Scratch.Add "count" 1 }}
head.html: {{ .Page.Scratch.Get "count" }}
{{ partial "head_custom.html" . }} ...

/layouts/partials/head_custom.html:

... {{ .Page.Scratch.Add "count" 1 }}
head_custom.html: {{ .Page.Scratch.Get "count" }} ...

Output:

... index.html: 1 ...
... head.html: 2 ...
... head_custom.html: 3 ...

Summary

This means that for a page using the example files above, the overall order of rendering would be:

9: /layouts/_default/single.html
10: ...
11: /layouts/partials/head.html
12: ...
13: /layouts/partials/head_custom.html
14: ...
15: ...
16: /layouts/partials/header.html
17: ...
/content/test.md
8: /layouts/shortcodes/parent.html
5: /layouts/shortcodes/child.html
6: /layouts/shortcodes/child.html
7: /layouts/shortcodes/child.html
4: /layouts/shortcodes/parent.html
1: /layouts/shortcodes/child.html
2: /layouts/shortcodes/child.html
3: /layouts/shortcodes/child.html
18: ...
19: /layouts/partials/footer.html
20: ...

Noting that 1,2,3,4 and 5,6,7,8 could be the other way around, at random.