HUGO

Multiple URLs to page depending on taxonomy (related content different)

Hi,

I’m trying to figure out how I should solve this problem. I’m using Hugo v0.29.

The basic idea is this:
“If visitor accesses a page from a category, I want the URL to be based on that category, so I can show similar pages for that category”.

This does break the idea of non-duplicate content, but, I would then use .Permalink as the link rel="canonical" (ref: hxxps://support.google.com/webmasters/answer/139066?hl=en) to specify that the post, independently of what tag you accessed it from, has one real link that is the correct permalink.

At the same time, I wanted to remove the word categories from the URL, by just having the category directly.

I’ve been able to get to this point:

[permalinks]
category = "/:filename"

(this puts all categories in the root, without the keyword category)

Then I set:

pagecat: "shirts"

In category/shirts/index.md

Then, on the category page, I loop out the pages like this:

		{{ $pagecat := .Params.pagecat }}
		{{ range $name, $taxonomy := .Site.Taxonomies.categories }}
			{{ if eq $name $pagecat }}
				{{ range $taxonomy.Pages }}
				<li><a href="{{ "" | relLangURL }}{{ $name | urlize }}/{{ .Params.Slug }}">{{ .Title }} {{ .Params.Price }}</a></li>
				{{ end }}
			{{ end }}
		{{ end }}

(This is using the technique explained here: hxxps://novelist.xyz/tech/custom-urls-for-category-pages-in-hugo/ )

As you see above, I’m not using the .Permalink, but instead building up the URL myself using the taxonomy name and the .Slug.

However, here’s the problem, I’m not able to regenerate versions for the same page under each taxonomy category so I can loop different items related to that category. I had an idea to hack this using alias.html that was implemented a while ago (hxxps://discourse.gohugo.io/t/customize-alias-page/4242/4) but the problem is that the alias.html-file is not specific to a section, and also it does not seem to be able to access the Page-attributes any more:

alias.html:

Test: {{ .Page.Params.Title }}

Gives:

Error: Error building site: template: alias.html:1:14: executing "alias.html" at <.Page.Params.title>: can't evaluate field Params in type *hugolib.Page

When buildling. Also, it seems like no test is actually verifying that the Page.Params can actually be accessed: https://github.com/gohugoio/hugo/blob/v0.29/hugolib/alias_test.go#L41 so this might actually be a bug that wasn’t spotted by the tests.

If alias.html would work, I could use that one as the non-Permalink-version of the page, having the link rel="canonical" header but the same content as the real page, which would solve this issue. The only problem then would be that the alias.html is not section dependent, but site-wide, but that might be something that would be possible to solve (maybe even I could do it).

So, question:
Is there any good way to solve the problem with different related information on the article, depending on from what taxonomy category you accessed it with by making copies of the page but being rendered for different taxonomies depending on the article? (I rather not fix this with javascript, and duplicate content is not an issue by using the link rel="canonical")

To understand my issue, I’ve attached a test-project (https://www.dropbox.com/s/b5u5iyqm4hdzeaz/test-project.zip?dl=1) that won’t even start due to the alias-error. When removing the {{ .Page.Params.Title }}in alias.html you will get it to build.

Would love to know how others have solved the issue with “different related content for the same article in different categories” before.

(Sorry for the garbled links, but new users wasn’t allowed to post more than two links in a post)

Regards,
Frans

Your post has a lot to unpack, so how about we step back and you explain a little more about the end results. You describe:

I personally don’t know what this looks like. Do you know of a site that does it, or can you describe how this looks with a few pages in an example?

Sorry for the wall of text, @maiki, I’ll try to explain better:

Let’s say I have articles for men and women, some articles will be posted for both, but accessing the article from the women-section, should still only show articles in the women section.

What I want to achieve is basically:

Listing articles for women:

https://example.com/women/

Listing articles for men:

https://example.com/men/

An article posted to both categories should show up as:

https://example.com/women/article1
https://example.com/men/article1

And depending on the category it was generated in, I would be able to loop the same taxonomy for more articles:

(watching the article from /women/article1 would list these ones)
https://example.com/women/article2
https://example.com/women/article3

(in /men/article1 it would list these ones)
https://example.com/men/article4
https://example.com/men/article5

As I mentioned, I would use .Permalink inside link rel=canonical to prevent crawlers to think I had duplicate content. alias.html would solve this, but as mentioned, doesn’t seem to be able to successfully read the .Page.Params of the page it’s redirecting to when customizing the alias-page.

Hope I was more clear this time, sorry for the confusion.

Yeah, that is a bit clearer. I’m sorry to say, I won’t be assisting with this. I don’t think that is how the canonical link element is supposed to be used, and having site infrastructure like that isn’t good for machines or people.

Good luck on figuring out the alias.html parameters issue. Since you already have that template created, maybe add {{ printf "%#v" . }} to it, via template debugging. :slight_smile:

Thanks, no worries, I understand it’s a bit of a weird pattern, however, the idea was basically to be able to present content differently in different sections, even though the original content was the same.

The debugging actually says the Page-parameter is in the alias-template, but Hugo won’t compile if you refer to any properties of it:

Thanks anyway for a quick reply :slight_smile:

I’ve never had a reason to change the alias template, and I doubt many others have either, so the way it works could have changes and no one would notice. That is a little out of my league, so maybe someone that knows that can assist.

But sorry, why are you creating aliases? Are you removing the meta refresh, and instead generating an entire page at that location?

@fransr
Have you found a solution for this?

I think the basic problem here is the same as trying to have prev/next links keep the select/current taxonomy/tags.

Also, selecting multiple taxonomy terms / tags seems to fall in the same category.

This can be seen on https://themes.gohugo.io/tags/blog/ already: if you select a theme, the prev/next links will just iterate through the themes, and the selected tag is not kept/remembered.

In this case I think ugly URLs (to pass through the current state of selection(s)) or session state would be required.

Yes I did find a solution, but I did it by forking Hugo and added some hacks myself. This is what I did:

diff --git a/hugolib/alias.go b/hugolib/alias.go
index a3fe5c24a..6d0cc9b9f 100644
--- a/hugolib/alias.go
+++ b/hugolib/alias.go
@@ -104,6 +104,8 @@ func (s *Site) publishDestAlias(allowRoot bool, path, permalink string, p *Page)
 		return err
 	}
 
+	p.Params["aliaslink"] = path
+
 	aliasContent, err := handler.renderAlias(isXHTML, permalink, p)
 	if err != nil {
 		return err
diff --git a/hugolib/alias.go b/hugolib/alias.go
index 6d0cc9b9f..98c49eedf 100644
--- a/hugolib/alias.go
+++ b/hugolib/alias.go
@@ -111,6 +111,8 @@ func (s *Site) publishDestAlias(allowRoot bool, path, permalink string, p *Page)
 		return err
 	}
 
+	delete(p.Params, "aliaslink")
+
 	return s.publish(targetPath, aliasContent)
 
 }

This gave me the option to use the aliases in the content:

url 		  = "/women/blue-sub"
aliases     = ["/men/power/blue-sub"]

And modify the alias.html-file into actually serving an alternative duplicate of the content, but still being able to provide the canonical for search engines not to treat it as duplicate content. This made it possible for me to maintain the current category:

alias.html

{{/* 
the product switch here is so products can maintain breadcrumbs in different categories.
this also forces you to always use .Page as the parent parameter in product pages since the
alias page only has that param exposed currently.
*/}}
{{ if eq .Page.Params.pagetype "products" }}
  {{ template "products/single.html" . }}
{{ else }}
<!DOCTYPE html><html><head><title>{{ .Permalink }}</title>
<link rel="canonical" href="{{ .Permalink }}"/>
<meta name="robots" content="noindex">
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
<meta http-equiv="refresh" content="0; url={{ .Permalink }}" /></head>
</html>
{{ end }}

And then in the product, using the Scratch-interface:

{{ .Page.Scratch.Set "current_category" .Page.Params.canonicalcat }}
{{ if isset .Page.Params "aliaslink" }}
  {{ $tmp := replaceRE "^/(.*)/[^/]+$" "$1" .Page.Params.aliaslink }}
  {{ .Page.Scratch.Set "current_category" $tmp }}
{{ end }}
{{ $category_url := printf "%s%s/" ("" | relLangURL) ($.Page.Scratch.Get "current_category") }}
{{ $.Page.Scratch.Set "current_category_url" $category_url }}

@fransr I am trying to achieve almost the same expected output as yours, where 2 URLs of a similar page but slightly different with 1 or 2 paragraph. I would like to keep it DRY instead of maintaining 2 different .md files

How did you “fork” the hugo source and add it to your local? What should do – the git commands and etc – to fork the hugo source in my local hugo site? So that I can modify .../hugolib/alias.go and it will use that instead of the actual hugo source

Thank you, looking forward to hearing from you