Search by

pollora / wp-cli

pollora

WP-CLI commands declared with PHP attributes: a class with #[WpCli], subcommands with #[Command], synopsis, hooks and conditions as attributes. Runs with or without Laravel.

Package info

github.com/Pollora/wp-cli

Homepage

pkg:composer/pollora/wp-cli

Statistics

Installs: 415

Dependents: 1

Suggesters: 0

Stars: 0

Open Issues: 0

v0.1.1 2026-10-13 08:37 UTC

This package is auto-updated.

Last update: 2026-10-13 08:38:22 UTC


README

Pollora WP-CLI: WP-CLI commands declared with PHP attributes

Latest version Total downloads Tests License

WP-CLI commands written as classes: #[WpCli] on a class registers it, its public methods become subcommands, and the command and subcommand names come from the class and method names unless you give them. Synopsis, when, before and after callbacks are attributes too; no WP_CLI::add_command() call to write.

Part of Pollora, the Laravel framework for WordPress, where it is installed and wired for you, with a pollora:make:wp-cli generator: see WP-CLI Commands. It runs without Laravel too, in a WordPress plugin, a Bedrock site or any PHP project.

Installation

composer require pollora/wp-cli

Requires PHP 8.3+. It builds on pollora/attributes and pollora/discovery. WP-CLI itself provides the WP_CLI classes when it runs.

Declaring commands

use Pollora\Attributes\WpCli;
use Pollora\Attributes\WpCli\Command;
use Pollora\Attributes\WpCli\Synopsis;

/**
 * Manage the reports.
 */
#[WpCli]
final class ReportsCommand
{
    public function __construct(private readonly ReportBuilder $reports) {}

    /**
     * Build a report.
     */
    #[Command('build')]
    #[Synopsis('<month> [--format=<format>]')]
    public function build(array $arguments, array $options): void
    {
        WP_CLI::success($this->reports->build($arguments[0], $options['format'] ?? 'csv'));
    }

    #[Command('rm')]
    public function deleteReport(array $arguments, array $options): void {}
}
wp reports build 2026-10 --format=json
wp reports rm 2026-09
  • The command name is the class name in kebab case, without its Command suffix: ReportsCommand → reports. #[WpCli('reports')] sets it. A class with __invoke() is a single command.
  • A method with #[Command] is a subcommand registered by this package: #[Command('rm')] names it, and its #[Synopsis], #[When], #[BeforeInvoke], #[AfterInvoke] and #[IsDeferred] become the matching WP_CLI::add_command() arguments.
  • WP-CLI also runs the class's other public methods as subcommands, under their method name, with their help read from the docblock.
  • The class is built once, with its constructor dependencies, and that instance runs every command and subcommand.

Wiring it outside Pollora

Run the discovery engine with WpCliDiscovery when WP-CLI loads your plugin:

use Pollora\Discovery\Domain\Models\DiscoveryLocation;
use Pollora\Discovery\Infrastructure\Services\DiscoveryEngine;
use Pollora\WpCli\Application\Services\WpCliService;
use Pollora\WpCli\Infrastructure\Adapters\WpCliAdapter;
use Pollora\WpCli\Infrastructure\Services\WpCliDiscovery;

if (defined('WP_CLI') && WP_CLI) {
    (new DiscoveryEngine)
        ->addLocation(new DiscoveryLocation('MyPlugin\\', __DIR__.'/src'))
        ->addDiscovery('wp_cli_commands', new WpCliDiscovery(new WpCliService(new WpCliAdapter)))
        ->run();
}

Commands are built by the engine's instance resolver: by reflection by default (constructor parameters typed with a class are built in turn), by your container if you give the engine a ContainerInstanceResolver (PSR-11). WpCliService and WpCliDiscovery take a PSR-3 logger.

Testing

composer test   # unit tests, PHPStan, Pint

License

MIT. See LICENSE.