Last week I added a random post button to the blog index.
Here’s how it works.

First create a simple JSON file with post url, title, and maybe tags.1 This is the template for generating the JSON:

[
  {% for post in site.posts %}
    {
      "title"    : "{{ post.title | escape }}",
      "tags"     : "{{ post.tags | join: ', ' }}",
      "url"      : "{{ post.url | prepend: site.baseurl }}"
    }{% unless forloop.last %},{% endunless %}
  {% endfor %}
]

You’ve got to add ‘layout: null’ at the top of the file to stop jekyll from messing with the layout.

Otherwise the JSON is nothing complicated, just a big collection of titles, tags, and links. At the moment with 316 posts it comes out as a 43.7kB file, or 7.8kB when compressed for transfer.

And here’s the javascript file:

async function postrandomiser(){
        const response = await fetch('post_list.json');
        const names = await response.json();
        const random = Math.floor(Math.random() * names.length);
        var randompost = names[random];
        location.href = randompost["url"];
};
document.getElementById('random-post-button').onclick = function(){
    postrandomiser();
}

Then just a button element to call the postrandomiser function.2

<button id="random-post-button">Random post</button>

Finally, some graceful degradation for people who don’t have Javascript enabled, a link wrapped inside a noscript tag.

<noscript>
  {% assign randompost = site.posts | sample: 1 %}
  <a href="{{ randompost.url | prepend: site.baseurl }}">Random post</a>
</noscript>

The ‘sample’ filter randomises the list of posts, and every time the site is generated you get another random url. It’s not as useful as a button which gives a random post with every page load, but good enough as an alternative.

  1. Most of the posts here don’t have tags, I only started using them recently. 

  2. No ‘onclick’ event added to the button itself. No inline scripts.