Sorting collections
5, 4, 3, 2, 1…, sorting content is an everyday developer's task when dealing with all sorts of content collections: articles, events, images or similar data needs to be sorted, for example, by date or title, in descending or ascending order, or even by a more complicated sorting algorithm.
Kirby's API comes with a built-in method for sorting: the sortBy() method. This method can be used with all sorts of collections (pages, files, users, roles, translations, structure field items etc.).
The sortBy($field, $direction = 'desc', $method = SORT_NATURAL
| SORT_FLAG_CASE)
method accepts three parameters:
$field
The content field or method you want to sort by, usually something like the date, the title etc.
$direction
The direction of your sort order, either desc
for descending, or asc
for ascending.
$method
The method takes an optional third parameter, the sort flag. The default is SORT_NATURAL
| SORT_FLAG_CASE
(human natural case-insensitive order), but you can override this e.g. with SORT_NUMERIC
when sorting numbers or with SORT_LOCALE_STRING
to sort according to the configured locale settings (or the language's locale settings if you use a multi-language setup). PHP also supports other sort flags you can use.
Kirby also provides a sort()
method, which is an alias and does exactly the same as sortBy()
. Use whichever you prefer.
Sorting by a single field
Let's assume you have a list of products, each with a price field. By default, the list should be sorted by price descending, with the most expensive product first:
Here, we pass two parameters to the sortBy()
method: the field we want to use for sorting (price
), and the sort order, here desc
. If you don't pass a sort order parameter, the default is ascending order.
An alternative would be to skip the second parameter and use Kirby's flip()
method instead to achieve exactly the same as above (however a bit slower for large data sets):
Sorting by multiple fields
Sometimes, we don't want to limit sorting to a single field. Let's assume we wanted to sort a list of books by the authors' last and first names:
Here, we have pass two sort fields with their sort order as parameters. Authors will now be sorted by lastname first, then by firstname. You can add more criteria to sort by if necessary.
Sorting by date
Another common use case for sorting is a list of blog articles sorted by date in reversed order, so that the most recent article appears first in the list. If your date field uses the default format yyyy-mm-dd
, you can use the same syntax that we saw above:
However this will break with different formats like dd.mm.yyyy
as the sorting from left to right will then first sort by day, ignoring the year. In this case you can use a callback to parse each date into a common format (a timestamp) before they are sorted:
Kirby will pass each page to the callback and will use the return value to determine the sorting order.
Sorting structure field entries
The same sorting methods outlined above can also be used with structure field entries - if you use the toStructure()
method.
An example: Suppose we have defined a structure field with three fields in our events blueprint:
Let's fetch the events, sort them by date and loop through them to output their content.
If you use yaml()
to create an array of events instead of a collection, and you want to sort that array, you can use the A::sort()
method from the toolkit, or check out the different ways to sort arrays in the PHP manual.
Custom sorting
Let's look at a sorting scenario that is beyond the usual sorting possibilities. Consider a structure field like this:
Now, instead of numbers, our sizes field contains sizes like S, M, L, XL, XXL
etc. Obviously, we cannot sort them alphabetically or otherwise, because they have no inherent order. So, what can we do? The solution here is to pass a callback to the sort method:
Sorting with Page Models
We cannot only use fields that exist in our content files for sorting. In fact, we can use all the methods the different collection classes (pages, files, etc.) provide (and that make sense to sort by). For example, you can sort by the template that is used by a page or file, if that makes sense for your use case. Or you can sort by a custom page model.
Let's assume for a moment that we wanted to sort our project pages by the number of images they have. Kirby doesn't have a native method that counts our images. We could now use a callback like in the previous example, but I wnt to show you another trick:
The page model
I won't go into details with Page Models here. You can read more about them in the docs
Now we can use this method to sort by:
Sorting files
Sorting files works just like with pages. We can sort by any file meta data field, or using built-in methods like modified()
, filename()
etc.
Some examples:
Note that the default sorting order of files is according to their order in the file system.
Sorting users
Users can also be sorted by any field in their profile or by inherent properties like role, language etc.
Some examples:
For files and users (and all the other stuff we can sort) we could also go to extremes, but let's keep it dry and finish here.