Shortcode - accessing a list of parameters of unknown length

Just need a a little syntax help (btw is there go documentation that might expand on this beyond Hugo docs??)

I have a shortcode. It currently reads a single parameter (class) but I want it to read as many parameters as given by the document and put them into the div class tag I am creating.
How do you “loop through” all parameters that might be given (in this case a list of parameters that will become html classes).

 <div class={{ .Get 0 }}} >   #should loop through all given parameters and add them all to this div class tag.
 {{ .Inner }}
 </div>

The code in document would look like this

 {{% format class1 class2 class3 etc %}}
 A bunc of text here.
 {{% /format %}}

and html should be

   <div class= class1 class2 class3 etc>
   A bunch of text here
  </dv>

Totally untested, but something like this should work:

<div class="{{ range .Params }}{{ . }} {{ end }}">

This will leave an extra space at the end; for more control – see http://discuss.gohugo.io/t/howto-delimiter-separated-tags/146

1 Like

Book Report: Works Great, Thanks!

Now then.

I am assuming this isn’t really a “hugo” syntax/construction but rather Go? In which case a little study of Go would allow me to figure out this and more complicated shortcodes and templates on my own? If that is true than can anyone suggest a nice, to the point, Go primer.

Go templates:

http://golang.org/pkg/text/template/
http://golang.org/pkg/html/template/

So “range” is a standad Go template construct. “.Params” is an array or slice from Hugo that is “rangeable”.

Many of the custom Hugo template functions operate on arrays or slices: These have become even more powerful in the latest codebase.

See where and first – two very useful functions to do “SQL like” stuff.

Also useful is the ordering and grouping stuff mentioned here:

@bjornerik

I have a related template syntax question.

Now I want to create multiple classes but with named parameters instead of a list.

I have this

but now I am adding a “width” parameter which I want to use to append a second class to my list of classes in my html tag.

Let’ make this generic. How to add any number of named parameters. Can “range” walk over a list(array) of named parameters instead of just the index of the parameters like I have now. Wild guess a kinda get/range combo?

It’s a string map, so this (totally untested) should work:

{{ $key, $val := range .Params }}
...
{{ end }}

So $key is array of wanted parameters names? and $val is returned value of that parameter from the key?

so like this??

<div class="{{["position","width"], $val := range .Params }} {{ $val }}{{ end }}">

A map is a dictionary - a list of key/value pairs, or in this case name/value pairs.

Something like this …

<div class="
{{ $key, $val := range .Params }}
{ $key }}{ $val }} 
{{ end }}
">

A little weird construction … so

param1=val1 param2=val2

class=“param1val2 param2val2” …

Still a bit confused. Where, in what you gave, do I specify which of the parameter/values I want to pull/filter from the complete list of parameters? In my case the values associated with named parameters “position” and “width”. Sorry, guess I just need you to spell it out for me with my example.

I thinks it’s better if you start with the target HTML. It’s little unclear what you want inside class="?"

For example

<figure class="left small">

“left” would come from the value of parameter “position” and “small” from the value of parameter “width”.

as in this example shortcode call image.html

 {{% image filename="01-000.jpg" caption="" width="small" position="left" %}}

I have other parameters and order is never the same so I want to pick these solely based on parameter name. Not a problem if only one (I just use Get) but with more that one I am confused about the syntax.

My complete shortcode image.html currently looks like this. Just don’t get how to cram .Get “width” and have it’s value placed after the other class from parameter “position”.

<figure 
{{ with .Get "position" }}class="{{.}}"{{ end }}>
{{ with .Get "link"}}<a href="{{.}}">{{ end }}

<img src="{{ .Page.Params.imagespath }}{{ .Get "filename" }}"{{ if or (.Get "alt") (.Get "caption") }}alt="{{ with .Get "alt"}}{{.}}{{else}}{{ .Get "caption" }}{{ end }}"{{ end }} />
{{ if .Get "link"}}</a>{{ end }}

{{ if or (or (.Get "title") (.Get "caption")) (.Get "attr")}} 

<figcaption>

{{ if or (.Get "caption") (.Get "attr")}}<p>
{{ .Get "caption" }}
{{ with .Get "attrlink"}}<a href="{{.}}"> {{ end }}
{{ .Get "attr" }}
{{ if .Get "attrlink"}}</a> {{ end }}
</p> {{ end }}

</figcaption>

{{ end }}

</figure>
{{% image filename="01-000.jpg" caption="" width="small" position="left" %}}

<figure class="
{{ $key, $val range .Params }
{{ if and (ne $key "filename") (ne $key "caption") }}
{ $val } 
{{ end }}
{{ end }}
">

There’s an invisible whitespace above that should separate the classes, I hope …

The above feels slightly hackish. For many params, it may be better to use positional params and reserve the first n for name, caption … and the rest for CSS classes.

EDIT IN: It should and, not or …

Hugo complained bitterly

ERROR: 2015/05/01 template: shortcodes/image.html:3: too many declarations in command
panic: runtime error: invalid memory address or nil pointer dereference
[signal 0xb code=0x1 addr=0x20 pc=0x480526]

Couple reasons why I am trying not to force positional parameters. 1. parameters are optional, 2. Editors will be writing the moustache code so don’t want to force an order on them which they will invariably screw up.

Other than this error can it be written without the ne. in other words the reverse to look for the two parameter names instead of just excluding others which may are may not be there.

like

and $key="position" or $key="width"

I’d eventually like to figure this out for this and other shortcodes. So unless you are keen on figuring this out for yourself don’t waste too much time. I can do a custom shortcode for now that will cover the width. Too maybe someone else has an idea how to tackle this. @spf13 maybe?

If you have a fixed number of params you know about, you can use .Get documented in docs.

<figure class="{{ .Get "width" }} {{ .Get "position" }}">

You can even use the index func:

<figure class="{{ index .Params "width" }} {{ index .Params "position" }}">

Ah duh,

I have been thinking that “Get” required “with” and then {{.}} which has been my point of confusion.

<figure class="{{ .Get "width" }} {{ .Get "position" }}">

This was what I was looking for all along. Just insert the Get where you want it no “with” necessary. Thx.

2 Likes