diff options
-rw-r--r-- | docs/content/en/content-management/urls.md | 8 | ||||
-rw-r--r-- | hugolib/alias.go | 21 | ||||
-rw-r--r-- | hugolib/alias_test.go | 21 | ||||
-rw-r--r-- | hugolib/page__meta.go | 6 | ||||
-rw-r--r-- | hugolib/site_render.go | 15 | ||||
-rw-r--r-- | hugolib/site_stats_test.go | 2 | ||||
-rw-r--r-- | hugolib/site_url_test.go | 2 |
7 files changed, 46 insertions, 29 deletions
diff --git a/docs/content/en/content-management/urls.md b/docs/content/en/content-management/urls.md index 25bd09165..5ba9e758e 100644 --- a/docs/content/en/content-management/urls.md +++ b/docs/content/en/content-management/urls.md @@ -82,9 +82,13 @@ The following is a list of values that can be used in a `permalink` definition i ## Aliases -For people migrating existing published content to Hugo, there's a good chance you need a mechanism to handle redirecting old URLs. +Aliases can be used to create redirects to your page from other URLs. -Luckily, redirects can be handled easily with **aliases** in Hugo. + +Aliases comes in two forms: + +1. Starting with a `/` meaning they are relative to the `BaseURL`, e.g. `/posts/my-blogpost/` +2. They are relative to the `Page` they're defined in, e.g. `my-blogpost` or even something like `../blog/my-blogpost` (new in Hugo 0.55). ### Example: Aliases diff --git a/hugolib/alias.go b/hugolib/alias.go index 599821c0a..972f7b01c 100644 --- a/hugolib/alias.go +++ b/hugolib/alias.go @@ -18,6 +18,7 @@ import ( "fmt" "html/template" "io" + "path" "path/filepath" "runtime" "strings" @@ -28,8 +29,6 @@ import ( "github.com/gohugoio/hugo/publisher" "github.com/gohugoio/hugo/resources/page" "github.com/gohugoio/hugo/tpl" - - "github.com/gohugoio/hugo/helpers" ) const ( @@ -132,13 +131,14 @@ func (a aliasHandler) targetPathAlias(src string) (string, error) { return "", fmt.Errorf("alias \"\" is an empty string") } - alias := filepath.Clean(src) - components := strings.Split(alias, helpers.FilePathSeparator) + alias := path.Clean(filepath.ToSlash(src)) - if !a.allowRoot && alias == helpers.FilePathSeparator { + if !a.allowRoot && alias == "/" { return "", fmt.Errorf("alias \"%s\" resolves to website root directory", originalAlias) } + components := strings.Split(alias, "/") + // Validate against directory traversal if components[0] == ".." { return "", fmt.Errorf("alias \"%s\" traverses outside the website root directory", originalAlias) @@ -182,15 +182,12 @@ func (a aliasHandler) targetPathAlias(src string) (string, error) { } // Add the final touch - alias = strings.TrimPrefix(alias, helpers.FilePathSeparator) - if strings.HasSuffix(alias, helpers.FilePathSeparator) { + alias = strings.TrimPrefix(alias, "/") + if strings.HasSuffix(alias, "/") { alias = alias + "index.html" } else if !strings.HasSuffix(alias, ".html") { - alias = alias + helpers.FilePathSeparator + "index.html" - } - if originalAlias != alias { - a.log.INFO.Printf("Alias \"%s\" translated to \"%s\"\n", originalAlias, alias) + alias = alias + "/" + "index.html" } - return alias, nil + return filepath.FromSlash(alias), nil } diff --git a/hugolib/alias_test.go b/hugolib/alias_test.go index f968caf23..095ae1be2 100644 --- a/hugolib/alias_test.go +++ b/hugolib/alias_test.go @@ -25,14 +25,14 @@ import ( const pageWithAlias = `--- title: Has Alias -aliases: ["foo/bar/"] +aliases: ["/foo/bar/", "rel"] --- For some moments the old man did not reply. He stood with bowed head, buried in deep thought. But at last he spoke. ` const pageWithAliasMultipleOutputs = `--- title: Has Alias for HTML and AMP -aliases: ["foo/bar/"] +aliases: ["/foo/bar/"] outputs: ["HTML", "AMP", "JSON"] --- For some moments the old man did not reply. He stood with bowed head, buried in deep thought. But at last he spoke. @@ -46,16 +46,17 @@ func TestAlias(t *testing.T) { assert := require.New(t) b := newTestSitesBuilder(t) - b.WithSimpleConfigFile().WithContent("page.md", pageWithAlias) + b.WithSimpleConfigFile().WithContent("blog/page.md", pageWithAlias) b.CreateSites().Build(BuildCfg{}) assert.Equal(1, len(b.H.Sites)) require.Len(t, b.H.Sites[0].RegularPages(), 1) // the real page - b.AssertFileContent("public/page/index.html", "For some moments the old man") - // the alias redirector + b.AssertFileContent("public/blog/page/index.html", "For some moments the old man") + // the alias redirectors b.AssertFileContent("public/foo/bar/index.html", "<meta http-equiv=\"refresh\" content=\"0; ") + b.AssertFileContent("public/blog/rel/index.html", "<meta http-equiv=\"refresh\" content=\"0; ") } func TestAliasMultipleOutputFormats(t *testing.T) { @@ -64,7 +65,7 @@ func TestAliasMultipleOutputFormats(t *testing.T) { assert := require.New(t) b := newTestSitesBuilder(t) - b.WithSimpleConfigFile().WithContent("page.md", pageWithAliasMultipleOutputs) + b.WithSimpleConfigFile().WithContent("blog/page.md", pageWithAliasMultipleOutputs) b.WithTemplates( "_default/single.html", basicTemplate, @@ -74,9 +75,9 @@ func TestAliasMultipleOutputFormats(t *testing.T) { b.CreateSites().Build(BuildCfg{}) // the real pages - b.AssertFileContent("public/page/index.html", "For some moments the old man") - b.AssertFileContent("public/amp/page/index.html", "For some moments the old man") - b.AssertFileContent("public/page/index.json", "For some moments the old man") + b.AssertFileContent("public/blog/page/index.html", "For some moments the old man") + b.AssertFileContent("public/amp/blog/page/index.html", "For some moments the old man") + b.AssertFileContent("public/blog/page/index.json", "For some moments the old man") // the alias redirectors b.AssertFileContent("public/foo/bar/index.html", "<meta http-equiv=\"refresh\" content=\"0; ") @@ -135,7 +136,7 @@ func TestTargetPathHTMLRedirectAlias(t *testing.T) { continue } if err == nil && path != test.expected { - t.Errorf("Expected: \"%s\", got: \"%s\"", test.expected, path) + t.Errorf("Expected: %q, got: %q", test.expected, path) } } } diff --git a/hugolib/page__meta.go b/hugolib/page__meta.go index 9f5f369b3..1e013db66 100644 --- a/hugolib/page__meta.go +++ b/hugolib/page__meta.go @@ -16,6 +16,7 @@ package hugolib import ( "fmt" "path" + "path/filepath" "regexp" "strings" "time" @@ -414,10 +415,11 @@ func (pm *pageMeta) setMetadata(p *pageState, frontmatter map[string]interface{} pm.params[loki] = pm.weight case "aliases": pm.aliases = cast.ToStringSlice(v) - for _, alias := range pm.aliases { + for i, alias := range pm.aliases { if strings.HasPrefix(alias, "http://") || strings.HasPrefix(alias, "https://") { - return fmt.Errorf("only relative aliases are supported, %v provided", alias) + return fmt.Errorf("http* aliases not supported: %q", alias) } + pm.aliases[i] = filepath.ToSlash(alias) } pm.params[loki] = pm.aliases case "sitemap": diff --git a/hugolib/site_render.go b/hugolib/site_render.go index c528e61a8..3c0897d2e 100644 --- a/hugolib/site_render.go +++ b/hugolib/site_render.go @@ -303,7 +303,20 @@ func (s *Site) renderAliases() error { f := of.Format for _, a := range p.Aliases() { - if f.Path != "" { + isRelative := !strings.HasPrefix(a, "/") + + if isRelative { + // Make alias relative, where "." will be on the + // same directory level as the current page. + // TODO(bep) ugly URLs doesn't seem to be supported in + // aliases, I'm not sure why not. + basePath := of.RelPermalink() + if strings.HasSuffix(basePath, "/") { + basePath = path.Join(basePath, "..") + } + a = path.Join(basePath, a) + + } else if f.Path != "" { // Make sure AMP and similar doesn't clash with regular aliases. a = path.Join(f.Path, a) } diff --git a/hugolib/site_stats_test.go b/hugolib/site_stats_test.go index 522b5636b..c722037b4 100644 --- a/hugolib/site_stats_test.go +++ b/hugolib/site_stats_test.go @@ -55,7 +55,7 @@ tags: %s categories: %s -aliases: [Ali%d] +aliases: [/Ali%d] --- # Doc ` diff --git a/hugolib/site_url_test.go b/hugolib/site_url_test.go index 10aa3bb28..9827f994b 100644 --- a/hugolib/site_url_test.go +++ b/hugolib/site_url_test.go @@ -26,7 +26,7 @@ import ( "github.com/stretchr/testify/require" ) -const slugDoc1 = "---\ntitle: slug doc 1\nslug: slug-doc-1\naliases:\n - sd1/foo/\n - sd2\n - sd3/\n - sd4.html\n---\nslug doc 1 content\n" +const slugDoc1 = "---\ntitle: slug doc 1\nslug: slug-doc-1\naliases:\n - /sd1/foo/\n - /sd2\n - /sd3/\n - /sd4.html\n---\nslug doc 1 content\n" const slugDoc2 = `--- title: slug doc 2 |