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>
4 Likes

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.

1 Like

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!

2 Likes

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 {}