Proposal for modifying `Param` to retrieve deeply nested params

Currently, the only way to access params with nested keys is to be explicit and static:

{{ .Params.author.favorites.color }}

This, for example, doesn’t work:

{{ $k := "author.favorites.color" }}
{{ .Param $k }} // Param doesn't understand nesting.

This doesn’t work either:

{{ $k := slice "author" "favorites" "color" }}
{{ index .Param $k... }} // Go templates don't understand variadic args.

What would be ideal is to be able to say something like:

{{ $k := slice "author" "favorites" "color" }}
{{ .Param $k }}

and fetch the value of this nested parameter. Here is a reference implementation illustrating the general idea. If this is agreeable with the Hugo folks I’d be happy to work on this and submit a PR.

One thing I foresee as being a big sticking point for success here is that sometimes Hugo uses map[string]interface{} and sometimes it uses map[interface{}]interface{},
as shown here. That means that it’ll be a little harder to write a consistent definition of how things should work.

1 Like

After some discussion with other folks, I have submitted a PR that I think addresses this problem:

I thought the difference in interface types would be an issue in writing this, but fortunately @spf13 has cast.ToStringMap, which is literally the exact function I needed and didn’t want to have to write since it’s not really in-scope for Hugo.

has this been accepted for v .20?

I’v been using consructions like this to access deeper keys.

{{ with $.Site.Params.youtube }}{{ $.Scratch.Set "maxwidth" .maxwidth }}{{ end }}

It was already in 0.19.
So you can do

.Param "myMap.MySomething"

And not have to worry about case issues.

Note that:

. $.Param.myMap.MySomething"

Should also be fine, but is less flexible. The .Param method (if called on Page) looks first in page params, then in site param, and you don’t have to worry about nil pointers that much.

so @bep Little help here

I am not familiar with the .Map key what’s that about and how can I use it in my example? A key I can create that can map to deeper keys? Is this documented?

in my toml

[params.youtube]
  # maxwidth = "800"  default maximum width for all youtubes default is 450
  #  wpad = "50"  # padding on both left and right when view width is < maxwidth  default is 5

What I wanted to do wanted to do.

{{ $.Scratch.Set "maxwidth" ( $.Site.Params.youtube.maxwidth | .Get "maxwidth" )  }}

what I ended up doing.

{{ with $.Site.Params.youtube }}{{ $.Scratch.Set "maxwidth" .maxwidth }}{{ end }}
{{ with .Get "maxwidth" }}{{ $.Scratch.Set "maxwidth" . }}{{ end }}

It is documented … in the TOML spec I would say: https://github.com/toml-lang/toml#user-content-table

So:

[params.youtube]
maxwidth = "800" 

Will create one map (other names for it would be tables or hash table) below params named youtube.

So from the template the above would be:

$.Site.Params.youtube.maxWidth

Note that I deliberately messed with the case in the example, it is case insensitive.

The same with the Param method:

$.Params "youtube.maxWidth"

You can nest it further if you want:

[params.youtube]
[params.youtube.config]
maxwidth = "800" 
$.Site.Params.youtube.config.maxWidth

Also note that the same constructs would be valid inside /data TOML files.

toml isn’t the issue…I get that…

but hugo complained bitterly about

$.Site.Params.youtube.maxWidth

in the post above where I said that’s what I wanted. That’s why I used the alternative

and the alternative you just suggested is no better with similar error

{{ with $.Params "youtube.disable_thumbs" }} nothumb="yes" {{ end }}

ERROR 2017/04/11 19:16:44 error processing shortcode theme/shortcodes/youtube.html
 ERR: template: theme/shortcodes/youtube.html:32:16: executing "theme/shortcodes/youtube.html" at <$.Params>: Params has arguments but cannot b
e invoked as function

OK, that is because I was wrong …

OK, so Hugo has some different params that needs to be sorted out, and from a shortcode (like in your example), this would be:

  1. $.Params, which would be the parameters sent to the shortcode (i.e. the Youtube ID in this case)
  2. $.Page.Params, is the page’s params (which may be what you want)
  3. $.Page.Site.Params which is tie site’s params (which also may be what you want, not sure).

So,

$.Page.Site.Params.youtube.maxWidth`
```

Should work if you have that params defined in site config.

just confirming that this worked! No more Hugo errors

{{ with $.Page.Site.Params.youtube.disable_thumb }} nothumb=“yes” {{ end }}

It never occured to me prefacing with .Page would get the reference correct. I always just assumed (logically?) that $.Site was always accessible everywhere (globally), shortcodes or partials or pages. It seems it is but only via the page being rendered.

maybe the points of this thread should be in the support or tips and tricks section? I can do that. In the docs?

I agree that this is non-intuitive, we should fix it:

Great,

but…'ll make a post since .2 just came out and it will be awhile. What’s a good post title for this issue that will bring the right search terms to it? “Accessing deeply nested site config parameters” ??

@dkebler I figured I would attempt to leverage your use case (and the feedback @bep gave us on this thread) to make the docs around shortcode templating a bit more comprehensive in the new docs site. I’d love some feedback if you have a moment :bow:

https://hugodocs.info/templates/shortcode-templates/#params