Fix menu URL when multiple permalinkable output formats

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
This commit is contained in:
Bjørn Erik Pedersen 2019-04-19 09:18:12 +02:00
parent 6c80acbd5e
commit ea529c847e
4 changed files with 105 additions and 32 deletions

View file

@ -92,10 +92,10 @@ Menu Main: {{ partial "menu.html" (dict "page" . "menu" "main") }}`,
th.assertFileContent("public/sect1/p1/index.html", "Single", th.assertFileContent("public/sect1/p1/index.html", "Single",
"Menu Sect: "+ "Menu Sect: "+
"/sect5/|Section Five||10|-|-|"+ "/sect5/|Section Five|Section Five|10|-|-|"+
"/sect1/|Section One||100|-|HasMenuCurrent|"+ "/sect1/|Section One|Section One|100|-|HasMenuCurrent|"+
"/sect2/|Sect2s||0|-|-|"+ "/sect2/|Sect2s|Sect2s|0|-|-|"+
"/sect3/|Sect3s||0|-|-|", "/sect3/|Sect3s|Sect3s|0|-|-|",
"Menu Main: "+ "Menu Main: "+
"/sect3/p5/|p5|atitle5|5|-|-|"+ "/sect3/p5/|p5|atitle5|5|-|-|"+
"/sect2/p4/|p4|atitle4|10|-|-|"+ "/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", th.assertFileContent("public/sect2/p3/index.html", "Single",
"Menu Sect: "+ "Menu Sect: "+
"/sect5/|Section Five||10|-|-|"+ "/sect5/|Section Five|Section Five|10|-|-|"+
"/sect1/|Section One||100|-|-|"+ "/sect1/|Section One|Section One|100|-|-|"+
"/sect2/|Sect2s||0|-|HasMenuCurrent|"+ "/sect2/|Sect2s|Sect2s|0|-|HasMenuCurrent|"+
"/sect3/|Sect3s||0|-|-|") "/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/|")
}

View file

@ -1416,7 +1416,8 @@ func (s *Site) getMenusFromConfig() navigation.Menus {
} }
menuEntry.MarshallMap(ime) 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 { if ret[name] == nil {
ret[name] = navigation.Menu{} ret[name] = navigation.Menu{}
@ -1477,7 +1478,7 @@ func (s *Site) assembleMenus() {
me := navigation.MenuEntry{Identifier: id, me := navigation.MenuEntry{Identifier: id,
Name: p.LinkTitle(), Name: p.LinkTitle(),
Weight: p.Weight(), Weight: p.Weight(),
URL: p.RelPermalink()} Page: p}
flat[twoD{sectionPagesMenu, me.KeyName()}] = &me flat[twoD{sectionPagesMenu, me.KeyName()}] = &me
} }
} }
@ -1506,7 +1507,7 @@ func (s *Site) assembleMenus() {
_, ok := flat[twoD{p.MenuName, p.EntryName}] _, ok := flat[twoD{p.MenuName, p.EntryName}]
if !ok { if !ok {
// if parent does not exist, create one without a URL // 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 flat[twoD{p.MenuName, p.EntryName}].Children = childmenu
} }

View file

@ -14,6 +14,8 @@
package navigation package navigation
import ( import (
"github.com/gohugoio/hugo/common/types"
"html/template" "html/template"
"sort" "sort"
"strings" "strings"
@ -24,17 +26,29 @@ import (
// MenuEntry represents a menu item defined in either Page front matter // MenuEntry represents a menu item defined in either Page front matter
// or in the site config. // or in the site config.
type MenuEntry struct { type MenuEntry struct {
URL string ConfiguredURL string // The URL value from front matter / config.
Page Page Page Page
Name string Name string
Menu string Menu string
Identifier string Identifier string
title string title string
Pre template.HTML Pre template.HTML
Post template.HTML Post template.HTML
Weight int Weight int
Parent string Parent string
Children Menu 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. // A narrow version of page.Page.
@ -72,8 +86,8 @@ func (m *MenuEntry) KeyName() string {
func (m *MenuEntry) hopefullyUniqueID() string { func (m *MenuEntry) hopefullyUniqueID() string {
if m.Identifier != "" { if m.Identifier != "" {
return m.Identifier return m.Identifier
} else if m.URL != "" { } else if m.URL() != "" {
return m.URL return m.URL()
} else { } else {
return m.Name 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 // IsSameResource returns whether the two menu entries points to the same
// resource (URL). // resource (URL).
func (m *MenuEntry) IsSameResource(inme *MenuEntry) bool { 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{}) { func (m *MenuEntry) MarshallMap(ime map[string]interface{}) {
@ -95,7 +110,7 @@ func (m *MenuEntry) MarshallMap(ime map[string]interface{}) {
loki := strings.ToLower(k) loki := strings.ToLower(k)
switch loki { switch loki {
case "url": case "url":
m.URL = cast.ToString(v) m.ConfiguredURL = cast.ToString(v)
case "weight": case "weight":
m.Weight = cast.ToInt(v) m.Weight = cast.ToInt(v)
case "name": case "name":

View file

@ -50,9 +50,7 @@ func PageMenusFromPage(p Page) (PageMenus, error) {
return nil, nil return nil, nil
} }
link := p.RelPermalink() me := MenuEntry{Page: p, Name: p.LinkTitle(), Weight: p.Weight()}
me := MenuEntry{Page: p, Name: p.LinkTitle(), Weight: p.Weight(), URL: link}
// Could be the name of the menu to attach it to // Could be the name of the menu to attach it to
mname, err := cast.ToStringE(ms) mname, err := cast.ToStringE(ms)
@ -81,7 +79,7 @@ func PageMenusFromPage(p Page) (PageMenus, error) {
} }
for name, menu := range menus { 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 { if menu != nil {
ime, err := cast.ToStringMapE(menu) ime, err := cast.ToStringMapE(menu)
if err != nil { 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. // The following logic is kept from back when Hugo had both Page and Node types.
// TODO(bep) consolidate / clean // 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 { for _, child := range me.Children {
if nme.IsSameResource(child) { 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. // The following logic is kept from back when Hugo had both Page and Node types.
// TODO(bep) consolidate / clean // 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) { if !me.IsSameResource(inme) {
return false return false