One pagination, two collections

Hello fellow Kirby lovers.
I’m having some trouble with pagination. :frowning_face:

So, there is two collection objects, both contains somes pages of the website.

The first collection (let’s name it $one) contains some articles.
The second collection (so $two) contains a lot of blog posts or equiv.

Both are displayed on the home page, like a ‘two speeds carrousel’. But with sources from different parts of a webiste.

The aim is to show only one item of $one and 28 items of $two on each page.
So i’m using the pagination()of $two to show and navigate through pages.
As the following :

$one->paginate(1, array('variable' => 'myPagi'));
$two->paginate(28, array('variable' => 'myPagi'));

$pagination = $two->pagination();

Unfortunately, the number of items on each collection doesn’t match at all. Therefor, after an unknown number of pages, $one will go dry, while $two will still have items to display. So, pagination break and do not know what to do.

The behavior i’d like to obtain is to freeze $one's last item after it’s last page , while pagination continue for $two. So newest items will be displayed, but the $one will not react to pagination anymore.

Something like :

if ($one->pagination()->countPages() > $two->pagination()->page()) {
    $one->pagination()->freeze()
}

Above code is metaphorical.

The thing is : I actually don’t know how to achieve this.
I tried to apply a perpetual offset to $one, but didn’t managed to get it to work.

Could someone help me to get me out of this ? :blush:
Or maybe even my logic doesn’t work, or i don’t understand pagination that well.
Any help will be appreciated. And if you need me to give more details, i’ll be happy to.

Love, Wizhou.

I’d approach this differently and build a single collection with the desired order of items, then paginate.

Hi texnine,

Yes, i wanted to do this at first. But i’ve got some issues with it also.

First of all, items of each collection doesn’t go in the same place in the page, and are linked to different elements.
So i used something like :

foreach($one->pagination(1) as $key => $element {

    do->that();
}

foreach ($two->pagination(28) as $key => $element {

    do->this();
}

Is that approach wrong and there is something simpler to acheave this ?

Also, when $one won’t have items anymore, wont it disapear ? And only the elements linked to the second collection be displayed ?

If i follow your logic, i’ll have to merge both collections, by sorting the to insert one items of $one every twenty-eighth item of $two, then paginate.

Will it work using slice() ? Moreother, to keep the separation of element, will i need to re-slice items of the pagination ?

And then, how do i keep last element of $one to be displayed ?

Thank you for your answer :slight_smile:
Wizhou.

Oh, I thought you were always showing 29 Elements, just mixed from one and two and in the same section. In your case, my approach probably wouldn’t work well. Have to think about this again, but somehow these two pagination objects don’t seem to make sense, hm.

I have an idea:

If you only paginate the collection that has more pages, and then for the smaller collection, you don’t use any pagination at all, but grab the item by offset. The offset is the pagination page minus 1.

$posts = page('somepage')->children()->visible()->paginate(28);
$pagination = $posts->pagination();
$articles = page('otherpage')->children()->visible();
$count = $articles->count();
$offset = $pagination->page() -1;
if($pagination->page() > $count) {
  $offset = $count - 1;
}


$article = $articles->offset($offset)->first();

Not sure if my calculation is quite correct, but I hope you get the idea.

If you don’t know which collection has more paginated pages, you would have to use some if statements to find that out first and then if need be, turn it all around.

Oh @texnixe, this idea seems great ! I’ll try it right away. :smiley:

//

Your idea was actually awesome ! And it’s working like a charm !
Each element are properly displayed, plus the pagination and the offset are pairing nicely.
Thank you a lot !
:heart_eyes:

1 Like

@Wizhou Keep in mind that if your $one collection (the one that only displays a single article) ever has more pages than the $two collection has pagination pages, this will stop working and you’d have to adapt the code to work with this possibility.

1 Like

@texnixe Ok thank you for the advice. I’ll integrate it right away.

For this case, i’d have to switch which Collection is paginated, depending on their number of items.
So, if this number is greater for the first collection, it’ll be paginated, and vice-versa.

However, to keep the logic, i used chunk() to group the second collection as in would have been in pagination.
As in the exemple bellow.

$posts = page('somepage')->children()->visible();
$articles = page('otherpage')->children()->visible();

$postsCount = $posts->count();
$articlesCount = $articles->count();

if ($postsCount > $articlesCount) {

    $posts = $posts->paginate(28);
    $pagination = $posts->pagination();
    $count = $articles->count();
    $offset = $pagination->page() -1;

    if($pagination->page() > $count) {
        $offset = $count - 1;
    }

    $articles = $articles->offset($offset)->first();

} else {

    $articles = $articles->paginate(1);
    $pagination = $articles->pagination();

    $posts = $posts->chunk(28);
    $count = $posts->count();

    $offset = $pagination->page() -1;

    if($pagination->page() > $count) {
        $offset = $count - 1;
    }

    $posts = $posts->offset($offset)->first();
    $articles = $articles->first();
}

It’s still possible to reduce this code size, but for this post, I’m presenting it as it.

Thanks again for your amazing help ! :slight_smile:
Whizou.

@Wizhou I think for your if-else statement the correct logic would be to compare the paginated pages, because you are using different pagination limits. So for example, if you have three articles and 56 posts, you would end up with three pagination pages for articles, but only 2 for posts, while there are obviously more posts than articles.