Can I register multiple files in a plugin?

I am registering a lot of blueprints, snippets and templates in my plugin.
Is there a way to register multiple files at once?

So instead of

Kirby::plugin('your/plugin', [
    'snippets' => [
        'header' => __DIR__ . '/snippets/header.php',
        // many more ...
    ]
]);

I would like to do something like

Kirby::plugin('your/plugin', [
    'snippets' => __DIR__ . '/snippets/'
]);

I have successfully tested the following code on my system.
There doesn’t seem to be a ready-to-use-solution by Kirby for this.

Kirby::plugin('your/plugin', [
    'blueprints' => array_reduce(glob(__DIR__ . '/blueprints/**/*.{yml}', GLOB_BRACE), function ($blueprints, $file) {
        $name = str_replace([__DIR__ . '/blueprints/', '.yml'], '', $file);
        $blueprints[$name] = $file;
        return $blueprints;
    }, []),

    'snippets' => array_reduce(glob(__DIR__ . '/snippets/*.php'), function ($snippets, $file) {
        $name = basename($file, '.php');
        $snippets[$name] = $file;
        return $snippets;
    }, []),

    'templates' => array_reduce(glob(__DIR__ . '/templates/*.php'), function ($templates, $file) {
        $name = basename($file, '.php');
        $templates[$name] = $file;
        return $templates;
    }, []),
]);

This assumes that the key and blueprint name are identical.
'topheader' => __DIR__ . '/snippets/header.php',
will not work.

Thanks a bunch, I was afraid I’d need to iterate the files myself.
Your code helped me get kickstarted. I needed it to look for extensions recursively though, as I wanted all files in subdirectories, too.

I ended up with these two helper functions:

/**
 * Recursively iterates through all files below the path matching the extension
 * 
 * @param string $path The root path for the search
 * @param string $extension File extension to look for
 */
function filesInDirectory(string $path, string $extension): Generator|null
{
    // return early if the path does not exist
    if (! is_dir($path)) return null;

    // recursively iterate through all files below the root path 
    // matching the extension
    $it = new RecursiveDirectoryIterator($path);
    $it = new RecursiveIteratorIterator($it);
    $it = new RegexIterator($it, '/\.' . $extension . '$/', RegexIterator::MATCH);

    yield from $it;
}

/**
 * Returns an array of extensions to require in a plugin
 */
function extensionsInDirectory($path, $extension)
{
    $files = iterator_to_array(filesInDirectory($path, $extension));
    $extensions = [];

    foreach ($files as $file) {
        $pathinfo = pathinfo($file->getPathname());
        $relativePath = ltrim(str_replace($path, '', $pathinfo['dirname']), '/');
        $key =  $relativePath == '' ? $pathinfo['filename'] : $relativePath . '/' . $pathinfo['filename'];

        $extensions[$key] = $file->getPathname();
    }

    return $extensions;
}

Now I can do this, when registering my plugin:

Kirby::plugin('my-name/my-plugin', [
    'blueprints' => extensionsInDirectory(__DIR__ . '/blueprints', 'yml'),
    'snippets'   => extensionsInDirectory(__DIR__ . '/snipptes', 'php'),
    'templates'  => extensionsInDirectory(__DIR__ . '/templates', 'php'),
    // ...
]);

No more worrying to forget adding a new snippet :slight_smile:

Make sure to check out Bruno’s plugin for this Autoloader | Kirby CMS Plugins

Sweet, thanks :slight_smile:
Wasted some time, learned something new, got something better.