How can I make pairs of information in the front matter?

Hi all,

I have some information, specifically URLs and human-readable names, that I need to both store in the front matter and pair in a logical way.
A multidimensional array was my first choice, but that doesn’t seem to work; I’ve tried:
mirrors = [["dl.site1.com/exe", "Site One"], ["dl.site2.org/exe", "Site2"]]
in my post.md, and then
<ul> {{ range .Params.mirrors }} <li>{{ .[0] }}</li> {{ end }} </ul>
in single.html as per another suggestion on the forums here. Like I said, no luck.

Am I just doing this wrong?
Is there a better way I could be doing this, given that I do not always know ahead of time how many pairs I will need per post?

Thanks in advance.

<li>{{ .[0] }}</li> is no valid syntax for accessing an element of a list in Go templates. Try instead the index template function as follows:

{{ index . 0 }}

Thank you, that helps.
{{ index $.Params.mirrors 2}} is giving me the result I would expect, but {{ index . 0 }} doesn’t print anything. What is index returning here? If all it returns is the index, how do I use that to access the array?

Thanks for your patience; I’m completely new to Go.

Well, index can return items from a map, slice, or array. Basically, it’s equivalent to the array[index] syntax that we know from many programming languages.

{{ index . 0 }} was meant as a replacement for <li>{{ .[0] }}</li>. In the loop you’re ranging over an two-dimensional array. The current element, represented by ., is an array and can be indexed.

The complete snippet would be

<ul>
{{ range .Params.mirrors }}
<li>{{ index . 0 }}</li>
{{ end }}
</ul>

So index . 0 is roughly equivalent to .[0]?

I’m running into the same blank return value problem; there are two <li>s created so I know it’s finding the mirrors array, but it’s not printing their contents.

Just to make sure I understand correctly: {{ range .Params.mirrors }} iterates through each top-level element int the array and sets . as a sort of pointer to whichever one we are iterating through right now. {{ index . 0 }} then accesses the 0th element of the array “pointed” to by .. Is this about correct?

That’s the idea that I had in my mind. But after revisiting the frontmatter definition I’m not sure if this syntax will work. After browsing other examples in the forum I found a version that’s more descriptive and works (I tested it this time).

The frontmatter:

[[mirrors]]
link = "dl.site1.com/exe"
text = "Site One"

[[mirrors]]
link = "dl.site2.com/exe"
text = "Site 2"

and the corresponding template code:

<ul>
{{ range .Params.mirrors }}
    <li>{{ .text }}</li>
{{ end }}
</ul>

Yup! That did the trick. Thank you very much for your help!

Just so I understand what’s going on here, is this an alternative way of creating an array, or are there being mirror objects created, or what?

I had a look at the TOML spec. Dictionaries and hash-tables are here called tables. [[mirrors]] denotes that this in an array of tables.

First, we tried to use multi-dimensional arrays. According to the spec they are fine since we don’t mix different types.

Hugo uses go-toml for parsing. The project’s README states: This library supports TOML version v0.4.0. Looking in the toml spec v0.4.0 we can see that

mirrors = [["dl.site1.com/exe", "Site One"], ["dl.site2.org/exe", "Site2"]]

should work as expected.

Maybe I missed something in between. Nonetheless, the current version is in my eyes more descriptive.

Yeah, everything I read says that multidimensional arrays should work; I thought I was just doing something wrong. I might still be.

Looking at the TOML to JSON comparison for the array of tables really helped; thanks again!

The array of tables, to me, is just as descriptive as a multidimensional array if it’s indented properly, but that probably has more to do with my C background than anything.

Thanks for your help with all this, I’m starting to see why people like Go.

Found this thread because I’m having a similar problem. I’m displaying a series of chapters, each has several authors (both primary and contributing) and those 2 groups of authors have institutional affiliations. I need to display the authors and their corresponding institutions for each chapter.

I set up the chapter front matter with an authors_list field which I ideally want to be a type of dictionary with a key:value pair so I can easily get the author and their institution, so something like:

authors_list = [ [Author1: Place1], [Author2: Place2], [Author3: Place3] ]

Having some issues accessing both of those items, or accessing first the author and then the institution (they need to be formatted differently).

Another issue is that when I call it in my template, e.g. {{ index $.Params.author_list 0}}

It prints out the [[ ]] in addition to the text.

Any suggestions appreciated!

FIgured it out. The suggestions from @digitalcraftsman above in post #6 were extremely helpful. For my solution, I put the following in the front matter of my content markdown file for that content type:

[[authors.lead]]
    name = "A"
    place = "B"
    
[[authors.lead]]
    name = "C"
    place = "D"
    
[[authors.lead]]
    name = "E"
    place = "F"

And in my single.html template for that content type:

    <ul>
        {{ range .Params.authors.lead }}
                <li>
                    <span class="person"> {{ .name }} </span><br/>
                    <span class="organization">{{ .place }}</span>
                </li>
        {{ end }}
    </ul>

Works like a charm. The TOML table syntax at first was hard to get my head around. Now just need to add about 50 more entries!

Nice! Is it possible to use where on these values?

I’ve found that if not all pages have the “mirrors” table you get problems so you have to do:

$pages := where .Site.Pages ".Params.mirrors" "!=" nil

And then I’m trying

where $pages ".Params.mirrors.text" "!=" nil

But I get the error:

error calling where: text is neither a struct field, a method nor a map element of type interface {}