Objective
Render something like this, from a base template, for each pager of a paginated collection:
<head>
...
<link rel="next" href="/books/page/4/">
<link rel="prev" href="/books/page/2/">
<link rel="canonical" href="https://example.org/books/page/3/">
...
</head>
Challenge
To get the URL of the next, previous, and current pager you must call the Paginator
method on a Page
object, but that also invokes pagination. The result of pagination is cached, so you can’t subsequently change (filter, sort, or group) the page collection in a list template (home, section, taxonomy, or term).
Our goal is to define the page collection and pager size (number of pages per pager) within a list template, but access the paginator from a base template before rendering the list. This sounds paradoxical (chicken/egg), but is easy to implement using Hugo’s base/block construct.
Approach
There are three pieces to this approach:
- The base template
- The list template
- The partial that renders the
link
elements within thehead
element
layouts/_default/baseof.html
<head>
...
{{ block "pagination" . }}{{ end }}
{{ partial "links-next-previous-canonical.html" . }}
...
</head>
layouts/posts/list.html
{{ define "pagination" }}
{{ $pages := .Pages.ByTitle }}
{{ .Store.Set "paginator" (.Paginate $pages 5) }}
{{ end }}
{{ define "main" }}
<h1>{{ .Title }}</h1>
{{ .Content }}
{{ with .Store.Get "paginator" }}
{{ range .Pages }}
<h2><a href="{{ .RelPermalink }}">{{ .LinkTitle }}</a></h2>
{{ end }}
{{ template "_internal/pagination.html" $ }}
{{ else }}
{{ range .Pages }}
<h2><a href="{{ .RelPermalink }}">{{ .LinkTitle }}</a></h2>
{{ end }}
{{ end }}
{{ end }}
If you’re not going to paginate a given list template, do not define a “pagination” block in the above, or leave its contents empty.
layouts/partials/links-next-previous-canonical.html
{{ $href := .Permalink }}
{{ with .Store.Get "paginator" }}
{{ $href = .URL | absURL }}
{{ with .Next }}
<link rel="next" href="{{ .URL }}">
{{ end }}
{{ with .Prev }}
<link rel="prev" href="{{ .URL }}">
{{ end }}
{{ end }}
<link rel="canonical" href="{{ $href }}">
Example
This example contains three list templates: one for a “books” section, one for a “films” section, and one for a “sculptures” section. Two of the list pages are paginated, but each with different settings. The other list page is not paginated.
git clone --single-branch -b hugo-forum-topic-50340 https://github.com/jmooring/hugo-testing hugo-forum-topic-50340
cd hugo-forum-topic-50340
hugo server
Related
This approach addresses this (somewhat) related issue:
https://github.com/gohugoio/hugo/issues/4507