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 :~)

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.