Skip to content

Instantly share code, notes, and snippets.

@vapvarun
Created February 23, 2026 19:37
Show Gist options
  • Select an option

  • Save vapvarun/fc55e5edd1e6b18d5111cb4362966780 to your computer and use it in GitHub Desktop.

Select an option

Save vapvarun/fc55e5edd1e6b18d5111cb4362966780 to your computer and use it in GitHub Desktop.
WP-CLI Search-Replace: The Complete Guide (tweakswp.com)
wp search-replace 'old-string' 'new-string' [table...] [--dry-run] [--precise] [--all-tables]
wp search-replace 'oldsite.com' 'newsite.com' --dry-run
# Output:
# +---------------------+-----------------------+--------------+------+
# | Table | Column | Replacements | Type |
# +---------------------+-----------------------+--------------+------+
# | wp_commentmeta | meta_value | 0 | SQL |
# | wp_comments | comment_author_url | 2 | SQL |
# | wp_comments | comment_content | 5 | SQL |
# | wp_options | option_value | 47 | PHP |
# | wp_postmeta | meta_value | 12 | PHP |
# | wp_posts | post_content | 156 | SQL |
# | wp_posts | guid | 89 | SQL |
# +---------------------+-----------------------+--------------+------+
# Success: 311 replacements to be made.
# Step 1: Back up the database
wp db export backup-before-migration.sql
# Step 2: Dry-run to see what changes
wp search-replace 'https://oldsite.com' 'https://newsite.com' --dry-run
# Step 3: Execute the replacement
wp search-replace 'https://oldsite.com' 'https://newsite.com'
# Step 4: Also replace without protocol (catches edge cases)
wp search-replace '//oldsite.com' '//newsite.com' --dry-run
wp search-replace '//oldsite.com' '//newsite.com'
# Step 5: Flush caches
wp cache flush
wp rewrite flush
# Back up first
wp db export backup-before-ssl.sql
# Preview changes
wp search-replace 'http://yoursite.com' 'https://yoursite.com' --dry-run
# Execute
wp search-replace 'http://yoursite.com' 'https://yoursite.com'
# Flush everything
wp cache flush
wp rewrite flush
# Catch any remaining http references
wp search-replace 'http://yoursite.com' 'https://yoursite.com' --all-tables --dry-run
# Back up production database first
wp db export production-backup.sql --path=/var/www/production
# Import the staging database to production
wp db import staging-export.sql --path=/var/www/production
# Replace staging URL with production URL
wp search-replace 'https://staging.yoursite.com' 'https://yoursite.com' --path=/var/www/production
# If staging uses a subdirectory
wp search-replace 'https://yoursite.com/staging' 'https://yoursite.com' --path=/var/www/production
# Replace file paths if server paths differ
wp search-replace '/home/staging/public_html' '/home/production/public_html' --path=/var/www/production
# Flush
wp cache flush --path=/var/www/production
wp rewrite flush --path=/var/www/production
# CDN migration — old URLs to new CDN
wp search-replace 'https://yoursite.com/wp-content/uploads' 'https://cdn.yoursite.com/wp-content/uploads' wp_posts wp_postmeta --dry-run
# Fix year/month directory changes
wp search-replace '/uploads/2024/01/' '/uploads/2025/01/' wp_posts --dry-run
# Update image references after changing upload directory
wp search-replace '/wp-content/uploads/' '/wp-content/media/' wp_posts wp_postmeta --dry-run
# Before replacement — note the byte count s:45
a:2:{s:4:"logo";s:45:"https://oldsite.com/wp-content/uploads/logo.png";s:5:"title";s:7:"My Site";}
# After WP-CLI replacement — byte count is automatically updated
a:2:{s:4:"logo";s:45:"https://newsite.com/wp-content/uploads/logo.png";s:5:"title";s:7:"My Site";}
# For deeply nested serialized data, use --precise
wp search-replace 'oldsite.com' 'newsite.com' --precise --dry-run
# Only search wp_posts and wp_postmeta
wp search-replace 'old-text' 'new-text' wp_posts wp_postmeta
# Only search the options table
wp search-replace 'old-value' 'new-value' wp_options
# Only search WooCommerce order tables
wp search-replace 'old-sku' 'new-sku' wp_wc_orders wp_wc_order_items
# List all tables in your database
wp db tables
# Replace all subdomains with a single domain
wp search-replace '(https?://)([a-z]+)\.oldsite\.com' '$1newsite.com' --regex --dry-run
# Remove tracking parameters from URLs
wp search-replace '(\?|&)utm_[a-z]+=[^&"\s]*' '' --regex wp_posts --dry-run
# Normalize www and non-www
wp search-replace 'https?://(?:www\.)?yoursite\.com' 'https://yoursite.com' --regex --dry-run
# Skip the guid column (usually recommended)
wp search-replace 'oldsite.com' 'newsite.com' --skip-columns=guid
# Skip multiple columns
wp search-replace 'oldsite.com' 'newsite.com' --skip-columns=guid,user_pass
# Skip specific tables entirely
wp search-replace 'oldsite.com' 'newsite.com' --skip-tables=wp_users,wp_usermeta
# Export the database
wp db export original.sql
# Run search-replace with --export flag
wp search-replace 'oldsite.com' 'newsite.com' --export=modified.sql
# Review the SQL diff if needed
diff original.sql modified.sql | head -100
# Import the modified database when ready
wp db import modified.sql
# 1. Always backup before every operation
wp db export backup-$(date +%Y%m%d-%H%M%S).sql
# 2. Check your table prefix
wp config get table_prefix
wp db tables
# 3. Be specific — avoid partial matches
# Too broad — will match unintended strings
wp search-replace 'site.com' 'newsite.com' --dry-run
# Better — specific enough to avoid false matches
wp search-replace 'https://oldsite.com' 'https://newsite.com' --dry-run
# 4. Always flush caches after search-replace
wp cache flush
wp rewrite flush
wp transient delete --all
# Replace across the entire network
wp search-replace 'oldnetwork.com' 'newnetwork.com' --network --dry-run
# Replace on a specific sub-site only
wp search-replace 'oldsite.com' 'newsite.com' --url=oldsite.com --dry-run
# Replace only in the main site's tables
wp search-replace 'old.com' 'new.com' --url=network.com --dry-run
# Optimized large-database replacement
wp search-replace 'oldsite.com' 'newsite.com' \
wp_posts wp_postmeta wp_options wp_comments wp_commentmeta \
--skip-columns=guid \
--report-changed-only \
--precise
#!/bin/bash
# WordPress migration script
set -e
SOURCE_URL="https://staging.example.com"
TARGET_URL="https://example.com"
SOURCE_PATH="/home/staging/public_html"
TARGET_PATH="/home/production/public_html"
BACKUP_DIR="/home/backups"
# Create timestamp
TIMESTAMP=$(date +%Y%m%d_%H%M%S)
echo "Starting migration: $SOURCE_URL -> $TARGET_URL"
# Backup production database
wp db export "$BACKUP_DIR/pre-migration-$TIMESTAMP.sql" --path=$TARGET_PATH
echo "Backup created: pre-migration-$TIMESTAMP.sql"
# Export staging database
wp db export /tmp/staging-export.sql --path=$SOURCE_PATH
# Import to production
wp db import /tmp/staging-export.sql --path=$TARGET_PATH
# Run replacements
wp search-replace "$SOURCE_URL" "$TARGET_URL" --path=$TARGET_PATH --skip-columns=guid
wp search-replace "$SOURCE_PATH" "$TARGET_PATH" --path=$TARGET_PATH
# Flush caches
wp cache flush --path=$TARGET_PATH
wp rewrite flush --path=$TARGET_PATH
wp transient delete --all --path=$TARGET_PATH
echo "Migration complete. Verify at: $TARGET_URL"
echo "Rollback: wp db import $BACKUP_DIR/pre-migration-$TIMESTAMP.sql --path=$TARGET_PATH"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment