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.commentsblog.articlescollectionscollection.productscustomer.addresses(maximum 20 per page)customer.orders(maximum 20 per page)metaobject_definition.valuespagesproduct.variantssearch.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="">« 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 »</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
| Property | Description |
|---|---|
paginate.current_page | Current 1-based page number |
paginate.current_offset | Items skipped before this page |
paginate.items | Total reachable items, capped at 25,000 |
paginate.pages | Total reachable pages |
paginate.page_size | Effective page size |
paginate.page_param | Query parameter used for this paginator |
paginate.parts | Page-number and ellipsis parts |
paginate.previous | Previous-page part, or nil on page 1 |
paginate.next | Next-page part, or nil on the last page |
Limits and edge cases
| Rule | Behavior |
|---|---|
| Minimum page size | 1 |
| Maximum page size | 250 |
| Maximum reachable item | 25,000 |
| Count above 25,000 | Resource count APIs return the 25,001 sentinel |
| Invalid or non-positive page | Page 1 |
| Page beyond the reachable range | Last 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.