Handle Taxonomy permalinks
authorBrian Chen <brian.chxn@gmail.com>
Tue, 7 Nov 2017 03:58:41 +0000 (22:58 -0500)
committerBjørn Erik Pedersen <bjorn.erik.pedersen@gmail.com>
Tue, 7 Nov 2017 22:05:48 +0000 (23:05 +0100)
Return the correct virtual Section for Taxonomy and TaxonomyTerm.
Restrict permalink expansion to only Pages and Taxonomies, but then
actually use expanded permalinks even for non-Pages.

Fixes #1208.

docs/content/content-management/taxonomies.md
docs/content/content-management/urls.md
hugolib/page.go
hugolib/page_paths.go
hugolib/taxonomy_test.go

index 978814a26ba79375ee7231537e2bd817ae7095af..0791590aef5b4370530cbb2e4c52d81a02eb399f 100644 (file)
@@ -132,7 +132,7 @@ Note that if you use `preserveTaxonomyNames` and intend to manually construct UR
 {{% note %}}
 You can add content and front matter to your taxonomy list and taxonomy terms pages. See [Content Organization](/content-management/organization/) for more information on how to add an `_index.md` for this purpose.
 
-Note also that taxonomy [permalinks](/content-management/urls/) are *not* configurable.
+Much like regular pages, taxonomy list [permalinks](/content-management/urls/) are configurable, but taxonomy term page permalinks are not.
 {{% /note %}}
 
 ## Add Taxonomies to Content
index f7b8cba895cb54de231f04bc3882b813f39e38da..4be6b72d0726d13b0e556f3aaa90cbc594190c6b 100644 (file)
@@ -45,6 +45,8 @@ permalinks:
 
 Only the content under `post/` will have the new URL structure. For example, the file `content/post/sample-entry.md` with `date: 2017-02-27T19:20:00-05:00` in its front matter will render to `public/2017/02/sample-entry/index.html` at build time and therefore be reachable at `https://example.com/2013/11/sample-entry/`.
 
+You can also configure permalinks of taxonomies with the same syntax, by using the plural form of the taxonomy instead of the section. You will probably only want to use the configuration values `:slug` or `:title`.
+
 ### Permalink Configuration Values
 
 The following is a list of values that can be used in a `permalink` definition in your site `config` file. All references to time are dependent on the content's date.
index 331a217d916356930fc50243e835ab3e869d44bd..d928b92f97c9c49ea8590a0e84465e54c4fce837 100644 (file)
@@ -758,7 +758,7 @@ func (p *Page) Type() string {
 // since Hugo 0.22 we support nested sections, but this will always be the first
 // element of any nested path.
 func (p *Page) Section() string {
-       if p.Kind == KindSection {
+       if p.Kind == KindSection || p.Kind == KindTaxonomy || p.Kind == KindTaxonomyTerm {
                return p.sections[0]
        }
        return p.Source.Section()
index 73fd622788e68e54701a0693fd095342bc1f329a..e18e0f10e21be2f28a9fdad6734ba5de14cdff2a 100644 (file)
@@ -99,15 +99,22 @@ func (p *Page) initTargetPathDescriptor() error {
                d.LangPrefix = p.Lang()
        }
 
-       if override, ok := p.Site.Permalinks[p.Section()]; ok {
-               opath, err := override.Expand(p)
-               if err != nil {
-                       return err
-               }
+       // Expand only KindPage and KindTaxonomy; don't expand other Kinds of Pages
+       // like KindSection or KindTaxonomyTerm because they are "shallower" and
+       // the permalink configuration values are likely to be redundant, e.g.
+       // naively expanding /category/:slug/ would give /category/categories/ for
+       // the "categories" KindTaxonomyTerm.
+       if p.Kind == KindPage || p.Kind == KindTaxonomy {
+               if override, ok := p.Site.Permalinks[p.Section()]; ok {
+                       opath, err := override.Expand(p)
+                       if err != nil {
+                               return err
+                       }
 
-               opath, _ = url.QueryUnescape(opath)
-               opath = filepath.FromSlash(opath)
-               d.ExpandedPermalink = opath
+                       opath, _ = url.QueryUnescape(opath)
+                       opath = filepath.FromSlash(opath)
+                       d.ExpandedPermalink = opath
+               }
        }
 
        p.targetPathDescriptorPrototype = d
@@ -151,7 +158,11 @@ func createTargetPath(d targetPathDescriptor) string {
        }
 
        if d.Kind != KindPage && len(d.Sections) > 0 {
-               pagePath = filepath.Join(d.Sections...)
+               if d.ExpandedPermalink != "" {
+                       pagePath = filepath.Join(pagePath, d.ExpandedPermalink)
+               } else {
+                       pagePath = filepath.Join(d.Sections...)
+               }
                needsBase = false
        }
 
index 4f8717d72ea83c58ee8de17278d634e9f1b28f32..bbde9354d8e2d0fea8e816981a0d9f35d287b425 100644 (file)
@@ -77,6 +77,10 @@ tag = "tags"
 category = "categories"
 other = "others"
 empty = "empties"
+permalinked = "permalinkeds"
+
+[permalinks]
+permalinkeds = "/perma/:slug/"
 `
 
        pageTemplate := `---
@@ -87,6 +91,8 @@ categories:
 %s
 others:
 %s
+permalinkeds:
+%s
 ---
 # Doc
 `
@@ -99,15 +105,15 @@ others:
        fs := th.Fs
 
        if preserveTaxonomyNames {
-               writeSource(t, fs, "content/p1.md", fmt.Sprintf(pageTemplate, "t1/c1", "- tag1", "- cat1", "- o1"))
+               writeSource(t, fs, "content/p1.md", fmt.Sprintf(pageTemplate, "t1/c1", "- tag1", "- cat1", "- o1", "- pl1"))
        } else {
                // Check lower-casing of tags
-               writeSource(t, fs, "content/p1.md", fmt.Sprintf(pageTemplate, "t1/c1", "- Tag1", "- cAt1", "- o1"))
+               writeSource(t, fs, "content/p1.md", fmt.Sprintf(pageTemplate, "t1/c1", "- Tag1", "- cAt1", "- o1", "- pl1"))
 
        }
-       writeSource(t, fs, "content/p2.md", fmt.Sprintf(pageTemplate, "t2/c1", "- tag2", "- cat1", "- o1"))
-       writeSource(t, fs, "content/p3.md", fmt.Sprintf(pageTemplate, "t2/c12", "- tag2", "- cat2", "- o1"))
-       writeSource(t, fs, "content/p4.md", fmt.Sprintf(pageTemplate, "Hello World", "", "", "- \"Hello Hugo world\""))
+       writeSource(t, fs, "content/p2.md", fmt.Sprintf(pageTemplate, "t2/c1", "- tag2", "- cat1", "- o1", "- pl1"))
+       writeSource(t, fs, "content/p3.md", fmt.Sprintf(pageTemplate, "t2/c12", "- tag2", "- cat2", "- o1", "- pl1"))
+       writeSource(t, fs, "content/p4.md", fmt.Sprintf(pageTemplate, "Hello World", "", "", "- \"Hello Hugo world\"", "- pl1"))
 
        writeNewContentFile(t, fs, "Category Terms", "2017-01-01", "content/categories/_index.md", 10)
        writeNewContentFile(t, fs, "Tag1 List", "2017-01-01", "content/tags/tag1/_index.md", 10)
@@ -146,10 +152,11 @@ others:
        // Make sure that each KindTaxonomyTerm page has an appropriate number
        // of KindTaxonomy pages in its Pages slice.
        taxonomyTermPageCounts := map[string]int{
-               "tags":       2,
-               "categories": 2,
-               "others":     2,
-               "empties":    0,
+               "tags":         2,
+               "categories":   2,
+               "others":       2,
+               "empties":      0,
+               "permalinkeds": 1,
        }
 
        for taxonomy, count := range taxonomyTermPageCounts {
@@ -170,6 +177,14 @@ others:
                require.Equal(t, "/blog/categories/cat1/", cat1.RelPermalink())
        }
 
+       pl1 := s.getPage(KindTaxonomy, "permalinkeds", "pl1")
+       require.NotNil(t, pl1)
+       if uglyURLs {
+               require.Equal(t, "/blog/perma/pl1.html", pl1.RelPermalink())
+       } else {
+               require.Equal(t, "/blog/perma/pl1/", pl1.RelPermalink())
+       }
+
        // Issue #3070 preserveTaxonomyNames
        if preserveTaxonomyNames {
                helloWorld := s.getPage(KindTaxonomy, "others", "Hello Hugo world")