Skip to content

paginate

paginate splits a supported collection into bounded pages and exposes a paginate object inside the block. It is the preferred way to fetch and render more than the ordinary loop slice.

Syntax

{% paginate collection.products by 24 %}
{% for product in collection.products %}
{{ product.title }}
{% endfor %}
{% endpaginate %}

The page size must be between 1 and 250. Sellerlane clamps a dynamic value into that range. A malformed or unclosed tag is rejected by theme validation.

Supported collections

  • article.comments
  • blog.articles
  • collections
  • collection.products
  • customer.addresses (maximum 20 per page)
  • customer.orders (maximum 20 per page)
  • metaobject_definition.values
  • pages
  • product.variants
  • search.results
  • pageable list settings documented by their setting type

Default navigation

{% paginate collection.products by 24 %}
<div class="product-grid">
{% for product in collection.products %}
{% render 'product-card', product: product %}
{% endfor %}
</div>
{{ paginate | default_pagination }}
{% endpaginate %}

Example output on page 2:

<span class="prev"><a href="?page=1" title="">&laquo; Previous</a></span>
<span class="page"><a href="?page=1" title="">1</a></span>
<span class="page current">2</span>
<span class="page"><a href="?page=3" title="">3</a></span>
<span class="next"><a href="?page=3" title="">Next &raquo;</a></span>

Existing safe filter, search, sort, and locale state is retained in generated links. Only the current paginator’s page parameter changes.

Custom accessible navigation

{% paginate blog.articles by 12, window_size: 5 %}
{% for article in blog.articles %}
<a href="{{ article.url }}">{{ article.title }}</a>
{% endfor %}
{% if paginate.pages > 1 %}
<nav aria-label="Blog pages">
{% if paginate.previous %}
<a href="{{ paginate.previous.url }}">Previous</a>
{% endif %}
{% for part in paginate.parts %}
{% if part.is_link %}
<a href="{{ part.url }}">{{ part.title }}</a>
{% else %}
<span aria-current="page">{{ part.title }}</span>
{% endif %}
{% endfor %}
{% if paginate.next %}
<a href="{{ paginate.next.url }}">Next</a>
{% endif %}
</nav>
{% endif %}
{% endpaginate %}

window_size must be a positive finite number. The runtime floors a fractional value and uses an effective minimum window of one page. It controls the compact run of page numbers between the first/last links and ellipses.

The paginate object

PropertyDescription
paginate.current_pageCurrent 1-based page number
paginate.current_offsetItems skipped before this page
paginate.itemsTotal reachable items, capped at 25,000
paginate.pagesTotal reachable pages
paginate.page_sizeEffective page size
paginate.page_paramQuery parameter used for this paginator
paginate.partsPage-number and ellipsis parts
paginate.previousPrevious-page part, or nil on page 1
paginate.nextNext-page part, or nil on the last page

Limits and edge cases

RuleBehavior
Minimum page size1
Maximum page size250
Maximum reachable item25,000
Count above 25,000Resource count APIs return the 25,001 sentinel
Invalid or non-positive pagePage 1
Page beyond the reachable rangeLast reachable page

Handle the sentinel as “more than 25,000”, not as an exact count:

{% if metaobjects.testimonial.values_count > 25000 %}
More than 25,000 entries
{% else %}
{{ metaobjects.testimonial.values_count }} entries
{% endif %}

Independent paginators

List settings receive a deterministic page_HASH parameter so several setting lists can paginate independently. Ordinary resource collections use their documented page parameter. To update two resource lists independently on one screen, place them in separate sections and use the Section Rendering API.

Never hard-code page for a setting list; use paginate.page_param or the URLs supplied by paginate.parts.

Performance

for ... limit restricts output but might still load the ordinary collection slice. Use paginate to communicate the requested slice to the data loader:

{% paginate collection.products by 4 %}
{% for product in collection.products limit: 4 %}
{% render 'product-card', product: product %}
{% endfor %}
{% endpaginate %}

All data loading remains inside the storefront’s two-second render budget. Filter before paginating when a result set exceeds 25,000 items.