Based on my understanding of how named parameters in Hugo shortcodes work, if you were to have a call with at least one named parameter, then checking whether .Get <name> is non-empty will work as a test to determine whether a parameter is set:

{{ if (ne (.Get "categories") "") }} do the thing {{ end }}

However, if a shortcode is called without any parameters at all, this breaks down. I’m guessing it may be something to do with .Params not being set to anything. And it might be that .Get returns something other than a string, which breaks the check to see whether it’s not an empty string (it’s not not an empty string, so… true?).

But this is pure speculation, and beyond the scope of this post. I don’t care why it doesn’t work, I just want a procedure that does.

Based on my testing, here is an approach that would do the trick. Check to see if .Params is defined, and if so, call Get. Otherwise, set a default. Using Go templates, with shortcutting ands and ors, this can be reduced to the following construct:

{{- $parCategories := or (and .Params (.Get "categories")) "" -}}

Then just use $parCategories when you need the parameter value.