Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

pagination: Include pager number in pager's Permalink/RelPermalink values #4507

Open
MunifTanjim opened this issue Mar 15, 2018 · 20 comments
Open

Comments

@MunifTanjim
Copy link
Contributor

Example:

In the https://example.com/blog/page/2/ page, the .Permalink is set to https://example.com/blog/.

Shouldn't .Permalink be set to https://example.com/blog/page/2?

Or is this by design?

Use case:

Quoted from Pagination & SEO: best practices:

Google is very clear now: each page within a paginated series should canonicalize to itself, so /page/2/ has a canonical pointing to /page/2/

If the .Permalink is set to https://example.com/blog/page/:number on paginated list templates, using the following code for including link(rel=canonical) tag to the HTML head would follow the best practice by default.

<link rel='canonical' href='{{ .Permalink }}'>

Otherwise, with the current .Permalink implementation, we have to come up with hacks that include checking if it's a list template and then extract the page number from the paginator pages.

@stale
Copy link

stale bot commented Jul 13, 2018

This issue has been automatically marked as stale because it has not had recent activity. The resources of the Hugo team are limited, and so we are asking for your help.
If this is a bug and you can still reproduce this error on the master branch, please reply with all of the information you have about it in order to keep the issue open.
If this is a feature request, and you feel that it is still relevant and valuable, please tell us why.
This issue will automatically be closed in the near future if no further activity occurs. Thank you for all your contributions.

@stale stale bot added the Stale label Jul 13, 2018
@MunifTanjim
Copy link
Contributor Author

Still applicable for Hugo v0.44

@stale stale bot removed the Stale label Jul 17, 2018
@stale
Copy link

stale bot commented Nov 14, 2018

This issue has been automatically marked as stale because it has not had recent activity. The resources of the Hugo team are limited, and so we are asking for your help.
If this is a bug and you can still reproduce this error on the master branch, please reply with all of the information you have about it in order to keep the issue open.
If this is a feature request, and you feel that it is still relevant and valuable, please tell us why.
This issue will automatically be closed in the near future if no further activity occurs. Thank you for all your contributions.

@stale stale bot added the Stale label Nov 14, 2018
@MunifTanjim
Copy link
Contributor Author

Still applicable for Hugo v0.51

@stale stale bot removed the Stale label Nov 14, 2018
@krispkrisp
Copy link

This is very important issue for larger website, since wrong canonical on pagination pages prevents from proper crawling and indexing, which leads to lower organic traffic.

@somethingSTRANGE
Copy link

I was looking for a way to access the permalink for paginated pages when I came across this issue. It would certainly be great to have a .Permalink that matched the generated page URL.

There was a useful article that helped with manually constructing paginated permalinks, but it only worked on a site's homepage and it failed if uglyURLs and/or paginatePath were overridden in the site's config.

The following may be useful to others looking to access a permalink that should mirror the paginated page's URL. I've tested it on paginated taxonomy lists, post/article lists, the home page, and elsewhere, and it seems to always produce the correct permalink.

If you're not using ugly URLs and a modified paginate path, you can use the following:

💡 You only need one reference to .Paginate per template. If you're already using one in your template, you can update the $paginator := .Paginate ... line below to reuse it.

{{ $paginator := .Paginate (where .Site.RegularPages ".Params.post" "!=" false) }}

{{ $permalink := .Permalink }}
{{ with $paginator }}
    {{ if and (or $.IsHome $.IsNode) (ne .PageNumber 1) }}
        {{ $permalink = print $permalink "page/" .PageNumber "/" }}
    {{ end }}
{{ end }}

When uglyURLs and/or paginatePath are overridden, it gets a bit more complex, but it's still pretty straightforward.

❗ It doesn't look like the config settings uglyURLs and paginatePath can be accessed in templates. If you've overridden them there, you'll want to duplicate those in your params file, so that you can access them in templates.

{{ $uglyURLs := $.Param "uglyURLs" | default false }}
{{ $paginatePath := $.Param "paginatePath" | default "page" }}
{{ $paginator := .Paginate (where .Site.RegularPages ".Params.post" "!=" false) }}

{{ $permalink := .Permalink }}
{{ with $paginator }}
    {{ if and (or $.IsHome $.IsNode) (ne .PageNumber 1) }}
        {{ $permalink = print $permalink $paginatePath "/" .PageNumber (cond $uglyURLs ".html" "/") }}
    {{ end }}
{{ end }}

@jmooring
Copy link
Member

jmooring commented Nov 28, 2021

From Google's documentation, last updated 2021-11-22, emphasis in original:

Don't use the first page of a paginated sequence as the canonical page. Instead, give each page in its own canonical URL.

@arif254
Copy link

arif254 commented Mar 12, 2022

@bep web.dev has started to issue a warning for this and penalizing in SEO score. (None of the suggested workarounds I found here and online works).

Document does not have a valid `rel=canonical`

Points to the domain's root URL (the homepage), instead of an equivalent page of content

@tyytytytyiigo
Copy link

This issue has had me scratching my head for days! This, coupled with the fact that Hugo caches the first instance of Paginator or Paginate has really tested my limits. Any plan in store to solve this?

@soul-ride
Copy link

Hopefully this will be resolved in nearest future. According to all SEO guides I found, pagination pages should have self-referring canonicals nowadays.

While there are several articles on workarounds in hugo forum, they are quite hard to implement in some situations.

I ended up disabling canonical header in my theme and using JS for this, as described here - https://developers.google.com/search/docs/crawling-indexing/javascript/javascript-seo-basics#properly-inject-canonical-links

It's also possible to use HTTP headers which maybe even better than JS - https://developers.google.com/search/docs/crawling-indexing/consolidate-duplicate-urls#rel-canonical-header-method

@wu0407
Copy link

wu0407 commented Dec 16, 2023

It also affects the tag og:url

<meta property="og:url" content="{{ .Permalink }}" />

@skrysmanski
Copy link

skrysmanski commented Feb 25, 2024

Just for reference, I used to use this to determine the permalink:

{{- strings.TrimSuffix "/" site.BaseURL -}}{{- .Paginator.URL -}}

Unfortunately, for me, this has unintended side effects like resetting the sorting on the paginator and creating paginated 404 pages. So it's not a real solution. (I am still looking for a solution.)

@tyler-copilot
Copy link

This is still an issue, and it needs to be fixed.

@robrich
Copy link

robrich commented Mar 28, 2024

I found a descent work-around in https://github.com/calintat/minimal/pull/122/files

@saikadaramakaisosjupita
Copy link

Here's the best solution I found in the discourse forum...

    {{- $canonicalURL := .Permalink -}}
    {{- with $paginator -}}
      {{- if gt $paginator.PageNumber 1 }}
        {{- $canonicalURL = .URL | absLangURL -}}
      {{- end }}
    {{- end -}}

But you must ensure that the $paginator value is the same as the one in your templates (home or list) because Hugo caches the first instance of .Paginator or .Paginate. if else can help here too.

@jmooring jmooring changed the title .Permalink doesn't contain the /page/:number part in paginated list templates pagination: Include pager number in pager's Permalink/RelPermalink values May 1, 2024
@jmooring
Copy link
Member

jmooring commented May 1, 2024

Simple example:

git clone --single-branch -b hugo-github-issue-4507 https://github.com/jmooring/hugo-testing hugo-github-issue-4507
cd hugo-github-issue-4507
hugo server

Although .Paginator.URL gives us the value we want, we can't use this at the top of a template (e.g., baseof.html) because it invokes pagination and the result is cached. The only workaround that I know of isn't pretty:

https://discourse.gohugo.io/t/control-pagination-and-page-collections-from-baseof-html/37643/8

In the above, you have to control all pagination from the top of your baseof.html template. That way you can access the .Paginator values later on.

@andreashaerter
Copy link

@somethingSTRANGE This won't work in every case as #2449 introduced multilang support for site.paginatePath (so setting it in a language file is possible):

{{ $uglyURLs := $.Param "uglyURLs" | default false }}
{{ $paginatePath := $.Param "paginatePath" | default "page" }}
{{ $paginator := .Paginate (where .Site.RegularPages ".Params.post" "!=" false) }}

{{ $permalink := .Permalink }}
{{ with $paginator }}
    {{ if and (or $.IsHome $.IsNode) (ne .PageNumber 1) }}
        {{ $permalink = print $permalink $paginatePath "/" .PageNumber (cond $uglyURLs ".html" "/") }}
    {{ end }}
{{ end }}

I therefore quickly hacked a partial which uses regular expressions to get the paginatePath:

{{ $canonicalUrl := "" }}

[...]
  {{ $canonicalUrl = .Permalink }}
  {{ if and .IsNode .Paginator }}
    {{ if gt .Paginator.PageNumber 1 }}
      {{ $paginatePath := (replaceRE `^.+/(.+)/\d(/|.html)$` "$1" .Paginator.URL) }}
      {{ $urlEnding := (replaceRE `^.+/(.+)/\d(/|.html)$` "$2" .Paginator.URL) }}
      {{ if or (and (ne $urlEnding "/") (ne $urlEnding ".html"))
               (eq $paginatePath "")
               (eq $paginatePath .Paginator.URL)
               (eq $paginatePath $canonicalUrl) }}
        {{ errorf "[theme] function/getCanonicalUrl.html: invalid detection of paginatePath (result: %q) or URL ending (result: %q). Please check your Hugo config (paginatePath and/or uglyURLs)." $paginatePath $urlEnding }}
      {{ end }}
      {{ $canonicalUrl = (printf "%s%s/%d%s" $canonicalUrl $paginatePath .Paginator.PageNumber $urlEnding) }}
    {{ end }}
  {{ end }}

[...]

{{ return $canonicalUrl }}

Not really nice, but works...

@jmooring
Copy link
Member

@bep bep added this to the v0.131.0 milestone Jul 30, 2024
@ribtoks
Copy link

ribtoks commented Aug 7, 2024

These workarounds are not generic enough. It should be done in the underlying "framework" (in Hugo) instead.

@bep bep modified the milestones: v0.131.0, v0.133.0 Aug 9, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests