Recently I created a website for my wife for her paintings as my first Hugo project. A really nice experience. Among other things, I created a small tool for creating labels for here painting and drawings. For that purpose, I added a property in the front matter of each page describing the painting indicating if the painting should be part of the exhibition or not. From a data modelling perspective, that was not a very sensible nor scalable approach, so I have extracted all information about exhibitions and instead placed in a data file.
The approach is pretty simple:
$exibitionPages := where site.RegularPages .Params.id “in” $exibitionArray
but instead, it filters out all pages. Note the shortcode makelabels are called from the pages ark1, ark2 and ark3 page located in contents/tools folder.
- I have used the same idea on another page on the site. However, instead of using the in operator, I use the in function.
Problem 1
Change this:
{{ $exibitionPages := where site.RegularPages .Params.id "in" $exibitionArray }}
to
{{ $exibitionPages := where site.RegularPages "Params.id "in" $exibitionArray }}
Problem 2
When Hugo unmarshals JSON data (data/udstilling.json), the numbers (ids) are of type float64. But Params.id is an int. So your where clause is comparing different types, resulting in an empty set.
Two options:
1) Use a different format for your data file, either TOML or YAML.
2) Cast all of the elements in the array to type int using apply
{{ $exibitionArray := union .Site.Data.udstilling.painting .Site.Data.udstilling.drawing }}
{{ $exibitionArray = apply $exibitionArray "int" "." }}
Thanks a lot, that worked beautifully, although I am still a bit confused. I understand that Hugo unmarshals the numbers to float64 and I, therefore, have to coerce the types int. What I am confused about is that using the in function, I can still test for membership of the array as shown in
{{ if in site.Data.udstilling.painting .Params.id }}
which can be found in line 22 in https://github.com/stavnstrup/la-art/blob/master/layouts/shortcodes/assetlist.html
You are correct.
{{ in (slice (float 1)) (int 1) }} --> true
The where function’s in operator is handled differently than the in function.
About 6 months ago we fixed some where function type mismatches related to strings:
https://github.com/gohugoio/hugo/pull/8461. Perhaps we need to make similar accommodations for integer/float comparisons, thought I don’t know how feasible that is.
This demonstrates the problem:
{{ where (slice (dict "a" (int 1))) "a" "in" (slice (int 1)) | len }} --> 1
{{ where (slice (dict "a" (int 1))) "a" "in" (slice (float 1)) | len }} --> 0
The solution provided has worked flawlessly for years. I last used that piece of code with Hugo 0.148.2, but with 0.152.2 it does not.
I have read all the changelogs, and the only related changes are
- A new
format option in transform.Unmarshal in 0.149.0 - however I do not use that function
- May an unintended side effect of the fixes in 0.152.1, unless they are purely YAML specific.
Has anybody else seen this behaviour?
We recently upgraded the YAML package. Check data types using the printf function’s %T verb.
Thanks, I was aware that I needed to check the types; I just did not know that go fmt’s printf function provided a %T verb.
But now I can see with my own eyes that the Hugo unmarshals JSON data to float64, and the use of apply with the function int coerce the data in the $exibitionArray to integer.
The reason my code does not work anymore is that now the $exibitionPages is empty because the type of the Params.id value is of type uint64 and not of type int as it used to be.
I can not find a function that enables me to apply to values in $exibitionArray to uint64.
Therefore, I will probably have to rewrite my code to make it work again.
I’ll look into this in the next day or two. I’m a little surprised that we’re getting an unsigned integer (uint64) instead of a signed integer (int64). Seems like we should get the same type regardless of whether the number is positive or negative.
EDIT 2025-11-24T21:02:02-08:00
I verified the behavior…
content:
---
title: Example
params:
a: 1
b: -1
c: 1.0
d: -1.0
---
template:
<pre>
{{ range $k, $v := .Params }}
{{ $k }} = {{ printf "%[1]v (%[1]T)" $v }}
{{ end }}
</pre>
result:
a = 1 (uint64)
b = -1 (int64)
c = 1 (float64)
d = -1 (float64)