4 minutes
Making Two Blocks Pagers Work at the Same Page
I stumbled into a case where we had to provide two views that are listing content. First display was listing news, and other display was listing news that are relevant to active context (custom made module, basically a taxonomy term).
Both displays must have a title to see what they are listing. The whole page is basically an arhive page listing news in two ways.
I created a view that has two displays: Page and Block, the page itself was titled as “Archive” and I added an header element containing markup <h2>News</h2>
and specified to be displayed only in that Page display.
Secondly I created a block that was using custom contextual filter to get those news that are having relevant active context, then I attached that block to be shown along with the page. The block’s title was set to “News relevant to you”.
The problem
Now I have a nice archive page that lists news under two subheadings, but now I see that both has pagers. When we use either pager, both blocks are paginated to that page.
Technically this is because the pagination is set as query parameter ?page=x
. So my first though was, that I should be able to specify the pagination query parameter for each display.
Turns out, that I wasn’t able to find any settings regarding to paginaton query parameter names. This smells like we need to pop up the hood and start to look the code.
How pagination works?
Pagination is managed by Views ViewsPager
plugins. Views core has four plugins:
"full"
known as Paged output, full pager"mini"
known as Paged output, mini pager"none"
known as Display all items"some"
known as Display a specified number of items
Both, none
and some
plugins are extending \Drupal\views\Plugin\views\pager\PagerPluginBase
abstract class, they are not fetching any pagination information from query parameters because all this information is fixed either by the purpose of plugin (Display all items) or plugin configuration (Display a specified number of items).
Therefore full
and mini
plugins are left to actually read the pagination’s page from user input. Both plugins extends \Drupal\views\Plugin\views\pager\SqlBase
abstract class.
In \Drupal\views\Plugin\views\pager\SqlBase->setCurrentPage($number = NULL)
you see that the method reads the page
query parameter, but it also parses it into an array. After that it set a new value for a global variable $pager_page_array
. From this I think that there must be a feature that allows us to have multiple pagers at the same page?
Was I looking for wrong thing?
As technical person, I of course was looking something that I was able to change the query parameter. I was wrong, I should’ve been reading more closely the settings I was given by the UI.
There is no query parameter name settings provided.
Pager ID
After reading more carefully, I saw there’s an setting called Pager ID, and there it is!
The description says:
Unless you’re experiencing problems with pagers related to this view, you should leave this at 0. If using multiple pagers on one page you may need to set this number to a higher value so as not to conflict within the
?page=
array. Large values will add a lot of commas to your URLs, so avoid if possible.
However, I realised that I’m not able to specify different pager ID for each display within one View. This is a minor limitation and it’s not actually blocking me at all.
I ended up creating one View having a Page display, using pager ID 0
(default). Then, another View having block Display, using pager ID 1
.
Summary
Views is a powerful tool for making many specific and sometimes complex things. It has been long time one of the most popular contributed module for years and finally landed to Drupal core on version 8.
I remember my first reaction to it’s UI in year 2010. I was overwhelmed by the all the things I can tweak, most of them are more clear to me, then there are somethings that I rarely use.
Views UI is a good example of how hard it can be to provide simple interface for complex things.