Sort list of content by data file?

I think I can do this thing, but I’m not sure, so someone shoot this down or give me a pointer, please. :slight_smile:

I’m pulling in data via getJSON, to pull in things like commit messages or forum posts (multiple possible sources, hence no .gitinfo). I show them in the single.html fine, but what I’d like to do is sort the content on the list page by the date of the latest message pulled in from the data file.

I’m not grokking how it works. :thinking:

I guess another way of asking is: can one set the variable for a piece of content that is exposed to the list context, via a data file?


The concrete example is the list at https://interi.org/awesome-lol/, a list of “awesome lists” I’m reading and logging. Some of the lists haven’t been updated in years, so I’d like to sort the lists by when they were last updated, by grabbing the date of the last commit message.

The template for the single pages is at https://allthe.codes/interi/web-layouts/src/branch/master/awesome-lol/single.html. I just use a generic list of titles (https://allthe.codes/tule/tule/src/branch/master/layouts/_default/list.html).

You could getJSON again in the list page, where you {{ range first 200 .Pages }}.

{{ $megalist := slice }}

{{ range first 200 .Pages }}
    {{- if isset .Params "allthecodes" -}}
    ... getJSON stuff ...
    {{ $megalist = $megalist | append (dict  "page" . "lastcommit" (index $commits 0) )}}
    {{ end }}
{{ end }}
<ul>
{{ range $k, $v := sort $megalist ".lastcommit.commit.committer.date" "asc" }}
<li>
    {{ $v.page }}
    {{ dateFormat "Jan 2 2006" $v.lastcommit.commit.committer.date}}
    {{$v.lastcommit.commit.message}}
</li>
{{ end }}
</ul>

… with the assumption that you wanted the pages sorted. If however you wanted all the latest commits sorted (eg last 200 regardless of which page they were associated with) just move the $megalist | append bit into where you do the range first 5 $commits.

1 Like

Thanks! My personal issue is I hardly use append, dict, or index, so that line is hard for my brain to parse. :slight_smile:

I added in the getJSON code, and switched to desc to get the latest list by commit message to the top. Here’s the complete code:

{{ $megalist := slice }}

{{ range first 200 .Pages }}
  {{- if isset .Params "allthecodes" -}}
  {{- $owner := .Params.allthecodes.owner | urlize -}}
  {{- $repo := .Params.allthecodes.repo | urlize -}}
  {{- $commits := getJSON "https://allthe.codes/api/v1/repos/" $owner "/" $repo "/commits" -}}

{{ $megalist = $megalist | append (dict  "page" . "lastcommits" (index $commits 0) )}}
{{ end }}
{{ end }}

<ul>
{{ range $k, $v := sort $megalist ".lastcommits.commit.committer.date" "desc" }}
<li>
    {{ $v.page }}
    {{ dateFormat "Jan 2 2006" $v.lastcommits.commit.committer.date}}
    {{$v.lastcommit.commit.message}}
</li>
{{ end }}
</ul>

The output is the commit messages from list, ex:

  • Page(/awesome-lol/awesome-cheminformatics.md) Jan 28 2020 add Rcpi
  • Page(/awesome-lol/awesome-selfhosted.md) Jan 28 2020 Merge pull request #1957 from rodavelino/fix-links
  • Page(/awesome-lol/awesome-diversity.md) Jan 28 2020 Update README.md
  • Page(/awesome-lol/awesome-jmeter.md) Jan 27 2020 Add action to run awesome-lint
  • Page(/awesome-lol/awesome-marvelous-amas.md) Jan 27 2020 Add Ale Muñoz (#229)
  • Page(/awesome-lol/awesome-mqtt.md) Jan 25 2020 add ESP-BLE2MQTT desc
  • Page(/awesome-lol/awesome-gravity-forms.md) Jan 24 2020 Clone Gravity Form Entry Add
  • Page(/awesome-lol/awesome-transit.md) Jan 23 2020 Add onebusaway-vdv-modules
  • Page(/awesome-lol/awesome-sre.md) Jan 23 2020 Add Resilience Roundup to Blogs section (#63)

I can kinda sorta follow the logic behind {{ $megalist = $megalist | append (dict "page" . "lastcommit" (index $commits 0) )}}. How would you suggest including the title and permalink in this slice? Do I use that slice to sort by the page in another range?

I really outta learn the concepts behind these functions, aside from the examples in the Hugo docs. :nerd_face:

$megalist here is an array of maps of the form:

{
    "page" : .Page object,
    "lastcommit" : (first item of $commits)
}

If these are the .Page’s values, you could grab them from $v.page ie

{{ $v.page.Permalink }} / {{ $v.page.Title }}

So then you could do

<li>
    The last commit for Page <a href="{{$v.page.Permalink}}">{{$v.page.Title}}</a>
    was on {{ dateFormat "Monday, Jan 2, 2006" $v.lastcommits.commit.committer.date }}: 
    <a href="{{ .html_url | safeURL }}">{{ $v.lastcommits.commit.message }}</a>
</li>

Edit:
I just realised that I’m making an assumption here that the $commits API returns a sorted list, and that therefore $commits[0] is the latest. Is that a valid assumption? If not I shall scratch my chin for a bit. :thinking:

1 Like

Simplified + annotated a little:

{{ define "main"  }}
{{ $megalist := slice }}

{{ range first 200 .Pages }}
  {{- if isset .Params "allthecodes" -}}
    {{- $owner := .Params.allthecodes.owner | urlize -}}
    {{- $repo := .Params.allthecodes.repo | urlize -}}
    {{- $commits := getJSON "https://allthe.codes/api/v1/repos/" $owner "/" $repo "/commits" -}}

    <!-- get the commit with the latest date (sorted according to $commits.commit.committer.date field) -->
    {{ $lastcommit := first 1 (sort $commits ".commit.committer.date" "desc" ) }}
    <!-- note that `first 1` returns an array of length 1, hence the need to get `index $lastcommit 0` below -->
    <!-- append dict to $megalist: 
        {
            "page" : .Page,
            "lastcommit" : $lastcommit[0]
        } 
    -->
    {{ $megalist = $megalist | append (dict  "page" . "lastcommit" (index $lastcommit 0) )}}
  {{ end }}
{{ end }}

<ul>
<!-- sort pages by commit date -->
{{ range sort $megalist ".lastcommit.commit.committer.date" "desc" }}
<li>
    The last commit for Page <a href="{{.page.Permalink}}">{{.page.Title}}</a>
    was on {{ dateFormat "Monday, Jan 2, 2006" .lastcommit.commit.committer.date }}: 
    <a href="{{ .lastcommit.html_url | safeURL }}">{{ .lastcommit.commit.message }}</a>
</li>
{{ end }}
</ul>
{{ end }}
2 Likes

Thanks, doubly so! First, for putting together this list for me (it works!). Second, because that was the part I was missing.

dict  "page" . "lastcommit" (index $commits 0)

I didn’t understand the dot usage here, my brain read it was somehow grabbing the lastcommit from the page object… but I know better now. And it makes a lot more sense, thanks!

So, that dot should be the “current Page” ( from the {{ range first 200 .Pages }} )

they way that dict works is:

{{ dict key1 value1 key2 value2 ... keyn valuen }}

so… {{ $megalist = $megalist | append (dict "page" . "lastcommit" (index $lastcommit 0) )}}

is saying :

define $megalist as…

$megalist plus (append) …

a dictionary with the following key/value pairs:

“page” which is the current page

and "lastcommit which is the first item (index ... 0) in $lastcommit a slice (array/list)

While you loop, $megalist will grow, page at a time (really overwriting itself each loop).

1 Like