Fix menu URL when multiple permalinkable output formats
authorBjørn Erik Pedersen <bjorn.erik.pedersen@gmail.com>
Fri, 19 Apr 2019 07:18:12 +0000 (09:18 +0200)
committerBjørn Erik Pedersen <bjorn.erik.pedersen@gmail.com>
Fri, 19 Apr 2019 08:29:52 +0000 (10:29 +0200)
In Hugo `0.55` we introduced the `permalinkable` config attribute on Output Format, default enabled for `AMP` and `HTML`.

This meant that a Page could have different `RelPermalink` and `Permalink` depending on the rendering format.

The menu `URL` did not reflect that fact.

Fixes #5849

hugolib/menu_test.go
hugolib/site.go
navigation/menu.go
navigation/pagemenus.go

index 5c692d2e7e21c663bbb0cbc80089548564e735bb..f1db3cb3ab3f140932e7c0ffae1ef8f93b306164 100644 (file)
@@ -92,10 +92,10 @@ Menu Main:  {{ partial "menu.html" (dict "page" . "menu" "main") }}`,
 
        th.assertFileContent("public/sect1/p1/index.html", "Single",
                "Menu Sect:  "+
-                       "/sect5/|Section Five||10|-|-|"+
-                       "/sect1/|Section One||100|-|HasMenuCurrent|"+
-                       "/sect2/|Sect2s||0|-|-|"+
-                       "/sect3/|Sect3s||0|-|-|",
+                       "/sect5/|Section Five|Section Five|10|-|-|"+
+                       "/sect1/|Section One|Section One|100|-|HasMenuCurrent|"+
+                       "/sect2/|Sect2s|Sect2s|0|-|-|"+
+                       "/sect3/|Sect3s|Sect3s|0|-|-|",
                "Menu Main:  "+
                        "/sect3/p5/|p5|atitle5|5|-|-|"+
                        "/sect2/p4/|p4|atitle4|10|-|-|"+
@@ -106,10 +106,10 @@ Menu Main:  {{ partial "menu.html" (dict "page" . "menu" "main") }}`,
 
        th.assertFileContent("public/sect2/p3/index.html", "Single",
                "Menu Sect:  "+
-                       "/sect5/|Section Five||10|-|-|"+
-                       "/sect1/|Section One||100|-|-|"+
-                       "/sect2/|Sect2s||0|-|HasMenuCurrent|"+
-                       "/sect3/|Sect3s||0|-|-|")
+                       "/sect5/|Section Five|Section Five|10|-|-|"+
+                       "/sect1/|Section One|Section One|100|-|-|"+
+                       "/sect2/|Sect2s|Sect2s|0|-|HasMenuCurrent|"+
+                       "/sect3/|Sect3s|Sect3s|0|-|-|")
 
 }
 
@@ -163,3 +163,62 @@ menu:
        )
 
 }
+
+// https://github.com/gohugoio/hugo/issues/5849
+func TestMenuPageMultipleOutputFormats(t *testing.T) {
+
+       config := `
+baseURL = "https://example.com"
+
+# DAMP is similar to AMP, but not permalinkable.
+[outputFormats]
+[outputFormats.damp]
+mediaType = "text/html"
+path = "damp"
+
+`
+
+       b := newTestSitesBuilder(t).WithConfigFile("toml", config)
+       b.WithContent("_index.md", `
+---
+Title: Home Sweet Home
+outputs: [ "html", "amp" ]
+menu: "main"
+---
+
+`)
+
+       b.WithContent("blog/html-amp.md", `
+---
+Title: AMP and HTML
+outputs: [ "html", "amp" ]
+menu: "main"
+---
+
+`)
+
+       b.WithContent("blog/html.md", `
+---
+Title: HTML only
+outputs: [ "html" ]
+menu: "main"
+---
+
+`)
+
+       b.WithContent("blog/amp.md", `
+---
+Title: AMP only
+outputs: [ "amp" ]
+menu: "main"
+---
+
+`)
+
+       b.WithTemplatesAdded("index.html", `{{ range .Site.Menus.main }}{{ .Title }}|{{ .URL }}|{{ end }}`)
+
+       b.Build(BuildCfg{})
+
+       b.AssertFileContent("public/index.html", "AMP and HTML|/blog/html-amp/|AMP only|/amp/blog/amp/|HTML only|/blog/html/|Home Sweet Home|/|")
+       b.AssertFileContent("public/amp/index.html", "AMP and HTML|/amp/blog/html-amp/|AMP only|/amp/blog/amp/|HTML only|/blog/html/|Home Sweet Home|/amp/|")
+}
index 693c79f6766278b8bda2190a6d4c7eed3a080d51..4952250933ac6f6952dba3122c3e6d626bd83a38 100644 (file)
@@ -1416,7 +1416,8 @@ func (s *Site) getMenusFromConfig() navigation.Menus {
                                        }
 
                                        menuEntry.MarshallMap(ime)
-                                       menuEntry.URL = s.Info.createNodeMenuEntryURL(menuEntry.URL)
+                                       // TODO(bep) clean up all of this
+                                       menuEntry.ConfiguredURL = s.Info.createNodeMenuEntryURL(menuEntry.ConfiguredURL)
 
                                        if ret[name] == nil {
                                                ret[name] = navigation.Menu{}
@@ -1477,7 +1478,7 @@ func (s *Site) assembleMenus() {
                                me := navigation.MenuEntry{Identifier: id,
                                        Name:   p.LinkTitle(),
                                        Weight: p.Weight(),
-                                       URL:    p.RelPermalink()}
+                                       Page:   p}
                                flat[twoD{sectionPagesMenu, me.KeyName()}] = &me
                        }
                }
@@ -1506,7 +1507,7 @@ func (s *Site) assembleMenus() {
                _, ok := flat[twoD{p.MenuName, p.EntryName}]
                if !ok {
                        // if parent does not exist, create one without a URL
-                       flat[twoD{p.MenuName, p.EntryName}] = &navigation.MenuEntry{Name: p.EntryName, URL: ""}
+                       flat[twoD{p.MenuName, p.EntryName}] = &navigation.MenuEntry{Name: p.EntryName}
                }
                flat[twoD{p.MenuName, p.EntryName}].Children = childmenu
        }
index 66721ea8a60c9757a575b2ee73447c7be4d98174..47d40a3c79b4b328e48504309fa48221a0d8234d 100644 (file)
@@ -14,6 +14,8 @@
 package navigation
 
 import (
+       "github.com/gohugoio/hugo/common/types"
+
        "html/template"
        "sort"
        "strings"
@@ -24,17 +26,29 @@ import (
 // MenuEntry represents a menu item defined in either Page front matter
 // or in the site config.
 type MenuEntry struct {
-       URL        string
-       Page       Page
-       Name       string
-       Menu       string
-       Identifier string
-       title      string
-       Pre        template.HTML
-       Post       template.HTML
-       Weight     int
-       Parent     string
-       Children   Menu
+       ConfiguredURL string // The URL value from front matter / config.
+       Page          Page
+       Name          string
+       Menu          string
+       Identifier    string
+       title         string
+       Pre           template.HTML
+       Post          template.HTML
+       Weight        int
+       Parent        string
+       Children      Menu
+}
+
+func (m *MenuEntry) URL() string {
+       if m.ConfiguredURL != "" {
+               return m.ConfiguredURL
+       }
+
+       if !types.IsNil(m.Page) {
+               return m.Page.RelPermalink()
+       }
+
+       return ""
 }
 
 // A narrow version of page.Page.
@@ -72,8 +86,8 @@ func (m *MenuEntry) KeyName() string {
 func (m *MenuEntry) hopefullyUniqueID() string {
        if m.Identifier != "" {
                return m.Identifier
-       } else if m.URL != "" {
-               return m.URL
+       } else if m.URL() != "" {
+               return m.URL()
        } else {
                return m.Name
        }
@@ -87,7 +101,8 @@ func (m *MenuEntry) IsEqual(inme *MenuEntry) bool {
 // IsSameResource returns whether the two menu entries points to the same
 // resource (URL).
 func (m *MenuEntry) IsSameResource(inme *MenuEntry) bool {
-       return m.URL != "" && inme.URL != "" && m.URL == inme.URL
+       murl, inmeurl := m.URL(), inme.URL()
+       return murl != "" && inmeurl != "" && murl == inmeurl
 }
 
 func (m *MenuEntry) MarshallMap(ime map[string]interface{}) {
@@ -95,7 +110,7 @@ func (m *MenuEntry) MarshallMap(ime map[string]interface{}) {
                loki := strings.ToLower(k)
                switch loki {
                case "url":
-                       m.URL = cast.ToString(v)
+                       m.ConfiguredURL = cast.ToString(v)
                case "weight":
                        m.Weight = cast.ToInt(v)
                case "name":
index c0d809ee3d7a9a958d5ad1b89cfb087a12f9d282..4d2c457675f6b1f913411b0a163096ea039062a8 100644 (file)
@@ -50,9 +50,7 @@ func PageMenusFromPage(p Page) (PageMenus, error) {
                return nil, nil
        }
 
-       link := p.RelPermalink()
-
-       me := MenuEntry{Page: p, Name: p.LinkTitle(), Weight: p.Weight(), URL: link}
+       me := MenuEntry{Page: p, Name: p.LinkTitle(), Weight: p.Weight()}
 
        // Could be the name of the menu to attach it to
        mname, err := cast.ToStringE(ms)
@@ -81,7 +79,7 @@ func PageMenusFromPage(p Page) (PageMenus, error) {
        }
 
        for name, menu := range menus {
-               menuEntry := MenuEntry{Page: p, Name: p.LinkTitle(), URL: link, Weight: p.Weight(), Menu: name}
+               menuEntry := MenuEntry{Page: p, Name: p.LinkTitle(), Weight: p.Weight(), Menu: name}
                if menu != nil {
                        ime, err := cast.ToStringMapE(menu)
                        if err != nil {
@@ -153,7 +151,7 @@ func (pm *pageMenus) HasMenuCurrent(menuID string, me *MenuEntry) bool {
 
        // The following logic is kept from back when Hugo had both Page and Node types.
        // TODO(bep) consolidate / clean
-       nme := MenuEntry{Page: pm.p, Name: pm.p.LinkTitle(), URL: pm.p.RelPermalink()}
+       nme := MenuEntry{Page: pm.p, Name: pm.p.LinkTitle()}
 
        for _, child := range me.Children {
                if nme.IsSameResource(child) {
@@ -183,7 +181,7 @@ func (pm *pageMenus) IsMenuCurrent(menuID string, inme *MenuEntry) bool {
 
        // The following logic is kept from back when Hugo had both Page and Node types.
        // TODO(bep) consolidate / clean
-       me := MenuEntry{Page: pm.p, Name: pm.p.LinkTitle(), URL: pm.p.RelPermalink()}
+       me := MenuEntry{Page: pm.p, Name: pm.p.LinkTitle()}
 
        if !me.IsSameResource(inme) {
                return false