Bulk Update WordPress Plugins and Themes Across Multiple Sites with WP-CLI

Managing updates for 10, 50, or 100 WordPress sites means logging into each dashboard, clicking through update screens, and praying nothing breaks. It wastes hours every week and delays critical security updates.

WP-CLI lets you update all plugins and themes across unlimited WordPress sites from your terminal—in minutes instead of hours. Add safety checks, automatic backups, and rollback capabilities, and you have enterprise-grade update automation.

In this guide, you’ll learn professional techniques for bulk updating WordPress installations safely, including pre-update backups, staged rollouts, and automated testing used by WordPress agencies managing hundreds of sites.

Why Bulk Update with WP-CLI?

WordPress updates are critical for security, but manual updates don’t scale.

Problems with Manual Updates

Time-consuming: Updating 50 sites manually takes 5-8 hours of repetitive clicking.

Security delays: Critical security patches sit uninstalled for days or weeks.

Inconsistent: Some sites get updated, others forgotten, creating security gaps.

No rollback: If an update breaks a site, you’re manually restoring backups.

Update fatigue: Developers avoid updates because the process is painful.

WP-CLI Bulk Update Advantages

Fast: Update 100 sites in under 30 minutes with automation scripts.

Consistent: Same update process across all sites prevents human error.

Safe: Automated backups before every update enable instant rollback.

Scheduled: Cron automation handles updates during maintenance windows.

Testable: Stage updates on test sites before production rollout.

According to WordPress security research, 60% of hacked WordPress sites were compromised due to outdated plugins. Efficient update workflows prevent breaches.

Single Site Update Operations

Master updating individual WordPress installations first.

Update All Plugins

# Update all plugins
wp plugin update --all

# Preview updates without installing
wp plugin update --all --dry-run

# Update excluding specific plugins
wp plugin update --all --exclude=woocommerce,elementor

# Update specific plugins only
wp plugin update wordfence yoast-seo contact-form-7

Update All Themes

# Update all themes
wp theme update --all

# Update specific theme
wp theme update astra

# Dry run to preview
wp theme update --all --dry-run

Update WordPress Core

# Update to latest version
wp core update

# Update to specific version
wp core update --version=6.4.2

# Update minor versions only (security updates)
wp core update --minor

Pro Tip: Always run --dry-run first to preview what will be updated before making changes.

Learn more in the official WP-CLI plugin update documentation.

Safe Update Workflow with Backups

Never update without backups and rollback capability.

Complete Backup Before Updates

#!/bin/bash
# safe-update.sh - Update with automatic backup

SITE_PATH="/var/www/html"
BACKUP_DIR="/backups"
DATE=$(date +%Y%m%d_%H%M%S)

cd "$SITE_PATH"

echo "Creating pre-update backup..."

# Backup database
wp db export "$BACKUP_DIR/db-before-update-$DATE.sql.gz"

# Backup files (plugins, themes, uploads)
tar -czf "$BACKUP_DIR/files-before-update-$DATE.tar.gz" \
    wp-content/plugins \
    wp-content/themes \
    wp-content/uploads

echo "✓ Backup complete"

# Update plugins
echo "Updating plugins..."
wp plugin update --all

# Update themes
echo "Updating themes..."
wp theme update --all

# Verify WordPress still works
if wp core is-installed; then
    echo "✓ Updates successful, WordPress functional"
else
    echo "✗ WordPress check failed, restoring backup..."
    wp db import "$BACKUP_DIR/db-before-update-$DATE.sql.gz"
    exit 1
fi

Rollback Failed Updates

#!/bin/bash
# rollback-update.sh - Restore last backup

BACKUP_DIR="/backups"

# Find most recent backup
LATEST_DB=$(ls -t "$BACKUP_DIR"/db-before-update-*.sql.gz | head -1)
LATEST_FILES=$(ls -t "$BACKUP_DIR"/files-before-update-*.tar.gz | head -1)

if [ -z "$LATEST_DB" ]; then
    echo "No backup found!"
    exit 1
fi

echo "Rolling back to backup: $LATEST_DB"

# Restore database
wp db import "$LATEST_DB"

# Restore files
tar -xzf "$LATEST_FILES" -C /var/www/html/

echo "✓ Rollback complete"

Bulk Update Across Multiple Sites

Update plugins and themes across all WordPress installations you manage.

Update Multiple Sites Script

#!/bin/bash
# bulk-update-sites.sh - Update all managed sites

SITES=(
    "/var/www/site1"
    "/var/www/site2"
    "/var/www/site3"
    "/var/www/client-site"
)

BACKUP_DIR="/backups"
LOG_FILE="/var/log/wp-bulk-updates.log"

log() {
    echo "[$(date '+%Y-%m-%d %H:%M:%S')] $@" | tee -a "$LOG_FILE"
}

log "=== Bulk WordPress Update Started ==="

for SITE in "${SITES[@]}"; do
    SITE_NAME=$(basename "$SITE")
    log "Processing: $SITE_NAME"

    cd "$SITE" || { log "ERROR: Cannot access $SITE"; continue; }

    # Check WordPress is installed
    if ! wp core is-installed 2>/dev/null; then
        log "WARNING: WordPress not found in $SITE, skipping"
        continue
    fi

    # Backup database
    BACKUP_FILE="$BACKUP_DIR/${SITE_NAME}-$(date +%Y%m%d).sql.gz"
    if wp db export "$BACKUP_FILE"; then
        log "✓ Backed up: $SITE_NAME"
    else
        log "✗ Backup failed for $SITE_NAME, skipping updates"
        continue
    fi

    # Update plugins
    log "Updating plugins for $SITE_NAME..."
    if wp plugin update --all --quiet; then
        log "✓ Plugins updated: $SITE_NAME"
    else
        log "✗ Plugin update failed: $SITE_NAME"
    fi

    # Update themes
    log "Updating themes for $SITE_NAME..."
    if wp theme update --all --quiet; then
        log "✓ Themes updated: $SITE_NAME"
    else
        log "✗ Theme update failed: $SITE_NAME"
    fi

    log "---"
done

log "=== Bulk Update Complete ==="

Use Case: Agencies managing dozens of client sites can update all installations in one maintenance window.

Update with Email Notifications

#!/bin/bash
# bulk-update-notify.sh - Updates with email reporting

ADMIN_EMAIL="admin@example.com"
REPORT="/tmp/update-report-$$.txt"

{
    echo "WordPress Bulk Update Report"
    echo "Generated: $(date)"
    echo "================================"
    echo ""

    # Update logic here (from previous script)
    # ...

} > "$REPORT"

# Email report
mail -s "WordPress Bulk Update Report" "$ADMIN_EMAIL" < "$REPORT"

rm "$REPORT"

Selective and Staged Update Strategies

Control exactly what gets updated and when.

Update Specific Plugins Only

#!/bin/bash
# update-security-plugins.sh - Update security plugins only

SECURITY_PLUGINS=(
    "wordfence"
    "sucuri-scanner"
    "ithemes-security"
    "all-in-one-wp-security-and-firewall"
)

for PLUGIN in "${SECURITY_PLUGINS[@]}"; do
    echo "Updating security plugin: $PLUGIN"
    wp plugin update "$PLUGIN" 2>/dev/null
done

echo "✓ Security plugins updated"

Staged Rollout Strategy

#!/bin/bash
# staged-update.sh - Update test sites first, then production

TEST_SITES=("/var/www/test1" "/var/www/staging")
PROD_SITES=("/var/www/prod1" "/var/www/prod2")

echo "Stage 1: Updating test sites..."
for SITE in "${TEST_SITES[@]}"; do
    cd "$SITE"
    wp plugin update --all
    wp theme update --all
done

echo "Test sites updated. Monitor for 24 hours before production."
read -p "Proceed with production updates? (y/n) " -n 1 -r
echo

if [[ ! $REPLY =~ ^[Yy]$ ]]; then
    echo "Production updates cancelled"
    exit 0
fi

echo "Stage 2: Updating production sites..."
for SITE in "${PROD_SITES[@]}"; do
    cd "$SITE"
    # Backup first
    wp db export "/backups/$(basename $SITE)-prod-$(date +%Y%m%d).sql.gz"
    wp plugin update --all
    wp theme update --all
done

echo "✓ Staged rollout complete"

Learn about WordPress staging environments best practices.

Exclude Problematic Plugins

#!/bin/bash
# update-exclude-known-issues.sh

# Plugins known to have issues in latest version
EXCLUDE_PLUGINS=(
    "broken-plugin"
    "problematic-theme-plugin"
)

# Build exclude parameter
EXCLUDE_PARAM=""
for PLUGIN in "${EXCLUDE_PLUGINS[@]}"; do
    EXCLUDE_PARAM="${EXCLUDE_PARAM}${PLUGIN},"
done

# Remove trailing comma
EXCLUDE_PARAM=${EXCLUDE_PARAM%,}

# Update all except excluded
wp plugin update --all --exclude="$EXCLUDE_PARAM"

echo "Updated all plugins except: $EXCLUDE_PARAM"

Automated Update Scheduling

Schedule bulk updates to run automatically during maintenance windows.

Weekly Automated Updates

#!/bin/bash
# weekly-auto-update.sh - Run via cron

LOG_FILE="/var/log/auto-updates.log"
BACKUP_DIR="/backups/auto"
SITES_DIR="/var/www"

log() {
    echo "[$(date '+%Y-%m-%d %H:%M:%S')] $@" | tee -a "$LOG_FILE"
}

log "=== Automated Weekly Update Started ==="

# Find all WordPress installations
find "$SITES_DIR" -maxdepth 2 -name "wp-config.php" | while read WP_CONFIG; do
    SITE_PATH=$(dirname "$WP_CONFIG")
    SITE_NAME=$(basename "$SITE_PATH")

    cd "$SITE_PATH"
    log "Updating: $SITE_NAME"

    # Backup
    mkdir -p "$BACKUP_DIR"
    wp db export "$BACKUP_DIR/$SITE_NAME-$(date +%Y%m%d).sql.gz" --quiet

    # Update
    wp plugin update --all --quiet
    wp theme update --all --quiet
    wp core update --minor --quiet

    log "✓ Updated: $SITE_NAME"
done

# Cleanup old backups (keep 30 days)
find "$BACKUP_DIR" -name "*.sql.gz" -mtime +30 -delete

log "=== Automated Update Complete ==="

Schedule with cron:

# Run every Sunday at 2 AM
0 2 * * 0 /usr/local/bin/weekly-auto-update.sh

Update Monitoring and Alerts

#!/bin/bash
# monitor-updates.sh - Check for available updates

SITES=("/var/www/site1" "/var/www/site2")
ALERT_EMAIL="admin@example.com"
UPDATES_FOUND=0

REPORT="/tmp/update-status-$$.txt"

{
    echo "WordPress Update Status Report"
    echo "Generated: $(date)"
    echo "=============================="
    echo ""

    for SITE in "${SITES[@]}"; do
        SITE_NAME=$(basename "$SITE")
        cd "$SITE"

        PLUGIN_UPDATES=$(wp plugin list --update=available --format=count 2>/dev/null)
        THEME_UPDATES=$(wp theme list --update=available --format=count 2>/dev/null)

        if [ "$PLUGIN_UPDATES" -gt 0 ] || [ "$THEME_UPDATES" -gt 0 ]; then
            echo "Site: $SITE_NAME"
            echo "  Plugins needing update: $PLUGIN_UPDATES"
            echo "  Themes needing update: $THEME_UPDATES"
            echo ""
            UPDATES_FOUND=$((UPDATES_FOUND + 1))
        fi
    done

    if [ "$UPDATES_FOUND" -eq 0 ]; then
        echo "All sites are up to date!"
    fi

} > "$REPORT"

# Send email if updates available
if [ "$UPDATES_FOUND" -gt 0 ]; then
    mail -s "WordPress Updates Available ($UPDATES_FOUND sites)" "$ALERT_EMAIL" < "$REPORT"
fi

rm "$REPORT"

Testing and Verification

Verify updates didn’t break functionality.

Post-Update Health Check

#!/bin/bash
# verify-updates.sh - Check sites after updates

SITES=("/var/www/site1" "/var/www/site2")

for SITE in "${SITES[@]}"; do
    SITE_NAME=$(basename "$SITE")
    cd "$SITE"

    echo "Checking: $SITE_NAME"

    # Check WordPress is functional
    if ! wp core is-installed 2>/dev/null; then
        echo "✗ WordPress check failed: $SITE_NAME"
        continue
    fi

    # Check database connection
    if ! wp db check 2>/dev/null; then
        echo "✗ Database check failed: $SITE_NAME"
        continue
    fi

    # Check site responds
    SITE_URL=$(wp option get siteurl 2>/dev/null)
    if curl -f -s "$SITE_URL" > /dev/null; then
        echo "✓ $SITE_NAME is healthy"
    else
        echo "✗ $SITE_NAME not responding"
    fi
done

Automated Testing Script

#!/bin/bash
# test-after-update.sh

# Critical pages to test
TEST_URLS=(
    "/"
    "/shop"
    "/checkout"
    "/my-account"
)

SITE_URL=$(wp option get siteurl)

echo "Testing critical pages..."

for PATH in "${TEST_URLS[@]}"; do
    URL="${SITE_URL}${PATH}"

    HTTP_CODE=$(curl -s -o /dev/null -w "%{http_code}" "$URL")

    if [ "$HTTP_CODE" -eq 200 ]; then
        echo "✓ $PATH - OK (200)"
    else
        echo "✗ $PATH - FAILED ($HTTP_CODE)"
    fi
done

Next Steps

You now have professional bulk update capabilities for WordPress sites at scale.

Week 1: Single site updates

  • Practice safe update workflows
  • Implement backup strategies
  • Test rollback procedures

Week 2: Multi-site automation

  • Build bulk update scripts
  • Add safety checks
  • Implement logging

Week 3: Staged rollouts

  • Create test/production workflows
  • Set up monitoring
  • Automate notifications

Week 4: Full automation

  • Schedule automated updates
  • Build health check systems
  • Document recovery procedures

Advanced Topics

  1. Zero-Downtime Updates – Update without taking sites offline
  2. Update Testing Automation – Automated functional testing
  3. Large-Scale WordPress Management – Managing 500+ sites

Get More Resources

Download update automation scripts including:

  • Complete bulk update system
  • Rollback automation
  • Health check templates

Join our email course for:

  • Weekly WP-CLI tutorials
  • WordPress automation strategies
  • Enterprise management techniques

Conclusion

Bulk updating WordPress sites with WP-CLI transforms a time-consuming, risky process into a fast, safe, automated workflow that scales to any number of installations.

What we covered:

✅ Single site update operations with safety checks ✅ Automated backup and rollback strategies ✅ Bulk update scripts for multiple sites ✅ Selective and staged update approaches ✅ Automated scheduling and monitoring ✅ Post-update testing and verification

Master these techniques, and you’ll manage WordPress updates across unlimited sites efficiently while maintaining security and minimizing downtime.

Ready for more? Learn WordPress deployment automation or continuous integration for WordPress.

Questions about bulk WordPress updates with WP-CLI? Drop a comment below!

Found this helpful? Share with other WordPress developers and agencies.