{"id":251354,"date":"2026-09-18T12:50:00","date_gmt":"2026-09-18T12:50:00","guid":{"rendered":"https:\/\/muhamedahmed.com\/wp-cli-commands\/"},"modified":"2026-11-02T04:15:18","modified_gmt":"2026-11-02T04:15:18","slug":"wp-cli-commands","status":"publish","type":"post","link":"https:\/\/muhamedahmed.com\/en\/wp-cli-commands\/","title":{"rendered":"WP-CLI Commands I Use Every Week (With Real Examples)"},"content":{"rendered":"<p><strong>WP-CLI commands<\/strong> let you manage WordPress from the terminal: export and import the database, update core, plugins and themes, run search-replace, manage users, regenerate images, flush caches, run cron events and manage WooCommerce data. The commands below are the ones I use most, with the exact syntax and the safety habits around them.<\/p>\n<p>This is part of my <a href=\"\/ai-tools-for-web-developers\/\">automation series<\/a>.<\/p>\n<h2>What is WP-CLI and why use it?<\/h2>\n<p>WP-CLI is the official command-line tool for WordPress. It is faster than clicking through the admin, works when the admin is broken, and makes tasks repeatable in scripts. On slow servers it also avoids web timeouts for long jobs, such as regenerating thousands of thumbnails.<\/p>\n<p>Check it is available:<\/p>\n<pre><code class=\"language-bash\">wp --info\nwp core version\n<\/code><\/pre>\n<p>Run commands from the WordPress root, or add <code>--path=\/path\/to\/site<\/code>.<\/p>\n<h2>Backups and the database<\/h2>\n<pre><code class=\"language-bash\"># Export before anything risky\nwp db export ~\/backups\/site-$(date +%F).sql\n\n# Import (overwrites the database!)\nwp db import ~\/backups\/site-2026-10-01.sql\n\n# Database size and tables\nwp db size --tables\n\n# Optimise tables\nwp db optimize\n<\/code><\/pre>\n<p>Rule I never break: export first, then change.<\/p>\n<h2>Updates<\/h2>\n<pre><code class=\"language-bash\">wp core check-update\nwp plugin list --update=available\nwp plugin update --all --dry-run\nwp plugin update woocommerce\nwp theme update --all\nwp core update &amp;&amp; wp core update-db\n<\/code><\/pre>\n<p>For stores, I update major plugins one at a time on staging first. Combined with a <a href=\"\/wordpress-plugin-audit-checklist\/\">plugin audit<\/a>, this keeps sites stable.<\/p>\n<h2>Search and replace<\/h2>\n<p>The classic use: moving a site to a new domain or from HTTP to HTTPS. WP-CLI handles serialised data correctly, unlike a raw SQL replace.<\/p>\n<pre><code class=\"language-bash\">wp search-replace 'http:\/\/old.example.com' 'https:\/\/example.com' --all-tables --dry-run\nwp search-replace 'http:\/\/old.example.com' 'https:\/\/example.com' --all-tables --precise\n<\/code><\/pre>\n<p>Read the dry-run output before running it for real. Useful for <a href=\"\/migrate-online-store-without-losing-seo\/\">migrations<\/a>.<\/p>\n<h2>Users<\/h2>\n<pre><code class=\"language-bash\">wp user list --role=administrator --fields=ID,user_login,user_registered\nwp user create jane jane@example.org --role=editor\nwp user update 12 --role=subscriber\nwp user application-password list 1\n<\/code><\/pre>\n<p>Reviewing administrators regularly is part of my <a href=\"\/wordpress-security-checklist\/\">security checklist<\/a>.<\/p>\n<h2>Content and options<\/h2>\n<pre><code class=\"language-bash\">wp post list --post_type=page --fields=ID,post_title,post_status\nwp post create --post_type=post --post_title='Draft title' --post_status=draft\nwp post meta get 123 _thumbnail_id\nwp option get permalink_structure\nwp option update blog_public 1   # make sure search engines are not discouraged\nwp rewrite flush\n<\/code><\/pre>\n<h2>Media<\/h2>\n<pre><code class=\"language-bash\">wp media regenerate --only-missing --yes\nwp media import ~\/images\/*.jpg --post_id=123\nwp media image-size\n<\/code><\/pre>\n<p><code>--only-missing<\/code> is gentle on slow servers. See <a href=\"\/convert-images-webp-avif-wordpress\/\">image optimisation<\/a>.<\/p>\n<h2>Cache and transients<\/h2>\n<pre><code class=\"language-bash\">wp cache flush                   # object cache\nwp transient delete --expired\nwp transient delete --all\n<\/code><\/pre>\n<p>Page cache plugins usually register their own commands; check <code>wp help<\/code> to see what is installed.<\/p>\n<h2>Cron<\/h2>\n<pre><code class=\"language-bash\">wp cron event list\nwp cron event run --due-now\nwp cron test\n<\/code><\/pre>\n<p>Details in the <a href=\"\/wp-cron\/\">WP-Cron guide<\/a>.<\/p>\n<h2>WooCommerce<\/h2>\n<p>WooCommerce adds commands under <code>wp wc<\/code>, mapping to its REST API. Most need a user:<\/p>\n<pre><code class=\"language-bash\">wp wc product list --user=1 --fields=id,name,sku,stock_quantity\nwp wc order list --user=1 --status=processing\nwp wc webhook list --user=1\nwp wc tool run clear_transients --user=1\n<\/code><\/pre>\n<p>Related: <a href=\"\/woocommerce-webhooks\/\">WooCommerce webhooks<\/a> and <a href=\"\/woocommerce-import-products-csv\/\">CSV product imports<\/a>.<\/p>\n<h2>Running PHP<\/h2>\n<pre><code class=\"language-bash\">wp eval 'echo get_bloginfo(&quot;name&quot;);'\nwp eval-file scripts\/fix-meta.php\nwp shell\n<\/code><\/pre>\n<p><code>eval-file<\/code> is my preferred way to run one-off data fixes: the script is reviewed, versioned and repeatable.<\/p>\n<h2>Writing a custom command<\/h2>\n<p>When I repeat the same steps, I make a command. In a plugin:<\/p>\n<pre><code class=\"language-php\">if ( defined( 'WP_CLI' ) &amp;&amp; WP_CLI ) {\n    WP_CLI::add_command( 'mx stale-drafts', function ( $args, $assoc ) {\n        $days  = isset( $assoc['days'] ) ? absint( $assoc['days'] ) : 90;\n        $posts = get_posts( array(\n            'post_status' =&gt; 'draft',\n            'numberposts' =&gt; -1,\n            'date_query'  =&gt; array( array( 'before' =&gt; &quot;$days days ago&quot; ) ),\n        ) );\n        foreach ( $posts as $p ) {\n            WP_CLI::log( sprintf( '%d  %s', $p-&gt;ID, $p-&gt;post_title ) );\n        }\n        WP_CLI::success( count( $posts ) . ' stale drafts.' );\n    } );\n}\n<\/code><\/pre>\n<p>Run with <code>wp mx stale-drafts --days=60<\/code>. Custom commands are also safer for AI-assisted work: one reviewed command is easier to trust than many ad-hoc changes.<\/p>\n<h2>Running remotely<\/h2>\n<p>WP-CLI supports SSH aliases in <code>wp-cli.yml<\/code>:<\/p>\n<pre><code class=\"language-yaml\">@prod:\n  ssh: user@example.com:22\/home\/user\/public_html\n<\/code><\/pre>\n<p>Then <code>wp @prod plugin list<\/code> runs on the server from your machine.<\/p>\n<h2>Safety habits<\/h2>\n<ul>\n<li>Export the database before data-changing commands.<\/li>\n<li>Use <code>--dry-run<\/code> when available.<\/li>\n<li>Test on staging first.<\/li>\n<li>Run heavy jobs off-peak on slow hosting.<\/li>\n<li>Keep scripts in version control.<\/li>\n<\/ul>\n<h2>Common mistakes<\/h2>\n<ul>\n<li>Running search-replace without a dry run.<\/li>\n<li>Running commands as root, creating files the web server cannot write.<\/li>\n<li>Forgetting <code>--user<\/code> for WooCommerce commands.<\/li>\n<li>Running from the wrong directory and changing another site.<\/li>\n<\/ul>\n<h2>Installing WP-CLI and checking your environment<\/h2>\n<p>On most managed and shared hosts in the region, including Hostinger and many cPanel providers, WP-CLI is already installed; run <code>wp --info<\/code> over SSH to confirm the version and the PHP binary it uses. If it is missing, the official handbook shows how to download the phar file and put it on your path (<a href=\"https:\/\/make.wordpress.org\/cli\/handbook\/guides\/installing\/\" target=\"_blank\" rel=\"noopener\">WP-CLI Handbook: Installing<\/a>). Keep WP-CLI itself current with <code>wp cli update<\/code> where you have permission, because new WordPress and WooCommerce releases sometimes need a newer CLI.<\/p>\n<p>A small detail that saves confusion: the PHP version used by the command line can differ from the one serving your website. If a command fails with a syntax error that the site does not show, compare <code>wp --info<\/code> with Site Health.<\/p>\n<h2>A safe update routine I use on client sites<\/h2>\n<p>Here is the sequence I run before and after monthly maintenance. It is short enough to memorise and covers the common failure points:<\/p>\n<pre><code>wp db export ~\/backups\/pre-update-$(date +%F).sql\nwp core check-update\nwp plugin list --update=available\nwp plugin update --all --dry-run\nwp plugin update --all\nwp theme update --all\nwp core update &amp;&amp; wp core update-db\nwp cache flush\nwp option get siteurl<\/code><\/pre>\n<p>The dry run lists what will change without changing it. If one plugin is known to be risky, such as a page builder or payment gateway with a big version jump, exclude it with <code>--exclude=plugin-slug<\/code> and update it separately on staging first. Every command and flag is documented in the official reference (<a href=\"https:\/\/developer.wordpress.org\/cli\/commands\/\" target=\"_blank\" rel=\"noopener\">WP-CLI Commands reference<\/a>).<\/p>\n<h2>Handy diagnostics<\/h2>\n<ul>\n<li><code>wp plugin list --status=active --fields=name,version,update<\/code> gives a quick inventory for a <a href=\"\/wordpress-plugin-audit-checklist\/\">plugin audit<\/a>.<\/li>\n<li><code>wp doctor<\/code> (an official package) runs a set of health checks, such as autoloaded option size and cron count (<a href=\"https:\/\/github.com\/wp-cli\/doctor-command\" target=\"_blank\" rel=\"noopener\">wp-cli\/doctor-command<\/a>).<\/li>\n<li><code>wp db size --tables<\/code> shows which tables are bloated, often logs or old sessions.<\/li>\n<li><code>wp option list --autoload=on --format=total_bytes<\/code> tells you how much data loads on every request; large values slow down every page.<\/li>\n<li><code>wp cron event list<\/code> shows overdue events; see the <a href=\"\/wp-cron\/\">WP-Cron guide<\/a> for fixing them.<\/li>\n<\/ul>\n<h2>Scripting for multiple sites<\/h2>\n<p>Freelancers and small agencies often manage ten to fifty client sites. WP-CLI aliases let you run the same command against several of them from your own machine. You define aliases in a <code>wp-cli.yml<\/code> or <code>~\/.wp-cli\/config.yml<\/code> file, each pointing at an SSH host and path, and then group them (<a href=\"https:\/\/make.wordpress.org\/cli\/handbook\/guides\/running-commands-remotely\/\" target=\"_blank\" rel=\"noopener\">WP-CLI Handbook: Running commands remotely<\/a>).<\/p>\n<pre><code>@client-a:\n  ssh: user@client-a.example:65002\/home\/user\/public_html\n@client-b:\n  ssh: user@client-b.example\/var\/www\/site\n@all-clients:\n  - @client-a\n  - @client-b<\/code><\/pre>\n<p>Then <code>wp @all-clients plugin list --update=available<\/code> gives you one report for every site. Start read-only like this; only move to bulk updates once you trust your backups on each site.<\/p>\n<h2>WP-CLI on bilingual WPML or Polylang sites<\/h2>\n<p>On multilingual sites, remember that search-replace touches every language, and that translation plugins store relationships in their own tables. Always include <code>--all-tables-with-prefix<\/code> on migrations so those tables are updated too, and test a few translated URLs afterwards. For language-specific content queries, the plugin&#8217;s own documentation is the reference, as core WP-CLI does not know about languages. More on structure in the <a href=\"\/wordpress-multilingual-site\/\">multilingual WordPress guide<\/a>.<\/p>\n<h2>Moving a site from staging to live<\/h2>\n<p>A typical WP-CLI migration from staging to production looks like this: export the staging database, import it on live, then replace the staging domain everywhere, including serialized data, which a plain SQL find-and-replace would corrupt.<\/p>\n<pre><code>wp db export staging.sql\nwp db import staging.sql\nwp search-replace 'https:\/\/staging.example.com' 'https:\/\/example.com' --all-tables-with-prefix --dry-run\nwp search-replace 'https:\/\/staging.example.com' 'https:\/\/example.com' --all-tables-with-prefix\nwp rewrite flush\nwp cache flush<\/code><\/pre>\n<p>Run the dry run first and read the count of replacements per table; an unexpected zero or a huge number is a sign the domain or protocol is wrong. Afterwards, log in, check a few pages, a form and, on stores, a test order.<\/p>\n<p>If you want routine WordPress work scripted for your team, <a href=\"\/contact\/\">contact me<\/a>.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>A practical list of WP-CLI commands for backups, updates, search-replace, users, media, cache, cron and WooCommerce, plus how to write your own custom command safely.<\/p>\n","protected":false},"author":1,"featured_media":252112,"comment_status":"closed","ping_status":"","sticky":false,"template":"","format":"standard","meta":{"site-sidebar-layout":"default","site-content-layout":"","ast-site-content-layout":"default","site-content-style":"default","site-sidebar-style":"default","ast-global-header-display":"","ast-banner-title-visibility":"","ast-main-header-display":"","ast-hfb-above-header-display":"","ast-hfb-below-header-display":"","ast-hfb-mobile-header-display":"","site-post-title":"","ast-breadcrumbs-content":"","ast-featured-img":"","footer-sml-layout":"","ast-disable-related-posts":"","theme-transparent-header-meta":"","adv-header-id-meta":"","stick-header-meta":"","header-above-stick-meta":"","header-main-stick-meta":"","header-below-stick-meta":"","astra-migrate-meta-layouts":"default","ast-page-background-enabled":"default","ast-page-background-meta":{"desktop":{"background-color":"","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"tablet":{"background-color":"","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"mobile":{"background-color":"","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""}},"ast-content-background-meta":{"desktop":{"background-color":"var(--ast-global-color-5)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"tablet":{"background-color":"var(--ast-global-color-5)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"mobile":{"background-color":"var(--ast-global-color-5)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""}},"footnotes":"","_mx_tldr":"WP-CLI is the official command-line tool for WordPress; it saves time and makes routine work repeatable.\nAlways back up the database before commands that change data, and use --dry-run where available.\nClear cache with wp cache flush for the object cache; page cache plugins often add their own commands.\nCustom commands let you turn repeated admin work into one reliable command.","_mx_faq":"What is WP-CLI? | WP-CLI is the official command-line interface for WordPress. It lets you manage plugins, themes, users, content, the database and settings from a terminal without using the admin dashboard.\nHow do I clear the cache with WP-CLI? | wp cache flush clears the WordPress object cache. Page caching plugins usually provide their own commands, and wp transient delete --all clears transients.\nIs WP-CLI available on shared hosting? | Many hosts include it over SSH. Check your host's documentation; if not installed, it can often be added as a single phar file in your home directory.\nCan WP-CLI break my site? | Commands that change data, such as search-replace or plugin updates, can. Take a database export first, use --dry-run when offered, and test on staging."},"categories":[112],"tags":[115,136,42,135],"class_list":["post-251354","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-automation-ai-tooling","tag-automation","tag-command-line","tag-wordpress","tag-wp-cli"],"_links":{"self":[{"href":"https:\/\/muhamedahmed.com\/en\/wp-json\/wp\/v2\/posts\/251354","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/muhamedahmed.com\/en\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/muhamedahmed.com\/en\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/muhamedahmed.com\/en\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/muhamedahmed.com\/en\/wp-json\/wp\/v2\/comments?post=251354"}],"version-history":[{"count":1,"href":"https:\/\/muhamedahmed.com\/en\/wp-json\/wp\/v2\/posts\/251354\/revisions"}],"predecessor-version":[{"id":252499,"href":"https:\/\/muhamedahmed.com\/en\/wp-json\/wp\/v2\/posts\/251354\/revisions\/252499"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/muhamedahmed.com\/en\/wp-json\/wp\/v2\/media\/252112"}],"wp:attachment":[{"href":"https:\/\/muhamedahmed.com\/en\/wp-json\/wp\/v2\/media?parent=251354"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/muhamedahmed.com\/en\/wp-json\/wp\/v2\/categories?post=251354"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/muhamedahmed.com\/en\/wp-json\/wp\/v2\/tags?post=251354"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}