From: Joe Mooring Date: Sat, 17 Jan 2026 09:33:44 +0000 (-0800) Subject: hugolib: Fix relative alias generation X-Git-Url: http://git.maquefel.me/?a=commitdiff_plain;h=32334d098e8ed87d9c3adb5255e0524606c93d68;p=brevno-suite%2Fhugo hugolib: Fix relative alias generation Closes #14381 --- diff --git a/hugolib/alias_test.go b/hugolib/alias_test.go index b7944b597..0fc75523d 100644 --- a/hugolib/alias_test.go +++ b/hugolib/alias_test.go @@ -191,3 +191,194 @@ aliases: b.AssertPublishDir("n/index.html", "yes/index.html", "no/index.html", "yes/index.html") } + +// Issue 14381 +func TestIssue14381(t *testing.T) { + t.Parallel() + + files := ` +-- hugo.toml -- +baseURL = 'https://example.org' +disableKinds = ['home', 'rss', 'sitemap', 'taxonomy', 'term'] + +[outputFormats.print] + isHTML = IS_HTML + mediaType = 'text/html' + path = 'print' + +[outputs] + page = ['html', 'print'] + section = ['html', 'print'] +-- content/foo/s1/_index.md -- +--- +title: s1 +aliases: [s1-alias] +--- +-- content/foo/s1/p1.md -- +--- +title: p1 +aliases: [p1-alias] +--- +-- content/foo/s2/_index.md -- +--- +title: s2 +aliases: [/s2-alias] +--- +-- content/foo/s2/p2.md -- +--- +title: p2 +aliases: [/p2-alias] +--- +-- layouts/all.html -- +{{ .Title }} +` + + // Test 1 + // Expected site structure: + // + // public/ + // ├── foo/ + // │ ├── s1/ + // │ │ ├── p1/ + // │ │ │ └── index.html + // │ │ ├── p1-alias/ + // │ │ │ └── index.html + // │ │ └── index.html + // │ ├── s1-alias/ + // │ │ └── index.html + // │ ├── s2/ + // │ │ ├── p2/ + // │ │ │ └── index.html + // │ │ └── index.html + // │ └── index.html + // ├── p2-alias/ + // │ └── index.html + // ├── print/ + // │ └── foo/ + // │ ├── s1/ + // │ │ ├── p1/ + // │ │ │ └── index.html + // │ │ └── index.html + // │ ├── s2/ + // │ │ ├── p2/ + // │ │ │ └── index.html + // │ │ └── index.html + // │ └── index.html + // └── s2-alias/ + // └── index.html + + f := strings.ReplaceAll(files, "IS_HTML", "false") + b := Test(t, f) + + b.AssertFileContent("public/foo/s1-alias/index.html", + `https://example.org/foo/s1/`, + ``, + ``, + ) + b.AssertFileContent("public/foo/s1/p1-alias/index.html", + `https://example.org/foo/s1/p1/`, + ``, + ``, + ) + b.AssertFileContent("public/s2-alias/index.html", + `https://example.org/foo/s2/`, + ``, + ``, + ) + b.AssertFileContent("public/p2-alias/index.html", + `https://example.org/foo/s2/p2/`, + ``, + ``, + ) + + b.AssertFileExists("public/print/foo/s1-alias/index.html", false) + b.AssertFileExists("public/print/foo/s1/p1-alias/index.html", false) + b.AssertFileExists("public/print/s2-alias/index.html", false) + b.AssertFileExists("public/print/p2-alias/index.html", false) + + // Test 2 + // Expected site structure: + // + // public/ + // ├── foo/ + // │ ├── s1/ + // │ │ ├── p1/ + // │ │ │ └── index.html + // │ │ ├── p1-alias/ + // │ │ │ └── index.html + // │ │ └── index.html + // │ ├── s1-alias/ + // │ │ └── index.html + // │ ├── s2/ + // │ │ ├── p2/ + // │ │ │ └── index.html + // │ │ └── index.html + // │ └── index.html + // ├── p2-alias/ + // │ └── index.html + // ├── print/ + // │ ├── foo/ + // │ │ ├── s1/ + // │ │ │ ├── p1/ + // │ │ │ │ └── index.html + // │ │ │ ├── p1-alias/ + // │ │ │ │ └── index.html + // │ │ │ └── index.html + // │ │ ├── s1-alias/ + // │ │ │ └── index.html + // │ │ ├── s2/ + // │ │ │ ├── p2/ + // │ │ │ │ └── index.html + // │ │ │ └── index.html + // │ │ └── index.html + // │ ├── p2-alias/ + // │ │ └── index.html + // │ └── s2-alias/ + // │ └── index.html + // └── s2-alias/ + // └── index.html + + f = strings.ReplaceAll(files, "IS_HTML", "true") + b = Test(t, f) + + b.AssertFileContent("public/foo/s1-alias/index.html", + `https://example.org/foo/s1/`, + ``, + ``, + ) + b.AssertFileContent("public/foo/s1/p1-alias/index.html", + `https://example.org/foo/s1/p1/`, + ``, + ``, + ) + b.AssertFileContent("public/s2-alias/index.html", + `https://example.org/foo/s2/`, + ``, + ``, + ) + b.AssertFileContent("public/p2-alias/index.html", + `https://example.org/foo/s2/p2/`, + ``, + ``, + ) + b.AssertFileContent("public/print/foo/s1-alias/index.html", + `https://example.org/print/foo/s1/`, + ``, + ``, + ) + b.AssertFileContent("public/print/foo/s1/p1-alias/index.html", + `https://example.org/print/foo/s1/p1/`, + ``, + ``, + ) + b.AssertFileContent("public/print/s2-alias/index.html", + `https://example.org/print/foo/s2/`, + ``, + ``, + ) + b.AssertFileContent("public/print/p2-alias/index.html", + `https://example.org/print/foo/s2/p2/`, + ``, + ``, + ) +} diff --git a/hugolib/site_render.go b/hugolib/site_render.go index 0edb56329..ea16a0498 100644 --- a/hugolib/site_render.go +++ b/hugolib/site_render.go @@ -335,13 +335,15 @@ func (s *Site) renderAliases() error { isRelative := !strings.HasPrefix(a, "/") if isRelative { - // Make alias relative, where "." will be on the - // same directory level as the current page. + // Resolve the alias relative to the current page's + // directory level, prepended by the output format's + // "path" setting, which may be empty. basePath := path.Join(p.targetPaths().SubResourceBaseLink, "..") - a = path.Join(basePath, a) - + a = path.Join(f.Path, basePath, a) } else { - // Make sure AMP and similar doesn't clash with regular aliases. + // Resolve the alias relative to the site root, + // prepended by the output format's "path" setting, + // which may be empty. a = path.Join(f.Path, a) }