Skip to main content

wp search-replace

Overview

Find and replace any string across all WordPress database tables — including inside PHP serialized data. The essential command for URL migrations, domain changes, and content updates.

What It Does​

wp search-replace scans every row and column across all (or specified) WordPress tables, finds strings matching the search term, and replaces them with the replacement string. Critically, it handles PHP serialized data correctly — updating byte-length counts so serialized arrays and objects remain valid after replacement.

Syntax​

wp search-replace <old-string> <new-string> [<table>...] [OPTIONS]

Arguments & Options​

Argument / FlagDefaultDescription
OLD_STRING—String to find
NEW_STRING—String to replace with
TABLE...All tablesSpecific tables to limit search to
--dry-run—Preview what would change without writing
--skip-columns=COLS—Skip specific columns (comma-separated)
--include-columns=COLS—Only search in these columns
--all-tables—Include all tables, not just with WP prefix
--network—Run on all sites in a multisite network
--precise—Use regex-capable matching (slower)
--recurse-objects—Handle nested serialized PHP objects
--no-report—Suppress results table output
--report-changed-only—Only show tables where replacements were made
--format=FORMATtableOutput format: table, json, csv, yaml
--export=FILE—Export SQL instead of writing to DB
--export_insert_size=N50Number of inserts per SQL query when exporting

Basic Usage​

Domain migration (the most common use case)​

wp search-replace 'http://old-domain.com' 'https://new-domain.com'

Always preview first with --dry-run​

wp search-replace 'http://old-domain.com' 'https://new-domain.com' --dry-run

Dry-run output:

+------------------+-----------+--------------+------+
| Table | Column | Replacements | Type |
+------------------+-----------+--------------+------+
| wp_options | option_value | 3 | SQL |
| wp_posts | post_content | 47 | SQL |
| wp_postmeta | meta_value | 12 | PHP |
+------------------+-----------+--------------+------+
Success: 62 replacements to be made.

Skip the guid column (WordPress best practice)​

wp search-replace 'http://old.com' 'https://new.com' --skip-columns=guid
Always skip the guid column

The guid column in wp_posts is used as a permanent unique identifier for posts. WordPress documentation recommends not changing it even during migrations.

Real-World Scenarios​

Scenario 1: Production → Staging migration​

# 1. Import production dump to staging
wp db import prod_dump.sql

# 2. Preview the replacements
wp search-replace 'https://example.com' 'https://staging.example.com' --dry-run --skip-columns=guid

# 3. Apply
wp search-replace 'https://example.com' 'https://staging.example.com' --skip-columns=guid

# 4. Flush cache
wp cache flush

Scenario 2: HTTP to HTTPS migration​

# Dry run
wp search-replace 'http://example.com' 'https://example.com' --dry-run --skip-columns=guid

# Apply
wp search-replace 'http://example.com' 'https://example.com' --skip-columns=guid
wp cache flush

Scenario 3: Change site path (moved to subdirectory)​

wp search-replace 'https://example.com' 'https://example.com/blog' --skip-columns=guid

Scenario 4: Multisite Network search-replace​

# Replace across all network sites
wp search-replace 'old-network.com' 'new-network.com' --network --skip-columns=guid

Scenario 5: Export replacements as SQL (without applying)​

wp search-replace 'http://old.com' 'https://new.com' --export=migration.sql --skip-columns=guid
# Review migration.sql, then apply:
wp db import migration.sql

Best Practices​

  1. Always run --dry-run first — see exactly what will change before committing.
  2. Always use --skip-columns=guid — guid is a permanent post identifier.
  3. Back up with wp db export before any search-replace on production.
  4. Include protocol in strings — replace http://example.com, not just example.com, to avoid partial matches.
  5. Flush cache after — wp cache flush clears stale cached values.
  6. Use --report-changed-only to quickly identify which tables were affected.

Troubleshooting​

ProblemCauseFix
Serialized data broken after manual SQL UPDATEUsed raw SQL instead of wp search-replaceUse wp search-replace — it fixes byte counts
URLs partially replacedString included protocol but DB has mixed http/httpsRun both: first http://, then https://
Site still loads old domainObject cache not clearedRun wp cache flush
Command too slow on large DBMany tables or large dataAdd --table to limit scope; run during off-peak
Dry-run shows 0 replacementsSearch string not in DBVerify string with wp db query "SELECT ..."

Quick Reference​

wp search-replace 'http://old.com' 'https://new.com' --dry-run --skip-columns=guid
wp search-replace 'http://old.com' 'https://new.com' --skip-columns=guid
wp search-replace 'old' 'new' --network --skip-columns=guid
wp search-replace 'old' 'new' --export=changes.sql
wp cache flush

Next Steps​