Pages vs Pagers and Pagination

Here is some sample code that ChatGPT insists is correct…

{{ range .Paginator.Pages }}
  <div class="post">
    <h2>{{ .Title }}</h2>
    <!-- Other content of the page -->
    <!-- Display the current page number -->
    <p>Page Number: {{ .PageNumber }}</p>
{{ end }}

But when I test this in list.html (using example project from forum topic 45971), .PageNumber is not valid when I loop using .Paginator.Pages, and .Title is not valid when I loop using Paginator.Pagers. Is there a way to loop so that .PageNumber and .Title are both available?
What exactly is the difference between Pages and Pagers?

You need to keep track of context (i.e., what the dot is).

Should be:

{{ range .Paginator.Pages }}
  <h2><a href="{{ .RelPermalink }}">{{ .LinkTitle }}</a></h2>
  {{ $.Paginator.PageNumber }}
{{ end }}

Thanks, I tried this, but $.Paginator.PageNumber is always 1 even when posts/ contains more than one article. I found a work-around using $.Scratch.Set and $.Scratch.Get to maintain the equivalent of the actual .PageNumber in a .Paginator.Pages loop…

{{ $.Scratch.Set "index" 0 }}
{{ range .Paginator.Pages }}
  {{ $.Scratch.Set "index" (add ($.Scratch.Get "index") 1) }}
  <h1>Page Number is {{ $.Scratch.Get "index" }}</h1>
{{ end }}

On the other hand, looping over .Paginator.Pagers yields .PageNumber that changes as it should.

Why does the paginator ignore the sort order of a collection of pages? Consider…

  {{ $paginator := .Paginate (.Pages.ByTitle) }}
  {{ range $paginator.Pages }}
       <h1>{{ .Title }}</h1><br>
       <h1>{{ .Summary }}</h1><br>
  {{ end }}
  {{ template "_internal/pagination.html" . }}

What happens is the paginator shows pages sorted by creation date (latest first),
not by title.

On the other hand, if the range parameter $paginator.Pages is replaced
with .Pages.ByTitle, all of the pages are displayed sorted by title, but
there is no pagination.

ChatGPT agrees that pagination does not respect the order of collections supplied, and provides a complicated work-around involving the use of Scratch. Perhaps there is a simpler way?

Then both of you are doing it wrong. Pagination was introduced years ago; it is well-tested and widely used.

I suspect you are calling either .Paginate and/or .Paginator twice on the same page. See

If you call .Paginator or .Paginate multiple times on the same page, you should ensure all the calls are identical. Once either .Paginator or .Paginate is called while generating a page, its result is cached, and any subsequent similar call will reuse the cached result. This means that any such calls which do not match the first one will not behave as written.

Regarding page numbers…

Let’s say my content has 27 articles, and that the paginate setting in my site configuration is 10 (the default). When I paginate, I will get 3 pagers. These are the .Paginator properties when viewing the 3rd pager :

.Paginator.NumberOfElements       7
.Paginator.PageNumber             3
.Paginator.Pagers                 [Pager 1 Pager 2 Pager 3]
.Paginator.Pages                  Pages(7)
.Paginator.PageSize               10
.Paginator.TotalNumberOfElements  27
.Paginator.TotalPages             3

All of those values are correct. The .Paginator.PageNumber refers to 1 of the 3 pagers, not 1 of the 27 elements.


Thanks, so I was confused by the fact that the paginator has its own notion of page, which can
contain two or more elements (which I was calling pages because .Pages is the collection).
So “pages” in .Pages are really elements, and “pages” in .Paginator can contain one or more
elements. The trick using .Scratch above is counting elements, not pages.

On possible double use of .Paginator, here is a simple list.html for the example project
from forum topic 45971, after creating content/posts/ with about 10 articles, and with config
setting paginate = 2…

{{ define "main" }}
  {{ template "_internal/pagination.html" . }}
  {{ range .Paginator.Pages.ByTitle }}
       <h1>{{ .Title }}</h1><br>
       <h1>{{ .Summary }}</h1><br>
  {{ end }}
{{ end }}

Bringing up localhost:1313/posts, we get two elements per page,
and there is a paginator at the top. But the pages appear ordered by date (most
recent first), not by title.

I tried the following variation based on the Hugo docs: replace the
range construction with {{ range (.Paginate .Pages.ByTitle).Pages }}.

The result is the same, pages appear in reverse chronological order,
not title order.

In case the line refering to pagination.html is causing the problem, I removed
it. The result is the same, the two most recent articles appear, and there is
no GUI to move to the next page in the paginator.

{{ range (.Paginate .Pages.ByTitle).Pages }}
      <h1>{{ .Title }}</h1><br>
      <h1>{{ .Summary }}</h1><br>
{{ end }}
{{ template "_internal/pagination.html" . }}

You need to sort before you paginate, and you must call the pagination template after you paginate.

If you call the pagination template before, it paginates the .Pages collection as received in context, caching the result.

1 Like

There must be something wrong with my configuration, as I tried many variations,
including this one that was closed in 2021:

In every case the elements are sorted based on date, not title. I modified the
closed solution by setting {{ $sortedPages := .Pages.ByParam "title" }}, and
the pages are clearly sorted before they are paginated. The proposed solution
even gets the index of the element on each page of the pagination.

No, just with your implementation. Try this (it paginates, then displays the pagination nav, then displays the pages sorted by title.

git clone --single-branch -b hugo-forum-topic-46136 hugo-forum-topic-46136
cd hugo-forum-topic-46136
hugo server

If you need additional assistance, please be prepared to share your project repository.

1 Like

Thanks for your patience. The linked code works, but for mysterious reasons to me.
For example, if I use your list.html, but change the range line to
{{ range (.Paginate .Pages.ByTitle).Pages }}, it still works, even though the
variable $paginator is not used. The list is sorted by title as desired.

Now, since $paginator is not used, lets delete the line where it is
defined. The result is the elements are no longer sorted by title, so we
are back to square one. Thus defining $paginator has the side-effect
of making the program work, even though it is not explicitly used.

I’m not sure how to make it any clearer. The example I provided is the way it should be done. Leave it alone.

1 Like

This topic was automatically closed 2 days after the last reply. New replies are no longer allowed.