Skip to main content

Pagination

This page shows you how to add pagination to your loops.

How it works​

Set a query name in the Loop block's sidebar (e.g. posts). This makes the query results available by name — including pagination — outside the loop.

Simple output​

Output fully functional pagination with a single expression:

{{ posts.pagination }}

This renders prev/next links and page numbers using WordPress's paginate_links() — no extra markup needed. Place it after the loop: the query name only exists once the loop has rendered. Before it, the name gives nothing, except posts, which is then the page's main query. For pagination before the loop, see Before the loop.

A named query reads its page from the URL: ?products-page=2 for a query named products, so several paginated loops can share a page.

With options​

Pass arguments to customize the output:

{{ posts.pagination({'mid_size': 1, 'end_size': 2}) }}
{{ posts.pagination({'show_all': true}) }}
{{ posts.pagination({'prev_text': '←', 'next_text': '→'}) }}

These are paginate_links() arguments — any option it accepts works here.

Query properties​

These are available on any named query result:

PropertyTypeDescription
posts.found_postsintTotal items across all pages
posts.paginationobjectRenders as HTML, or access sub-properties
posts.pagination.prevobject or ''Previous page
posts.pagination.nextobject or ''Next page
posts.pagination.pagesarrayPage objects to display
posts.pagination.currentintCurrent page number
posts.pagination.totalintTotal number of pages

Page object​

Each item in pagination.pages:

PropertyTypeDescription
page.linkstringURL to the page
page.titlestringPage number, or …
page.namestringPage number
page.classstringCSS classes
page.currentboolTrue if this is the current page

pages holds the pages around the current one, the first and last pages, and a gap entry (…, class dots) where pages are skipped; show_all, mid_size and end_size set which, as in paginate_links(). The current page and the gaps have no link. prev is '' on the first page, next on the last.

Before the loop​

If you need pagination or a total count before the loop, use a Variable block with the Query source:

{% set myquery = get_posts() %}

<p>{{ myquery.found_posts }} posts</p>
{{ myquery.pagination }}

{% for post in myquery %}
<h2>{{ post.title }}</h2>
{% endfor %}

Custom pagination​

Loop over pagination.pages for full control over the markup:

<nav class="pagination">
{% if posts.pagination.prev %}
<a href="{{ posts.pagination.prev.link }}">Previous</a>
{% endif %}

{% for page in posts.pagination.pages %}
{% if page.link %}
<a href="{{ page.link }}">{{ page.title }}</a>
{% endif %}
{% if not page.link %}
<span class="{{ page.class }}">{{ page.title }}</span>
{% endif %}
{% endfor %}

{% if posts.pagination.next %}
<a href="{{ posts.pagination.next.link }}">Next</a>
{% endif %}
</nav>

Main query pagination​

For archives and search results using Inherit Query, use the posts variable directly:

<h1>Archive ({{ posts.found_posts }} posts)</h1>

{% for post in posts %}
<h2>{{ post.title }}</h2>
{% endfor %}

{{ posts.pagination }}
Common mistake

A Variable block is only needed when you want pagination before the loop. If pagination comes after, assign a query name in the Loop block and reference it directly — no Variable block required.

Next steps​

  • Loop — loop concept and data sources
  • Query Posts — all query arguments for posts and custom post types
  • Variable block — store queries for reuse