Sort posts by title, case insensitive

There was a post last year about sorting posts by title that are case insensitive, but no solutions were given. Here’s the link for reference.

Do any of you have any advice on how to do this? If I sort my posts by title, all posts that are capitalized are sorted first and thereafter lowercase posts are sorted. Thanks

1 Like

This would require a custom sorting function to be added to Hugo. Even in golang’s sort package https://golang.org/src/sort/sort.go there doesn’t seem to be a case-insensitive sort. Take a look here if you’re interested. You can either write a sort.Interface to implement custom case insensitive sorting, or check out sortutil lib for golang. Patrick has implemented a case insensitive sort function in sortutil lib. https://github.com/patrickmn/sortutil

You can install it like so: go get github.com/pmylund/sortutil

Then you can import it into Hugo’s https://github.com/spf13/hugo/blob/master/hugolib/pageSort.go and implement the case insensitive sort function here, and use the func CiAsc(slice interface{}) from sortutil.

https://github.com/patrickmn/sortutil/blob/master/sortutil.go#L55 Take a peek here to see how Patrick is implementing this.

You can then build Hugo from source with your new sortutil library and your new case insensitive sort function, and test it out in your site. Perhaps even submit a PR if it works flawlessly.

This is not entirely too trivial.

Hugo gurus please verify if my advice is not crazy. Thanks! :slight_smile:

Another work around using Hugo functions is to create a slice of lower cased param values. Loop over them and for each instance that lower case matches an actual page title which you also lower case output what you want. Some code we use

Here integration_title have various caps and is sorted but not case insensitive
{{ $lower := sort $integrations "Params.integration_title" }}

Set slice
{{ $.Scratch.Set "lower_titles" (slice) }}

Range over all params lower case them and add to slice

{{ range $lower }}`
  
  {{ $.Scratch.Add "lower_titles" (lower .Params.integration_title) }}

{{ end }}

Now sort the slice which is all lower case, range over initial slice and when the lower case param matches show what you need from the original slice.

{{ range sort ($.Scratch.Get "lower_titles") }}

  {{ $lower_int := . }}

    {{ range $int := $integrations }}

      {{ if eq $lower_int (lower $int.Params.integration_title) }}
        <li><a href="{{.Permalink}}">{{ .Params.integration_title}}</a></li>
      {{ end }}

    {{ end }}

{{ end }}
2 Likes

Thank you peterpan!

For a real world implementation of this workaround, see this code of publiccode.eu.

I also needed case insensitive sorting.

Thanks to you, this is what I came up with:

  {{- range (where .Data.Pages ".Params.client" "!=" nil) -}}
    {{- $.Scratch.Add "clients_sites" (slice .Params.client) -}}
  {{- end -}}
  {{- $.Scratch.Add "clients" (union .Site.Params.clients.names ($.Scratch.Get "clients_sites")) -}}
  {{- $.Scratch.Set "lower_clients" (slice) -}}
  {{- range ($.Scratch.Get "clients") -}}
    {{- $.Scratch.Add "lower_clients" (lower . ) -}}
  {{- end -}}
  {{- $.Scratch.Set "clients_sorted" (slice) -}}
  {{- range sort ($.Scratch.Get "lower_clients") -}}
    {{- $lower_int := . -}}
    {{- range  $.Scratch.Get "clients"}}
      {{ if eq (lower .) $lower_int }}
        {{- $.Scratch.Add "clients_sorted" ( . ) -}}
      {{- else -}}
      {{ end }}
    {{- end -}}
  {{- end -}}
  <span>{{ delimit (.Scratch.Get "clients_sorted") ", </span> <span>" }}</span>