Pagination does not work correctly for comment fields that are rendered using #lazy_builder.
So, for the content type, a comments field has been added, for which a custom FieldFormatter has been created that extends CommentDefaultFormatter, and render comments with pagination using #lazy_builder.
Everything is displayed correctly, but the path to the pages in pagination is not formed correctly and when you click to pages then will be displayed comments from the first page.
There are 2 problems here:
The numbering does not work as it always displays the results from the 1st page.
Description:
Pagination that added on the build of comments causes
html/core/modules/comment/src/CommentStorage.php
(
$query = $query->extend('Drupal\Core\Database\Query\PagerSelectExtender')
->limit($comments_per_page);
), which calls html/core/lib/Drupal/Core/Database/Query/PagerSelectExtender.php
and in the execute()
method calls the createPager
method from PageManager
($pager = $pager_manager->createPager($total_items, $this->limit, $this->element);
), according to the createPager
method in html/core/lib/Drupal/Core/Pager/PagerManager.php
calls the findPage
method with html/core/lib/Drupal/Core/Pager/PagerParameters.php
, and it is this method that returns the ID of the page to which the link is in the pager, and it is this method that returns it incorrectly if #lazy_builder is used, since this method receives an array of 2 values, and always returns 0, although it should be only one meaning.
An additional parameter is added to the page ID in the pager link (E.G.? Page = 1,2), and accordingly ",2" is an extra parameter, it is added only if comments are displayed using #lazy_builder (see attachments). This parameter completely breaks pagination work.
Description:
At the moment when the links for the pager (html/core/includes/pager.inc
) are canceled, the getUpdatedParameters
method is called on the preprocess_pager
from the PagerManager
$options = [
'query' => $pager_manager->getUpdatedParameters($parameters, $element, $pager_max - 1),
];
$items['last']['href'] = Url::fromRoute($route_name, $route_parameters, $options)->toString();
This method contains 2 parameters, one of which is unnecessary and does not need to be added to the query.
Solution for the first problem:
/**
* {@inheritdoc}
*/
public function findPage($pager_id = 0) {
$pages = $this->getPagerQuery();
if (count($pages) === 1) {
return (int) reset($pages);
}
return (int) ($pages[$pager_id] ?? 0);
}
Was added:
if (count($pages) === 1) {
return (int) reset($pages);
}
The solution may be better, but this is a working version at the moment.
Solution for the second problem:
Preprocess pager
$items = &$variables['items'];
$pattern = '/%2C.$/';
// Change href for all pager items except "pages"
// (E.G. first, previous, next, last, etc.).
foreach ($items as $key => $item) {
if (isset($item['href'])) {
$items[$key]['href'] = preg_replace($pattern, '', $item['href']);
}
}
// Change href for pager "pages" items.
foreach ($items['pages'] ?? [] as $key => &$item) {
$items['pages'][$key]['href'] = preg_replace($pattern, '', $item['href']);
}
This is also a working version, but the solution may be better :)
Needs work
11.0 π₯
base system
The change is currently missing an automated test that fails when run with the original code, and succeeds when the bug has been fixed.
Not all content is available!
It's likely this issue predates Contrib.social: some issue and comment data are missing.