Sorry for the clickbait title, but this is really annoying me.
See, I have a project with dozens of pages in the same section, which are not going anywhere.
I wanted to order the page collection by filenames, which are numbered: this is not possible easily, not with basenames, that is.
But it won’t do with weights easier, because decimal weights apparently won’t work.
Given that it will eventually adds up to a hundred, and sometimes they are inserted in the middle, I need a scheme that doesn’t require editing ten files just to add new content. I’d be happy if I could add a weight such as 10.5 for 10-bis for instance.
0 or 1,5 is the same as no weight at all, 1.5 is the same as 1 but takes precedence over 1, and negative values take precedence over everything.
This doesn’t make sense, it should be -2<-1.5<-1<0<1<1.5<2 with no special value.
looks like you want the things to behave as you want them to behave. I would say there’s nothing broken but works as designed. (technical details section at the end)
back to the good old C64 times where we had to manually number lines in source code, you could start with 1000, 2000, 3000 - will last some time
but I would go with this one:
use a new param that is a float:
[params]
order = 23.2
use it like this
site.RegularPages.ByParam "order"
you may use 0 or 0.0 here (see below)
or if there’s a rule implement some custom automatic sort partial(Cached) where you split the .Path by hyphen and sort by number and title.
Turning weight into a float would be a change request but as floats are much slower than int’s and lack proper equality comparision … guess someone will say no
I do share the performance concern, but since the program converts floats into integer anyway instead of throwing errors, I am unsure how doing comparisons instead of conversions would impact performance so much.
Order should be: 0.md > 0-bis.md > 1.md > 2.md > 2-bis.md
How I get there I don’t care, as long as (hopefully) I don’t need to write out manually wanky weights or a custom parameter.
I want to sort by the content file path in a given section, yes, not the URL or anything like that.
here’s a partial that takes a list of pages and sorts them as described:
just the bare logic - no error checking. for example
no check if the thing before the first hyphen is empty or not a number
no test if the page is backed by a file
stuff after the - starting with digits is sorted by ascii
call it like this:
{{- range (partial "sortPages" site.RegularPages) -}}
{{- warnf "%s" .Path }}
{{- end }}
_partials/sortPages.html
{{- /* use map functionality of newScratch which is much faster than maps merge when using a dict */ -}}
{{- $sortedPages := newScratch }}
{{- range . }}
{{- $sortkeys := split .File.BaseFileName "-" }}
{{- /* all before first hyphen */ -}}
{{- $key1 := index $sortkeys 0 }}
{{- /* rejoin the remainer of the elements created by split */ -}}
{{- $key2 := delimit ($sortkeys | last (sub (len $sortkeys) 1)) "-" }}
{{- /*
sort is always ascii, make sure 2 is greater than 10 by filling up to 10 digits
use that one combined with the rest as map key and set the current page as "value"
*/ -}}
{{ $sortedPages.SetInMap "toSort" (printf "%010s-%s" $key1 $key2) . }}
{{- end }}
{{- /* sorting a map by key removes the key */ -}}
{{ return $sortedPages.GetSortedMapValues "toSort" }}
the splitting could be done with regex - too late for today
ok couldn’t resist, here it is:
errors out if a filename does not start with a digit
does not need a hyphen after the first digits
can be easily adjusted by changing the regex
{{- $sortedPages := newScratch }}
{{ $key1 := ""}}
{{ $key2 := ""}}
{{- range $page := . }}
{{ with findRESubmatch `^(\d+)(.*)$` .File.BaseFileName 1 }}
{{- $key1 = index (index . 0) 1 }} {{/* first submatch: the starting digits */}}
{{- $key2 = index (index . 0) 2 }} {{/* second submatch: the rest */}}
{{- $sortedPages.SetInMap "toSort" (printf "%010s%s" $key1 $key2) $page }}
{{ else }}
{{- errorf "page '%s' : filename does not start with a digit: '%s'" .Path .File.BaseFileName }}
{{ end }}
{{- end }}
{{ return $sortedPages.GetSortedMapValues "toSort" }}
Just some believe system notes thrown in from the sidelines, but I do numbered filenames for the past 20 years in 001.txt, 002.txt, etc. format because that is sortable even for the worst sorter.
It’s not a Hugo issue that 10 comes before 2 if the sorting is alphabet/string based, that’s the same with any file sorting system. Some systems have an added “natural” sorting algorithm that understands when you are counting, but for instance. I also don’t suggest increments of 1, because that will lead to issues down the road when we decide to put something between page a and b. It’s static, but you want it extensible. Take a long enough zerofilled number as filename and then increment in 10s or 100s. Sort sections by increment*10 or increment*100 (docs are from 01000-title.md to 01999-title.md) so you end up with a nicely sortable scriptkiddie sortation.
Putting too much information into the filename (sorting, numbering of headlines, title) will lead to issues. That’s why you have the front matter. If the properties that are there by default don’t work, then add params frontmatter and work with your own system.
But I want the URL of the page to stay at /docs/1-title! — use slug front matter. But I want to add a new page in front of all the other pages! — use negative weights.
Regarding the front matter sorting: Do integers. You will thank yourself later if you use any other system that parses front matter. Floats have issues in many programming languages. Even “proper” money calculating libraries make you save and calculate with 100 cent instead of 1 dollar if you want to round on cent. How this number looks like on the CMS side is task of the CMS.
For your specific issue I would “just” multiply the weight front matter by 100 or even by 1000. Then segment by .Section = 'docs' and sort by weight. This should take care of the sorting of the current content. If you have a new page between 01200-title.md and 01300-title.md then add it at 01250-title.md.
yeah, indeed but Hugo makes it harder cause you cannot have numerical keys. And you cannot add info to the page. Although we could do a little more complex stuff and do a number sort.
working file based a file identifies the source. decoupling source and target may lead to issues later find your source for a page for example is not just a one click.
will work a period of time, depends which sections get new content how often … but I coded much years ago having these manual ascii sort an on the long run it hit me most of the time. It halves the available page range every time
for this use case, it’s just a compare of manual values, no calculation. I don’t see the floating calculation problems here but on the long run… with 1.25e-20
if the expected number of pages is not too high, and injecting a page in the middle is not a daily thing I also would go with these zero filled numbers in the file name.
I finally opted for zero-padded names. Less readable than the natural numbers (corresponding to the exercice number) but close enough and I don’t need to wonder how these stupidly dumb systems are gonna treat them.
Seriously, we’re in 2026 and most systems (filesystems, linux, windows, Go libraries, etc) still aren’t smart enough by default to offer natively and simply to sort files in various human-centric ways, using metadata and across directories ? Pathetic.
I’ll never have more than three entries between integers or more than 200 integer entries in total, 0105 to denote 10-bis is adequate.