I've been making a few upgrades to my blog design recently, and one of the things I've wanted to do for quite a long time was create a "Random Post" link that my readers could click on to browse through my archives.  

Only just recently was I able to accomplish this, thanks to some very neat features that my blog engine Ghost provides.

Complicated computer code
The finished code won't look like this. I think. Photo by Markus Spiske / Unsplash

Come along with me as we discover how to create a "random post" link in a Ghost blog!


Instantiating the Content API Class

Everything we're going to do in this post is done in JavaScript; the final working code is at the end of the post.

The first set of code you need to see is this:

<script src="https://unpkg.com/@tryghost/[email protected]/umd/content-api.min.js"></script>
    <script type="text/javascript">
        const api = new GhostContentAPI({
            url: 'https://exceptionnotfound.net',
            key: '86f8c06bb62e02383b5272206d',
            version: 'v2'
        });
    </script>
</script>

That first <script> tag pulls in the Ghost JavaScript SDK that we need in order to run any samples in this post.  It is inside the second <script> that the rest of our code will be placed.

The JS code in the second <script> instantiates a class GhostContentAPI, which allows us to call the Content API via a set of methods.  This class needs three inputs:

  • url: The root URL of your Ghost blog site.
  • key: The API key for this integration.
  • version: The version number (which always starts with a 'v') of the API call.

The first and third should be obvious, but the second requires some explanation.

The "key" is termed an API key, and you can generate one in your Ghost admin site. Here's how to do that:

  1. In the Ghost admin site, click on Integrations, then click Add Custom Integration.
  2. Create a name for your new integration.
  3. Find the field "Content API Key"; this is the key you need to use the Content API.
If you're wondering why I didn't black out the Admin API Key, it's because this integration is already deleted.

With the API Key in hand, we can create some calls to the Content API to get a random post.

Generating a Random Post

Note: This methodology assumes that a link for the "random" post already exists on the page in question.

There's immediately problem with our quest to generate a random post; Ghost does not provide such functionality natively.  There's no random() method or anything like that.  Instead, we need to come up with our own methodology to get a random post.

Here's the methodology I went with:

  • First, get all posts.
  • Second, randomly order these posts.
  • Third, use the post at the first index of the array as the "random" post.

The first part is relatively simple: here's the query to get all posts:

api.posts
    .browse({limit: 'all', fields: 'url, title'})
    .then((posts) => {
	});
})

Note the call to browse(), with two parameters.  The 'limit' parameter says how many posts to return; in this case we want all posts, so the value is 'all'.  The 'fields' parameter says which fields that are part of a post object to return; this can be quite a lot of data, so we limit the fields being returned to just the URL and title since that's all we need to create a link.

The second part of this methodology, randomly ordering the posts, is also relatively simple.  We need to use something called the Fisher-Yates Shuffle algorithm to randomly reorder the posts.  That method looks like this:

function shuffle(array) {
	var currentIndex = array.length, temporaryValue, randomIndex;

    // While there remain elements to shuffle...
    while (0 !== currentIndex) {

        // Pick a remaining element...
        randomIndex = Math.floor(Math.random() * currentIndex);
        currentIndex -= 1;

        // And swap it with the current element.
        temporaryValue = array[currentIndex];
        array[currentIndex] = array[randomIndex];
        array[randomIndex] = temporaryValue;
    }
        
    return array;
}

The final part of this methodology is simple now that we have all the pieces: we just use jQuery to change the content and URL of the existing random link.

api.posts
    .browse({limit: 'all', fields: 'url, title'})
    .then((posts) => {
        var randomPosts = shuffle(posts);
        $(".random-post-link").replaceWith("<li><a href='" + randomPosts[0].url + "'>" + randomPosts[0].title + "</a></li>");
})

The Final Code

Here's the combined total code for this random link:

<script src="https://unpkg.com/@tryghost/[email protected]/umd/content-api.min.js"></script>
    <script type="text/javascript">
    	const api = new GhostContentAPI({
            url: 'https://exceptionnotfound.net',
            key: '86f8c06bb62e02383b5272206d',
            version: 'v2'
        });
        
        api.posts
            .browse({limit: 'all', fields: 'url, title'})
            .then((posts) => {
                var randomPosts = shuffle(posts);
                $(".random-post-link").replaceWith("<li><a href='" + randomPosts[0].url + "'>" + randomPosts[0].title + "</a></li>");
        })
        
        function shuffle(array) {
            var currentIndex = array.length, temporaryValue, randomIndex;

            // While there remain elements to shuffle...
            while (0 !== currentIndex) {

                // Pick a remaining element...
                randomIndex = Math.floor(Math.random() * currentIndex);
                currentIndex -= 1;

                // And swap it with the current element.
                temporaryValue = array[currentIndex];
                array[currentIndex] = array[randomIndex];
                array[randomIndex] = temporaryValue;
            }

            return array;
        }
    </script>
</script>

Where Do I Put This?

In my blog, this code is injected to the bottom of every page using the Code Injection tab in my Ghost Admin.  In your site, you can put it anywhere your scripts would normally be called.

Drawbacks

There's one major drawback of this methodology: if the number of posts is large, this script might be unacceptably slow.

At the time of this writing I have around 330 published posts.  In my tests, this seemed to be acceptable in terms of performance, but only when selecting just the title and URL of the posts as show above; including any other fields made the query take seconds longer.

If you're going to use this method on blogs with thousands of posts, you may want to find an alternate option.

Summary

Using the Ghost JavaScript SDK and Content API, we can now select a "random" post and place it in a link.

What do you think of this methodology?  Do you see something that can be improved?  Please feel free to share in the comments!

Happy Coding!