{{craftSnippets}}
Home Articles Plugins Starter theme Components on Github Gists About
  • Home
  • Articles
  • Ellipsis pagination component for Craft CMS
Posted on May 10, 2019 by Piotr Pogorzelski
Updated on Jun 26, 2019

Ellipsis pagination component for Craft CMS

Ellipsis pagination on github gists
Select based pagination on github gists
This pagination Twig template component shows only page links close to the currently displayed page - rest of links are replaced with an ellipsis.
Table of contents:
  • Ellipsis pagination features
  • Ellipsis pagination code
  • Usage
  • Paginated search results
  • Pagination select widget
  • SEO friendly pagination
  • Pagination plugin
  • Further reading
  • Article update history

To properly make use of this pagination component, make sure you know how Craft paginate Twig tag works. You can read about it in Craft docs.

I recommend reading my other pagination related article - Building dynamic, AJAX based pagination for Craft CMS.

Ellipsis pagination features #

Let's sum up the main features of this pagination template component:

  • In order to avoid creating a long list of pagination links, excessive links are omitted and replaced with an ellipsis. Only a specific number of links close to link to current page is showed. There are also links to first, last, previous and next page.
  • If pagination list has only one page of results, it will not show at all. Not much use in pagination with just a single link.
  • You can choose how many links close to link to currently viewed page are shown.
  • Component has proper ARIA attributes that make it accessible - aria-label, aria-role and aria-current are used. You can adjust text in aria-label attributes using static translations.
  • Component makes use of Seomatic if this plugin is installed.

Pagination component uses Bulma css classes. Here's how it looks like:

Ellipsis pagination code #

Here's Twig code of pagination component:

{# requires pageInfo variable #}

{# settings #}
{% set neighbours = 1 %}

{# symbols #}
{% set prev = '❮' %}
{% set next = '❯' %}
{% set dots = "…" %}

{# single numeric link #}
{% macro numericLink(url, number, current) %}
<li>
    <a href="{{url}}" data-number="{{number}}" class="pagination-link {{current ? 'is-current' : null}}" aria-label="{{current ? 'current page'|t : 'go to page'|t ~ ' ' ~ number}}" {{current ? 'aria-current="page"'}}>{{number}}</a>
</li>
{% endmacro %}

{# next/prev link #}
{% macro textLink(url, content, aria, number) %}
<li>
    <a href="{{url}}" data-number="{{number}}" class="pagination-link" aria-label="{{aria}}">{{content|raw}}</a>
</li>
{% endmacro %}

{# ellipsis #}
{% macro ellipsis(content) %}
<li>
    <span class="pagination-ellipsis">{{content|raw}}</span>
</li>
{% endmacro %}

{# pagination logic #}
{% if pageInfo is defined and pageInfo.totalPages > 1 %}
{% import _self as self %}

{# seomatic #}
{# https://github.com/nystudio107/craft-seomatic#pagination-and-seo #}
{% if seomatic is defined %}
    {% do seomatic.helper.paginate(pageInfo) %}
{% endif %}


<nav class="pagination" role="navigation" aria-label="{{'pagination'|t}}">
<ul class="pagination-list">

    {# previous #}
    {% if pageInfo.prevUrl %}
        {{ self.textLink(pageInfo.prevUrl, prev, 'previous page'|t, pageInfo.currentPage - 1) }}
    {% endif %}

    {# first #}
    {% if pageInfo.currentPage - neighbours > 1  %}
        {{ self.numericLink(pageInfo.firstUrl, '1') }}
    {% endif %}

    {# ellipsis before current #}
    {% if pageInfo.currentPage - neighbours > 2 %}
        {{ self.ellipsis(dots) }}
    {% endif %}

    {# links before current #}
    {% for page, url in pageInfo.getPrevUrls(neighbours) %}
        {{ self.numericLink(url, page) }}
    {% endfor %}

    {# current #}
    {{ self.numericLink('', pageInfo.currentPage, true) }}

    {# links after current #}
    {% for page, url in pageInfo.getNextUrls(neighbours) %}
        {{ self.numericLink(url, page) }}
    {% endfor %}

    {# ellipsis after current #}
    {% if pageInfo.totalPages - pageInfo.currentPage > neighbours + 1 %}
        {{ self.ellipsis(dots) }}
    {% endif %}

    {# last #}
    {% if pageInfo.currentPage + neighbours < pageInfo.totalPages %}
        {{ self.numericLink(pageInfo.lastUrl, pageInfo.totalPages) }}
    {% endif %}

    {# next #}
    {% if pageInfo.nextUrl %}
        {{ self.textLink(pageInfo.nextUrl, next, 'next page'|t, pageInfo.currentPage + 1) }}
    {% endif %}

</ul>
</nav>
{% endif %}

Usage #

In order to use pagination component, you need to pass pageInfo variable generated by paginate tag to it. At beggining of the file, you can find few settings:

  • neighbours - number of links close to current page link that are shown.
  • prev and next - variables used for setting content of links to previous and next page. By default they contain arrows. Same with ellipsis variable - by default it has assigned html entity of three dots.

To make modifying repeatable parts of pagination easier, numeric links, text links and ellipsis elements are contained within macros.

Paginated search results #

Search results or filtered lists of entries rely on URL paramater appended to address, for example domain.com/search?phrase=something.

Since Craft CMS 3.1.31, these paramaters are automatically appended to pagination links. If you want to use this pagination component in earlier versions of Craft that for some reasons cannot be updated, you will need to append URL params to pagination links manually.

You can do this by modyfying numericLink macro used in component:

{% macro numericLink(url, number, current) %}
{% set urlParams = craft.app.request.getQueryStringWithoutPath() is not empty ? '?' ~ craft.app.request.getQueryStringWithoutPath() %}
<li>
    <a href="{{url~urlParams}}" data-number="{{number}}" class="pagination-link {{current ? 'is-current' : null}}" aria-label="{{current ? 'current page'|t : 'go to page'|t ~ ' ' ~ number}}" {{current ? 'aria-current="page"'}}>{{number}}</a>
</li>
{% endmacro %}

Pagination select widget #

If you want to let users quickly navigate through large amount of paginated pages, you might want to use <select> based navigation.

{# settings #}
{% set info = pageInfo %}
{# logic #}
{% if info.totalPages > 1 %}
<select name="" id="" onchange="document.location.href = this.options[this.selectedIndex].value;">
{% for link in info.getRangeUrls( 1, info.totalPages ) %}
    <option value="{{link}}" {{info.currentPage == loop.index ? 'selected="selected"'}}>{{'page'|t}} {{loop.index}}</option>
{% endfor %}
</select>
{% endif %}

This code will render <select> HTML element with each <option> representing page of paginated content. Selecting option will open associated page in browser (just like clicking a link) thanks to a bit of inline written JS code. <select> based navigation is especially useful on mobile devices - mobile browsers render nice big widget if the user wants to choose an option from <select>.

SEO friendly pagination #

If you use Seomatic, component will run function that makes Seomatic append pagination related code to <head> part of the website. This code will make google aware that pagination is used.

If you don't use Seomatic (or any other SEO plugin) you can do that manually. THIS article on Craft CMS blog describes how it can be done.

Pagination plugin #

As an alternative to using Twig component, you can use Pagination plugin.

It gives you less flexibility than using Twig code - pagination plugin just renders list of links that can be tweaked a bit using configuration options. There is no way to add some more advanced things like ARIA tags.

Still, for simpler projects where you just want to quickly set up some simple pagination, it might be a good solution.

Further reading #

  • Building dynamic, AJAX based pagination for Craft CMS - article on craftSnippets
  • Paginate tag in Craft CMS docs
  • Creating SEO-Friendly Pagination Links
  • Acceessible pagination

Article update history #

  • 26 June 2019 - updated pagination component to take into account that since Craft 3.1.31, URL params are appended to pagination links automatically.

TAGS:
#twig component #navigation
If you want to get latest updates on Craft CMS tutorials and components, follow me on Twitter or subscribe to RSS feed.
Quick links for this article:
Ellipsis pagination on github gists
Select based pagination on github gists
Articles on blog:
  • User account management with Craft CMS
  • Frontend testing for Craft CMS websites with Codeception and Cypress
  • Building reactive Craft Commerce product page with Sprig plugin
  • Dynamically generated PDF attachments for Freeform submissions
  • Using template hooks in Craft CMS
  • Alpine JS modal component for Craft CMS
  • Using template UI elements to extend Craft CMS control panel
  • Matrix within a Matrix - possible solutions for Craft CMS
  • Universal email template for Craft CMS
  • Creating attributes table from entry fields in Craft CMS
  • Namespacing forms in Craft CMS
  • Creating map-based navigation for Craft CMS
  • Placeholder image macro for Craft CMS
  • Building AJAX contact form with Craft CMS
  • Using incognito field plugin for Craft CMS
  • Email footer creator made with Craft CMS
  • Infinite scrolling and lazy loading with Craft CMS
  • Using Javascript in Twig templates with Craft CMS
  • Twig templating tips and tricks for Craft CMS
  • Basic SEO functionality for Craft CMS
  • Working with dates in Craft CMS templates
  • Working with SVG images in Craft CMS templates
  • Responsive and lazy-loaded youtube videos with Craft CMS
  • Debugging and inspecting Twig templates in Craft CMS
  • Creating article excerpts with Twig component in Craft CMS
  • Adding favicons to Craft CMS website
  • Truncating text with Twig macros in Craft CMS
  • Universal language switcher for Craft CMS
  • Read time macro for Craft CMS
  • Using attr() function to render HTML attributes in Craft CMS
  • Building dynamic, AJAX based pagination for Craft CMS
  • How to add Disqus comments to Craft CMS website
  • Ellipsis pagination component for Craft CMS
  • Converting email addresses into links using Twig macro
  • Breadcrumb created from URL for Craft CMS
  • Best developer-oriented Craft CMS plugins
  • Search autocomplete component for Craft CMS
  • RSS feed - template component for Craft CMS
  • Testing emails sent by Craft CMS using Mailtrap
  • Quick edit link - Twig component for Craft CMS
  • Filtering entries in control panel using Searchit plugin
  • Fetching routes into Twig templates in Craft CMS


User account management with Craft CMS

Frontend testing for Craft CMS websites with Codeception and Cypress

Building reactive Craft Commerce product page with Sprig plugin

Dynamically generated PDF attachments for Freeform submissions

Using template hooks in Craft CMS

Alpine JS modal component for Craft CMS

Using template UI elements to extend Craft CMS control panel

Matrix within a Matrix - possible solutions for Craft CMS

Copyright ©2023 Piotr Pogorzelski