shithub: hugo

Download patch

ref: 298ebc37c2d485ab34735f81541a5deaf079b03e
parent: 2618cfbeaa06bd2a4d26b3e3999e3c9ca9a49854
author: John Feminella <jxf+github@jxf.me>
date: Fri Feb 10 03:01:25 EST 2017

hugolib: Add ability to sort by frontmatter parameters


--- a/docs/content/templates/list.md
+++ b/docs/content/templates/list.md
@@ -237,6 +237,18 @@
     </li>
     {{ end }}
 
+### Order by Parameter
+Order based on the specified frontmatter parameter. Pages without that
+parameter will use the site's `.Site.Params` default. If the parameter is not
+found at all in some entries, those entries will appear together at the end
+of the ordering.
+
+The below example sorts a list of posts by their rating.
+
+    {{ range (.Data.Pages.ByParam "rating") }}
+      <!-- ... -->
+    {{ end }}
+
 ### Reverse Order
 Can be applied to any of the above. Using Date for an example.
 
--- a/hugolib/pageSort.go
+++ b/hugolib/pageSort.go
@@ -15,6 +15,8 @@
 
 import (
 	"sort"
+
+	"github.com/spf13/cast"
 )
 
 var spc = newPageCache()
@@ -272,6 +274,31 @@
 	}
 
 	pages, _ := spc.get(key, p, reverseFunc)
+
+	return pages
+}
+
+func (p Pages) ByParam(paramsKey interface{}) Pages {
+	paramsKeyStr := cast.ToString(paramsKey)
+	key := "pageSort.ByParam." + paramsKeyStr
+
+	paramsKeyComparator := func(p1, p2 *Page) bool {
+		v1, _ := p1.Param(paramsKeyStr)
+		v2, _ := p2.Param(paramsKeyStr)
+		s1 := cast.ToString(v1)
+		s2 := cast.ToString(v2)
+
+		// Sort nils last.
+		if s1 == "" {
+			return false
+		} else if s2 == "" {
+			return true
+		}
+
+		return s1 < s2
+	}
+
+	pages, _ := spc.get(key, p, pageBy(paramsKeyComparator).Sort)
 
 	return pages
 }
--- a/hugolib/pageSort_test.go
+++ b/hugolib/pageSort_test.go
@@ -20,6 +20,7 @@
 	"testing"
 	"time"
 
+	"github.com/spf13/cast"
 	"github.com/spf13/hugo/helpers"
 	"github.com/spf13/hugo/source"
 	"github.com/stretchr/testify/assert"
@@ -113,6 +114,34 @@
 	assert.True(t, probablyEqualPages(p2, p1.Reverse()))
 }
 
+func TestPageSortByParam(t *testing.T) {
+	var k interface{} = "arbitrary"
+
+	unsorted := createSortTestPages(10)
+	delete(unsorted[9].Params, cast.ToString(k))
+
+	firstSetValue, _ := unsorted[0].Param(k)
+	secondSetValue, _ := unsorted[1].Param(k)
+	lastSetValue, _ := unsorted[8].Param(k)
+	unsetValue, _ := unsorted[9].Param(k)
+
+	assert.Equal(t, "xyz100", firstSetValue)
+	assert.Equal(t, "xyz99", secondSetValue)
+	assert.Equal(t, "xyz92", lastSetValue)
+	assert.Equal(t, nil, unsetValue)
+
+	sorted := unsorted.ByParam("arbitrary")
+	firstSetSortedValue, _ := sorted[0].Param(k)
+	secondSetSortedValue, _ := sorted[1].Param(k)
+	lastSetSortedValue, _ := sorted[8].Param(k)
+	unsetSortedValue, _ := sorted[9].Param(k)
+
+	assert.Equal(t, firstSetValue, firstSetSortedValue)
+	assert.Equal(t, secondSetValue, lastSetSortedValue)
+	assert.Equal(t, lastSetValue, secondSetSortedValue)
+	assert.Equal(t, unsetValue, unsetSortedValue)
+}
+
 func BenchmarkSortByWeightAndReverse(b *testing.B) {
 
 	p := createSortTestPages(300)
@@ -154,6 +183,9 @@
 			},
 			Site:   &info,
 			Source: Source{File: *source.NewFile(filepath.FromSlash(fmt.Sprintf("/x/y/p%d.md", i)))},
+			Params: map[string]interface{}{
+				"arbitrary": "xyz" + fmt.Sprintf("%v", 100-i),
+			},
 		}
 		w := 5
 
--