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:
| Property | Type | Description |
|---|---|---|
posts.found_posts | int | Total items across all pages |
posts.pagination | object | Renders as HTML, or access sub-properties |
posts.pagination.prev | object or '' | Previous page |
posts.pagination.next | object or '' | Next page |
posts.pagination.pages | array | Page objects to display |
posts.pagination.current | int | Current page number |
posts.pagination.total | int | Total number of pages |
Page object
Each item in pagination.pages:
| Property | Type | Description |
|---|---|---|
page.link | string | URL to the page |
page.title | string | Page number, or … |
page.name | string | Page number |
page.class | string | CSS classes |
page.current | bool | True 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 }}
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