Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

"pagination" variable in "pagination.html.twig" doesn't containt the right data. #31

Open
KennethJoris opened this issue Mar 12, 2018 · 11 comments

Comments

@KennethJoris
Copy link

KennethJoris commented Mar 12, 2018

On a twig template i use the 'Collection Object Methods' to difine a collection like it states in the GRAV documentation:

{% set collection = page.collection({
         'items': '@self.children', 
         'pagination': true, 
         'order': {'by': 'title'}, 
         'limit': 1}) 
%}

I pass this data to the plugin 'pagination.html.twig' template.

{% if config.plugins.pagination.enabled and collection.params.pagination %}
    {% include 'partials/pagination.html.twig' with {'base_url':page.url, 'pagination':collection.params.pagination} %}
{% endif %}

Here i have my issue:

  • "collection.params.pagination" will always return 1 (as 1 is the same as true).

In the plugin template '' the first condition will therefore always return false.

{% set pagination = pagination|default(page.collection.params.pagination) %}
{% if pagination|length > 1 %} ... {% endif %}

Looking inside the plugin template its unclear to me what correct data is expected.
And how to pass this through?

@KennethJoris
Copy link
Author

I made a small twig pagination that works with the Grav Collection Methods:

Example:

       {% set collection = page.collection({
		'items': '@self.children', 
		'pagination': true, 
		'order': {'by': 'title'}, 
		'limit': 2}) 
	%}
	
	{% set itemsInCollection = page.collection({'items': collection.params.items})|length %}
	{% set itemsPerPage = collection.params.limit %}
	{% set pagesInCollection = (itemsInCollection / itemsPerPage)|round(0, 'ceil') %}
	{% set currentPage = uri.param('page')|default('1') %}

	<ul class="pagination">
	{% for i in range(1, pagesInCollection) %}
		<li {% if currentPage is same as('' ~ i ~ '') %} class="currentpage" {% endif %}>
			<a href="{{ page.url ~ '/page' ~ system.param_sep ~ i }}">{{ i }}</a>
		</li>
	{% endfor %}
	</ul>

	{# Render the list of blog posts (automatically filtered when using pagination) #}
	{% for child in collection %}
	   {{ child.title }} <br>
	{% endfor %}

@ghost
Copy link

ghost commented Aug 7, 2018

This problem takes a lot of my time at the moment. When I look inside the grav-skeleton-blog-site the pagination param is a \Grav\Plugin\PaginationHelper, in the flow of my templates it is only a boolean = true. I tried calls like do paginate( collection, limit ) like described in the README. This should do the magic, it calls paginateCollection in grav-plugin-pagination/pagination.php, which overwrites the pagination param with a \Grav\Plugin\PaginationHelper and slices the collection. The call does not work for me at the moment, I will investigate more. It is rather confusing, that a parameter is changed to another type and meaning, why not use another name?

Also I don't know where it is done in the blog skeleton. Any advice appreciated.

@ghost
Copy link

ghost commented Aug 7, 2018

I think I found the reason. In the grav-skeleton-blog-site the preparation of the collection is done by the onCollectionProcessed-event, but, as I suppose, only for the default collection, not for another defined collection.

So the call to do paginate() is essential, but really not working.
The reason is: the version 1.3.2 installed by bin/gpm install pagination is different from the version 1.3.2 installed by the zip. The twig folder is missing and the onTwigExtensions-event not registered. Also blueprints.yaml, README.md and other files are different.

When I install from ZIP, do paginate() does it's job.

@grantholle
Copy link

I'm having the same problem using v1.4.1. I tried installing using gpm and zip (which was the same version).

The collection.params.pagination never gets the "magic", just remains true.

@grantholle
Copy link

I figured out my proglem. I was including limit in my collection() call.

If I exclude the limit from my collection parameters and only pass what my limit is do the do paginate(collection, limit) it works as expected.

@azamatg
Copy link

azamatg commented Mar 4, 2019

If I exclude the limit from my collection parameters and only pass what my limit is do the do paginate(collection, limit) it works as expected.

can you explain this please?

I cannot find the way to get this strange unusable plugin work

@Heraes-git
Copy link

Heraes-git commented Apr 21, 2019

I have exactly the same problem as @Genenenenaam and tried the do paginate( collection, limit ) as @tremel did : but I have a blank paginator, in raw HTML, without pages to paginate.

2019-04-21_17h30m45s_chrome

I tried again with excluding the limit: from the frontmatter as @grantholle suggested, and this time, I have a Crikey error :

2019-04-21_17h25m21s_chrome

So it seems that the plugin is totally broken (no rendering + no CSS loaded in the assets in the <head>).

@numito
Copy link

numito commented May 19, 2019

Hello,

There is an issue with the pagination plugin, if you have a collection to has less items than the limit, you get empty pagination instead of not getting a paginator at all. The reason is the pagination variable is initialized to true, and then never changed to an empty array. There the pagination|length gives 4 because it counts the number of letters in the word true instead of counting an empty array.

There are 2 ways to fix this issue on line 124 of file pagination.php.
Solution 1: set the pagination variable to an empty array instead of true
$collection->setParams(['paginationEnabled' => array()]);
Solution 2: don't set the pagination variable unless there is enough item and instead to show there is pagination activated but not enough item to paginate set a variable called paginationEnabled to true.
$collection->setParams(['paginationEnabled' => 'true']);

Solution 1 makes has my preference.

Regards,
Numa

@rhukster
Copy link
Member

How about a pull request?

@Heraes-git
Copy link

Heraes-git commented Aug 1, 2019

Hi, I come back here to give more infos on what I discovered about the bugs.
I'm not familiar with GIT pushes, and anyway I didn't find any PHP fixes, so it's pure workaround and good practice here 👍 . I just dump that, as a memo for further documentation edition.

Summary :

1 - How to use the plugin correctly (conflict)
2 - Excerpt of a full template processing
3 - The problem with modular pages
4 - Insights of the PHP, for possible fixes

1 - How to use the plugin correctly (conflict)

In short : there's two way of calling the plugin in a page, and we can't use both or it will conflicts !

Reminder

The plugin necessitate two things :

  • A pagination: true field in the frontmatter.
  • A {% include... %} of the plugin's template in order to insert it and to use what it has generated during the PHP page processing (due to any presence of its activation in a page).

And it allows one thing :

  • To process the pagination manually in the template, with a {% do paginate() %}, in order to tweak some variables.

First method

  1. We declare all necessary option in the frontmatter, wich are composed of only two :
content:
    pagination: true
    limit: [integer]
  1. We do NOT use a {% do paginate() %}.

Second method

  1. We declare one option in the frontmatter, the most essential one :
content:
    pagination: true
  1. We do NOT use a limit: field.
  2. We use {% do paginate() %}.

2 - Excerpt of a full template processing

  • I use a preprocessing of the collection in order to define a default one if nothing has been declared in the frontmatter (make the template to be "independent" and bullet-proof).
  • Also, I condition the {% do paginate() %} so its use is only triggered when the limit: field is absent.
{# *** Collection preprocessing *** #}
{% if page.collection %}
	{% set collection = page.collection() %}
	{% set limit = page.header.content.limit ?: '5' %}
{% else %}
	{% set limit = '5' %}
	{% set collection_options = { items: {'@page.children': page.url}, 'limit': limit, 'order': {'by': 'date', 'dir': 'desc'}, 'pagination': true } %}
	{% set collection = page.collection(collection_options) %}
{% endif %}
{# *** /Collection preprocessing *** #}
{% if config.plugins.pagination.enabled and collection.params.pagination and not page.header.content.limit %}
	{% do paginate(collection, limit) %}
{% endif %}

{% for item in collection %}
... Things to display the items...
{% endfor %}

{% if config.plugins.pagination.enabled and collection.params.pagination %}
		{% include "partials/pagination.html.twig" with {'base_url':page.url, 'pagination':collection.params.pagination} %}
{% endif %}

3 - Problem with modular pages, and workaround

Modular page are rendered differently, and some things can be impossible to reach in the PHP during the events.

So, because of this, the presence of a frontmatter pagination field is just checked during the WHOLE* page processing (* meaning, the parent page that a modular can have !) but not during the processing of the modular sub-page. Consequently, the pagination plugin doesn't find the frontmatter field, and doesn't load the CSS wich results in a raw <ul> !

So as a solution, just load manually the asset in your template that extends the base.html.twig, by rewritting any {% block %} that would have been created (or that you can create) around the assets.css() in the header of the base.html.twig.

{% block assets %}
  {{ parent() }}
  {% do assets.addCss('plugin://pagination/css/pagination.css') %}
{% endblock %}

Or directly in the base.html.twig, add inside the header :

{% if page.route == "/your_page" %}
  {% do assets.addCss('plugin://pagination/css/pagination.css', {'group':'workaround'}) %}
{% endif %}
{{ assets.css('workaround') }}

I've conditioned it to a route, and assigned it to a group for more control, but that's totally optional.

@Heraes-git
Copy link

4 - Insights of the PHP, for possible fixes

  • First, I found that the paginate twig function is declared in the PaginationTwigExtension.php.
new \Twig_SimpleFunction('paginate', [$this, 'paginateFunc']),
  • Then, this function calls the $pag->paginateCollection(...) method.
  • The paginateCollection() method does nothing bad : it just rewrites the limit: field with the thing that it received as a $limit argument. It's strange, maybe a loop, but why not. I first thought it was bugging here.
  • But I understood that the onCollectionProcessed(Event $event) method is triggered first. In it, we can find :
$this->pagination = new PaginationHelper($collection);
$collection->setParams(['pagination' => $this->pagination]);
  • And in the '/classes/paginationhelper.php', there is a _construct in wich :
$params = $collection->params();
...
$this->items_per_page = $params['limit'];
  • Then the items_per_page is use a single time in :
$this->page_count = ceil($collection->count() / $this->items_per_page);

But I don't understand why it would make the plugin to bug. 🤔

Anyway, it is clearly here, at this moment when the page_count is done, that the plugin fails if we have a set a limit: field in the frontmatter !

I tried to set an integer, or between quotes ' '; but nothing works.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

6 participants