4

Specifically I'm looking to list an array's contents in random order on a page each time it is generated.

So, given page.array = [1, 2, 3] the following:

{% for i in page.array %}
  <p>{{ i }}</p>
{% endfor %}

<!-- 
  Yields:
  <p>1</p>
  <p>2</p>
  <p>3</p>
-->

How do I randomize that order? (hopefully with syntax somewhat like the following)

{% for i in page.array.shuffle %}
  <p>{{ i }}</p>
{% endfor %}

<!--
  Yielding something like this, or a random reordering:
  <p>3</p>
  <p>1</p>
  <p>2</p>
-->
Mike Jarema
  • 1,187
  • 1
  • 11
  • 16

3 Answers3

10

I managed to achieve this by adding a custom filter via Jekyll's plugin system:

# _plugins/shuffle.rb
module Jekyll
  module ShuffleFilter
    def shuffle(array)
      array.shuffle
    end
  end
end

Liquid::Template.register_filter(Jekyll::ShuffleFilter)

And using:

{% assign shuffled_array = page.array | shuffle %}
{% for i in shuffled_array %}
  <p>{{ i }}</p>
{% endfor %}
Mike Jarema
  • 1,187
  • 1
  • 11
  • 16
  • 1
    I can't figure out for the life of me how to install this plugin. Any guidance would be appreciated. – bryan Jul 13 '17 at 13:56
  • 1
    @bryan using jekyll v3.6.2 all I had to do was drop the custom filter into a file in `_plugins`, eg. `_plugins/shuffle.rb` – Mike Jarema Nov 08 '17 at 18:03
  • Is there any way to achieve the same functionality with only the Jekyll plugins found in the GitHub Pages gem? Github-pages does not support custom plugins. – fangda Mar 24 '18 at 03:01
  • If you know the length you could use the `sample` filter, but I don't know of any way for a dynamic length of array. – Scott Buchanan Apr 19 '18 at 14:22
  • Thank you! This is my first working custom plugin! – Martin Delille Jun 11 '22 at 16:52
5

The currently accepted answer uses a custom filter, but this is not possible in some common Jekyll environments, such as GitHub Pages.

An easy workaround that does work on GitHub Pages is to use Jekyll's sample filter and pass it the size of the array. For example, here is a Markdown-formatted Jekyll template that will print the titles of your Jekyll blog posts in random order on each Jekyll build:

---
title: Posts in random order
---

{% assign n = site.posts | size %}
{% assign posts = site.posts | sample: n %}
{% for post in posts %}
    * {{ post.title }}
{% endfor %}
M12
  • 737
  • 1
  • 9
  • 14
0

After trying solutions discussed here, I realized it is better using JS because I can shuffle the list dynamically anytime I want. It is easy to implement. Here is an example:

html

<div id="my-list">
  {% for i in page.array %}
    <p>{{ i }}</p>
  {% endfor %}
</div>

js

var myList = document.querySelector('#my-list');
for (var i = myList.children.length; i >= 0; i--) {
    myList.appendChild(myList.children[Math.random() * i | 0]);
}

Reference: javascript - shuffle HTML list element order

mnishiguchi
  • 2,051
  • 23
  • 17