wp-cli/language-command
A WP-CLI package for installing, activating, and managing WordPress language packs from the command line, covering core, themes, and plugins so you can add or update translations across your site quickly and consistently.
This is not a Laravel package — there is no service provider, facade, or config file to publish. It is a WP-CLI command bundle that ships inside WP-CLI itself, so in most environments wp language already works and wp package install wp-cli/language-command is only needed if you are pinning a specific version or running a stripped-down WP-CLI PHAR.
Minimal steps:
wp core is-installed returns 0). Every subcommand needs wp-config.php and a database connection, even list.wp help language # top-level: core / plugin / theme
wp help language core # install, list, update, uninstall, is-installed
wp help language plugin # adds <plugin> / --all positional handling
wp language core list --status=installed --format=json
First real use case: a deploy step that guarantees a locale is present and active for a WordPress site your Laravel app fronts (headless content API, marketing site behind a Laravel gateway, or a multisite you operate).
wp language core install pt_BR --activate
wp language plugin install woocommerce pt_BR
wp language theme install storefront pt_BR
If you are on Laravel side, wrap it once and never touch raw shell again:
use Symfony\Component\Process\Process;
function wp(string $sitePath, array $args): array
{
$process = new Process(['wp', ...$args, '--path='.$sitePath, '--format=json'], timeout: 300);
$process->run();
return [
'ok' => $process->isSuccessful(),
'stdout' => $process->getOutput(),
'stderr' => $process->getErrorOutput(),
'code' => $process->getExitCode(),
];
}
Map Laravel locales to WP locales explicitly. WordPress uses its own codes (pt_BR, nl_NL, ja, de_DE, zh_CN). Do not derive them from config('app.locale'); keep a lookup table so an unknown Laravel locale fails loudly instead of silently installing nothing.
Use is-installed as an idempotency gate, not install as a no-op. install re-downloads every time; the exit-code contract is the cheap check:
wp language core is-installed pt_BR || wp language core install pt_BR --activate
Exit code 0 = installed, 1 = not installed. Never parse the human output for this.
Deploy ordering matters. Language packs are versioned against the exact core/plugin/theme version string. Install translations after wp core update / plugin updates, never before:
wp core update --minor
wp plugin update --all
wp theme update --all
wp language core update
wp language plugin update --all
wp language theme update --all
Use --dry-run in "report" jobs. wp language plugin update --all --dry-run gives you the "what changed upstream" signal for a nightly digest without touching a live site.
Pull machine-readable output with --format=json/--fields, never the table. Tables are for humans and change column widths between versions:
wp language plugin list --all --fields=plugin,language,status,update --format=json
Then in PHP, filter for status === 'installed' && update !== 'none' to build the update queue yourself.
Fan out by enumerating plugins first. --all is convenient but opaque when one plugin has no translation; if you need per-item error handling, loop:
wp plugin list --field=name --format=json
# then: wp language plugin install <name> pt_BR
Use --activate instead of a second call. wp language core install nl_NL --activate is one round trip. Note wp language core activate is deprecated; the replacement is wp site switch-language nl_NL (in multisite terms: the language is a site option, not a network option).
Artisan command shape. A single wp:languages:sync {--dry-run} {--site=} command that (a) checks core is-installed, (b) installs missing core packs, (c) iterates active plugins, (d) runs updates, and (e) emits a --format=summary result is the right granularity. Keep one command; don't build four.
Cache wp-content/languages/ in CI/Docker. It is a pure download directory. Baking it into an image build saves minutes per pipeline, and re-running update at deploy time is cheap and safe when the directory is already populated.
Persist the directory across deploys. On immutable/containerized hosting, wp-content/languages must be on a persisted volume or rebuilt on every release — otherwise translations silently vanish on the next deploy while wp option get WPLANG still says pt_BR.
wp language core activate still works but emits a deprecation warning; pin your scripts to wp site switch-language. Grep old runbooks for language core activate.--format on update changes the output contract, not just the formatting. Without --format, you get progress lines and success/warning/error messages on stderr; with --format=json, you get structured data. Do not add --format=json to a job whose logs you read manually and then wonder where the progress went.wp language core list without --status=installed returns all available languages (hundreds), most marked uninstalled. Always filter — unfiltered output is a common cause of "the command hung" reports on slow connections.1.7.2 and the translation pack is built for 1.7.1, install may report success while the update column stays available. Check update and updated fields rather than trusting the success line.install/update hits downloads.wordpress.org. Air-gapped builds, restricted egress, or a CI proxy will fail these calls — make them a separate, skippable pipeline stage rather than blocking composer install-style setup.Language_Pack_Upgrader, which honors FS_METHOD. If wp-content is root-owned and PHP runs as www-data, you get "Could not create directory" — fix the mount ownership, not FS_METHOD=direct.wp language core install puts files in the shared wp-content/languages; wp site switch-language writes a per-site option. Looping sites with --url= on a large network is slow — batch it and log per-site results.--all on plugin install/uninstall is a blunt instrument. It targets all plugins, including inactive ones, and multiplies download time linearly. Prefer the explicit plugin list unless you genuinely want everything.When I try ... for expected failures. In Behat, an error output makes When I run fail the scenario; wp language ... is-installed on a missing pack exits 1 and needs try. Same lesson applies to your Laravel feature tests — assert on exit codes, not on error strings.translations_api, async_update_translation, upgrader_process_complete) or register your own WP_CLI::add_command. There is no plugin-style extension hook exposed by this command package itself.Symfony\Process, pinned to a tested WP-CLI version in your image, and assert the version at boot (wp --version) so a host upgrade doesn't change translation behavior under you.How can I help you explore Laravel packages today?