Config filters for plugin development

Config filters

In Kirby we already have something called collection filters. In this post I will write about a solution I came up with that I now call config filters.


Let’s say you have a plugin that output values from a collection. Maybe we want to the user to be able to change these values on different conditions.


In $args we have defaults which is an array with default values from the plugin, that can be replaced. We can send other data as well, for example the current page object of the collection.

c::set('my_plugin.filter', function($args) {
    $args['defaults']['title'] = 'hello world';
    return $args['defaults'];


I made some comments in the code.

// $item is a page object in a foreach loop

// Set up default values of the collection
$defaults = [
    'title' => $item->title(),
    'url' => $item->url(),

// Set results to defaults as fallback
$results = $defaults;

// Set the config to a filter variable
$filter = c::get('my_plugin.filter');
// Check if the config filter is an anonymous function
if(is_callable($filter)) {
    // Call the config filter with defaults array and the page object
    $callback = call($filter, [
        'args' => [
            'defaults' => $defaults,
            'page' => $item
// Set results to the config filter results if it's an array
if($callback && is_array($callback)) {
    $results = $callback;

print_r($results); // In a real case you would probably return it from a function here

It may look much to do but it’s quite powerful for the user in the end.

1 Like

missing the part of filtering said collection. maybe adjust example code in config file to make use of $page and $filter?
i understand it can be applied to anything not just filtering collections, but it would make it easier to follow.

otherwise i like the ideas of closures for plugins. @pedroborges did something like that for his sitemap plugin ‘sitemap.process’ afaik.

Yes, it looks similar to that sitemap plugin configs. I will soon release a brand new plugin where I use this idea.

I agree that there is room for improvement in the example above. I made a function out if it that looks kind of like this:

$filtered_result = callback('filter.array', $page->field_with_array(), $page),

In the above I use $page->field_with_array() as the default / fallback. I send the $page to make it accessable in the config option. The filter.array is my config option key (without prefix).

In config.php it will look something like this:

c::set('filter.array', function($args) {
    $args['data']['title'] = 'hello world';
    $args['data']['url'] = $args['page']->slug() . '/something-else';
    return $args['data'];

If this option does not exist, it will just return $page->field_with_array() to $filtered_result.

It takes something in, filter it, and return it out again. It’s really similar how WordPress filters work. I don’t like everything with WordPress, but I think they succeded with actions and filters.