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.
- Quick Start
- Single Commands
- Command Suites (Subcommands)
- Automatic Slug Generation
- WP-CLI Attributes
- Command Generator
- Examples
- Best Practices
<?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.
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}'");
}
}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 create
wp user-management delete
wp user-management list-usersUse #[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 slug
wp user-management rm # Uses custom slug
wp user-management list # Uses auto-generated slugThe "Command" suffix is automatically removed:
| Class Name | Generated Slug |
|---|---|
UserManagementCommand |
user-management |
DatabaseCleanupCommand |
database-cleanup |
CacheHelper |
cache-helper |
| Method Name | Generated Slug |
|---|---|
createUser() |
create-user |
deleteById() |
delete-by-id |
list() |
list |
Override auto-generation when needed:
#[WpCli('cache')] // Custom command slug
class CacheManagementCommand
{
#[Command('flush')] // Custom subcommand slug
public function clearAllCaches(): void { }
public function warmup(): void { } // Auto: "warmup"
}wp cache flush # Custom slug
wp cache warmup # Auto-generated slugDefine 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}!");
}
}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 loads
class EarlyCommand { }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...');
}
}Control registration timing:
use Pollora\Attributes\WpCli\IsDeferred;
#[WpCli]
#[IsDeferred(false)] // Register immediately (default is true)
class MyCommand { }<?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...');
}
}Generate command classes with Artisan:
# Basic command
php artisan pollora:make-wp-cli TestCommand --description="Test command"
# In a theme
php artisan pollora:make-wp-cli ThemeCommand --theme=mytheme --description="Theme utilities"
# In a plugin
php artisan pollora:make-wp-cli PluginCommand --plugin=myplugin --description="Plugin tools"| 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 |
<?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");
}
}<?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 flush
wp cache warmuppublic function __invoke(array $arguments, array $options): void
{
try {
$this->doSomething();
WP_CLI::success('Done!');
} catch (\Exception $e) {
WP_CLI::error($e->getMessage());
}
}public function __invoke(array $arguments, array $options): void
{
if (empty($arguments[0])) {
WP_CLI::error('First argument is required.');
return;
}
}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();
}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);
}
}
}class MyCommand
{
public function __construct(
private MyService $service
) {}
public function __invoke(array $arguments, array $options): void
{
$this->service->doSomething();
}
}Commands are automatically discovered in:
app/Cms/Commands/themes/{theme}/app/Cms/Commands/plugins/{plugin}/app/Cms/Commands/