WP-CLI Commands
The Pollora framework provides a declarative way to create WordPress CLI commands using PHP attributes. Commands are automatically discovered and registered with intelligent slug auto-generation.
Table of Contents
Section titled “Table of Contents”- Quick Start
- Single Commands
- Command Suites (Subcommands)
- Automatic Slug Generation
- WP-CLI Attributes
- Command Generator
- Examples
- Best Practices
Quick Start
Section titled “Quick Start”<?php
namespace App\Commands;
use Pollora\Attributes\WpCli;use WP_CLI;
#[WpCli]/** * A simple hello world command */class HelloWorldCommand{ public function __invoke(array $arguments, array $options): void { WP_CLI::success('Hello, World!'); }}wp hello-worldThat’s it! The command slug is auto-generated from the class name.
Single Commands
Section titled “Single Commands”For commands without subcommands, use the __invoke() method:
<?php
namespace App\Commands;
use Pollora\Attributes\WpCli;use WP_CLI;
#[WpCli]/** * Create a new user * * ## OPTIONS * * <username> * : The username for the new user * * [--role=<role>] * : The user role * --- * default: subscriber * --- * * ## EXAMPLES * * wp user-create john --role=editor */class UserCreateCommand{ public function __invoke(array $arguments, array $options): void { $username = $arguments[0] ?? null; $role = $options['role'] ?? 'subscriber';
if (!$username) { WP_CLI::error('Username is required.'); return; }
WP_CLI::success("User '{$username}' created with role '{$role}'"); }}Command Suites (Subcommands)
Section titled “Command Suites (Subcommands)”WP-CLI automatically registers all public methods as subcommands. Method names are converted to kebab-case.
<?php
namespace App\Commands;
use Pollora\Attributes\WpCli;use WP_CLI;
#[WpCli]/** * User management commands */class UserManagementCommand{ /** * Create a new user */ public function create(array $arguments, array $options): void { WP_CLI::success('User created'); }
/** * Delete a user */ public function delete(array $arguments, array $options): void { WP_CLI::success('User deleted'); }
/** * List all users */ public function listUsers(array $arguments, array $options): void { WP_CLI::success('Listing users...'); }}wp user-management createwp user-management deletewp user-management list-usersCustom Subcommand Names with #[Command]
Section titled “Custom Subcommand Names with #[Command]”Use #[Command] only when you need a custom slug different from the method name:
<?php
namespace App\Commands;
use Pollora\Attributes\WpCli;use Pollora\Attributes\WpCli\Command;use WP_CLI;
#[WpCli]/** * User management commands */class UserManagementCommand{ #[Command('new')] // Custom slug instead of "create-user" /** * Create a new user */ public function createUser(array $arguments, array $options): void { WP_CLI::success('User created'); }
#[Command('rm')] // Custom slug instead of "delete-user" /** * Delete a user */ public function deleteUser(array $arguments, array $options): void { WP_CLI::success('User deleted'); }
// No #[Command] needed - auto-generates "list" from method name public function list(array $arguments, array $options): void { WP_CLI::success('Listing users...'); }}wp user-management new # Uses custom slugwp user-management rm # Uses custom slugwp user-management list # Uses auto-generated slugAutomatic Slug Generation
Section titled “Automatic Slug Generation”Class Name → Command Slug
Section titled “Class Name → Command Slug”The “Command” suffix is automatically removed:
| Class Name | Generated Slug |
|---|---|
UserManagementCommand | user-management |
DatabaseCleanupCommand | database-cleanup |
CacheHelper | cache-helper |
Method Name → Subcommand Slug
Section titled “Method Name → Subcommand Slug”| Method Name | Generated Slug |
|---|---|
createUser() | create-user |
deleteById() | delete-by-id |
list() | list |
Custom Slugs
Section titled “Custom Slugs”Override auto-generation when needed:
#[WpCli('cache')] // Custom command slugclass CacheManagementCommand{ #[Command('flush')] // Custom subcommand slug public function clearAllCaches(): void { }
public function warmup(): void { } // Auto: "warmup"}wp cache flush # Custom slugwp cache warmup # Auto-generated slugWP-CLI Attributes
Section titled “WP-CLI Attributes”#[Synopsis]
Section titled “#[Synopsis]”Define command arguments and options:
use Pollora\Attributes\WpCli\Synopsis;
#[WpCli]#[Synopsis('<name> [--greeting=<greeting>] [--uppercase]')]class GreetCommand{ public function __invoke(array $arguments, array $options): void { $name = $arguments[0]; $greeting = $options['greeting'] ?? 'Hello'; WP_CLI::success("{$greeting}, {$name}!"); }}#[When]
Section titled “#[When]”Control when the command is available:
use Pollora\Attributes\WpCli\When;
#[WpCli]#[When('after_wp_load')] // Execute after WordPress loads (most common)class MyCommand { }
#[WpCli]#[When('before_wp_load')] // Execute before WordPress loadsclass EarlyCommand { }#[BeforeInvoke] / #[AfterInvoke]
Section titled “#[BeforeInvoke] / #[AfterInvoke]”Execute callbacks before/after the command:
use Pollora\Attributes\WpCli\BeforeInvoke;use Pollora\Attributes\WpCli\AfterInvoke;
#[WpCli]#[BeforeInvoke([self::class, 'setup'])]#[AfterInvoke([self::class, 'cleanup'])]class MyCommand{ public function __invoke(array $arguments, array $options): void { WP_CLI::success('Command executed'); }
public static function setup(): void { WP_CLI::debug('Setting up...'); }
public static function cleanup(): void { WP_CLI::debug('Cleaning up...'); }}#[IsDeferred]
Section titled “#[IsDeferred]”Control registration timing:
use Pollora\Attributes\WpCli\IsDeferred;
#[WpCli]#[IsDeferred(false)] // Register immediately (default is true)class MyCommand { }Complete Example
Section titled “Complete Example”<?php
namespace App\Commands;
use Pollora\Attributes\WpCli;use Pollora\Attributes\WpCli\Synopsis;use Pollora\Attributes\WpCli\When;use Pollora\Attributes\WpCli\BeforeInvoke;use WP_CLI;
#[WpCli('greet')]#[When('after_wp_load')]#[Synopsis('<name> [--greeting=<greeting>] [--format=<format>]')]#[BeforeInvoke([self::class, 'validate'])]/** * Greet someone with style * * ## EXAMPLES * * wp greet John * wp greet John --greeting="Bonjour" */class GreetCommand{ public function __invoke(array $arguments, array $options): void { $name = $arguments[0]; $greeting = $options['greeting'] ?? 'Hello';
WP_CLI::success("{$greeting}, {$name}!"); }
public static function validate(): void { WP_CLI::debug('Validating input...'); }}Command Generator
Section titled “Command Generator”Generate command classes with Artisan:
# Basic commandphp artisan pollora:make-wp-cli TestCommand --description="Test command"
# In a themephp artisan pollora:make-wp-cli ThemeCommand --theme=mytheme --description="Theme utilities"
# In a pluginphp artisan pollora:make-wp-cli PluginCommand --plugin=myplugin --description="Plugin tools"Options
Section titled “Options”| Option | Description |
|---|---|
--description, -d | Command description (required) |
--force, -f | Overwrite existing files |
--theme | Generate in specific theme |
--plugin | Generate in specific plugin |
--module | Generate in specific module |
--path | Custom generation path |
Examples
Section titled “Examples”Database Cleanup
Section titled “Database Cleanup”<?php
namespace App\Commands;
use Pollora\Attributes\WpCli;use WP_CLI;
#[WpCli]/** * Clean up database */class DatabaseCleanupCommand{ public function __invoke(array $arguments, array $options): void { $dryRun = isset($options['dry-run']);
if ($dryRun) { WP_CLI::log('DRY RUN MODE'); }
$spamCount = get_comments(['status' => 'spam', 'count' => true]);
if (!$dryRun && $spamCount > 0) { global $wpdb; $wpdb->delete($wpdb->comments, ['comment_approved' => 'spam']); }
WP_CLI::success("Cleaned {$spamCount} spam comments"); }}Cache Management Suite
Section titled “Cache Management Suite”<?php
namespace App\Commands;
use Pollora\Attributes\WpCli;use Pollora\Attributes\WpCli\Command;use WP_CLI;
#[WpCli('cache')]/** * Cache management commands */class CacheCommand{ #[Command('flush')] /** * Flush all caches */ public function flushAll(array $arguments, array $options): void { wp_cache_flush(); WP_CLI::success('All caches flushed'); }
public function warmup(array $arguments, array $options): void { get_posts(['numberposts' => 10]); WP_CLI::success('Cache warmed up'); }}wp cache flushwp cache warmupBest Practices
Section titled “Best Practices”Error Handling
Section titled “Error Handling”public function __invoke(array $arguments, array $options): void{ try { $this->doSomething(); WP_CLI::success('Done!'); } catch (\Exception $e) { WP_CLI::error($e->getMessage()); }}Input Validation
Section titled “Input Validation”public function __invoke(array $arguments, array $options): void{ if (empty($arguments[0])) { WP_CLI::error('First argument is required.'); return; }}Progress Bars
Section titled “Progress Bars”public function __invoke(array $arguments, array $options): void{ $items = $this->getItems(); $progress = \WP_CLI\Utils\make_progress_bar('Processing', count($items));
foreach ($items as $item) { $this->process($item); $progress->tick(); }
$progress->finish();}Dry Run Support
Section titled “Dry Run Support”public function __invoke(array $arguments, array $options): void{ $dryRun = isset($options['dry-run']);
foreach ($items as $item) { if ($dryRun) { WP_CLI::log("Would delete: {$item->title}"); } else { $this->delete($item); } }}Service Injection
Section titled “Service Injection”class MyCommand{ public function __construct( private MyService $service ) {}
public function __invoke(array $arguments, array $options): void { $this->service->doSomething(); }}Discovery Locations
Section titled “Discovery Locations”Commands are automatically discovered in:
app/Cms/Commands/themes/{theme}/app/Cms/Commands/plugins/{plugin}/app/Cms/Commands/