wp search-replace handles serialised data; SQL does not

Running a REPLACE() over the database to change a domain looks like it works, until a widget disappears or a theme setting resets. PHP serialised strings encode their own length, and a find-and-replace of different length leaves every one of them corrupt and unreadable.

# corrupts every serialised option containing the string
UPDATE wp_options SET option_value = REPLACE(option_value, 'old.com', 'new.com');

# unserialises, replaces, re-serialises
wp search-replace 'old.com' 'new.com' --all-tables --precise --dry-run

WP-CLI walks the data structure properly and rewrites the lengths. Always run it with --dry-run first — it reports the number of replacements per table, which is the cheapest way to notice that the search string was too broad. --all-tables matters when plugins have their own tables, since the default only covers those with the WordPress prefix.