diff --git a/docs/content/en/content-management/urls.md b/docs/content/en/content-management/urls.md index f498d02ea..774bd9a58 100644 --- a/docs/content/en/content-management/urls.md +++ b/docs/content/en/content-management/urls.md @@ -91,6 +91,9 @@ The following is a list of values that can be used in a `permalink` definition i `:slug` : the content's slug (or title if no slug is provided in the front matter) +`:slugorfilename` +: the content's slug (or filename if no slug is provided in the front matter) + `:filename` : the content's filename (without extension) diff --git a/resources/page/permalinks.go b/resources/page/permalinks.go index cd9c1dc15..c31d22a3c 100644 --- a/resources/page/permalinks.go +++ b/resources/page/permalinks.go @@ -72,18 +72,19 @@ func NewPermalinkExpander(ps *helpers.PathSpec) (PermalinkExpander, error) { p := PermalinkExpander{ps: ps} p.knownPermalinkAttributes = map[string]pageToPermaAttribute{ - "year": p.pageToPermalinkDate, - "month": p.pageToPermalinkDate, - "monthname": p.pageToPermalinkDate, - "day": p.pageToPermalinkDate, - "weekday": p.pageToPermalinkDate, - "weekdayname": p.pageToPermalinkDate, - "yearday": p.pageToPermalinkDate, - "section": p.pageToPermalinkSection, - "sections": p.pageToPermalinkSections, - "title": p.pageToPermalinkTitle, - "slug": p.pageToPermalinkSlugElseTitle, - "filename": p.pageToPermalinkFilename, + "year": p.pageToPermalinkDate, + "month": p.pageToPermalinkDate, + "monthname": p.pageToPermalinkDate, + "day": p.pageToPermalinkDate, + "weekday": p.pageToPermalinkDate, + "weekdayname": p.pageToPermalinkDate, + "yearday": p.pageToPermalinkDate, + "section": p.pageToPermalinkSection, + "sections": p.pageToPermalinkSections, + "title": p.pageToPermalinkTitle, + "slug": p.pageToPermalinkSlugElseTitle, + "slugorfilename": p.pageToPermalinkSlugElseFilename, + "filename": p.pageToPermalinkFilename, } patterns := ps.Cfg.GetStringMapString("permalinks") @@ -266,6 +267,14 @@ func (l PermalinkExpander) pageToPermalinkSlugElseTitle(p Page, a string) (strin return l.pageToPermalinkTitle(p, a) } +// if the page has a slug, return the slug, else return the filename +func (l PermalinkExpander) pageToPermalinkSlugElseFilename(p Page, a string) (string, error) { + if p.Slug() != "" { + return l.ps.URLize(p.Slug()), nil + } + return l.pageToPermalinkFilename(p, a) +} + func (l PermalinkExpander) pageToPermalinkSection(p Page, _ string) (string, error) { return p.Section(), nil } diff --git a/resources/page/permalinks_test.go b/resources/page/permalinks_test.go index ca106c236..7baf16503 100644 --- a/resources/page/permalinks_test.go +++ b/resources/page/permalinks_test.go @@ -36,6 +36,7 @@ var testdataPermalinks = []struct { {"/:section/", true, "/blue/"}, // Section {"/:title/", true, "/spf13-vim-3.0-release-and-new-website/"}, // Title {"/:slug/", true, "/the-slug/"}, // Slug + {"/:slugorfilename/", true, "/the-slug/"}, // Slug or filename {"/:filename/", true, "/test-page/"}, // Filename {"/:06-:1-:2-:Monday", true, "/12-4-6-Friday"}, // Dates with Go formatting {"/:2006_01_02_15_04_05.000", true, "/2012_04_06_03_01_59.000"}, // Complicated custom date format @@ -102,9 +103,13 @@ func TestPermalinkExpansionMultiSection(t *testing.T) { page.section = "blue" page.slug = "The Slug" + page_slug_fallback := newTestPageWithFile("/page-filename/index.md") + page_slug_fallback.title = "Page Title" + permalinksConfig := map[string]string{ - "posts": "/:slug", - "blog": "/:section/:year", + "posts": "/:slug", + "blog": "/:section/:year", + "recipes": "/:slugorfilename", } ps := newTestPathSpec() @@ -120,6 +125,14 @@ func TestPermalinkExpansionMultiSection(t *testing.T) { expanded, err = expander.Expand("blog", page) c.Assert(err, qt.IsNil) c.Assert(expanded, qt.Equals, "/blue/2012") + + expanded, err = expander.Expand("posts", page_slug_fallback) + c.Assert(err, qt.IsNil) + c.Assert(expanded, qt.Equals, "/page-title") + + expanded, err = expander.Expand("recipes", page_slug_fallback) + c.Assert(err, qt.IsNil) + c.Assert(expanded, qt.Equals, "/page-filename") } func TestPermalinkExpansionConcurrent(t *testing.T) {