Skip to content

Filtering Compendium

This guide will give you an overview about the many versatile ways of filtering collections of pages, files, users, and languages that are available in Kirby. It is sort of a compendium of many examples taken from solutions in the forum.

Filtering by listed/unlisted

In Kirby, pages can be either listed (folder with prepended number/date) or unlisted. Kirby has two handy built-in methods to filter pages according to their status:

$collection = page('projects')->children()->listed();
$collection = page('projects')->children()->unlisted();

Filter page collections by a single field

Often, you only want to display all pages that have a certain value in a special field, e.g. a category or a tags field. For this task, you can use the filterBy() method:

// filter a collection by a value in a single value field
$collection = page('projects')
  ->children()
  ->filterBy('category', 'webdesign');

// filter a collection by a value in a field with a comma separated list of values
$collection = page('projects')
  ->children()
  ->filterBy('tags', 'webdesign', ',');

Note the use of the delimiter in the second example to get a value from a comma separated list. If you use other delimiters in your fields, you can, of course, change the delimiter.

Filtering using filter operators

With the above example, you only get results that fit a single value. You can fine tune your filter results by using the operator parameter in the filterBy() method:

Pages

// get all pages with a date after now
$collection = page('blog')
  ->children()
  ->filterBy('date', '>', time());

// get all pages with a title that starts with "A" or a number
$collection = page('blog')
  ->children()
  ->filterBy('title', '<', 'B');

Files

// get all images that contain a string
$images = page('blog')
  ->images()
  ->filterBy('filename', '*=', 'cover-');

// get all file types exept images
$files = page('blog')
  ->images()
  ->filterBy('type', '!=', 'image');

Available filter operators

Method Function
== all values that match exactly
!= all values that don't match
*= all values that contain the given string
!*= all values that don't contain the given string
^= all values that start with the given string
!^= all values that don't start with the given string
$= all values that end with the given string
!$= all values that don't end with the given string
* all values that match the given regular expression
!* all values that don't match the given regular expression
> all values that are greater than the given value
>= all values that are greater or equal the given value
< all values that are smaller than the given value
<= all values that are smaller or equal the given value
in takes an array as parameter, matches all values that are included in the array
not in takes an array as parameter, matches all values that are not included in the array
between takes an array as parameter with two parameters. First is the min value, second is the max value

Filtering by methods

You cannot only filter by custom field methods in your content files but also by methods of a pages', files', users' collection. Here are some examples:

Pages

// filter by page template
$collection = page('projects')
  ->children()
  ->filterBy('template', 'article');

// filter by intended template
$collection = page('projects')
  ->children()
  ->filterBy('intendedTemplate', 'article');

// filter by depth
$collection = $site
  ->index()
  ->filterBy('depth', 2);

// filter by modified date
$collection = $site
  ->index()
  ->filterBy('modified', '>', strtotime('2018-04-30'));

Files

// filter by file extension
$images = $page
  ->images()
  ->filterBy('extension', 'png');

// filter by type
$files = $page
  ->files()
  ->filterBy('type', 'document');

Users

// filter by role
$users = $kirby
  ->users()
  ->filterBy('role', 'editor');

Filter collections by more than one field/method

You can also string together multiple filterBy() methods to narrow down your filter results (using AND logic):

Pages

// fetch all events with a template that is neither "concert" nor "exhibition"
$collection = page('events')
  ->children()
  ->filterBy('template', '!=', 'concert')
  ->filterBy('template', '!=', 'exhibition');

You can, of course, achieve the same result with the not in filter

$collection = page('events')
  ->children()
  ->filter(function ($p) {
    return $p->template() != 'concert' && $p->template() != 'exhibition';
  });

You can also use the new not in filter:

// fetch all events with a template that is neither "concert" nor "exhibition"
$collection = page('events')
  ->children()
  ->filterBy('template', 'not in', ['concert', 'exhibition']);

Files

// fetch all files that are neither videos nor images
$files = $page
  ->images()
  ->filterBy('type', '!=', 'video')
  ->filterBy('type', '!=', 'image');

Users

// fetch all users that are neither admins nor editors
$files = $kirby
  ->users()
  ->filterBy('role', '!=', 'admin')
  ->filterBy('role', '!=', 'editor');

Fun with filtering by date

Since the date field is a bit special, I'll cover this here a bit more extensively.

Filtering from - to

For a simple from - to filtering of dates, you can string together two filterBy() methods as seen above:

// fetch all blog post of 2018 using beginning and end dates
$collection = page('blog')
  ->children()
  ->filterBy('date', '>', strtotime('2018-01-01'))
  ->filterBy('date', '<', strtotime('2018-12-31'));

If you just happen to have the year as a variable, you can use a filter with callback:

$year     = date('Y');
$articles = page('blog')
  ->children()
  ->filter(function ($page) use ($year) {
    return $page->date()->toDate('Y') === $year;
  });

Custom date fields

Events often use custom startdate and enddate date fields. The filterBy() method currently does not work with custom date fields. To filter events with either their ending or beginning in the future, you can use a filter with a callback:

$events = page('events')
  ->children()
  ->filter(function ($child) {
    return $child->startdate()->toDate() > time() || $child->enddate()->toDate() > time();
  });

Note that the date method here uses two parameters. The first is the format parameter, the second is the name of the custom field.

With just two little changes to the above code, you can fetch all events that are happening right now:

$events = page('events')
  ->children()
  ->filter(function ($child) {
    return $child->startdate()->toDate() > time() && $child->enddate()->toDate() < time();
  });

Filtering using the search method

Another option of filtering collections is by using the search() method. There is another cookbook recipe on how to add a search to your site.