Plugins

Plugins let you extend LacePHP without touching the core. Drop third-party or custom code into weave/Plugins, and LacePHP will auto-discover, register routes, middleware or CLI commands for you—keeping your application modular and upgrade-safe.

Why Plugins Matter

  • Modularity Keep reusable features in separate packages or folders, not mixed with your app or framework.

  • Discoverability LacePHP auto-discovers any class implementing PluginInterface under weave/Plugins.

  • Extensibility Plugins can register routes, middleware, service providers or CLI commands at boot time.

PluginManager Overview

LacePHP’s PluginManager handles discovery and registration:

use Lacebox\Sole\PluginManager;

$pm = new PluginManager();
$pm->discoverFromFolder(__DIR__);       // load PHP files under weave/Plugins
$pm->discoverFromComposer('vendor');    // load composer packages with lace-plugin.json
$pm->registerAll($router, $config);     // let plugins add routes/middleware
$pm->bootAll($config);                  // call plugin boot logic
$commands = $pm->getCommands();         // pull in CLI commands

Creating a Simple Plugin

  1. Implement the PluginInterface in weave/Plugins/MyFeature/MyPlugin.php:

    <?php
    namespace Weave\Plugins\MyFeature;
    
    use Lacebox\Shoelace\PluginInterface;
    use Lacebox\Shoelace\RouterInterface;
    
    class MyPlugin implements PluginInterface
    {
        public function register(RouterInterface $router, array $config): void
        {
            // e.g. add a new route
            $router->addRoute(
                'GET',
                '/hello-plugin',
                fn() => 'Hello from MyPlugin!'
            );
        }
    
        public function boot(array $config): void
        {
            // run once at framework startup
            if (! empty($config['myfeature']['enabled'])) {
                // set up services, load configs, etc.
            }
        }
    }
    
  2. Enable any config in config/lace.php:

    return [
        'myfeature' => [
            'enabled' => true,
            // other settings...
        ],
    ];
    

No further wiring is needed—LacePHP will discover and invoke your plugin automatically.

Built-in ShoeAI Plugin

LacePHP ships with an AI helper plugin under weave/Plugins/ShoeAI. It demonstrates:

  • Implementing both PluginInterface and CommandProviderInterface

  • Registering multiple CLI commands for AI features

Review weave/Plugins/ShoeAI/AiCommands.php:

<?php
namespace Weave\Plugins\ShoeAI;

use Lacebox\Shoelace\PluginInterface;
use Lacebox\Shoelace\CommandProviderInterface;
use Lacebox\Shoelace\RouterInterface;
use Lacebox\Sole\Cli;
use Weave\Plugins\ShoeAI\Agents\{
    Credentials,
    ShoeAIStatus,
    ShoeGenie,
    ShoeBuddy
};

class AiCommands implements PluginInterface, CommandProviderInterface
{
    public function register(RouterInterface $router, array $config): void
    {
        // no HTTP routes needed here
    }

    public function boot(array $config): void
    {
        // optional boot-time setup
    }

    public function registerCommands(Cli $cli): void
    {
        $cli->register('ai:activate', 'Activate your AI license', fn($argv)=>Credentials::enable());
        $cli->register('ai:status',   'Show AI subscription status',  fn($argv)=>ShoeAIStatus::status());
        $cli->register('ai:scaffold','Scaffold code from a prompt',    fn($argv)=>ShoeGenie::scaffold($argv[2] ?? null));
        $cli->register('ai:rollback','Rollback scaffolded code',      fn($argv)=>ShoeGenie::rollback());
        $cli->register('ai:buddy',   'AI peer-coding buddy',           fn($argv)=>ShoeBuddy::ask($argv[2] ?? null, (int)($argv[3] ?? 0), $argv[4] ?? null));
    }
}

When LacePHP starts, these commands become available:

php lace ai:activate
php lace ai:status
php lace ai:scaffold "Build a REST API for posts"
php lace ai:rollback
php lace ai:buddy Controllers/MyController.php 10 "Why does this line fail?"

Composer-Published Plugins

Publish a plugin as a Composer package:

  1. Add a lace-plugin.json alongside your composer.json:

    {
      "pluginClass": "Vendor\\MyPlugin\\MainPlugin"
    }
    
  2. Implement PluginInterface (and/or CommandProviderInterface) in MainPlugin.

  3. Require via composer:

    composer require vendor/my-laceplugin
    

LacePHP’s discoverFromComposer() will detect and load it automatically.

Registering CLI Commands Manually

Plugins (or your app) can add commands at runtime:

$pm->registerCommands([
    \weave\Plugins\MyFeature\MyCommand::class,
]);

LacePHP will include these classes when assembling the CLI.

Best Practices

  • Single responsibility: per plugin group related features together.

  • Namespace correctly: follow PSR-4 under weave/Plugins/YourPlugin/.

  • Use Composer: for shareable plugins—others can install with composer require.

  • Keep `boot()` light: defer heavy work to services or on-demand hooks.

Warning

  • Plugin discovery loads every PHP file under weave/Plugins—avoid duplicate class names.

  • Ensure your register() logic does not override core routes or middleware unintentionally.

  • Sanitize configuration values before use in boot() to prevent runtime errors.

By writing plugins, even a complex AI feature like ShoeAI, you can add or share functionality cleanly, without touching LacePHP’s core code.