Managing and batch updating multiple WordPress sites from the terminal with wp-cli#
Anyone managing multiple WordPress installations knows how tedious routine maintenance can be: opening dozens of browser tabs, logging into separate /wp-admin dashboards, clicking update on plugins, and hoping nothing crashes.
Using WP-CLI over SSH replaces this manual clicking. With it, you create users, update plugins, run database backups, and execute search-and-replace queries in seconds.
Here is a practical guide covering secure installation (with or without root privileges), safe credential workflows, and a batch Bash script to update all sites on a server.
1. Prerequisites and PHP CLI checks#
Before downloading the binary, make sure PHP CLI is installed and running:
# Verify PHP CLI version
php --version
If the command is not found, install PHP CLI and standard extensions:
# Debian / Ubuntu
sudo apt-get update
sudo apt-get install php-cli php-mysql php-xml php-mbstring php-curl -y
# RHEL / Rocky Linux / AlmaLinux
sudo dnf install php-cli php-mysqlnd php-xml php-mbstring php-curl -y
2. Global installation with root access#
To make wp accessible system-wide:
# 1. Download official PHAR binary
curl -sO https://raw.githubusercontent.com/wp-cli/builds/gh-pages/phar/wp-cli.phar
# 2. Validate integrity with SHA-256
curl -sLO https://raw.githubusercontent.com/wp-cli/builds/gh-pages/phar/wp-cli.phar.sha256 && shasum -a 256 -c wp-cli.phar.sha256
# 3. Make executable and move to global PATH
chmod +x wp-cli.phar
sudo mv wp-cli.phar /usr/local/bin/wp
# 4. Verify installation
wp --info
3. Local installation on shared hosting without root#
In jailed shell environments or shared hosting accounts:
# 1. Create personal bin directory
mkdir -p ~/bin
curl -sO https://raw.githubusercontent.com/wp-cli/builds/gh-pages/phar/wp-cli.phar
chmod +x wp-cli.phar
mv wp-cli.phar ~/bin/wp
# 2. Add to PATH in ~/.bashrc
echo 'export PATH="$HOME/bin:$PATH"' >> ~/.bashrc
source ~/.bashrc
4. The danger of plaintext passwords in CLI arguments#
Safe ways to manage passwords:#
# Option 1: Set password interactively via prompt (never written to history)
wp user update 1 --prompt=user_pass --skip-email
# Option 2: Let WP-CLI generate a secure random password
wp user create new-admin admin@yourdomain.com --role=administrator
# Option 3: Use temporary environment variables
export WP_PASS="TemporaryPassword123!"
wp user create new-admin admin@yourdomain.com --role=administrator --user_pass="$WP_PASS"
unset WP_PASS
5. Fast backups streaming into gzip#
Before updating themes or plugins, create a compressed database snapshot:
# Export database directly through gzip (saves disk I/O and storage)
wp db export - | gzip > backup-$(date +%Y%m%d-%H%M%S).sql.gz
# Restore compressed dump
gunzip -c backup-XXXX.sql.gz | wp db import -
# Optimize and repair tables
wp db optimize
wp db repair
6. Daily operational commands#
A. Core updates and checksum verification#
# Check available updates
wp core check-update
wp plugin list --update=available
wp theme list --update=available
# Update all plugins and themes
wp plugin update --all
wp theme update --all
# Audit WordPress core integrity against official checksums
wp core verify-checksums
B. Migrations and search-and-replace#
# 1. Preview changes with dry-run
wp search-replace 'https://old-site.com' 'https://new-site.com' --all-tables --dry-run
# 2. Execute replacements across all tables
wp search-replace 'https://old-site.com' 'https://new-site.com' --all-tables
C. Cache flushing#
# Clear transients and object cache
wp transient delete --all
wp cache flush
7. Defining project defaults in wp-cli.yml#
Create a wp-cli.yml in your project root to disable destructive commands and configure shortcuts:
path: /var/www/site/public_html
disabled_commands:
- db drop
- db reset
skip-plugins:
- akismet
8. Managing WordPress multi-site networks#
# List network subsites
wp site list
# Update core and plugins across the network
wp core update --network
wp plugin update --all --network
9. Batch Bash script for multi-site servers#
If you manage a server with multiple client sites, this script discovers all WordPress directories, creates backups, and updates plugins with logging:
#!/usr/bin/env bash
set -euo pipefail
BASE_DIR="${1:-/home}"
LOG_FILE="/var/log/wp-update-$(date +%Y%m%d-%H%M%S).log"
BACKUP_DIR="/root/wp-backups/$(date +%Y%m%d)"
mkdir -p "$BACKUP_DIR"
log() { echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" | tee -a "$LOG_FILE"; }
SITES=$(find "$BASE_DIR" -maxdepth 5 -name wp-config.php -not -path "*/wp-content/*" 2>/dev/null)
for wpconfig in $SITES; do
site=$(dirname "$wpconfig")
SITE_NAME=$(basename "$(dirname "$site")")
log "Updating site: $site"
# 1. Database backup
wp --path="$site" --no-color --skip-plugins db export "$BACKUP_DIR/${SITE_NAME}-pre-update.sql" --quiet 2>/dev/null || true
# 2. Update core and plugins
wp --path="$site" --no-color core update --skip-plugins --quiet || true
wp --path="$site" --no-color plugin update --all --quiet || true
# 3. Verify checksums
wp --path="$site" --no-color core verify-checksums --quiet || log "Checksum alert on $site"
done
log "Batch update routine finished."
Practical production takeaways#
- Use --skip-plugins during crashes: If an update causes a fatal 500 error, WP-CLI still runs when passing
--skip-plugins, allowing you to deactivate the broken plugin directly. - Pipes save time and storage: Piping dumps directly through
gzipprevents creating giant uncompressed.sqlfiles on your disk. - Audit checksums periodically: Running
wp core verify-checksumsis the fastest method to verify that core WordPress files have not been modified or infected. - Secure admin surfaces: Pair CLI operations with a thorough WordPress technical security audit and verify web server permissions with our Nginx cache permissions guide.
Was this article helpful?
Leave a quick reaction to help prioritize future technical guides:
This post is licensed under CC BY-NC.



Comments
Join the discussion below.
0 comments