Shuffle and pagination 2

Hi,
I found a topic that describe exactly my problem. I’m trying to use shuffle and paginate at the same time without getting same items inside the loop. So I tried to include the plugins provided by @lukaskleinschmidt

// site/plugins/shuffleOnce.php

// shuffle pages by a session based seed or supply a seed
pages::$methods['shuffleOnce'] = function($pages, $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($pages->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 $pages;
  $collection->data = array();
  foreach($keys as $key) {
    $collection->data[$key] = $pages->data[$key];
  }

  return $collection;
};

with that lines :

<?php $pro = $site->find('projets')->children()->visible()->shuffleOnce()->paginate(3) ?>
<?php foreach($pro as $project): ?> 
...
 <?php endforeach ?>

But I don’t understand the logic, every time I refresh the page, the order is the same. I would like to shuffle the projects collection, return to pagination, and get them shuffling every time I refresh the page. Any suggestions ?

As i understand it, the order will always stick until you clear your session. If you closed your browser completely and came back, you will probably get a different order. This is intended by that plugin, to ensure you get the same order through out the course of your visit.

If you shuffle again on page 3, you might end up with items that were on page 5 being moved to page 1, and never see them again. Im not sure i understand the logic in what you want.

From what I can tell, that plugin uses the current time as a seed value in a session. You need to find a way to change that seed or remove it so that it gets set again. i dont think there is a reliable way to detect a refresh with PHP, since that is more of a front end thing. PHP is server side. You might need to use javascript to set a cookie on reload and react to the value of that on a reload, since you can you read cookies with PHP.

In other words, use Javascript to set the seed in a cookie and instead of setting the seed in the session, get that plugin to read the seed from the cookie instead. Then get the javascript to update the seed in the cookie on a page reload. That way, i dont think the shuffle will happen when you move between the pagination pages, only when you reload.

Thank you ! I was just wondering if we could do it any other way without this seed system. I didn’t expected to have to store a session to use shuffle and pagination at the same time. My idea was to show mutiple projects randomly and paginate them. This way we could be able to get a new random order each time we refresh the page.

In my project, it doesn’t make sense to store the same random, because the user might want to refresh the page to generate a new layout.

I’m quite surprised at the complexity of accomplishing this simple thing

The problem lies with shuffle. It runs every time you call it, which happens every time you you move form page to page because you are essentially re-parsing the template for the page again.

The other way of course, depending on your project, is to use javascript to shuffle & paginate. For example, you could probably roll something with list.js.

That probably makes more sense since theres no benefit to being able to jump to a specific pagination page url, since everyones getting a different project order anyway. It’s not like you’ll be able to bookmark page 3 of the pagination and get the same projects on that page 3 days later, so i think javascript pagination is probably fine in this case.

Oh ! and I forget to say the pagination here allows me to use infinite-scroll :slight_smile: With all that you said, I understand better the issue and maybe I have to resign myself to store the session, after all, why not…

1 Like

You could omit the session and set a seed on each page load.
I suspect you do the infinite loading with some kind of ajax call.
You could make the seed available for your javascript ( data-seed) and use it to always get the same collection.

<?php
// site/plugins/seededShuffle.php

// shuffle pages by a session based seed or supply a seed
pages::$methods['seededShuffle'] = function($pages, $seed) {
  mt_srand($seed);

  $keys = array_keys($pages->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 $pages;
  $collection->data = array();
  foreach($keys as $key) {
    $collection->data[$key] = $pages->data[$key];
  }

  return $collection;
};
<div data-seed="<?= $seed = time() ?>">
  <?php foreach ($site->find('projets')->children()->visible()->seededShuffle($seed)->paginate(3) as $project): ?>
    ...
  <?php endforeach ?>
</div>