Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Extension Command Laravel Package

wp-cli/extension-command

WP-CLI extension-command provides wp plugin and wp theme commands for managing WordPress extensions from the command line. Install from wordpress.org, activate or deactivate, update, delete, and handle multisite network activation, with bulk actions, exclusions, and force reactivation.

View on GitHub
Deep Wiki
Context7

Getting Started

This is not a Composer library you pull into a Laravel app — it's the WP-CLI command package that provides wp plugin and wp theme. You consume it through the wp binary, either the shipped phar, the wordpress:cli Docker image, or wp-cli/wp-cli-bundle as a dev dependency in a Bedrock-style WordPress repo. Your Laravel code touches it through deploy scripts, Envoy tasks, or a queued Process call.

Minimal setup:

# Local or container
composer require --dev wp-cli/wp-cli-bundle
vendor/bin/wp --info

# Docker (WordPress stack)
docker compose run --rm wpcli plugin list --allow-root

Always run against a known root, since WP-CLI walks up from cwd:

wp plugin list --path=/var/www/html --format=json

Look here first, in this order:

  1. wp help plugin — the authoritative command reference. The README is generated from these docblocks, so the CLI help is always the current source of truth.
  2. wp plugin list — inventory: name, status, version, update, update_version, auto_update.
  3. wp plugin get <slug> --format=json — per-plugin detail, including requires_wp, requires_php, requires_plugins.

First real use case, an audit you can run on any environment in one line:

wp plugin list --fields=name,status,version,update,update_version --format=table
wp plugin list --update=available --field=name   # just what's outdated

That single command replaces clicking through wp-admin and is the foundation for everything below.

Implementation Patterns

Inventory and reporting into your tooling. Never scrape the table output. --format=json plus --field= are the stable interfaces:

wp plugin list --status=active --field=name                 # newline list, pipe-friendly
wp plugin list --status=active --format=json | jq -r '.[].name'
wp plugin get woocommerce --field=version                   # single scalar
wp plugin list --format=csv --fields=name,version,update

From Laravel, run these with Symfony\Component\Process or Illuminate\Process, pass --format=json, and json_decode stdout. Keep stderr separate for error surfacing.

Idempotent provisioning. Exit codes make this clean — is-installed and is-active return 0/1:

wp plugin is-installed akismet || wp plugin install akismet --activate
wp plugin is-active akismet   || wp plugin activate akismet

Wrap it in a bash function or an Envoy macro and your environment bootstrap (Docker entrypoint, Forge/Envoyer deploy hook, test fixture setup) becomes rerunnable without a "already installed" wall of errors.

Deploy artifact installs. Build the plugin as a zip in CI, then install the artifact rather than pulling from wordpress.org:

wp plugin install ./build/my-plugin.zip --force --activate

Use --slug=my-plugin when the archive's top-level folder name doesn't match the slug you want in wp-content/plugins. Note this option cannot be combined with multiple plugins in one invocation.

Bulk maintenance, especially on multisite.

wp plugin update --all --minor            # patch/minor only, skip majors
wp plugin update --all --dry-run          # see what would change first
wp plugin activate $(wp plugin list --recently-active --field=name)
wp plugin activate bbpress --network      # network-wide
wp plugin list --status=active-network

--recently-active is the useful trick for restoring state after a "deactivate everything to bisect a bug" session — it ignores the status filter and returns what was active before.

Dependency handling. Since plugin headers now declare Requires Plugins, let the command resolve it:

wp plugin install my-plugin --with-dependencies --activate
wp plugin install-dependencies my-plugin --activate   # plugin already present

State restoration after config changes. wp plugin activate <slug> --force deactivates and reactivates to re-run activation hooks — the CLI equivalent of "deactivate/reactivate to flush rewrite rules," useful after changing permalinks or registering CPTs in a deploy.

CI caching. Downloads land in ~/.wp-cli/cache (or WP_CLI_CACHE_DIR). Cache that directory between CI runs and repeated wp plugin install calls become near-instant:

- uses: actions/cache@v4
  with:
    path: ~/.wp-cli/cache
    key: wp-cli-${{ hashFiles('composer.lock') }}

Composer-managed plugins (Bedrock). If composer.json owns plugin versions, do not wp plugin install on deploy — it desyncs the lockfile and gets wiped by the next composer install. Restrict WP-CLI to state operations (activate, deactivate, list as verification) and let Composer handle installation.

Theme parity. Everything above has a wp theme equivalent (wp theme install, wp theme activate, wp theme list, wp theme update), so one wrapper class can serve both.

Gotchas and Tips

  • wp plugin delete does not deactivate or uninstall. It removes files only, potentially leaving active-plugin entries and orphaned options. The order you usually want is deactivate --uninstall, then delete.
  • Exit code 1 is a normal answer, not a failure. Under set -e or Laravel's Process::throw(), wp plugin is-active foo will abort your script whenever the plugin is inactive. Use explicit conditionals, or || true with a captured code.
  • --all with --exclude is comma-separated and slug-based. wp plugin deactivate --all --exclude=hello,wordpress-seo. Easy to get wrong by passing space-separated names.
  • Slug vs file path. hello vs hello/hello.php. Most commands take the slug; if a command misbehaves, check wp plugin get <slug> --field=file for the canonical relative path.
  • Must-use plugins and dropins are in list but can't be toggled. --status=must-use and --status=dropin filter for them. Dropins (e.g. object-cache.php) require --status=dropin to appear; activation commands will not touch them.
  • Multisite context needs --url. Running --network on a single site errors; running per-site operations on multisite without --url=https://subsite.example.com operates on the wrong option set. Network-active plugins show as active-network, not active, so a naive --status=active check will lie to you.
  • Update checks are network-bound and slow. wp plugin list calls wordpress.org for every plugin. In scripts where you only need status, add --skip-update-check. Symptom: a list call taking 10–30 seconds on a machine with a blocked outbound connection.
  • --force overwrites local modifications. Never blanket wp plugin install $(wp plugin list --field=name) --force on an environment with hotfixed plugins — you silently delete the patch. Use it for artifact-based deploys, not for "update everything."
  • Stale cache installs stale versions. If --version=1.2.3 or an artifact install keeps resolving to an old file, clear it: wp cli cache clear, or delete ~/.wp-cli/cache.
  • GitHub archive installs get renamed. The downloaded folder (wp-envato-market-master) is normalized on install; if the resulting directory is wrong, pin it with --slug. Expect this when installing from archive/master.zip URLs.
  • Output pollution breaks parsers. WP-CLI prints progress and color when attached to a TTY. In scripts and queues set NO_COLOR=1 and WP_CLI_QUIET=1, and prefer --format=json over --format=table. Always parse stdout, and treat non-empty stderr as a warning channel, not necessarily a failure.
  • --allow-root in containers, but watch file ownership. Running wp plugin install as root creates files the www-data user cannot update later. Match UIDs, or chown after install.
  • Debugging is a flag, not a log dive. wp <command> --debug shows the underlying HTTP requests, archive extraction paths, and PHP errors. This is the first thing to reach for when an install "succeeds" but the plugin isn't listed.
  • --insecure is a last resort. It exists for TLS handshake failures in odd CI images and disables certificate validation entirely.
  • Version pinning is underused. --version=2.6.9 for a specific release, --version=dev for trunk from wordpress.org. Pin versions in seed and fixture scripts so test environments are reproducible.
  • The README is generated (wp scaffold package-readme). Editing it directly is futile — change the command docblock and regenerate, and wp help <command> is where users actually find the option list.
  • Premium/private plugins are invisible to update commands. wp plugin update --all only handles wordpress.org-hosted extensions; anything else needs the zip/URL install path with --force.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
dakiquang/laravel-oauth-refresh-lock
woda/laravel-worktrees
dalefranks/ramasite
faghy/laracashbook
roundly-consulting/google-places-for-laravel
roundly-consulting/kubernetes-api-for-laravel
roundly-consulting/plausible-for-laravel
gvp/gvp-laravel-template
metasyncsite/laravel-metasync-client
roundly-consulting/onboarding-for-laravel
andydefer/laravel-notification
adachsoft/cli-process-tester
jhaskell13/laraflow
sebastienheyd/boilerplate-media-manager
ccast/tagixo-primix
pretendtrue/laravel-builder
sawmainek/laravel-scout-tntsearch-driver
tomshaw/laravel-calendar-table
dibakar/laravel-ownership
adachsoft/changelog-linter