Testing for optional shortocde parameters - isset and with errors

In my shortcode, I tried to use the following isset code to apply a conditional logic depending on whether an id parameter is passed to the shortcode. This works when the shortcode is called with an id parameter, but the isset condition causes a panic runtime error when the shortcode is called without parameters.

{{ if (isset .Params "id") }}
  Param $id is set = "{{ .Get "id" }}".
{{ else }}
  Param $id is not set.
{{ end }}

When I use similar code to check whether an unnamed parameter was passed as the first shortcode parameter (0), everything works as expected, including when the shortcode is called without parameters:

{{ if (isset .Params 0) }}
  Param 0 is set = "{{ .Get 0 }}".
{{ else }}
  Param 0 is not set.
{{ end }}

I also tested the following, based on answers I saw in the forum, and it causes a similar panic error when the shortcode is called without an id parameter. In addition, when the shortcode is called with an id parameter I get the error “can’t evaluate field Params in type string” for the Get call in the with clause (and the same if I use .Params.id instead of .Get "id"):

{{ with .Params.id }}
  Param $id is set = "{{ .Get "id" }}".
{{ else }}
  Param $id is not set.
{{ end }}

I am using Hugo version 0.24 on Windows (in a Unix Git shell).

[UPDATE] Based on the with example in the Hugo Shortocdes doc (https://gohugo.io/extras/shortcodes/#creating-your-own-shortcodes), I found that the following code works both when the shortcode receives an id parameter and when it does not:

{{ with (.Get "id") }}
  $id = "{{ . }}".
{{ else }}
  No shortcode $id parameter.
{{ end }

However, when the id parameter is explicitly set to an empty string in the shortcode call (id="") the else clause is executed (the same as when id is not passed at all), unlike what you would expect for an isset condition. While this can certainly be useful, there are situations where I would like the behavior to be different if the user explicitly passes an empty string or doesn’t pass it at all, which I should be able to achieve with isset except it doesn’t work for me for named shortcode parameters.

Have you seen .IsNamedParams? You can see an example of it’s use in the embedded youtube shortcode.

1 Like

How will that help me? I saw only one mention of IsNamedParams in the Hugo docs, within the Vimeo code sample on the Shortcodes page, and I saw in the Release Notes that this is a boolean shortcode property that was added in v0.15.0. I assume that this property evaluates to true if the shortcode has named parameters. But how does this help me test whether a specific named parameter was set in a given shortcode call?

@sharonl what you want to do is harder to do than it could be – I cannot quickly come up with a solution for you. But it would be fairly simple to add a new method on shortcode so you could say

.IsSet "someNamedParam"
.IsSet 0

If you could create a GitHub issue, I should be able to implement it, and while it does not solve your short time problem (unless you build from source), it will help people in the future …

I’ll gladly open a GitHub issue, but I’m not quite sure I correctly understood your vision.

I was under the impression that what I’m trying to do is quite standard. The Hugo docs explicitly state that a shortcode can have optional parameters, and my understanding was that the purpose of isset is to test whether a specific parameter was set — which in the context of a shortcode means whether it was passed in the shortcode call (or was passed with an empty string). I saw several examples that use the exact same isset syntax that I use, yet in my tests it causes a panic error when used for a named parameter that is not passed in the specific shortcode call; (as indicated, the same code works without errors for unnamed parameters, but it’s harder to support unnamed optional parameters). I couldn’t find any reports of other people having the same issue, but I can’t see anything that I’m doing different.

Based on the different syntax in your answer — .IsSet versus isset — I also tried using an {{ if .IsSet "id" }} condition, but this causes the following error even when the shortcode is called with an id parameter: “can’t evaluate field IsSet in type type *hugolib.ShortcodeWithPage”. But maybe that’s because this is not supported yet, it’s only your proposed changes?

@bep Can you please just let me know whether the syntax {{ if (isset .Params "param-name") }} is expected to work as a way for testing whether param-name was passed in the shortcode call, or whether I misunderstood something?

As I wrote above, I saw multiple instances that refer to this syntax, and I didn’t find reports of similar issues as I had encountered (which is that the build breaks if the shortcode is called without the optional tested parameter); yet I can’t see what I might be doing wrong. Thanks.

Since I had not made any progress with this issue, and the problem continues with Hugo v0.25.1, I opened an issue for this in the hugo GH repo — Issue #3785.

@sharonl,
I better understand what you’re trying to do now. I closed Issue #3785 because it was too close to an existing issue.

Please create a new issue along the lines of “Shortcodes need the ability to check if a parameter is set.” Don’t worry about the panic issue since we’re tracking that separately.

Thanks @moorereason. I was under the impression, though, that this is exactly what isset was designed for — i.e., test whether a parameter was set (hence the function name …). This is also what I gathered from the Hugo documentation and third-party examples. If this is not the case, I’m not sure what’s the intended purpose of isset, unless it’s meant to check whether site or page parameters are set but not shortcode parameters?!
Also, as I had indicated, isset does seem to successfully test whether an enumerated unnamed shortocde parameter is set.

The Example gist Display section of the Hugo Shortcodes documentation includes the definition of a Hugo image shortcode that includes many if isset "<named parameter>" tests, such as the following:

{{ if isset .Params "class" }}class="{{ index .Params "class" }}"{{ end }}>

So seemingly this syntax should be supported, yet when I use it, it causes a kernel panic? (The Introduction to Hugo Templating page also has similar isset examples, but I thought maybe there’s a specific problem with the shortcode uses.) Unless isset is used in these cases to check whether the parameter was set to an empty string, and not whether it was passed to the shortcode (i.e., the shortcode would require always passing the parameter), which means that Hugo doesn’t really support optional named paraemters?!

I found a way to do what I want by using an if $var condition instead of isset. This works well for both named and positional (unnamed) parameters. The only drawback compared to how I initiially envisioned the isset behavior is that the if condition evaluates to false both when the parameter is not passed in the shortcode call and when it’s passed and explicitly set to an empty string. So if we want to behave differently if the user explicitly sets a parameter to an empty string, this is currently not supported; however, this is something I can live with. (Currently, I don’t really need to support this scenario, and if I do I can always require a unique non-empty parameter value to apply the explicit-empty-string logic.)

This is my POC code for a named parameter; the same code also works for a positional parameter by replacing Get "var" with Get 0:

{{ $var := .Get "var" }}

if $var returns 
{{if $var }}
  true.
{{ else }}
  false.
{{ end }}
$var = "{{ $var }}".

I would still like to understand the intended behavior of isset (and why it’s named this way if it’s not designed to test whether a parameter was set …), as well as why using the same syntax as in the Hugo documentation doesn’t work as expected, but at least I’m not blocked in my development.

1 Like

That looks to be the case. I’m a little confused as to why we’ve never noticed this before when we are using isset in our embedded figure shortcode.

I’ll have to spend more time digging into this, but it will likely be next week before I’ll have time for that.

My thoughts exactly! Because what I’m doing seems to match the examples in the documentation, which are supposedly working examples that Hugo and third parties are using, so what’s the difference here? I look forward to hearing what you come up with when you get the change. 10x

Just to wrap up this discussion to those who end up here from searching.

You can now (in version 0.8 and likely much earlier) do the requested operation in the following manner:

A portion of a shortcode:

{{ if isset .Params `class` }}
<div class="pa4 mh3 {{.Get `class`}} br4 h-100">
{{ else }}
<div class="pa4 mh3 bg-white br4 h-100">
{{ end }}

Perhaps there’s an even shorter way or clearer way of doing this.

1 Like