Skip to content

Instantly share code, notes, and snippets.

@maxpou
Last active February 26, 2023 20:28
Show Gist options
  • Star 23 You must be signed in to star a gist
  • Fork 5 You must be signed in to fork a gist
  • Save maxpou/612359ed4af4cc5c4f06 to your computer and use it in GitHub Desktop.
Save maxpou/612359ed4af4cc5c4f06 to your computer and use it in GitHub Desktop.
Example of pagination with Twig
{#
Parameters:
* nbPages (int): number of pages
* currentPage (int): current pages
* url (string): route name & query (string): route parameter
ex: list/page-5?q=myFilter (5 = page and query = myFilter)
#}
{% spaceless %}
{% if nbPages > 1 %}
{# Number of page around current page+1 #}
{% set nearbyPagesLimit = 4 %}
<div>
<ul class="pagination">
{% if currentPage != 1 %}
<li>
<a href="{{ path(url, { 'page': 1, 'q': query }) }}">First</a>
</li>
{% endif %}
{% for i in 1..nbPages %}
{% if 0 == (currentPage - nearbyPagesLimit) - loop.index %} {# dot before #}
<li class="disabled"><a href="#">...</a></li>
{% elseif 0 == (currentPage + nearbyPagesLimit) - loop.index %} {# dot after #}
<li class="disabled"><a href="#">...</a></li>
{% elseif 0 < (currentPage - nearbyPagesLimit) - loop.index %} {# hide all before #}
{% elseif 0 > (currentPage + nearbyPagesLimit) - loop.index %} {# hide all after #}
{% else %}
<li {% if currentPage == loop.index %} class="active"{% endif %}>
<a href="{{ path(url, { 'page': loop.index, 'q': query }) }}">{{ loop.index }}</a>
</li>
{% endif %}
{% endfor %}
{% if currentPage != nbPages %}
<li>
<a href="{{ path(url, { 'page': nbPages, 'q': query }) }}">Last</a>
</li>
{% endif %}
</ul>
</div>
{% endif %}
{% endspaceless %}
@Qrzysio
Copy link

Qrzysio commented Jan 31, 2020

Updated.

Dropping page number for page no. 1.

BEFORE:
www.example.com/articles/page-1
www.example.com/articles/page-2
www.example.com/articles/page-3

NOW:
www.example.com/articles/
www.example.com/articles/page-2
www.example.com/articles/page-3

{% macro pagination(total, current, url, nearbyPagesLimit = 4) %}

    {# Create "main_url" variable with link for the first page #}
    {% set foo = url|split('/') %}
    {% set foo = foo|slice(0, -1) %}
    {% set main_url = foo|join('/') ~ "/" %}

    {% apply spaceless %}
        {% if total > 1 %}
            <div class="row">
                <div class="col-md-12 blog-posts">
                    <nav>
                    <ul class="pagination theme-colored2">
                        {% if current > 1 %}
                            <li><a class="prev page-numbers" href="{{ (url ~ (current-1))|e }}/">&laquo;</a></li>
                        {% endif %}

                        {% for i in 1..total %}
                            {% if 0 == (current - nearbyPagesLimit) - loop.index %}
                                <li><a class="page-numbers" href="{{ (url ~ 1)|e }}/">1</a></li>
                                {% if 1 != loop.index %}
                                    <li><a href="#"><span class="page-numbers">...</span></a></li>
                                {% endif %}
                            {% elseif 0 == (current + nearbyPagesLimit) - loop.index  and (current + nearbyPagesLimit) < total %}
                                <li><a href="#"><span class="page-numbers">...</span></a></li>
                            {% elseif 0 < (current - nearbyPagesLimit) - loop.index %}
                                <!-- #1 -->
                            {% elseif 0 > (current + nearbyPagesLimit) - loop.index %}
                                <!-- #2 -->
                            {% else %}
                                    {% if current == loop.index  %}
                                        <li class="active"><a href="#"><span class="page-numbers" aria-current="page">{{ loop.index }}</span></a></li>
                                    {% else %}
                                        {% if loop.index == 1 %}
                                            <li><a class="page-numbers" href="{{ main_url }}">{{ loop.index }}</a></li>
                                        {% else %}
                                            <li><a class="page-numbers" href="{{ url ~ loop.index }}/">{{ loop.index }}</a></li>
                                        {% endif %}
                                    {% endif %}
                            {% endif %}
                        {% endfor %}
                        {% if current != total  and (current + nearbyPagesLimit) < total %}
                            <li><a class="page-numbers" href="{{ (url ~ total)|e }}/">{{ total }}</a></li>
                        {% endif %}
                        {% if current < total %}
                            <li><a class="next page-numbers" href="{{ (url ~ (current+1))|e }}/">&raquo;</a></li>
                        {% endif %}
                    </ul>
                    </nav>
                </div>
            </div>
        {% endif %}
    {% endapply %}
{% endmacro %}

{{ _self.pagination(total, current, url) }}

@db306
Copy link

db306 commented Apr 20, 2020

@Qrzysio you're missing a </nav>

@Qrzysio
Copy link

Qrzysio commented Apr 20, 2020

Correct. Thanks a lot. I've updated the code.

@skylord123
Copy link

{% macro pagination(total, current, pageQueryParam = 'page', nearbyPagesLimit = 4) %}
    {% if total > 1 %}
        <ul class="pagination my-4">
            {% for i in 1..total %}
                {% if 0 == (current - nearbyPagesLimit) - loop.index %}
                    <li class="page-item"><a href="{{ (app.request.pathInfo ~ '?' ~ (app.request.query.all|merge({(pageQueryParam): 1})|url_encode))|e }}" class="page-link">1</a></li>
                    {% if 1 != loop.index %}
                        <li class="page-item">
                            <a href="javascript:void(0)" class="page-link">...</a>
                        </li>
                    {% endif %}
                {% elseif 0 == (current + nearbyPagesLimit) - loop.index  and (current + nearbyPagesLimit) < total %}
                    <li class="page-item">
                        <a href="javascript:void(0)" class="page-link">...</a>
                    </li>
                {% elseif 0 < (current - nearbyPagesLimit) - loop.index %}
                {% elseif 0 > (current + nearbyPagesLimit) - loop.index %}
                {% else %}
                    <li class="page-item{{ current == loop.index ? ' active' }}">
                        <a href="{{ (app.request.pathInfo ~ '?' ~ (app.request.query.all|merge({(pageQueryParam): loop.index})|url_encode))|e }}" class="page-link">{{ loop.index }}</a>
                    </li>
                {% endif %}
            {% endfor %}
            {% if current != total  and (current + nearbyPagesLimit) < total %}
                <li class="page-item"><a href="{{ (app.request.pathInfo ~ '?' ~ (app.request.query.all|merge({(pageQueryParam): total})|url_encode))|e }}" class="page-link">{{ total }}</a></li>
            {% endif %}
        </ul>
    {% endif %}
{% endmacro %}

I didn't like how the page had to be passed in with the macro so I decided to make it use the app.request object to retain all query parameters and only modify the page query parameter (with the option to change what the page query param is called). This assumes that pagination will always be hitting the same route the user is already on (which is true in my case but if not for your case you can easily modify the macro).

I also changed it to display via bootstrap 4.

@cadot-info
Copy link

thanks, for your share ;-)

@cadot-eu
Copy link

cadot-eu commented Apr 20, 2022

Pagination with a variable.

	<nav aria-label="Page navigation example">
		<ul
			class="pagination justify-content-center">
			{# precedent #}
			<li class="page-item {{ app.request.query.get('page')==1 or app.request.query.get('page')==0 ? 'disabled' }} ">
				{% if app.request.query.get('page') is defined and app.request.query.get('page')>1 %}
					{% set precedent = app.request.query.get('page') -1 %}
				{% else %}
					{% set precedent = 1 %}
				{% endif %}
				<a class="page-link" href="{{ path('¤entity¤_index',{'page':precedent,'tri':app.request.query.get('tri'),'ordre':app.request.query.get('ordre')}) }}">
					<span aria-hidden="true">&laquo;</span>
				</a>
			</li>
			{% if pagesMaxi/10>6 %}
				{# 1 #}
				<li class="page-item">
					<a class="page-link" href="{{ path('¤entity¤_index',{'page':1,'tri':app.request.query.get('tri'),'ordre':app.request.query.get('ordre')}) }}">1</a>
				</li>
				{# pages millieu #}
				{% for item in 1..5 %}
					<li class="page-item">
						<a class="page-link " href="{{ path('¤entity¤_index',{'page':(pagesMaxi/10/6*loop.index)|number_format(0),'tri':app.request.query.get('tri'),'ordre':app.request.query.get('ordre')}) }}">{{(pagesMaxi/10/6*loop.index)|number_format(0)}}</a>
					</li>
				{% endfor %}
				{# maxi #}
				<li class="page-item">
					<a class="page-link" href={{ path('¤entity¤_index',{'page':(pagesMaxi/10)|number_format(0),'tri':app.request.query.get('tri'),'ordre':app.request.query.get('ordre')} ) }}>{{(pagesMaxi/10)|number_format(0)}}</a>
				</li>
			{% else %}
				{% for item in 1..(pagesMaxi/10)|number_format(0) %}
					<li class="page-item">
						<a class="page-link " href="{{ path('¤entity¤_index',{'page':loop.index,'tri':app.request.query.get('tri'),'ordre':app.request.query.get('ordre')}) }}">{{loop.index}}</a>
					</li>
				{% endfor %}
			{% endif %}
			{# suivant #}
			<li class="page-item {{ app.request.query.get('page') >= (pagesMaxi/10)|number_format ? 'disabled' }}">
				{% if app.request.query.get('page')==0 %}
					{% set suivant = 2 %}
				{% else %}
					{% set suivant = app.request.query.get('page') +1 %}
				{% endif %}
				<a class="page-link" href="{{ path('¤entity¤_index',{'page':suivant,'tri':app.request.query.get('tri'),'ordre':app.request.query.get('ordre')}) }}">
					<span aria-hidden="true">&raquo;</span>
				</a>
			</li>
		</ul>
	</nav>

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment