This started off as a quick message in discord and then I realized I was about to write way more than I wanted, so it became a blogpost.
I did some more work on the site last night, fixing a few things here and there while also adding in a /blogroll section. I wanted the blogroll to be generated from a data file - my idea being to use to my database program, ninox1, to build a form that I could then use to enter in the link data. From Ninox - I can export it as a CSV. And i had started this path KNOWING that hugo can parse CSV information, there were a few things that I did not know;
CSV files are NOT data files in the same way a TOML/YAML/JSON file are. Meaning you can not throw them in the data folder and walk away. Hugo will yell at you.
CSV files are mostly used to generate a table because, unlike those formats previously listed, you don’t have proper key/value pairs. Hell, a CSV file doesn’t even need a header row. It can just be a list of stuff separated by some kind of punction, often (as the namesake implies) a comma.
I started to think about using a CSV file and a hugo content adapter to actually create the index page and subsequent link list entries for me, but the more I read the documentation and reviewed the processes (and checked out the most excellent sample site built using that method) I found it to be overkill. What I wanted was a nice looking list of links with space for me to talk about them. I started to write a shortcode based off the example on the transform.Unmarshal
documentation page. This is where I ran into the problem with CSV’s and the way they organize information.
I tried a bunch of methods, but the end result I wanted was to get the data into a position where I could range through the map
and call each piece of information by it’s appropriate header information. For example, this is how a csv is formatted;
id,date,link,linkname,description
1,2025-05-29,https://cyberbuffalo.party,"this is a cool website with cool stuff on it and you should all bookmark it and visit it everyday"
and this is how it needs to look;
id:1;
link:https//cyberbuffalo.party
this is kind of oversimplifying things and that’s because I don’t have a complete and full grasp of data handling, marshaling, unmarshaling, etc. Inside my shortcode, I cheated a bit and built a partial that our lord and savior of the hugo forums, jmooring, casually whipped up in response to someone else who was struggling with a similar problem of data handling.
csv-to-map.html
{{ $headerRow := index . 0 }}
{{ $s := slice }}
{{ range . | after 1 }}
{{ $m := dict }}
{{ range $k, $v := . }}
{{ $m = merge $m (dict (index $headerRow $k) $v) }}
{{ end }}
{{ $s = $s | append $m }}
{{ end }}
{{ return $s }}
Inside of my shortcode, where this partial is called from, we’re doing something interesting. When you first define a variable you can define it as a collection:
{{ $data := dict }}
This is standard protocol for a lot of reasons, one of them being if you define a new variable inside of a statement it can be lost because it becomes part of that context. Define it first and then you have access to it without worry. Later, after I’ve imported the data file and everything, I redefine that $data
variable by passing it into that partial!
{{ $data = partial "csv-to-map.html" . }}
that’s some slick ass shit and maybe the easiest way to maneuver what I was trying to do. Another useful function I employed while working through this was {{ debug.Dump ARG }}
. Debug spits up a printout of whatever you want. This was a tip from good old Rappy. I find it incredibly useful to help you visualize what your context is, aka the dot. It also helped me to organize the $data
map.
One last thing here before I wrap up, I have footnotes now! I hadn’t really seen a need for them until that comment up above about Ninox. I see the light!
Have I talked about Ninox on this website yet? It’s a database program that I found last year after having some downtown from work and needing a project to keep me busy at night. I used it to build a giant database of all the photoshoot/commercial jobs I’ve worked on all the way back to 2011! It was a lot of work but it taught me a lot and I think it ultimately gave me the motivation (and confidence!) to really work on this website. ↩︎