Access .Params data from withing range scope using $

Suppose I have this frontmatter data:

currency: '$'
products:
  - item: 
    price: 

I can range data from products array like this:

{{ range .products }}
{{ printf "%#v" .price }}
{{ end }}

The documentation - Introduction to templating - says:

Within a ‘range’ or ‘with’ block you can access the context passed into the template by prepending a dollar sign ($) to the dot:

{{ range .products }}
{{ printf "%#v" $.currency }}
{{ end }}

This throws an error: can’t evaluate field currency in type page.Page
But I can get data from the .Site level:

{{ range .products }}
{{ printf "%#v" $.Site.Params.currency }}
{{ end }}

Why can’t I get the data from .Params level, what am I doing wrong?

As it should. The currency key is a custom field, available under .Params.

To help you keep this clear in your head, I would get into the habit of explicitly placing custom fields under the params key in your front matter as described in the documentation.

Dear Joe, thank you for the info - I’ve missed this very important update!
However I can’t find the way to access these custom keys.

The Documentation instructs me to have this notation for custom keys in my frontmatter:

params:
  currency: '$'

and access it like this:

{{ .Params.currency }}

but it does not work for me. How can I output this value?
Thank you!

That notation is correct if the current context is the page context.

When inside a with or range statement you need to access the page context:

{{ range .products }}
  {{ printf "%#v" $.Params.currency }}
{{ end }}

Sorry, with this frontmatter:

params:
  currency: '$'

and this code:

{{ range .products }}
{{ printf "%#v" $.Params.currency }}
{{ end }}

I’m getting the output:

<nil> <nil> <nil> <nil> <nil>

The {{ printf "%#v" $.Params }} gives the following:

maps.Params{"bgimage":"", "categories":"vehicles", "description":"Cars, Vans, SUVs, Trucks, Buses, Special vehicles, Motorcycles, Scooters, Bicycles, Spare parts and accessories", "draft":false, "iscjklanguage":false, "title":"Vehicles"}

which looks to me like:

"bgimage":"" - is not present in the frontmatter, but somewhere in HTML,

"categories":"vehicles" is present in the frontmatter,

"description":"Cars, Vans, SUVs, Trucks, Buses, Special vehicles, Motorcycles, Scooters, Bicycles, Spare parts and accessories" looks like contents of "tags", not "description",

"draft":false - is a standard element in the frontmatter,

"iscjklanguage":false - is something new, never seen this before,

"title":"Vehicles" - is something wrong, “Vehicles” is “categories”, not Title.

Maybe I need to tune some settings?

I am unable to reproduce what you describe. Please show an example with all of the front matter, and let me know the Hugo version.

dump question. hope you are not talking about a shortcode?

Not sure what you mean, but I’m not using any shortcode at the moment.

$ go version
go version go1.23.5 linux/amd64

$ hugo version
hugo v0.141.0-e7bd51698e5c3778a86003018702b1a7dcb9559a+extended linux/amd64 BuildDate=2025-01-16T13:11:18Z VendorInfo=gohugoio

Here is the whole frontmatter:

---
date: 2024-12-25T20:45:19+04:00
draft: false
controlcode: '483ed7573ee2'
categories: 'vehicles'
link: 'vehicles/vehicles250510t2045190'
title: 'MERCEDES BENZ S 550'
products:
  - image: 'vehicles/vehicles250510T2045191.jpg'
    item: 'MERCEDES BENZ S 550'
    description: |
      ავტომანქანის რეალიზაციას ახდენს ავტოჰაბი, ავტომანქანების სანახავად გვეწვიეთ შემდეგ მისამართზე: ქ. თბილისი, დიღომი, ბობ უოლშის ქუჩა, I შესახვევი #2 (ოლიმპიური ქალაქის მიმდებარედ) ავტოჰაბის (AUTOHUB) მეორადი ავტომობილების ბაზრობა. GOOGLE MAP link: https://goo.gl/maps/B73MbzjbT1e5hyPTA ყველა ავტომობილი ტექნიკურად შემოწმებულია.(იქოქება, დადის) Autohub მობ: +სამუშაო საათები ორშაბათი-პარასკევი 10:00-18:00, შაბათი 10:00-14:00
    tags: 'cars'
    price: 13900
    mileage: 221512
  - image: 'vehicles/vehicles250510T2045192.jpg'
    item: 'MERCEDES BENZ S 550'
    description: |
      ავტომანქანის რეალიზაციას ახდენს ავტოჰაბი, ავტომანქანების სანახავად გვეწვიეთ შემდეგ მისამართზე: ქ. თბილისი, დიღომი, ბობ უოლშის ქუჩა, I შესახვევი #2 (ოლიმპიური ქალაქის მიმდებარედ) ავტოჰაბის (AUTOHUB) მეორადი ავტომობილების ბაზრობა. GOOGLE MAP link: https://goo.gl/maps/B73MbzjbT1e5hyPTA ყველა ავტომობილი ტექნიკურად შემოწმებულია.(იქოქება, დადის) Autohub მობ: +სამუშაო საათები ორშაბათი-პარასკევი 10:00-18:00, შაბათი 10:00-14:00
    tags: 'cars'
    price: 13900
    mileage: 221512
  - image: 'vehicles/vehicles250510T2045193.jpg'
    item: 'MERCEDES BENZ S 550'
    description: |
      ავტომანქანის რეალიზაციას ახდენს ავტოჰაბი, ავტომანქანების სანახავად გვეწვიეთ შემდეგ მისამართზე: ქ. თბილისი, დიღომი, ბობ უოლშის ქუჩა, I შესახვევი #2 (ოლიმპიური ქალაქის მიმდებარედ) ავტოჰაბის (AUTOHUB) მეორადი ავტომობილების ბაზრობა. GOOGLE MAP link: https://goo.gl/maps/B73MbzjbT1e5hyPTA ყველა ავტომობილი ტექნიკურად შემოწმებულია.(იქოქება, დადის) Autohub მობ: +სამუშაო საათები ორშაბათი-პარასკევი 10:00-18:00, შაბათი 10:00-14:00
    tags: 'cars'
    price: 13900
    mileage: 221512
  - image: 'vehicles/vehicles250510T2045194.jpg'
    item: 'MERCEDES BENZ S 550'
    description: |
      ავტომანქანის რეალიზაციას ახდენს ავტოჰაბი, ავტომანქანების სანახავად გვეწვიეთ შემდეგ მისამართზე: ქ. თბილისი, დიღომი, ბობ უოლშის ქუჩა, I შესახვევი #2 (ოლიმპიური ქალაქის მიმდებარედ) ავტოჰაბის (AUTOHUB) მეორადი ავტომობილების ბაზრობა. GOOGLE MAP link: https://goo.gl/maps/B73MbzjbT1e5hyPTA ყველა ავტომობილი ტექნიკურად შემოწმებულია.(იქოქება, დადის) Autohub მობ: +სამუშაო საათები ორშაბათი-პარასკევი 10:00-18:00, შაბათი 10:00-14:00
    tags: 'cars'
    price: 13900
    mileage: 221512
  - image: 'vehicles/vehicles250510T2045195.jpg'
    item: 'MERCEDES BENZ S 550'
    description: |
      ავტომანქანის რეალიზაციას ახდენს ავტოჰაბი, ავტომანქანების სანახავად გვეწვიეთ შემდეგ მისამართზე: ქ. თბილისი, დიღომი, ბობ უოლშის ქუჩა, I შესახვევი #2 (ოლიმპიური ქალაქის მიმდებარედ) ავტოჰაბის (AUTOHUB) მეორადი ავტომობილების ბაზრობა. GOOGLE MAP link: https://goo.gl/maps/B73MbzjbT1e5hyPTA ყველა ავტომობილი ტექნიკურად შემოწმებულია.(იქოქება, დადის) Autohub მობ: +სამუშაო საათები ორშაბათი-პარასკევი 10:00-18:00, შაბათი 10:00-14:00
    tags: 'cars'
    price: 13900
    mileage: 221512
  - image: 'vehicles/vehicles250510T2045196.jpg'
    item: 'MERCEDES BENZ S 550'
    description: |
      ავტომანქანის რეალიზაციას ახდენს ავტოჰაბი, ავტომანქანების სანახავად გვეწვიეთ შემდეგ მისამართზე: ქ. თბილისი, დიღომი, ბობ უოლშის ქუჩა, I შესახვევი #2 (ოლიმპიური ქალაქის მიმდებარედ) ავტოჰაბის (AUTOHUB) მეორადი ავტომობილების ბაზრობა. GOOGLE MAP link: https://goo.gl/maps/B73MbzjbT1e5hyPTA ყველა ავტომობილი ტექნიკურად შემოწმებულია.(იქოქება, დადის) Autohub მობ: +სამუშაო საათები ორშაბათი-პარასკევი 10:00-18:00, შაბათი 10:00-14:00
    tags: 'cars'
    price: 13900
    mileage: 221512
tags: ['cars']
params:
  currency: '₾'
sellers: 'Autohub'
sellertype: 'business'
id: 3468990459
tel: '+995 595 52 10 17'
whatsapp: 'yes'
iban: 'GE90TB0000000103893082'
address: 'ქ. თბილისი, დიღომი, ბობ უოლშის ქუჩა, I შესახვევი #2 '
email: 'info@autohub.ge'
delivery: 'no-delivery'
options: 'features'
fee: 111
expiryDate: '2025-05-10'
language: 'en'
---

whatever you do, your code above and the frontmatter and your results do not look like your code renders the page you expect.

hugo won’t pick something (bgimage) from HTML and add to the frontmatter data…

guessing, I would say you may be on a “Vehicles” Section Page, or Taxonomy(?)

Try for these to check which page you are on play with $and .

  • Console output: {{ warnf "%s" (debug.Dump $) }}
  • Code Block on Page: {{ highlight (jsonify (dict "indent" " ") $) "JSON" }}

Looks like your layout chain does something mmh unexpected for you
… cachedPartial, Paginator, Taxonomy, …

complete chain and code will help.

;tr;tr

and as @jmooring said it works fine

I put your frontmatter to a default hugo theme single page and added all works fine. It does not even matter where you define the currency (global or in params) There are so many custom global params - and all print fine.

here’s my mainblock of _default/single.html

{{ define "main" }}
   <h1>Frontmatter - Globals</h1>
   {{ range $k, $v := .Params }}
      {{ if ne $k "products" }}
         &nbsp;&nbsp;&nbsp;{{ printf "%#v : %#v" $k $v }}<br />
      {{ end }}
   {{ end }}
   <h1>Products</h1>

   {{ range $i, $product := .Params.products }}
      <h2>Product: {{ $i }}</h2>
      {{ printf "Currency: %#v" $.Params.currency }}<br />
      {{ range $k, $v := $product }}
         {{ printf "-  %#v -- %#v" $k $v }}<
      {{ end }}
      <hr />
   {{ end }}
{{ end }}
Output

“address” : “ქ. თბილისი, დიღომი, ბობ უოლშის ქუჩა, I შესახვევი #2 "
“categories” : “vehicles”
“controlcode” : “483ed7573ee2”
“currency” : “₾”
“date” : time.Date(2024, time.December, 25, 20, 45, 19, 0, time.Location(”“))
“delivery” : “no-delivery”
“draft” : false
“email” : “info@autohub.ge”
“expirydate” : time.Date(2025, time.May, 10, 0, 0, 0, 0, time.UTC)
“fee” : 111
“iban” : “GE90TB0000000103893082”
“id” : 3468990459
“iscjklanguage” : false
“language” : “en”
“lastmod” : time.Date(2024, time.December, 25, 20, 45, 19, 0, time.Location(”“))
“link” : “vehicles/vehicles250510t2045190”
“options” : “features”
“publishdate” : time.Date(2024, time.December, 25, 20, 45, 19, 0, time.Location(”"))
“sellers” : “Autohub”
“sellertype” : “business”
“tags” : string{“cars”}
“tel” : “+995 595 52 10 17”
“title” : “MERCEDES BENZ S 550”
“whatsapp” : “yes”
Products
Product: 0
Currency: “₾”

  • “description” – “ავტომანქანის რეალიზაციას ახდენს ავტოჰაბი, ავტომანქანების სანახავად გვეწვიეთ შემდეგ მისამართზე: ქ. თბილისი, დიღომი, ბობ უოლშის ქუჩა, I შესახვევი #2 (ოლიმპიური ქალაქის მიმდებარედ) ავტოჰაბის (AUTOHUB) მეორადი ავტომობილების ბაზრობა. GOOGLE MAP link: Google Maps ყველა ავტომობილი ტექნიკურად შემოწმებულია.(იქოქება, დადის) Autohub მობ: +სამუშაო საათები ორშაბათი-პარასკევი 10:00-18:00, შაბათი 10:00-14:00\n”
  • “image” – “vehicles/vehicles250510T2045191.jpg”
  • “item” – “MERCEDES BENZ S 550”
  • “mileage” – 221512
  • “price” – 13900
  • “tags” – “cars”
    Product: 1
    Currency: “₾”
  • “description” – "ავტომანქანის რეალიზაციას ახდენს ავტოჰაბი, ავტომანქანების სანახავად გვეწვიეთ შემდეგ მისამართზე: ქ. თბილისი, დიღომი, ბობ უოლშის ქუჩა, I

Hello @irkode, I’m really puzzled how to proceed, because I don’t understand what’s going on:
I’ve changed a few frontmatters to comply with custom fields update - but still, with this code

params:
  currency: '₾'

I can’t access my custom params with recommended means:

{{ range .products }}
  {{ printf "%#v" $.Params.currency }}
{{ end }}

I’m getting

<nil> <nil> <nil> <nil> <nil> <nil>

because ‘currency’ is not in the Params:

maps.Params{"bgimage":"", "categories":"vehicles", "description":"Cars, Vans, SUVs, Trucks, Buses, Special vehicles, Motorcycles, Scooters, Bicycles, Spare parts and accessories", "draft":false, "iscjklanguage":false, "title":"Vehicles"}

I’ve upgraded to

go version go1.24.1 linux/amd64
hugo v0.145.0-666444f0a52132f9fec9f71cf25b441cc6a4f355+extended linux/amd64 BuildDate=2025-02-26T15:41:25Z VendorInfo=gohugoio

but the result is still the same.

I will appreciate if you can send me a sample of your default hugo theme single page with any frontmatter where I could see how you can access custom params from within range function using this method:

{{ range .something }}
  {{ printf "%#v" $.Params.custom }}
{{ end }}

Of course I can save my currency parameter to a variable and access it, but the fact that my config does not work as it should is bothersome.

Thank you!

Have you tried this solution :

You cannot, that’s why my code uses: .Params.products
( $i is optional to get the index of the product)

{{ range $i, $product := .Params.products }}

but if your $ context is correct {{ printf “Currency: %#v” $.Params.currency }}` is working inside the loop.

As I said, my educated guess is, That your context item is a different page than the expected.

to replay my template:

  • create a bare site with some posts

    hugo new theme --themesDir . mysite
    cd mysite
    
  • copy the content from my post to layouts/_default/single.html

  • edit content/posts/post-1.md
    add the frontmatter you posted.

  • run hugo server

  • browse to http://localhost:1313/posts/post-1/

it will

  • print all global frontmatter fields
  • range over all produces
  • first prints the currency using $context
  • than all fields of current product.

all that said, since you tell you get different front matter fields and values than you expect there is sokmething going on with all the templating around.

impossible to track down without FULL sources.

@Cloud-Forge asked if I tried the @irkode’s notation:

{{range .Params.products }}

And I didn’t try it because it worked fine without that:

{{range .products }}

This creates confusin: we generally call frontmatter data Params - and now inside that Params we should call custom parameters ‘params:’?

{{range .Params.params.products }}?

last comment:

I tested with 0.124 and 140+ versions and I can in no way range .products directly in page context. but this works

{{ with .Params }}
   {{ range .products }}
      {{ .price }} in {{ $.Params.currency }}
   {{ end }}
{{ end }}

:warning: a statement like {{ with $params := .Params }} will not only assign to $params but change the dot-context, too. with

that’s why I recommended to print the current . and $ context

@irkode, I have to tell you that with this frontmatter:

currency: '₾'
params:
  products:
      price: 13900
      price: 13900
      price: 13900
      price: 13900
      price: 13900
      price: 13900

(there are 6 images with a description and price) - this HTML:

{{ with .Params }}
   {{ range .products }}
      {{ .price }} in {{ $.Params.currency }}
   {{ end }}
{{ end }} 

produces the following actual result:

13900 in
13900 in
13900 in
13900 in
13900 in
13900 in

while the expected result is

13900 in ₾

because the {{ $.Params.currency }} can not access the top level value from within the range scope.

Which means as of now this is definitely a bug, that I hope will be fixed soon.
Well, it happens.
Waiting for dev to fix the bug.
Thanks!

No, it is not.

I don’t know what you’re doing wrong, but you’re doing it wrong.

I suggest you share a complete, reproducible example if you want someone to help you.

context less code snippets and stripped of yaml files won’t bring us closer.

if you set it up like i described, it works. so there must be something around with your setup. what did the warnf output print…

even if this would be a bug, we cannot discover without the whole context.

@jmooring: Joe, I asked @irkode to send me the simplest single-page example of this method:

{{ with .Params }}
   {{ range .products }}
      {{ .price }} in {{ $.Params.currency }}
   {{ end }}
{{ end }}

getting the value from the top-level parameter:

---
currency: '₾'
params:
  products:
      price: 13900
---

but he could not. If he could - he would.
I’m using the code that is - after removeing everything irrelevant - is the same.

Besides, IMO prepending custom parameters with ‘params:’ creates confusion, as we already use Params name to call the frontmatter data, and having within Params another params is confusing.

Ignoring repeated requests for a link to your repository will probably not get you any closer to a solution.
You just post snippets out of context. No one can do anything useful with this. OTOH, you want someone else to provide you with a working, complete example. Just do exactly that - provide a complete sample site that exhibits the problem.