Pagination + Shuffle

Hello Kirby community,

I have a page on which content should appear randomly, but it’s gonna be lots of posts so I wanted a pagination with infinite scroll. Now the problem is, that everytime the infinite scroll script loads the next page, the shuffle function shuffles from beginning, so the posts get doubled.

I found two threads (Shuffle and pagination 2 & Shuffle and pagination combo) to the same topic and I tried to implement these solutions but it didn’t work on my site. How can I get that the posts are shuffled only when the page loads? Does Kirby 3 offer other ways to do this?

Could you please post your code?

Template:

<div class="products" data-infinite-scroll='{ "path": "?page;{{#}}&seed=<?= $seed = get('seed', time()) ?>", "append": ".product-box" }'>
    <?php foreach ($products = $page->children()->shuffle()->paginate(10) as $product): ?>
      <div class="post">
      ...
      </div>
    <?php endforeach ?>
  </div>

plugins/seededShuffle/index.php:

<?php

Kirby::plugin('my-name/seededShuffle', [
    'pagesMethods' => [
        'seededShuffle' => function($seed) {
            mt_srand($seed);

            $keys = array_keys($this->data);
            $size = count($keys);

            for ($i = 0; $i < $size; ++$i) {
                list($chunk) = array_splice($keys, mt_rand(0, $size - 1), 1);
                array_push($keys, $chunk);
            }

            $collection = clone $this;
            $collection->data = [];

            foreach ($keys as $key) {
                $collection->data[$key] = $this->data[$key];
            }

            return $collection;
        }
    ]
]);
?>

And Infite Scroll script.

With these three components I get endless scrolling and loading on my page. But I have only 21 Posts right now.

I had the same task, and it seems like the code you posted is working fine. I’ve added a session specific seed like @lukaskleinschmidt suggested here: https://forum.getkirby.com/t/shuffle-and-pagination-combo/8588/9:

// site/plugins/shuffleSeed/index.php
<?php

Kirby::plugin('bruno/shuffleSeed', [
    'pagesMethods' => [
        'shuffleSeed' => function($seed = null) {

            if(is_null($seed)) {
                $seed = s::get('seed');
            
                if(is_null($seed)) {
                  $seed = time();
                  s::set('seed', $seed);
                }
            }

            mt_srand($seed);

            $keys = array_keys($this->data);
            $size = count($keys);

            for ($i = 0; $i < $size; ++$i) {
                list($chunk) = array_splice($keys, mt_rand(0, $size - 1), 1);
                array_push($keys, $chunk);
            }

            $collection = clone $this;
            $collection->data = [];

            foreach ($keys as $key) {
                $collection->data[$key] = $this->data[$key];
            }

            return $collection;
        }
    ]
]);
?>

and then wherever it’s needed:

$elements = $elements->shuffleSeed()->paginate($numberOfPages);
// or
$elements = $elements->shuffleSeed($myCustomSeed)->paginate($numberOfPages);

working like a charm! Thanks :~)

1 Like

having about 500 pages in my collection, I found the shuffle algorithm above is showing some deficiency (pages in front of the collection are not getting as thoroughly shuffled as pages more towards the end of the collection, which is not ideal if the pages are pre-sorted by a field with only a small number of possible inputs. In my case – 500+ pages with one of ~10 different topics each – the first items in the returned collection would always belong to the same topic).

I replaced this shuffle loop:

for ($i = 0; $i < $size; ++$i) {
    list($chunk) = array_splice($keys, mt_rand(0, $size - 1), 1);
    array_push($keys, $chunk);
}

with this:

$order = array_map(function($val) {return mt_rand(); }, range(1, $size));
array_multisort($order, $keys);

and it seems to be working better.

3 Likes

Hello Bruno and thanks for sharing your code, i’m currently using it for a project and it works fine !
Still I have some randomization issues even with your last edit.

I combined this code with a masonry-infinite scroll and the more I scroll, the more it seems to be randomized but when I refresh the window, my first set of 6 pages are (almost) always the same, in a slightly different order. Changing the seed doesn’t affect it.

I am very novice PHP developer, I used the same plugin without changing anything.

Do you have an idea ? (or someone else ?)

Thanks !

hi odeno,
don’t really have a solution and am not versed enough in “proper” programming to know why this happens. I’d recommend googling around for different methods of shuffling an array based on seed, i.e here PHP shuffle with seed? - Stack Overflow where apparently first linked thread OP got their solution from
sorry that I can’t be of any further help…

Ok I understand, I may have to spend some nights googling then…
Thanks anyway !

Hey!

Was about to make a forum post about a similar issue with a blocks collection and found this which solved the issue by just switching it to a blocksMethod. Bruno thanks a lot for this!

1 Like