picocms / Pico

Pico is a stupidly simple, blazing fast, flat file CMS.
http://picocms.org/
MIT License
3.83k stars 617 forks source link

Twig pagination (proposal) and Page Tree (question) #443

Closed bricebou closed 6 years ago

bricebou commented 6 years ago

HI,

I've worked on a pagination system using Twig and Twig only (after reading https://github.com/picocms/Pico/issues/404 and https://github.com/picocms/Pico/issues/419), that could be used in any pages of my website. I've managed to reproduce the one I generated with my version on Pico-Pagination for my online website, momh.fr.

So here is the code:

{% set excludedpages = 0 %}
{% set pagesbis = [] %}
{% for page in pages %}
  {% if page.meta["template"] == "category" or page.meta["template"] == "supcategory" or page.title == "Blog" %}
    {% set excludedpages = excludedpages + 1 %}
  {% else %}
    {% set pagesbis = pagesbis|merge([page]) %}
  {% endif %}
{% endfor %} 

{% set slicelength = 5 %}
{% set basepage = 1 %}
{% set pagiurl = base_url ~ "/?page=" %}
{% set maxpage = (pages|length - excludedpages) / slicelength %}

{% set maxpage = maxpage|round(0, 'ceil') %}

{% if url_param('page', 'int') is not null %}
  {% set basepage = url_param('page', 'int') %}
  {% set slicestart = slicelength * (basepage - 1) %}
{% else %}
  {% set slicestart = 0 %}
  {% set basepage = 1 %}
{% endif %}

{% set nextpage = basepage + 1 %}
{% set prevpage = basepage - 1 %}     

{% for page in pagesbis|slice(slicestart, slicelength, preserve_keys) %}
  <article class="post">
    <h1><a href="{{ page.url }}">{{ page.title }}</a></h1>
      <p class="meta clearfix">
        <span class="date_lsp">
          le {{ page.date|date("d/m/Y", "Europe/Paris") }} {% if page.meta["Category"] %}dans {{ page.meta["Category"] }} {% endif %}
        </span>
        {% if page.meta["Tags"][0] != "" %}
          <span class="tags_lsp">
            <i class="fa fa-tags"></i>{% for tag in page.meta["Tags"] %}<a class="hvr_over" href="{{ base_url }}/tag/{{ tag }}">#{{ tag }}</a>{% endfor %}
          </span>
        {% endif %} 
      </p>
      {# <p class="excerpt">{{ page.excerpt }}</p> #}
  </article>
{% endfor %}

<div class="pagination clearfix">
  <ul>
    {% if prevpage is not null %}
      <li class="pi" {% if prevpage < 1 %}style="visibility: hidden;"{% endif %}><a href="{% if prevpage == 1 %}{{ base_url }}{% else %}{{ pagiurl ~ prevpage }}{% endif %}" title="Plus récents" id="prev_page_link"><i class="fa fa-clock-o"></i><i class="fa fa-angle-right"></i></a></li>
    {% endif %}

    {% for item in range(1, maxpage|number_format) %}
      <li class="pi {%if item == basepage %} pi_a{%endif %}"><a href="{% if item == 1 %}{{ base_url }}{% else %}{{ pagiurl ~ item }}{% endif %}" class="page_item {%if item == basepage %} page_active{%endif %}">{%if item == basepage %}<i class="fa fa-clock-o"></i><span>{{ item }}</span>{% else %}{{ item }}{%endif %}</a></li>
    {% endfor %}

    {% if nextpage is not null %}
      <li class="pi" {% if nextpage > maxpage %}style="visibility: hidden;"{% endif %}><a href="{{ pagiurl ~ nextpage }}" title="Plus anciens" id="next_page_link"><i class="fa fa-angle-left"></i><i class="fa fa-clock-o"></i></a></li>
    {% endif %}
  </ul>
</div> {# END .pagination #}

I'm quite satisfied (because it's working ^^ and because I can apply this code, with minor changes, to my tag pages, generated with the PicoTags plugin) but unsatisfied due to the double array parsing (the first one to remove some pages - categories - and the second to display the results).

Maybe you can think of a better way of achieving this ?

I've thought of the new Page Tree system. First, I can't figure out how to use it, even with minimal examples I found in https://github.com/picocms/Pico/issues/412 or https://github.com/picocms/Pico/issues/414. Even, after reading https://phrozenbyte.github.io/Pico/in-depth/features/page-tree/

Here is a screenshot of my website content folder. momh_content_structure

In the index.twig, called only for the content root index.md, I've tried several snippets without success... :-/

I think I understand that Page Tree could generate from scratch an array without the simple index.md nodes ? So, the length of this array wouldn't have to be modified... Is that correct ? If so, could you give me first steps ?

Thanks again and in advance :)

bricebou commented 6 years ago

I've tried to work on a better way to integrate this pagination on different template files and I produced this how-to on my website: http://momh.fr/tutos/Pico/pico_twig_pagination

@PhrozenByte You can copy this, if you think it's good and useful, into the picocms website. If you find a better way, let me know !

Here it is: inside your index.twig (for example), paste this code and set the variables:

{#  number of pages to display per page #}
{% set pagi_slice_length = 5 %}
{#  the array of pages to use #}
{% set pagi_pages_array = pages %}
{#  the base URL of the page the pagination applied
    it can be a more complex string, concatenated like this:
    base_url ~ "/tag/" ~ current_tag
#}
{% set pagi_base_url = base_url %}
{#  the name to use as the URL parameter (?page=xxx) #}
{% set pagi_http_param = 'page' %}

{% if url_param(pagi_http_param, 'int') is not null %}
{% set pagi_basepage = url_param(pagi_http_param, 'int') %}
{% set pagi_slice_start = pagi_slice_length * (pagi_basepage - 1) %}
{% else %}
{% set pagi_slice_start = 0 %}
{% set pagi_basepage = 1 %}
{% endif %}

{% set pagi_maxpage = (pagi_pages_array|length / pagi_slice_length)|round(0, 'ceil') %}

{% for page in pagi_pages_array|slice(pagi_slice_start, pagi_slice_length, preserve_keys) %}      
    <article>
        <h2 class="h1"><a href="{{ page.url }}">{{ page.title }}</a></h2>
    </article>
{% endfor %}

{% include 'includes/pagination.twig' with [pagi_basepage, pagi_maxpage, pagi_base_url, pagi_http_param] %}

You have to create a includes/pagination.twig file in which you have to paste this code:

{% set pagi_next_page = pagi_basepage + 1 %}
{% set pagi_prev_page = pagi_basepage - 1 %}
{% if pagi_maxpage > 1 %}
  <ul>
    {% if pagi_prev_page is not null %}
      <li class="pi" {% if pagi_prev_page < 1 %}style="visibility: hidden;"{% endif %}><a href="{% if pagi_prev_page == 1 %}{{ pagi_base_url }}{% else %}{{ pagi_base_url ~ '/?' ~ pagi_http_param ~ '=' ~  pagi_prev_page }}{% endif %}" title="Newest posts" id="prev_page_link">Newest posts</a></li>
    {% endif %}

    {% for item in range(1, pagi_maxpage|number_format) %}
      <li class="pi {%if item == pagi_basepage %} pi_a{%endif %}"><a href="{% if item == 1 %}{{ pagi_base_url }}{% else %}{{ pagi_base_url ~ '/?' ~ pagi_http_param ~ '=' ~ item }}{% endif %}" class="page_item {%if item == pagi_basepage %} page_active{%endif %}">{{ item }}</a></li>
    {% endfor %}

    {% if pagi_next_page is not null %}
      <li class="pi" {% if pagi_next_page > pagi_maxpage %}style="visibility: hidden;"{% endif %}><a href="{{ pagi_base_url ~ '/?' ~ pagi_http_param ~ '=' ~ pagi_next_page }}" title="Older posts" id="next_page_link">Older posts</a></li>
    {% endif %}
  </ul>
{% endif %}

It's awful, but it works ! ^^

A live example: momh.fr/

stale[bot] commented 6 years ago

This issue has been automatically marked as stale because it has not had recent activity. It will be closed in two days if no further activity occurs. Thank you for your contributions! :+1:

PhrozenByte commented 6 years ago

Comment for un-stale-ing this issue

Didn't forget about answering this, just haven't had time for it yet...

bricebou commented 6 years ago

No worry @PhrozenByte :-) I've just updated my second comment (I forgot the pagi_pages_array variable in my for loop).

stale[bot] commented 6 years ago

This issue has been automatically marked as stale because it has not had recent activity. It will be closed in two days if no further activity occurs. Thank you for your contributions! :+1:

bricebou commented 6 years ago

Comment for un-stale-ing this issue

I'm going to work on adding options to display only X items when the maxpage is too important.

stale[bot] commented 6 years ago

This issue has been automatically marked as stale because it has not had recent activity. It will be closed in two days if no further activity occurs. Thank you for your contributions! :+1:

bricebou commented 6 years ago

Just in time !

So I've worked on a a way to reduce the number of displayed pages !

Here is my new includes/pagination.twig:

{% set pagi_next_page = pagi_basepage + 1 %}
{% set pagi_prev_page = pagi_basepage - 1 %}
{% if pagi_max_near_by is null %}
  {% set pagi_max_near_by = 2 %}
{% endif %}

{% if pagi_maxpage > 1 %}
  <ul>
    {% if pagi_prev_page is not null %}
      <li class="pi" {% if pagi_prev_page < 1 %}style="visibility: hidden;"{% endif %}><a href="{% if pagi_prev_page == 1 %}{{ pagi_base_url }}{% else %}{{ pagi_base_url ~ '/?' ~ pagi_http_param ~ '=' ~  pagi_prev_page }}{% endif %}" title="Newest posts" id="prev_page_link">Newest posts</a></li>
    {% endif %}

    {% if pagi_basepage - pagi_max_near_by > 1 %}
      <li class="pi">&hellip;</li>
    {% endif %}

    {% for item in range(1, pagi_maxpage|number_format) %}
      <li {% if pagi_basepage - pagi_max_near_by > item or pagi_basepage + pagi_max_near_by < item  %}style="display:none;"{% endif %} class="pi {%if item == pagi_basepage %} pi_a{%endif %}"><a href="{% if item == 1 %}{{ pagi_base_url }}{% else %}{{ pagi_base_url ~ '/?' ~ pagi_http_param ~ '=' ~ item }}{% endif %}" class="page_item {%if item == pagi_basepage %} page_active{%endif %}">{{ item }}</a></li>
    {% endfor %}

    {% if pagi_basepage + pagi_max_near_by < pagi_maxpage %}
      <li class="pi">&hellip;</li>
    {% endif %}

    {% if pagi_next_page is not null %}
      <li class="pi" {% if pagi_next_page > pagi_maxpage %}style="visibility: hidden;"{% endif %}><a href="{{ pagi_base_url ~ '/?' ~ pagi_http_param ~ '=' ~ pagi_next_page }}" title="Older posts" id="next_page_link">Older posts</a></li>
    {% endif %}
  </ul>
{% endif %}

I've made a new blog post about that here: http://momh.fr/tutos/Pico/pico_twig_pagination_bis

And you can see it live here: http://momh.fr/?page=5

PhrozenByte commented 6 years ago

We already promote plugins and themes on our website, unfortunately there isn't really a counterpart for Twig snippets yet. Anyway, creating one might be a good idea. There's just the currently not really used Cookbook on our website. As always, help is highly appreciated!

The snippets look really great and are exactly the way it should be used. Just some minor notes:

stale[bot] commented 6 years ago

This issue has been automatically marked as stale because it has not had recent activity. It will be closed in two days if no further activity occurs. Thank you for your contributions! :+1: