WordPress Site Cloning and Migration Automation with WP-CLI

Cloning WordPress sites manually means exporting databases through phpMyAdmin, FTPing thousands of files, running search-replace SQL queries that break serialized data, and spending hours fixing broken configurations. One mistake destroys the entire clone.

WP-CLI transforms WordPress cloning and migration into a fast, automated process—clone production to staging in minutes, migrate sites between hosts reliably, and replicate environments for testing without manual intervention or data corruption.

In this guide, you’ll build a complete WordPress site cloning and migration system using WP-CLI, with automated scripts, safety checks, and verification procedures used by professional WordPress agencies.

Why Automate WordPress Cloning and Migration?

WordPress site migration manually is error-prone and doesn’t scale.

Problems with Manual Cloning/Migration

Time-consuming: Manual cloning takes 2-4 hours for medium sites.

Error-prone: Database exports fail, files get missed, URLs break.

Serialized data corruption: Manual search-replace destroys widget settings and options.

No validation: Can’t verify clone completeness or data integrity.

Not repeatable: Each clone requires same tedious manual steps.

WP-CLI Cloning/Migration Advantages

Fast: Clone complete sites in 5-10 minutes instead of hours.

Safe: WordPress-aware operations preserve serialized data.

Scriptable: One-command cloning for any site at any time.

Verifiable: Automated checks ensure complete, accurate clones.

Consistent: Same process every time guarantees reliability.

According to WordPress development surveys, agencies save 20+ hours monthly by automating site cloning for staging and development.

Basic Site Cloning

Clone a WordPress site locally with essential components.

Complete Local Clone Script

#!/bin/bash
# clone-wordpress-site.sh - Clone WordPress site locally

set -euo pipefail

SOURCE_PATH="$1"
DEST_PATH="$2"

if [ -z "$SOURCE_PATH" ] || [ -z "$DEST_PATH" ]; then
    echo "Usage: $0 <source_path> <dest_path>"
    exit 1
fi

echo "Cloning WordPress site..."
echo "Source: $SOURCE_PATH"
echo "Destination: $DEST_PATH"

# Create destination directory
mkdir -p "$DEST_PATH"

# Copy WordPress files
echo "Copying files..."
rsync -av --exclude='wp-content/cache' \
    --exclude='wp-content/backup*' \
    "$SOURCE_PATH/" "$DEST_PATH/"

# Export database from source
echo "Exporting database..."
cd "$SOURCE_PATH"
wp db export /tmp/clone-db.sql

# Create new database config for destination
cd "$DEST_PATH"

# Get source database details
SOURCE_DB=$(wp config get DB_NAME)
SOURCE_USER=$(wp config get DB_USER)
SOURCE_PASS=$(wp config get DB_PASSWORD)

# Create new database
NEW_DB="cloned_${SOURCE_DB}"
mysql -u"$SOURCE_USER" -p"$SOURCE_PASS" -e "CREATE DATABASE IF NOT EXISTS ${NEW_DB};"

# Update wp-config.php
wp config set DB_NAME "$NEW_DB"

# Import database
echo "Importing database..."
wp db import /tmp/clone-db.sql

# Cleanup
rm /tmp/clone-db.sql

# Update URLs if needed
SOURCE_URL=$(wp option get siteurl)
echo "Current site URL: $SOURCE_URL"
read -p "Enter new site URL (or press Enter to keep same): " NEW_URL

if [ -n "$NEW_URL" ]; then
    echo "Updating URLs..."
    wp search-replace "$SOURCE_URL" "$NEW_URL"
    wp option update home "$NEW_URL"
    wp option update siteurl "$NEW_URL"
fi

# Clear caches
wp cache flush
wp rewrite flush

echo "✓ Clone complete: $DEST_PATH"

Run it:

chmod +x clone-wordpress-site.sh
./clone-wordpress-site.sh /var/www/production /var/www/staging

Learn about WordPress directory structure.

Remote Site Migration

Migrate WordPress sites between servers or hosting providers.

Complete Remote Migration Script

#!/bin/bash
# migrate-wordpress-remote.sh - Migrate between servers

set -euo pipefail

SOURCE_HOST="$1"
SOURCE_PATH="$2"
DEST_PATH="$3"
OLD_URL="$4"
NEW_URL="$5"

if [ -z "$NEW_URL" ]; then
    echo "Usage: $0 <source_host> <source_path> <dest_path> <old_url> <new_url>"
    echo "Example: $0 user@old-server.com /var/www/html /var/www/html https://oldsite.com https://newsite.com"
    exit 1
fi

TEMP_DIR="/tmp/wp-migration-$"
DATE=$(date +%Y%m%d_%H%M%S)

mkdir -p "$TEMP_DIR"

echo "=== WordPress Remote Migration Started ==="
echo "From: $SOURCE_HOST:$SOURCE_PATH"
echo "To: $DEST_PATH"
echo "URL: $OLD_URL$NEW_URL"

# Step 1: Export database from source
echo "Step 1/6: Exporting database from source..."
ssh "$SOURCE_HOST" "cd $SOURCE_PATH && wp db export - | gzip" > "$TEMP_DIR/database.sql.gz"

# Verify database export
DB_SIZE=$(stat -c%s "$TEMP_DIR/database.sql.gz")
if [ "$DB_SIZE" -lt 1000 ]; then
    echo "✗ Database export too small, aborting"
    exit 1
fi

# Step 2: Transfer files from source
echo "Step 2/6: Transferring files from source..."
rsync -avz --progress \
    --exclude='wp-content/cache/*' \
    --exclude='wp-content/backup*' \
    "$SOURCE_HOST:$SOURCE_PATH/" "$DEST_PATH/"

# Step 3: Backup destination (if exists)
if [ -d "$DEST_PATH" ]; then
    echo "Step 3/6: Backing up destination..."
    cd "$DEST_PATH"
    if wp core is-installed 2>/dev/null; then
        wp db export "/backups/dest-before-migration-$DATE.sql.gz" || true
    fi
fi

# Step 4: Import database
echo "Step 4/6: Importing database..."
cd "$DEST_PATH"
wp db import "$TEMP_DIR/database.sql.gz"

# Step 5: Update URLs
echo "Step 5/6: Updating URLs..."
wp search-replace "$OLD_URL" "$NEW_URL" --dry-run --report
wp search-replace "$OLD_URL" "$NEW_URL"
wp search-replace "//$(echo $OLD_URL | sed 's~http[s]*://~~')" "//$(echo $NEW_URL | sed 's~http[s]*://~~')"

# Update WordPress options
wp option update home "$NEW_URL"
wp option update siteurl "$NEW_URL"

# Step 6: Verify and cleanup
echo "Step 6/6: Verifying migration..."
if wp core is-installed; then
    echo "✓ WordPress installation verified"
else
    echo "✗ WordPress verification failed"
    exit 1
fi

if wp db check; then
    echo "✓ Database healthy"
else
    echo "✗ Database issues detected"
    exit 1
fi

# Clear caches
wp cache flush
wp rewrite flush

# Cleanup
rm -rf "$TEMP_DIR"

echo "=== Migration Complete ==="
echo "Site URL: $NEW_URL"
echo "Backup: /backups/dest-before-migration-$DATE.sql.gz"

Push to Production

#!/bin/bash
# push-to-production.sh - Push staging to production

STAGING_PATH="/var/www/staging"
PROD_PATH="/var/www/production"
STAGING_URL="https://staging.example.com"
PROD_URL="https://example.com"

read -p "This will overwrite production. Continue? (y/n) " -n 1 -r
echo
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
    exit 0
fi

# Backup production first
cd "$PROD_PATH"
echo "Backing up production..."
wp db export "/backups/prod-$(date +%Y%m%d_%H%M%S).sql.gz"

# Export from staging
cd "$STAGING_PATH"
echo "Exporting staging..."
wp db export /tmp/staging-push.sql.gz

# Copy files
echo "Copying files..."
rsync -av --delete \
    --exclude='wp-config.php' \
    "$STAGING_PATH/" "$PROD_PATH/"

# Import to production
cd "$PROD_PATH"
echo "Importing database..."
wp db import /tmp/staging-push.sql.gz

# Update URLs
echo "Updating URLs for production..."
wp search-replace "$STAGING_URL" "$PROD_URL"
wp option update home "$PROD_URL"
wp option update siteurl "$PROD_URL"

# Clear caches
wp cache flush
wp rewrite flush

# Cleanup
rm /tmp/staging-push.sql.gz

echo "✓ Staging pushed to production"

Advanced Cloning Features

Add professional features to cloning automation.

Selective Cloning

#!/bin/bash
# selective-clone.sh - Clone only specific components

SOURCE_PATH="$1"
DEST_PATH="$2"
CLONE_TYPE="$3"  # database, files, plugins, themes, uploads

case "$CLONE_TYPE" in
    database)
        echo "Cloning database only..."
        cd "$SOURCE_PATH"
        wp db export /tmp/db-clone.sql.gz
        cd "$DEST_PATH"
        wp db import /tmp/db-clone.sql.gz
        rm /tmp/db-clone.sql.gz
        ;;

    files)
        echo "Cloning files only..."
        rsync -av "$SOURCE_PATH/" "$DEST_PATH/"
        ;;

    plugins)
        echo "Cloning plugins..."
        rsync -av "$SOURCE_PATH/wp-content/plugins/" "$DEST_PATH/wp-content/plugins/"
        ;;

    themes)
        echo "Cloning themes..."
        rsync -av "$SOURCE_PATH/wp-content/themes/" "$DEST_PATH/wp-content/themes/"
        ;;

    uploads)
        echo "Cloning uploads..."
        rsync -av "$SOURCE_PATH/wp-content/uploads/" "$DEST_PATH/wp-content/uploads/"
        ;;

    *)
        echo "Usage: $0 <source> <dest> <database|files|plugins|themes|uploads>"
        exit 1
        ;;
esac

echo "✓ Selective clone complete"

Clone with Sanitization

#!/bin/bash
# clone-sanitized.sh - Clone for development, remove sensitive data

SOURCE_PATH="$1"
DEST_PATH="$2"

# Clone site
bash /usr/local/bin/clone-wordpress-site.sh "$SOURCE_PATH" "$DEST_PATH"

cd "$DEST_PATH"

echo "Sanitizing clone for development..."

# Deactivate security plugins
wp plugin deactivate wordfence sucuri-scanner --quiet

# Remove sensitive data
echo "Removing sensitive user data..."

# Anonymize user emails
for user_id in $(wp user list --field=ID); do
    USERNAME=$(wp user get $user_id --field=user_login)
    wp user update $user_id --user_email="${USERNAME}@example.test"
done

# Remove real passwords (force password reset)
for user_id in $(wp user list --field=ID); do
    wp user update $user_id --user_pass="development"
done

# Remove payment gateway credentials
wp option update woocommerce_stripe_settings '{"enabled":"no"}'
wp option update woocommerce_paypal_settings '{"enabled":"no"}'

# Disable external services
wp plugin deactivate google-analytics mailchimp --quiet

# Enable debug mode
wp config set WP_DEBUG true --raw
wp config set WP_DEBUG_LOG true --raw

echo "✓ Clone sanitized for development"

Multi-Environment Sync

Synchronize WordPress across development, staging, and production.

Environment Sync System

#!/bin/bash
# sync-environments.sh - Sync between dev/staging/prod

OPERATION="$1"  # pull or push
ENV_FROM="$2"   # dev, staging, prod
ENV_TO="$3"     # dev, staging, prod

# Environment paths
declare -A PATHS=(
    ["dev"]="/var/www/dev"
    ["staging"]="/var/www/staging"
    ["prod"]="/var/www/production"
)

# Environment URLs
declare -A URLS=(
    ["dev"]="http://dev.local"
    ["staging"]="https://staging.example.com"
    ["prod"]="https://example.com"
)

if [ -z "$ENV_TO" ]; then
    echo "Usage: $0 <pull|push> <from_env> <to_env>"
    echo "Environments: dev, staging, prod"
    exit 1
fi

SOURCE_PATH="${PATHS[$ENV_FROM]}"
DEST_PATH="${PATHS[$ENV_TO]}"
SOURCE_URL="${URLS[$ENV_FROM]}"
DEST_URL="${URLS[$ENV_TO]}"

echo "Syncing $ENV_FROM$ENV_TO"

# Confirmation for production
if [ "$ENV_TO" == "prod" ]; then
    read -p "WARNING: Syncing to production. Continue? (y/n) " -n 1 -r
    echo
    if [[ ! $REPLY =~ ^[Yy]$ ]]; then
        exit 0
    fi
fi

# Backup destination
cd "$DEST_PATH"
echo "Backing up $ENV_TO..."
wp db export "/backups/${ENV_TO}-before-sync-$(date +%Y%m%d).sql.gz"

# Clone
cd "$SOURCE_PATH"
wp db export /tmp/env-sync.sql.gz

rsync -av \
    --exclude='wp-config.php' \
    --exclude='wp-content/cache' \
    "$SOURCE_PATH/" "$DEST_PATH/"

cd "$DEST_PATH"
wp db import /tmp/env-sync.sql.gz

# Update URLs
wp search-replace "$SOURCE_URL" "$DEST_URL"
wp option update home "$DEST_URL"
wp option update siteurl "$DEST_URL"

# Clear caches
wp cache flush
wp rewrite flush

rm /tmp/env-sync.sql.gz

echo "✓ Environment sync complete: $ENV_FROM$ENV_TO"

Clone Verification

Validate clones are complete and functional.

Complete Verification Script

#!/bin/bash
# verify-clone.sh - Verify WordPress clone

CLONE_PATH="$1"

if [ -z "$CLONE_PATH" ]; then
    echo "Usage: $0 <clone_path>"
    exit 1
fi

cd "$CLONE_PATH"

echo "Verifying WordPress clone..."

# Check WordPress is installed
if ! wp core is-installed 2>/dev/null; then
    echo "✗ WordPress not properly installed"
    exit 1
fi
echo "✓ WordPress installed"

# Check database connection
if ! wp db check 2>/dev/null; then
    echo "✗ Database connection failed"
    exit 1
fi
echo "✓ Database connected"

# Verify post count matches
# (Would need original count passed in for real comparison)
POST_COUNT=$(wp post list --format=count)
echo "✓ Posts: $POST_COUNT"

# Verify user count
USER_COUNT=$(wp user list --format=count)
echo "✓ Users: $USER_COUNT"

# Verify plugins
PLUGIN_COUNT=$(wp plugin list --format=count)
echo "✓ Plugins: $PLUGIN_COUNT"

# Check for broken URLs
SITE_URL=$(wp option get siteurl)
echo "Site URL: $SITE_URL"

# Test site accessibility
if curl -f -s "$SITE_URL" > /dev/null; then
    echo "✓ Site accessible"
else
    echo "✗ Site not accessible"
    exit 1
fi

# Verify file permissions
if [ -w wp-content ]; then
    echo "✓ wp-content writable"
else
    echo "✗ wp-content not writable"
fi

echo "✓ Clone verification complete"

Next Steps

You now have complete WordPress site cloning and migration automation capabilities.

Week 1: Basic cloning

  • Practice local clones
  • Test database operations
  • Master URL replacement

Week 2: Remote migrations

  • Set up SSH access
  • Transfer between servers
  • Handle production pushes

Week 3: Advanced features

  • Selective cloning
  • Data sanitization
  • Multi-environment sync

Week 4: Production deployment

  • Build verification systems
  • Automate complete workflows
  • Document procedures

Advanced Topics

  1. Blue-Green Deployments – Zero-downtime migrations
  2. Database Sync Strategies – Incremental updates
  3. Large Site Optimization – Handle massive WordPress sites

Get More Resources

Download cloning scripts including:

  • Complete automation system
  • Verification tools
  • Multi-environment management

Join our email course for:

  • Weekly WP-CLI tutorials
  • Migration best practices
  • DevOps workflows

Conclusion

WordPress site cloning and migration automation with WP-CLI transforms hours of manual work into fast, reliable, one-command operations you can trust.

What we covered:

✅ Complete local site cloning automation
✅ Remote migration between servers
✅ Advanced selective and sanitized cloning
✅ Multi-environment synchronization
✅ Clone verification and validation
✅ Production-ready workflows

Master these techniques, and you’ll clone WordPress sites effortlessly—whether creating staging environments, migrating to new hosts, or replicating sites for development.

Ready for more? Learn WordPress backup automation or deployment pipelines.

Questions about WordPress cloning and migration? Drop a comment below!

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