aboutsummaryrefslogtreecommitdiffhomepage
path: root/resources
diff options
context:
space:
mode:
authorn1xx1 <[email protected]>2024-08-01 12:14:29 +0200
committerGitHub <[email protected]>2024-08-01 12:14:29 +0200
commit566fe7ba12e7ecabadffa9ec76b319d04063c78b (patch)
tree227ffdfe6d1cb203f87f2930b9d892adb243805c /resources
parent92573012e83bf8d71a247027d2f7f7f43a9c42b7 (diff)
downloadhugo-566fe7ba12e7ecabadffa9ec76b319d04063c78b.tar.gz
hugo-566fe7ba12e7ecabadffa9ec76b319d04063c78b.zip
resources/page: Expand parmalinks tokens in `url`
This change allows to use permalink tokens in url front matter fields. This should be useful to target more specific pages instead of using a global permalink configuration. It's expected to be used with cascade. Fixes #9714
Diffstat (limited to 'resources')
-rw-r--r--resources/page/permalinks.go44
-rw-r--r--resources/page/permalinks_integration_test.go39
2 files changed, 72 insertions, 11 deletions
diff --git a/resources/page/permalinks.go b/resources/page/permalinks.go
index 67c63c4b2..05911f0ea 100644
--- a/resources/page/permalinks.go
+++ b/resources/page/permalinks.go
@@ -40,6 +40,8 @@ type PermalinkExpander struct {
expanders map[string]map[string]func(Page) (string, error)
urlize func(uri string) string
+
+ patternCache *maps.Cache[string, func(Page) (string, error)]
}
// Time for checking date formats. Every field is different than the
@@ -71,7 +73,10 @@ func (p PermalinkExpander) callback(attr string) (pageToPermaAttribute, bool) {
// NewPermalinkExpander creates a new PermalinkExpander configured by the given
// urlize func.
func NewPermalinkExpander(urlize func(uri string) string, patterns map[string]map[string]string) (PermalinkExpander, error) {
- p := PermalinkExpander{urlize: urlize}
+ p := PermalinkExpander{
+ urlize: urlize,
+ patternCache: maps.NewCache[string, func(Page) (string, error)](),
+ }
p.knownPermalinkAttributes = map[string]pageToPermaAttribute{
"year": p.pageToPermalinkDate,
@@ -102,6 +107,16 @@ func NewPermalinkExpander(urlize func(uri string) string, patterns map[string]ma
return p, nil
}
+// ExpandPattern expands the path in p with the specified expand pattern.
+func (l PermalinkExpander) ExpandPattern(pattern string, p Page) (string, error) {
+ expander, err := l.getOrParsePattern(pattern)
+ if err != nil {
+ return "", err
+ }
+
+ return expander(p)
+}
+
// Expand expands the path in p according to the rules defined for the given key.
// If no rules are found for the given key, an empty string is returned.
func (l PermalinkExpander) Expand(key string, p Page) (string, error) {
@@ -129,17 +144,11 @@ func init() {
}
}
-func (l PermalinkExpander) parse(patterns map[string]string) (map[string]func(Page) (string, error), error) {
- expanders := make(map[string]func(Page) (string, error))
-
- for k, pattern := range patterns {
- k = strings.Trim(k, sectionCutSet)
-
+func (l PermalinkExpander) getOrParsePattern(pattern string) (func(Page) (string, error), error) {
+ return l.patternCache.GetOrCreate(pattern, func() (func(Page) (string, error), error) {
if !l.validate(pattern) {
return nil, &permalinkExpandError{pattern: pattern, err: errPermalinkIllFormed}
}
-
- pattern := pattern
matches := attributeRegexp.FindAllStringSubmatch(pattern, -1)
callbacks := make([]pageToPermaAttribute, len(matches))
@@ -157,7 +166,7 @@ func (l PermalinkExpander) parse(patterns map[string]string) (map[string]func(Pa
callbacks[i] = callback
}
- expanders[k] = func(p Page) (string, error) {
+ return func(p Page) (string, error) {
if matches == nil {
return pattern, nil
}
@@ -173,12 +182,25 @@ func (l PermalinkExpander) parse(patterns map[string]string) (map[string]func(Pa
}
newField = strings.Replace(newField, replacement, newAttr, 1)
-
}
return newField, nil
+ }, nil
+ })
+}
+
+func (l PermalinkExpander) parse(patterns map[string]string) (map[string]func(Page) (string, error), error) {
+ expanders := make(map[string]func(Page) (string, error))
+
+ for k, pattern := range patterns {
+ k = strings.Trim(k, sectionCutSet)
+
+ expander, err := l.getOrParsePattern(pattern)
+ if err != nil {
+ return nil, err
}
+ expanders[k] = expander
}
return expanders, nil
diff --git a/resources/page/permalinks_integration_test.go b/resources/page/permalinks_integration_test.go
index 9a76ac602..2b9e878b1 100644
--- a/resources/page/permalinks_integration_test.go
+++ b/resources/page/permalinks_integration_test.go
@@ -193,3 +193,42 @@ List.
b.AssertFileContent("public/libros/fiction/index.html", "List.")
b.AssertFileContent("public/libros/fiction/2023/book1/index.html", "Single.")
}
+
+func TestPermalinksUrlCascade(t *testing.T) {
+ t.Parallel()
+
+ files := `
+-- layouts/_default/list.html --
+List|{{ .Kind }}|{{ .RelPermalink }}|
+-- layouts/_default/single.html --
+Single|{{ .Kind }}|{{ .RelPermalink }}|
+-- hugo.toml --
+-- content/cooking/delicious-recipes/_index.md --
+---
+url: /delicious-recipe/
+cascade:
+ url: /delicious-recipe/:slug/
+---
+-- content/cooking/delicious-recipes/example1.md --
+---
+title: Recipe 1
+---
+-- content/cooking/delicious-recipes/example2.md --
+---
+title: Recipe 2
+slug: custom-recipe-2
+---
+`
+ b := hugolib.NewIntegrationTestBuilder(
+ hugolib.IntegrationTestConfig{
+ T: t,
+ TxtarString: files,
+ LogLevel: logg.LevelWarn,
+ }).Build()
+
+ t.Log(b.LogString())
+ b.Assert(b.H.Log.LoggCount(logg.LevelWarn), qt.Equals, 0)
+ b.AssertFileContent("public/delicious-recipe/index.html", "List|section|/delicious-recipe/")
+ b.AssertFileContent("public/delicious-recipe/recipe-1/index.html", "Single|page|/delicious-recipe/recipe-1/")
+ b.AssertFileContent("public/delicious-recipe/custom-recipe-2/index.html", "Single|page|/delicious-recipe/custom-recipe-2/")
+}