Set option in plugin, when not defined in config.php


In a plugin, in Kirby 3, how can I set an option to a default value when none has been defined in config.php? That option is re-used several times inside the plugin, so using the alternate syntax of option("someOption", "default value"); is not DRY. I prefer to do this once in the plugin’s index.php.

In Kirby 2, you could do the following:

if (c::get("someOption") == "") {
    c::set("someOption", "default value");


Add 'options' into your plugin ring. See here.


omg, it’s literally in the docs. :see_no_evil:


I’m off to weekend mode now


Hrm, I was too soon…

How can I access that default value, that has been set in plugin options, early in the bootstrap phase (before the route is being evaluated)? Are plugin options already loaded then?
I’ld need it in a helper function for the route pattern.

I tried:

$kirby = App::instance();

but this results in null.

Maybe someone from the core team can chime in on this to figure out any potential race conditions in the bootstrap?


When and where are you trying to call that option exactly?


Here it goes :sweat_smile:

Below is a simplified use case of a plugin I try to build. The RouterPatternHelper::getOverviewPattern() function returns an array of patterns which match the localized slugs of a given “overview page”, who’s id (in the default language) is set in the plugin’s overviewPageId-option. But it contains an opinionated default value (“overview”) in the plugin that should be able to be overriden in the config.php (but it should also be possible to not set it in the config.php, and rely on the default page id, as set in the plugin’s options).

The “problem” I try to solve is that I find it error-prone to always have to manually build pattern-arrays which match a certain page in a multilingual setup (e.g.: “/en/overview/xxx”, “/nl/overzicht/xxx”, “/de/ubersicht/xxx”, …), especially because slugs can be altered by website editors and I want to still have a positive match for that page afterwards in my route.

This is my attempt to get this working; and where I’m stuck:

// site/plugins/myPlugin/index.php

include __DIR__ . DS . 'classes' . DS . 'RouterPatternHelper.php';

Kirby::plugin('bvdputte/myPlugin', [
    'options' => [
        'overviewPageId' => 'overview'
    'routes' => require_once __DIR__ . '/routes.php'
// site/plugins/myPlugin/classes/RouterPatternHelper.php

namespace bvdputte\myPlugin;
use Kirby\Cms\App;

class RouterPatternHelper {

     * Prepare the router pattern to match the overview page
     * @return object
    public static function getOverviewPattern()
        $kirby = App::instance();
        $overviewPage = $kirby->find(option("bvdputte.myPlugin.overviewPageId")); // <- I need this to work

        $overviewPattern = [];
        foreach($overviewPage->translations() as $lang) {
            $pattern = "(:any)/" . $home->slug($lang->code()) . "/(:any)";
            array_push($overviewPattern, $pattern);

        return $overviewPattern;
// site/plugins/myPlugin/routes.php

return [
        'pattern' => bvdputte\myPlugin\RouterPatternHelper::getOverviewPattern(),
        'action' => function($lang, $id) {
            // Do something

I hope this makes sense…


What if you just use the option() helper?


without calling the App::instance?


What if you just use the option() helper?

This has no effect, and still works only if the option is set in config.php too. When I remove it there (it’s still in the plugin’s index.php, so the fallback should work), I get an error because it resolves as null

So… my setup kinda works, but I only have to find a way to keep it working when no option is set in config.php, so it falls back to the option defined in the plugin.


Hm, the strange thing is, that if I use the call to
bvdputte\myPlugin\RouterPatternHelper::getOverviewPattern() inside the action, e.g.


return [
        'pattern' => 'overview,
        'action' => function() {
           return array(bvdputte\myPlugin\RouterPatternHelper::getOverviewPattern());

it returns the option value alright (I just returned the option value from the function for testing), or if I call `dump(bvdputte\myPlugin\RouterPatternHelper::getOverviewPattern()) in a template. But somehow it doesn’t like it in the pattern.


It confuses me too. But maybe it’s a racing condition? Or maybe there’s another way to what I want to do?

Perhaps one of the core devs could enlighten us?


Just on my phone, so maybe I missed something skimming over this, but one approach could be to return the routes array in a callback function:


Yay, that works.


Yep, I just tested this and can confirm it works. Thank you!

1 last thing: how do I setup “callbacks” in routes via a require_once to a separate file where I manage all my routes? Is that possible?



    'routes' => function($kirby) {
        return require_once __DIR__ . '/routes.php';



return [
        'pattern' => bvdputte\myPlugin\RouterPatternHelper::getOverviewPattern(),
        'action' => function() {
           return 'whatever'


Thx @texnixe and @distantnative for your help!