Own Controller for Snippet

Hi, i know i can pass variables to snippets like that:

snippet('snippetname', ['helloWorld' => 'Hello World!'])

But how to define a complete Controller linked to the Snippet?
The only solution i found is using a site.php controller but i think it will get unorganized if i have more than one snippet which needs a controller.

Is there a good way to solve this?

You can overwrite the snippet component and add a controller in there.
Something like this works as a plugin.

<?php // site/plugins/site/index.php

use Kirby\Cms\App as Kirby;
use Kirby\Toolkit\A;
use Kirby\Toolkit\F;
use Kirby\Toolkit\Tpl as Snippet;

Kirby::plugin('lukaskleinschmidt/site', [
    'components' => [
        'snippet' => function (Kirby $kirby, string $name, array $data = []) {
            $snippets = A::wrap($name);

            foreach ($snippets as $name) {
                $name = (string) $name;
                $file = $kirby->root('snippets') . '/' . $name . '.php';

                if (file_exists($file) === false) {
                    $file = $kirby->extensions('snippets')[$name] ?? null;
                }

                if ($file) {
                    break;
                }
            }

            return Snippet::load($file, snippet_controller($name, $data));
        }
    ],
    // You could also register controllers here
    'snippets' => [
        // Register a callback 
        'snippetname.controller' => function (array $data = []) {
            return array_merge($data, [
                …
            ]);
        },
        // Register a file 
        'snippetname.controller' => __DIR__ . '/snippets/snippetname.controller.php',
    ]
]);

function snippet_controller(string $name, array $data = []): array
{
    $name .= '.controller';
    $file = kirby()->root('snippets') . '/' . $name . '.php';

    if (file_exists($file) === false) {
        $file = kirby()->extensions('snippets')[$name] ?? null;
    }

    if (is_string($file) && is_file($file)) {
        $file = F::load($file);
    }

    if (is_callable($file)) {
        $data = call_user_func($file, $data);
    }

    return $data;
}

A controller could then look like this.

<?php // site/snippets/snippetname.controller.php

return function (array $data = []) {
    return array_merge($data, [
        …
    ]);
};

Thanks for your answer. This isnt really what i want to Archive. My Goal ist to outsource everything Like snippets, Templates, Controllers and scss into a Plugin, so that i Just have to Touch the Plugin to make Changes for my customer.

For example ‘snippets/navigation-default.twig’ is extended by ‘snippets/navigation.twig’ in the Plugin. Same for other Stuff.
If i now make a generell Change in my Template i have to think about the Controller folder because this isnt outsorced in my Plugin.

So the Goal ist to outsource the Controller into a Plugin.

With this approach you can actually register the snippets and controllers in a plugin.
It is just of matter of the correct naming.

Kirby::plugin('your/plugin', [
    'snippets' => [
        'header'            => __DIR__ . '/snippets/header.php',
        'header.controller' => __DIR__ . '/snippets/header.controller.php',
    ]
]);
1 Like

I finally found the time today and packed it into a tiny plugin.

2 Likes

Hi, thanks for your message. I will take a look at it :wink: