From a77548830407851d3a8d24085a7f5dc131ca886e Mon Sep 17 00:00:00 2001 From: =?utf8?q?Bj=C3=B8rn=20Erik=20Pedersen?= Date: Sun, 11 Jan 2026 15:30:33 +0100 Subject: [PATCH] Fix some default site redirect woes * The fix for #14357 yesterday sadly had the assumption that default language/version/role always was the first site in the sites matrix. This is common, but not always true. * Also, that fix forgot to add a redirect the other way when `defaultContentLanguageInSubdir` was disabled, e.g. from `/en/` to `/`. * This commit also renames config option `DisableDefaultDimensionRedirect` to `DisableDefaultSiteRedirect`. This is stricly a breaking change, but it's only been out for a day, and the old name didn't make much sense. Fixes #14361 --- .prettierignore | 1 + config/allconfig/allconfig.go | 7 +-- hugolib/site.go | 10 +++- hugolib/site_render.go | 35 ++++++++----- .../sitematrix_integration_test.go | 52 +++++++++++++++++-- tpl/tplimpl/embedded/templates/alias.html | 2 +- 6 files changed, 85 insertions(+), 22 deletions(-) create mode 100644 .prettierignore diff --git a/.prettierignore b/.prettierignore new file mode 100644 index 000000000..838f027a0 --- /dev/null +++ b/.prettierignore @@ -0,0 +1 @@ +tpl/tplimpl/embedded/templates/** \ No newline at end of file diff --git a/config/allconfig/allconfig.go b/config/allconfig/allconfig.go index 01be23fc6..118f57d69 100644 --- a/config/allconfig/allconfig.go +++ b/config/allconfig/allconfig.go @@ -607,12 +607,13 @@ type RootConfig struct { DefaultOutputFormat string // Disable generation of redirect to the default language when DefaultContentLanguageInSubdir is enabled. - // Note that this currently is an alias for DisableDefaultDimensionRedirect introduced in v0.154.4. + // Note that this currently is an alias for DisableDefaultSiteRedirect introduced in v0.154.5. // It's not obvious how a more fine grained setup would work. DisableDefaultLanguageRedirect bool - // Disable generation of redirect to the default dimension when DefaultContentRoleInSubdir or DefaultContentVersionInSubdir or DefaultContentLanguageInSubdir is enabled. - DisableDefaultDimensionRedirect bool + // Disable generation of redirects to the default site when DefaultContentRoleInSubdir or DefaultContentVersionInSubdir or DefaultContentLanguageInSubdir is enabled. + // The default site is the site is the combination of defaultContentLanguage, defaultContentVersion and defaultContentRole. + DisableDefaultSiteRedirect bool // Disable creation of alias redirect pages. DisableAliases bool diff --git a/hugolib/site.go b/hugolib/site.go index 6dbe307bf..849d48dcc 100644 --- a/hugolib/site.go +++ b/hugolib/site.go @@ -138,7 +138,8 @@ func (s *Site) resolveDimensionNames() types.Strings3 { } type siteLanguageVersionRole struct { - siteVector sitesmatrix.Vector + siteVector sitesmatrix.Vector + isDefaultLanguage bool roleInternal roles.RoleInternal role roles.Role @@ -186,6 +187,10 @@ func (s siteLanguageVersionRole) Version() versions.Version { return s.version } +func (s siteLanguageVersionRole) isDefault() bool { + return s.isDefaultLanguage && s.roleInternal.Default && s.versionInternal.Default +} + func (s *Site) Debug() { fmt.Println("Debugging site", s.Lang(), "=>") // fmt.Println(s.pageMap.testDump()) @@ -341,7 +346,8 @@ func NewHugoSites(cfg deps.DepsCfg) (*HugoSites, error) { frontmatterHandler: frontmatterHandler, store: hstore.NewScratch(), siteLanguageVersionRole: &siteLanguageVersionRole{ - siteVector: sitesmatrix.Vector{i, 0, 0}, + isDefaultLanguage: language.IsDefault(), + siteVector: sitesmatrix.Vector{i, 0, 0}, }, } diff --git a/hugolib/site_render.go b/hugolib/site_render.go index 45f24a624..0edb56329 100644 --- a/hugolib/site_render.go +++ b/hugolib/site_render.go @@ -203,8 +203,8 @@ func pageRenderer( } } - if p.IsHome() && p.outputFormat().IsHTML && s.siteVector.IsFirst() { - if err = s.renderDefaultDimensionRedirect(p); err != nil { + if p.IsHome() && p.outputFormat().IsHTML && s.isDefault() { + if err = s.renderDefaultSiteRedirect(p); err != nil { if sendErr(err) { continue } else { @@ -368,18 +368,17 @@ func (s *Site) renderAliases() error { return w.Walk(context.TODO()) } -// renderDefaultDimensionRedirect creates a redirect to the main dimension's home, +// renderDefaultSiteRedirect creates a redirect to the default site's home, // depending on if it lives in sub folder (e.g. /en) or not. -func (s *Site) renderDefaultDimensionRedirect(home *pageState) error { - if s.conf.DisableDefaultLanguageRedirect || s.conf.DisableDefaultDimensionRedirect { +// The default site is the site is the combination of defaultContentLanguage, +// defaultContentVersion and defaultContentRole. +func (s *Site) renderDefaultSiteRedirect(home *pageState) error { + if s.conf.DisableDefaultLanguageRedirect || s.conf.DisableDefaultSiteRedirect { return nil } - shouldAdd := s.conf.DefaultContentLanguageInSubdir && !s.Conf.IsMultihost() - shouldAdd = shouldAdd || s.conf.DefaultContentVersionInSubdir || s.conf.DefaultContentRoleInSubdir - if !shouldAdd { - return nil - } + addRedirectInRoot := s.conf.DefaultContentLanguageInSubdir && !s.Conf.IsMultihost() + addRedirectInRoot = addRedirectInRoot || s.conf.DefaultContentVersionInSubdir || s.conf.DefaultContentRoleInSubdir homeLink := home.pageOutput.targetPaths().Link // This doesn't have any baseURL paths in it. @@ -388,10 +387,20 @@ func (s *Site) renderDefaultDimensionRedirect(home *pageState) error { var ps []string if of.Path != "" { - // For OutputFormats with a path, creating more than one alias will easily create path clashes without much value. - ps = []string{paths.AddLeadingAndTrailingSlash(of.Path)} + if addRedirectInRoot { + // For OutputFormats with a path, creating more than one alias will easily create path clashes without much value. + ps = []string{paths.AddLeadingAndTrailingSlash(of.Path)} + } } else { - ps = []string{"/"} + if addRedirectInRoot { + ps = append(ps, "/") + } + + if s.Conf.IsMultilingual() && !s.conf.DefaultContentLanguageInSubdir && !s.Conf.IsMultihost() { + // Create redirect from e.g. /en => / + ps = append(ps, homeLink+s.Lang()+"/") + } + // /guest/v1.0.0/en/ // /,/guest/,/guest/v1.0.0 = /guest/v1.0.0/en/ // /guest/v1.0.0/ diff --git a/hugolib/sitesmatrix/sitematrix_integration_test.go b/hugolib/sitesmatrix/sitematrix_integration_test.go index c7b6a237e..60a3e8a11 100644 --- a/hugolib/sitesmatrix/sitematrix_integration_test.go +++ b/hugolib/sitesmatrix/sitematrix_integration_test.go @@ -1281,8 +1281,23 @@ defaultContentLanguageInSubDir = true defaultContentVersionInSubDir = true defaultContentRoleInSubDir = true disableDefaultLanguageRedirect = false -disableDefaultDimensionRedirect = false +disableDefaultSiteRedirect = false defaultContentLanguage = "en" +defaultContentVersion = "v1.0.0" +defaultContentRole = "guest" +[languages] +[languages.en] +weight = 2 +[languages.nn] +weight = 1 +[versions] +[versions."v1.0.0"] +weight = 2 +[versions."v2.0.0"] +weight = 1 +[roles] +[roles.guest] +[roles.member] [outputs] home = [ 'rss', 'amp', 'html'] -- layouts/home.html -- @@ -1334,7 +1349,7 @@ func TestSitesMatrixRedirectsDisableDefaultLanguageRedirect(t *testing.T) { } runTest(strings.ReplaceAll(files, "disableDefaultLanguageRedirect = false", "disableDefaultLanguageRedirect = true")) - runTest(strings.ReplaceAll(files, "disableDefaultDimensionRedirect = false", "disableDefaultDimensionRedirect = true")) + runTest(strings.ReplaceAll(files, "disableDefaultSiteRedirect = false", "disableDefaultSiteRedirect = true")) } func TestSitesMatrixRedirectsDefaultContentVersionInBase(t *testing.T) { @@ -1361,7 +1376,7 @@ defaultContentLanguageInSubDir = true defaultContentVersionInSubDir = true defaultContentRoleInSubDir = true disableDefaultLanguageRedirect = false -disableDefaultDimensionRedirect = false +disableDefaultSiteRedirect = false defaultContentLanguage = "en" [languages] [languages.en] @@ -1384,3 +1399,34 @@ Home. b.AssertFileContent("public/en/guest/v1.0.0/index.html", "Home.") b.AssertFileContent("public/en/guest/v1.0.0/amp/index.html", "Home.") } + +func TestSitesMatrixRedirectsDefaultContentLanguageInBase(t *testing.T) { + t.Parallel() + + files := ` +-- hugo.yml -- +baseURL: https://example.org +disableKinds: [taxonomy] +defaultContentVersionInSubDir: true +defaultContentRoleInSubDir: true +defaultContentLanguage: en +languages: + en: + languageName: English + bn: + languageName: Bengali + fr: + languageName: French +-- layouts/all.html -- +All. + +` + b := hugolib.Test(t, files) + + b.AssertFileContent("public/guest/v1.0.0/en/index.html", "url=https://example.org/guest/v1.0.0/\"", `lang="en"`) + + files = strings.ReplaceAll(files, "defaultContentVersionInSubDir: true", "defaultContentVersionInSubDir: false") + + b = hugolib.Test(t, files) + b.AssertFileContent("public/guest/en/index.html", "url=https://example.org/guest/\"") +} diff --git a/tpl/tplimpl/embedded/templates/alias.html b/tpl/tplimpl/embedded/templates/alias.html index 4b3ee33eb..9d5db0962 100644 --- a/tpl/tplimpl/embedded/templates/alias.html +++ b/tpl/tplimpl/embedded/templates/alias.html @@ -1,4 +1,4 @@ - + {{ .Permalink }} -- 2.39.5