Creating partials and shortcodes (a recommendation)

tl;dr

Make a partial that expects to receive a dictionary as the argument. The dictionary should contain (dict "page" $.Page "site" $.Site) as a minimum if indeed the partial uses those objects. You can then refer to the $.Page using .page in the partial.

Make a shortcode with the same filename that contains

{{- partial (printf "%s.html" .Name) (merge .Params (dict "page" $.Page "site" $.Site)) -}}

Partials are chunks of HTML with Hugo commands in. They can be called from other HTML templates or other partials (which are bits of template) but not directly from markdown content (but follow this guide and you can!).

When calling a partial, you can only pass it one argument, which traditionally is “.” – that is (usually) a reference to the current $.Page (be careful though because if you’re in a loop, . might be the current value in the loop so cutting and pasting code in and out of loops can break things). This one parameter can be quite limiting, so for a number of partials written for this site the partial expects to receive a dict object (i.e. a hash), which is the recommended way to provide a partial with multiple arguments. For our purposes, this should have as a minimum:

(dict "page" $.Page "site" $.Site)

which ensures that the partial has access to the $.Page object in the .page key and to the $.Site object with .site. You can also obviously pass it other parameter values with other parameter keys. If you want to make parameters optional (I recommend this) then assign the value to a variable using default at the top of the partial use something like:

{{- $page := .page -}}
{{- $mandatoryparam1 := .manadatoryparam1 -}}
{{- $optionalparam := default defaultval .optionalparam -}}

default stops hugo from complaining about a missing index.

Your template could call the partial themes/jalview/layouts/partials/mything.html with something like

{{ partial "mything.html" (dict "page" $.Page "site" $.Site "manadatoryparam1" $val1) }}

(and you could add in the "optionalparam" key with value if you wanted to).

We now have a cunning trick to make a partial that operates like this also work as a shortcode, with attribute style key=val pairs, and with almost no extra work at all!

Using a Shortcode to call your partial

Shortcodes are similar to partials, but can be called directly from markdown content, e.g. a shortcode saved as themes/jalview/layouts/shortcodes/mything.html can be called in the markdown, with extra parameters provided in a neat attribute style, e.g.

{{% myshortcode key1="val1" key2="val2" %}}

or

{{< myshortcode key1="val1" key2="val2" >}}

If we make a shortcode that calls the partial (with the partial function) it can also supply a dict of parameters. We can completely automate this with a shortcode saved in a file of the same name as the partial you want it to call (but in the shortcodes folder), that looks like this:

{{- partial (printf "%s.html" .Name) (merge .Params (dict "page" $.Page "site" $.Site)) -}}

This one line of code is saved as a shortcode called themes/jalview/layouts/shortcodes/shortcode_to_partial.html so you can just copy that (you don’t need to edit it!) to mything.html with

cd themes/jalview/layouts/shortcodes
cp shortcode_to_partial.html mything.html

I’d say make a symbolic link but this might not be preserved through git on all platforms.

You can now use your partial in markdown content by calling this shortcode, e.g.

{{% mything mandatoryparam1="windows" optionalparam=true %}}

What does this shortcode do?

  • First of all it uses the partial function to call the partial with the filename given next…
  • The next parameter, (printf "%s.html" .Name), simply takes the shortcode name (which is the filename without the .html) and adds on a .html, i.e. it’s the same filename as the shortcode, but because we’re giving this to the partial function, this time it refers to the partial with the same filename.
  • The final argument is a merging of two dictionaries. .Params is the dict of attribute style key="val" pairs that you use in the markdown when calling the shortcode, and the second dictionary is just (dict "page" $.Page "site" $.Site) to ensure the page and site get sent with the correct parameter names (assuming you’ve followed the guidelines above for creating your partial).

Shortcode with .Inner text

If you want to use a shortcode block with inner text, say something like

{{<mything key="val">}}
Here's some stuff to format as a mything!
{{</mything>}}

Then use a shortcode containing

{{- partial (printf "%s.html" .Name) (merge .Params (dict "page" $.Page "site" $.Site "text" (trim .Inner " \n"))) -}}

which will also send the inner text to the partial with the key “text” (the partial can then get at this with .text). The above code is in the file shortcode_to_partial_with_text.html).

The reason for not using this code with the "text" parameter for every partial (which could just ignore the .text value if not wanted) is that the mere act of looking at .Inner seems to make Hugo expect an ending {{</mything>}} in the markdown. Unless there is one the rest of your document’s content gets missed!