Fix order of GetTerms
authorBjørn Erik Pedersen <bjorn.erik.pedersen@gmail.com>
Mon, 15 Jun 2020 14:33:09 +0000 (16:33 +0200)
committerBjørn Erik Pedersen <bjorn.erik.pedersen@gmail.com>
Mon, 15 Jun 2020 20:23:02 +0000 (22:23 +0200)
Preserve the order from front matter, which would be behaviour when doing this manually (before GetTerms).

Fixes #7213

common/collections/order.go [new file with mode: 0644]
hugolib/content_map.go
hugolib/content_map_page.go
hugolib/page.go
hugolib/taxonomy_test.go
resources/page/pages_sort.go

diff --git a/common/collections/order.go b/common/collections/order.go
new file mode 100644 (file)
index 0000000..4bdc3b4
--- /dev/null
@@ -0,0 +1,20 @@
+// Copyright 2020 The Hugo Authors. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package collections
+
+type Order interface {
+       // Ordinal is a zero-based ordinal that represents the order of an object
+       // in a collection.
+       Ordinal() int
+}
index ddcc7070734ffd2ead5a2d2ba21eaba2e90dbc1c..8af55347897befbc25f16653ac5c728bb2392540 100644 (file)
@@ -264,6 +264,7 @@ func (b *cmInsertKeyBuilder) newTopLevel() {
 }
 
 type contentBundleViewInfo struct {
+       ordinal    int
        name       viewName
        termKey    string
        termOrigin string
index 7516a702923f7e0c9e71dda6e0da21338c99ec4b..8c7ecc3419643c79a8186c684412f523ca5ba78c 100644 (file)
@@ -579,7 +579,6 @@ func (m *pageMap) attachPageToViews(s string, b *contentNode) {
                if vals == nil {
                        continue
                }
-
                w := getParamToLower(b.p, viewName.plural+"_weight")
                weight, err := cast.ToIntE(w)
                if err != nil {
@@ -587,11 +586,12 @@ func (m *pageMap) attachPageToViews(s string, b *contentNode) {
                        // weight will equal zero, so let the flow continue
                }
 
-               for _, v := range vals {
+               for i, v := range vals {
                        termKey := m.s.getTaxonomyKey(v)
 
                        bv := &contentNode{
                                viewInfo: &contentBundleViewInfo{
+                                       ordinal:    i,
                                        name:       viewName,
                                        termKey:    termKey,
                                        termOrigin: v,
index 083e702ed7cdfeff0c2a51442711b193c5682222..baf5e7f69151a573407d0757b74990e513123fcd 100644 (file)
@@ -132,6 +132,7 @@ func (p *pageState) GitInfo() *gitmap.GitInfo {
 }
 
 // GetTerms gets the terms defined on this page in the given taxonomy.
+// The pages returned will be ordered according to the front matter.
 func (p *pageState) GetTerms(taxonomy string) page.Pages {
        if p.treeRef == nil {
                return nil
@@ -147,8 +148,9 @@ func (p *pageState) GetTerms(taxonomy string) page.Pages {
 
        m.taxonomies.WalkQuery(pageMapQuery{Prefix: prefix}, func(s string, n *contentNode) bool {
                key := s + self
-               if _, found := m.taxonomyEntries.Get(key); found {
-                       pas = append(pas, n.p)
+               if tn, found := m.taxonomyEntries.Get(key); found {
+                       vi := tn.(*contentNode).viewInfo
+                       pas = append(pas, pageWithOrdinal{pageState: n.p, ordinal: vi.ordinal})
                }
                return false
        })
@@ -1006,3 +1008,22 @@ func (s *Site) sectionsFromFile(fi source.File) []string {
 
        return parts
 }
+
+var (
+       _ page.Page         = (*pageWithOrdinal)(nil)
+       _ collections.Order = (*pageWithOrdinal)(nil)
+       _ pageWrapper       = (*pageWithOrdinal)(nil)
+)
+
+type pageWithOrdinal struct {
+       ordinal int
+       *pageState
+}
+
+func (p pageWithOrdinal) Ordinal() int {
+       return p.ordinal
+}
+
+func (p pageWithOrdinal) page() page.Page {
+       return p.pageState
+}
index 97058dd19124358dd7b3d4e4e662393b64a95088..64f560d251a4371b5b90afaaeee1d0f1ece26acf 100644 (file)
@@ -644,12 +644,12 @@ Cats Paginator {{ range $cats.Paginator.Pages }}{{ .RelPermalink }}|{{ end }}:EN
 Categories Pages: /categories/birds/|/categories/cats/|/categories/dogs/|/categories/funny/|/categories/gorillas/|:END
 Funny Pages: /section/p1/|/section/p2/|:END
 Cats Pages: /section/p1/|/section/|:END
-P1 Terms: /categories/cats/|/categories/funny/|:END
-Section Terms: /categories/birds/|/categories/cats/|/categories/dogs/|:END
+P1 Terms: /categories/funny/|/categories/cats/|:END
+Section Terms: /categories/cats/|/categories/dogs/|/categories/birds/|:END
 Home Terms: /categories/dogs/|/categories/gorillas/|:END
 Cats Paginator /section/p1/|/section/|:END
-Category Paginator /categories/birds/|/categories/cats/|/categories/dogs/|/categories/funny/|/categories/gorillas/|:END
-`)
+Category Paginator /categories/birds/|/categories/cats/|/categories/dogs/|/categories/funny/|/categories/gorillas/|:END`,
+       )
        b.AssertFileContent("public/404.html", "\n404 Terms: :END\n\t")
        b.AssertFileContent("public/categories/funny/index.xml", `<link>http://example.com/section/p1/</link>`)
        b.AssertFileContent("public/categories/index.xml", `<link>http://example.com/categories/funny/</link>`)
index b0e7f8e323a231594831e0a105c58e9a099e0cdd..85817ffdaa9d545c7526e5e331ebfb576a503101 100644 (file)
@@ -16,6 +16,8 @@ package page
 import (
        "sort"
 
+       "github.com/gohugoio/hugo/common/collections"
+
        "github.com/gohugoio/hugo/resources/resource"
 
        "github.com/gohugoio/hugo/compare"
@@ -37,6 +39,19 @@ type pageSorter struct {
 // pageBy is a closure used in the Sort.Less method.
 type pageBy func(p1, p2 Page) bool
 
+func getOrdinals(p1, p2 Page) (int, int) {
+       p1o, ok1 := p1.(collections.Order)
+       if !ok1 {
+               return -1, -1
+       }
+       p2o, ok2 := p2.(collections.Order)
+       if !ok2 {
+               return -1, -1
+       }
+
+       return p1o.Ordinal(), p2o.Ordinal()
+}
+
 // Sort stable sorts the pages given the receiver's sort order.
 func (by pageBy) Sort(pages Pages) {
        ps := &pageSorter{
@@ -49,8 +64,12 @@ func (by pageBy) Sort(pages Pages) {
 var (
 
        // DefaultPageSort is the default sort func for pages in Hugo:
-       // Order by Weight, Date, LinkTitle and then full file path.
+       // Order by Ordinal, Weight, Date, LinkTitle and then full file path.
        DefaultPageSort = func(p1, p2 Page) bool {
+               o1, o2 := getOrdinals(p1, p2)
+               if o1 != o2 && o1 != -1 && o2 != -1 {
+                       return o1 < o2
+               }
                if p1.Weight() == p2.Weight() {
                        if p1.Date().Unix() == p2.Date().Unix() {
                                c := compare.Strings(p1.LinkTitle(), p2.LinkTitle())