How to concatenate node paths using variables

I made an article on my website from this post, with syntax highlighting.

In a template, you sometimes need to load data from a path based on a parameter in your content file’s front matter. For example, you may want to add an author to every post that tells the visitor a bit more about the writer. You want to tell Hugo who the author is, and let the template load all of that person’s info from the data folder.

The first step is simple. We just have to properly set the author variable in the post’s front matter. We will use it to access the right file in our database:

+++
author = "nathan"
+++

Based on this variable, in your template/partial, you want to access a specific data file stored in the data/authors/ folder of your website, named exactly the same as your author variable in your content piece. In my case, this file is data/authors/admin.toml.

The content of this file can be accessed from your template using the following node path: .Site.Data.authors.admin
The problem is, we don’t always want to have the page’s author set to Admin. If a guest writes a post for my website, I want to use his name instead. For every content piece, the author’s name is available at .Params.author in your template, as we added this variable to our content’s front matter. So you want to load the data from the file at .Site.Data.authors called the same as the variable .Params.author.

To do that, in go template, we have to use the index function. Index takes 2 parameters: the first one is a node path, and the 2nd one is a string corresponding to the data we want to access. For example:

{{ index .Site.Data.authors “admin” }} 

Will return the content of .Site.Data.authors.admin. Now, as the variable .Params.author is a string, we can use it with the index function. So this:

{{ index .Site.Data.authors .Params.author }} 

Will return the content of the data file at data/authors/our_post_author.

You can put your index operation in parentheses and keep going down the node tree by adding a “.” right after it:

{{ (index .Site.Data “authors”).admin}}

Last but not least, by nesting parentheses, you can compound multiple index operations together and access more complex paths that way:

{{ index (index .Site.Data "authors") "admin" }}

In my case, the result looks like this:

I hope this helps! As a non-web developer, I find it hard sometimes to wrap my head around the way go template work. It’s really simple once you know how to do it, but it can take a while before you find how to use a function the right way, even with the help of the documentation.

Happy Hugo coding!
Nathan

5 Likes

This is great @gdquest Thanks so much for this.

Maybe someone knows how to get the second level parameter from the .Data file?

I have this strings in \data\names.yaml

John:
      fullname:John Smith

How to get “John Smith” from this if .Title = John?

I tried this code in the template, but it produces nothing.

<div>{{ index (index .Site.Data.names .Title) "fullname" }}</div>

@Mikhail: What is .Title exactly? Is it a variable in your front matter? In that case you need to type .Params.Title instead of .Title.

{{ (index .Site.Data.names .Params.Title).fullname }}

Whenever you have an issue with something like that, start by doing hardcoded tests. That way, you will know straight away if your problem is coming from the variable you’re using to index the data:

{{ (index .Site.Data.names "John").fullname }}

If this works, you only have to replace “John” by a variable.

.Title is the title of the generated node (list of tag). This string works correctly and produces an array.

index .Site.Data.names .Title

But the array includes all string that are in the section of John:. I can not choose from an array “John” only “fullname” option.

What does .Title print in your case? Here it’s just the title of the current page. It works for me if I name the page John.

.Title in Node is the taxonomy term (tag). I tried all your suggestions, but they either do not generate or produce an error when generating.

index .Site.Data.names .Title

generate: “fullname:John Smith”

{{ (index .Site.Data.names "John").fullname }}

generate in terminal:

ERROR: 2016/04/20 Error while rendering taxonomy recipient: template: theme/_default/list.html:12:77: executing "theme/_default/list.html" at <"John"...>: can't evaluate field fullname in type string

Oh, I see! I actually don’t use taxonomies and I don’t use data in my list templates. Can’t help in that case, sorry.

No problems. Maybe someone else will read this topiс.:eyeglasses:

1 Like

@Mikhail, I’m pretty sure you need a space after the colon to separate the key from the value.

1 Like

Hmm. Indeed the case in the absence of a space. It was originally, but Hugo report errors and I deleted it. Thank you very much for your help, @moorereason.

Working code:

{{ index (index .Site.Data.names .Title) "fullname" }}

And in \data\names.yaml

John:
  fullname: John Smith

This is awesome! You should definitely add this to the “Extras > Data Files” documentation. It would be so much better than the hard-coded examples there. Thanks a lot!