Textpattern tips, tutorials and code snippets

Shuffle a list

Sometimes we want to output our content in random order, and most Textpattern list tags tags accept sort="rand()" attribute, which often does the trick. But in a recent forum conversation the following challenge was submitted:

How do I output article images in random order in an article list without the images ending up grouped by article? In other words, how do I gather all the image id’s from a group of articles and display them randomly so that the images aren’t grouped by article, but still maintain the ability to permlink each image to it’s respective article?

The initial basis

To begin with we can randomise the output of the articles and the article_image images they contain and store it in a variable:

<txp:variable name="image_links">
	<txp:article_custom limit="9999" sort="rand()" break="br">
		<txp:images sort="rand()" break="br">
			<txp:permlink><txp:image /></txp:permlink>
		</txp:images>
	</txp:article_custom>
</txp:variable>

But that hasn’t quite resolved it: the images are still grouped by article, even though their order is randomised in each group. Another approach might be to gather all the images id’s of all articles first, then pass them to <txp:images id="gathered_image_ids" sort="rand()" /> tag, but then we would no longer be able to link the images back to their articles.

Shuffle the output

Well, if we can not shuffle items before the tag output, why not shuffle the output itself? The content of <txp:variable name="image_links" /> is something like:

<a href="art-1"><img src="img-1" /></a><br />
<a href="art-1"><img src="img-2" /></a><br />
...
<a href="art-100"><img src="img-999" /></a>

Add some PHP

All we have to do is to split it by <br />, mix the chunks and display the result. This takes three lines of PHP code:

<txp:php>
	// split the links by '<br />'
	$links = do_list(parse('<txp:variable name="image_links" />'), '<br />');
	// mix the array
	shuffle($links);
	// join mixed links by '<br />' again
	echo implode('<br />', $links);
</txp:php>

And, as we are shuffling here, you can now remove sort="rand()" attribute from image_links construction for better performance.

Note: if you have your site set to HTML5, you may need to replace <br /> with <br> in the above code example.

Other (plugin-based) solutions were proposed on the Forum thread, but ultimately “all roads Rome lead to” (live-shuffled)!