Serialized data in WordPress migrations can turn an apparently simple database search-and-replace operation into corrupted settings, broken widgets, missing plugin configuration and data that PHP can no longer read correctly.
The problem is not WordPress migration itself. The problem is treating every database value as ordinary text.
A migration often appears to require something as simple as:
old domain
https://oldsite.com
↓
new domain
https://newsite.com
It is tempting to replace every occurrence of the old URL directly in the database.
For ordinary strings, that may work.
For serialized PHP data, it can break the structure because serialized strings store their own length as part of the encoded value.
The core problem looks like this:
Original serialized value
↓
Replace text with a different-length string
↓
Stored length no longer matches actual length
↓
PHP cannot unserialize the value correctly
↓
WordPress or a plugin receives invalid data
This guide explains what serialized data is, why WordPress uses it, how naive database replacement damages it, where serialized values commonly appear and how to migrate WordPress URLs without corrupting the database.
What is serialized data?
Serialization converts a PHP value such as an array or object into a string representation that can be stored or transported.
Consider this PHP array:
$settings = array(
'color' => 'blue',
'layout' => 'wide',
);
PHP can serialize that structure:
serialize( $settings );
The resulting value resembles:
a:2:{
s:5:"color";
s:4:"blue";
s:6:"layout";
s:4:"wide";
}
The notation contains information about the structure and the values stored inside it.
For example:
a:2:
→ array containing 2 elements
s:5:"color";
→ string containing 5 bytes
s:4:"blue";
→ string containing 4 bytes
The important detail for migration is the number stored before each serialized string.
Serialized strings contain their own length
Consider:
s:4:"blue";
This means:
s
→ string
4
→ length of the string
"blue"
→ value
PHP expects those pieces to agree.
If you manually change the value:
s:4:"green";
the structure is now invalid because green contains five characters while the serialized metadata still says four.
The correct serialized value would be:
s:5:"green";
This is the fundamental reason blind text replacement can damage serialized WordPress data.
Why does WordPress contain serialized data?
WordPress database tables frequently need to store values more complex than a single string or number.
For example, an option may represent:
- multiple settings;
- a list of enabled features;
- theme configuration;
- widget configuration;
- plugin settings;
- nested arrays;
- relationships between configuration values.
Rather than creating a separate database column for every possible configuration property, WordPress and plugins can store structured values inside existing fields.
This is one reason understanding The WordPress Database Structure, Explained is useful before attempting direct database manipulation.
WordPress automatically serializes some values
WordPress provides APIs that can transparently serialize complex values before storing them.
For example:
update_option(
'example_settings',
array(
'layout' => 'wide',
'items' => 12,
)
);
The application can work with a PHP array while WordPress handles the stored representation.
The official maybe_serialize() documentation describes the WordPress helper used to serialize data when appropriate.
When retrieving values, WordPress can perform the opposite operation.
The official maybe_unserialize() documentation describes that process.
Where can serialized data appear in WordPress?
Serialized values can appear in several parts of the WordPress database.
Common locations include:
wp_options;wp_postmeta;wp_usermeta;- plugin-specific tables;
- theme-specific configuration;
- custom application tables.
The exact database prefix does not have to be wp_, so production installations may use different table names.
Serialized data in wp_options
The options table is one of the most important places to consider during migration.
It can contain:
- active plugin information;
- theme configuration;
- widget configuration;
- plugin settings;
- rewrite-related data;
- transients;
- site-wide application settings.
Some values are simple strings:
blogname
→ Example Website
Others can contain serialized arrays.
A global SQL replacement across option_value therefore treats structurally different types of data as though they were all plain text.
Serialized data in post meta
Post metadata is another common location.
A custom field can contain:
simple text
or:
array(
'image' => 'https://oldsite.com/image.jpg',
'size' => 'large',
'align' => 'center',
)
If that array is serialized, changing the URL without recalculating its serialized length can corrupt the complete metadata value.
Serialized data in user meta
User metadata can also contain structured values.
For more context on what WordPress stores there, see WordPress User Meta Explained.
During migration, user-related values should therefore not be treated as automatically safe for arbitrary SQL replacement.
Plugins can serialize their own settings
WordPress Core is only part of the problem.
Plugins can store their own:
- arrays;
- objects;
- configuration structures;
- page-builder data;
- form settings;
- integration configuration;
- cached structures.
That means you cannot safely assume that an unfamiliar plugin table contains only ordinary strings.
Before manipulating plugin data directly, understand what the plugin stores and how it expects that data to be encoded.
Theme settings may also contain serialized values
Themes can store:
- Customizer settings;
- layout preferences;
- color configuration;
- header settings;
- footer settings;
- background images;
- logo references.
Some of those structures may contain URLs pointing to the source environment.
A migration therefore needs to update the URLs without destroying the structure containing them.
The classic WordPress migration problem
Suppose a site moves from:
https://dev.example.com
to:
https://www.example.com
The database may contain the development URL in:
- post content;
- metadata;
- options;
- widgets;
- plugin settings;
- theme settings;
- custom tables.
The migration therefore needs a search-and-replace operation.
The dangerous assumption is:
URL is text
↓
SQL can replace text
↓
problem solved
That assumption ignores serialization.
A concrete serialized URL example
Imagine this PHP structure:
$settings = array(
'homepage' => 'https://old.example.com',
);
A simplified serialized representation could contain:
s:23:"https://old.example.com";
Now suppose the domain is replaced with a longer value:
https://production.example.com
A blind text replacement can leave something conceptually equivalent to:
s:23:"https://production.example.com";
The string has changed.
The stored length has not.
The serialized structure is therefore invalid.
What happens when PHP encounters corrupted serialized data?
PHP attempts to interpret the encoded structure according to its serialization syntax.
If the stored length does not correspond to the actual value, unserialization can fail.
From WordPress’s perspective, that can manifest as:
- settings disappearing;
- widgets resetting;
- plugin configuration becoming unavailable;
- theme options disappearing;
- custom fields returning unexpected values;
- PHP warnings;
- application logic failing.
The migration may therefore appear successful at the database level while breaking application-level configuration.
Why SQL REPLACE() is dangerous for WordPress migrations
A commonly suggested migration query resembles:
UPDATE wp_options
SET option_value =
REPLACE(
option_value,
'https://old.example.com',
'https://new.example.com'
);
SQL sees strings.
It does not understand PHP serialization semantics.
It can therefore replace:
old text
→
new text
without updating:
s:23:
→
s:23:
even when the replacement changes the actual serialized string length.
SQL does exactly what you asked, not what WordPress needs
The database server has no general reason to know that part of an arbitrary text column contains PHP serialized data.
From its perspective:
REPLACE(old, new)
is a text transformation.
From WordPress’s perspective, the same transformation may be modifying a structured encoded value.
That distinction is why direct database operations require particular care during migration.
Does SQL replacement always break serialized data?
No.
If the replaced strings have exactly the same byte length, the stored serialized length may remain valid.
For example, replacing one five-character ASCII string with another five-character ASCII string does not inherently create a length mismatch.
But that does not make blind SQL replacement a sound migration strategy.
You still need to account for:
- nested structures;
- objects;
- encoded values;
- custom storage formats;
- unexpected plugin tables;
- multibyte strings;
- data that should not be changed at all.
Serialized length is based on bytes
An additional complication is that PHP serialized string lengths relate to bytes, not simply the number of characters a human sees.
With ordinary ASCII strings, these often correspond neatly.
With multibyte UTF-8 characters, they may not.
This means manual repair based purely on visible character counting can introduce additional errors.
What about JSON?
JSON is structurally different from PHP serialized data.
A JSON object might look like:
{
"homepage": "https://old.example.com"
}
JSON does not encode each string using the same explicit length notation as PHP serialization.
Replacing a URL with a different-length URL therefore does not create the same serialized-length mismatch.
However, blind replacement can still be dangerous if:
- the replacement creates invalid escaping;
- the value is encoded more than once;
- the string is embedded inside another format;
- only specific occurrences should change;
- the plugin maintains checksums or derived data.
The general lesson remains: understand the storage format before modifying it.
Serialized data can be nested
A serialized array can contain another serialized or structured value.
For example:
array(
'layout' => array(
'hero' => array(
'image' => 'https://old.example.com/hero.jpg',
),
),
);
A serialization-aware migration tool must preserve the complete nested structure while changing the relevant string.
Serialized objects are more complicated
PHP can serialize objects as well as arrays.
Object serialization can include:
- class names;
- property names;
- property visibility information;
- nested values;
- references to other structures.
This is another reason treating the database as a collection of arbitrary strings can be unreliable.
Why WordPress migrations need application-aware replacement
A safer migration tool can conceptually perform:
Read stored value
↓
Detect serialized data
↓
Unserialize structure
↓
Traverse values
↓
Replace matching strings
↓
Serialize structure again
↓
Store corrected value
The new serialized representation automatically contains the correct lengths.
This is fundamentally different from replacing raw bytes inside the stored representation.
WP-CLI search-replace understands serialized data
WP-CLI provides a WordPress-aware search-and-replace command:
wp search-replace
The official WP-CLI search-replace documentation specifically describes the command as intelligently handling PHP serialized data.
This makes it substantially more appropriate for WordPress migration work than a blind SQL REPLACE() operation.
Start with a dry run
Before modifying the database, inspect what the replacement would affect.
For example:
wp search-replace \
'https://old.example.com' \
'https://new.example.com' \
--all-tables-with-prefix \
--dry-run
The --dry-run option allows you to review the operation without committing changes.
This is an important migration habit because serialization safety does not mean every matching string should necessarily be changed.
Serialization-aware does not mean decision-aware
A tool can safely preserve serialized structures while still changing data you intended to keep.
For example, an old production URL might appear in:
- historical logs;
- analytics records;
- external API payloads;
- migration history;
- archived content;
- plugin caches.
Whether those values should change is a separate question.
Therefore:
Serialization-aware replacement
=
structurally safer
but not automatically
=
semantically correct replacement
Back up before running search-replace
Any broad database transformation should begin with a recoverable backup.
TheOneWP’s Backup Manager can provide complete, database-only or files-only backups depending on the recovery requirement.
For a database URL migration, at minimum ensure that the original database can be restored.
Better still, verify the recovery process before performing high-impact migration work.
See How to Test a WordPress Backup Restore.
Prepare the database before migration
A migration is easier to validate when you understand what the source database contains.
Before changing anything, inspect:
- table structure;
- database size;
- custom tables;
- plugin tables;
- old staging data;
- unnecessary temporary data;
- environment-specific configuration.
The full preparation workflow is covered in Preparing a WordPress Database for Migration.
Use staging to test the migration process
A database migration should ideally be rehearsed before production cutover.
A staging or isolated environment lets you test:
database export
↓
database import
↓
URL replacement
↓
cache cleanup
↓
application validation
For environment strategy, see WordPress Staging Site Best Practices.
Keep staging and production clearly separated
A migrated staging database may contain production:
- email addresses;
- API credentials;
- payment settings;
- webhook destinations;
- scheduled jobs;
- analytics identifiers.
Environment separation therefore matters beyond URL replacement.
See Distinguishing Staging from Production in WordPress for a broader explanation of environment identification and isolation.
Plan the complete migration before changing the database
URL replacement is only one stage of migration.
A complete workflow may involve:
inventory
↓
backup
↓
database preparation
↓
file transfer
↓
database transfer
↓
configuration
↓
URL migration
↓
DNS
↓
validation
↓
monitoring
Use Planning a WordPress Site Migration: a Checklist to coordinate the broader process.
Which URLs commonly need changing during migration?
Depending on the migration, you may need to update:
- site URL;
- home URL;
- media URLs;
- internal links;
- page-builder references;
- theme settings;
- widget URLs;
- plugin settings;
- custom field values;
- custom table data.
The complete URL migration process is covered in How to Migrate WordPress URLs Safely.
Do siteurl and home require serialization-aware replacement?
The standard siteurl and home option values themselves are normally ordinary strings.
They can be inspected with WP-CLI:
wp option get siteurl
wp option get home
and updated through WordPress-aware commands where appropriate:
wp option update siteurl 'https://new.example.com'
wp option update home 'https://new.example.com'
The danger arises when administrators assume that because those two values are simple strings, every other URL in wp_options is equally simple.
Do not update only siteurl and home
Changing:
siteurl
home
does not automatically rewrite every absolute URL stored elsewhere in the database.
You may still have old-domain references in:
- post content;
- metadata;
- widgets;
- plugin configuration;
- theme configuration;
- custom tables.
This is why migration requires a broader audit.
How WordPress stores media URLs
Media records involve database metadata and physical files.
Depending on the content and plugin architecture, absolute URLs can appear in:
- post content;
- custom fields;
- page-builder data;
- theme configuration;
- plugin configuration.
Updating database URLs does not transfer the underlying files.
A migration must therefore coordinate database replacement with filesystem migration.
Page builders make migration data more complex
Page builders may store layout configuration in:
- post meta;
- JSON;
- serialized PHP arrays;
- custom database tables;
- proprietary encoded formats.
Some builders also provide their own migration or URL replacement tools.
When a site relies heavily on a builder, consult that builder’s migration requirements rather than assuming a generic database replacement covers every stored reference.
Widgets are a classic serialization example
Traditional WordPress widget settings have historically provided a common example of structured values stored in the options table.
A widget may contain configuration such as:
array(
'title' => 'Contact us',
'url' => 'https://old.example.com/contact/',
)
If that structure is serialized, direct raw replacement of a differently sized hostname can invalidate the option.
The result can be missing or reset widget configuration after migration.
Theme modifications can contain structured data
Theme configuration may contain references to:
- logos;
- background images;
- header images;
- custom CSS;
- layout options.
Those values should be included in migration validation rather than assuming that successful page content replacement means the theme is complete.
Custom fields require particular attention
Custom fields can store almost anything.
One field might contain:
123
another:
https://old.example.com/file.pdf
and another:
serialized nested configuration
This variability is exactly why raw SQL across all metadata can be dangerous.
What does is_serialized() do?
WordPress provides is_serialized() to determine whether data appears to be serialized.
The official is_serialized() documentation describes the function and its supported behavior.
A simplified application workflow might be:
if ( is_serialized( $value ) ) {
// Handle as structured serialized data.
}
However, migration tools need to do more than merely detect serialization. They need to modify the contained values safely and then serialize the resulting structure correctly.
Do not manually repair serialized lengths unless necessary
When corrupted serialized data is discovered, manually editing length values may appear straightforward.
For a tiny known value, it may technically be possible.
For real WordPress data containing nested arrays, multibyte strings and plugin-specific structures, manual repair is error-prone.
A safer strategy is usually:
recover original valid value
↓
unserialize correctly
↓
modify underlying value
↓
serialize again
If the original database is still available, restoring the valid source value is generally preferable to reconstructing damaged serialization manually.
How to identify serialization corruption
Possible signs include:
- settings disappearing immediately after migration;
- widgets resetting;
- theme configuration vanishing;
- plugin options reverting to defaults;
- PHP unserialize warnings;
- custom fields returning false or empty values;
- page-builder layouts breaking;
- unexpected errors in administrative screens.
These symptoms do not automatically prove serialization corruption, but they justify inspecting affected database values.
Inspect the database before changing it
TheOneWP’s Database Manager can help inspect WordPress database tables and stored values before migration-related changes.
Useful questions include:
- Which tables contain the old domain?
- Which tables belong to WordPress Core?
- Which belong to plugins?
- Which contain custom application data?
- Which values appear serialized?
- Which tables actually need migration changes?
Search before replacing
Before executing a migration replacement, first determine where the source value occurs.
With WP-CLI, a dry run is particularly useful:
wp search-replace \
'https://old.example.com' \
'https://new.example.com' \
--all-tables-with-prefix \
--dry-run
Review the results before removing --dry-run.
Why –all-tables-with-prefix requires thought
The option can include tables sharing the WordPress database prefix, including plugin-created tables.
That can be useful because plugins frequently store URLs outside standard Core tables.
It also means the replacement scope can become broad.
Before executing it:
- identify custom tables;
- understand important integrations;
- inspect the dry-run output;
- create a backup;
- test the process outside production where possible.
Do not blindly use –all-tables
A database can contain tables unrelated to the WordPress installation being migrated.
Changing every matching value across every database table can affect unrelated applications.
Migration scope should therefore be deliberate.
Use precise search strings
A replacement such as:
old.example.com
→
new.example.com
has a different scope from:
https://old.example.com
→
https://new.example.com
And:
http://old.example.com
→
https://new.example.com
may represent another migration case entirely.
Before replacing anything, determine which source URL variants actually exist.
Check HTTP and HTTPS variants
Older WordPress databases may contain both:
http://old.example.com
https://old.example.com
particularly if HTTPS was introduced later in the site’s history.
Searching only for one variant can leave stale references behind.
Check www and non-www variants
A site may also contain:
https://example.com
https://www.example.com
because of historical configuration changes, imported content or manually entered links.
Do not assume the current canonical hostname is the only form stored in the database.
Canonical URL configuration is a separate concern
Database migration and canonicalization are related but different.
After migration, verify that the new environment communicates the intended canonical URLs.
See WordPress Canonical URLs, Explained.
Relative URLs reduce some migration problems but do not eliminate them
Relative internal references can reduce dependence on a specific hostname in certain contexts.
But WordPress and its ecosystem still use absolute URLs for many purposes.
Changing an entire site architecture to avoid migration replacement is therefore not a substitute for understanding how stored data works.
GUID values deserve special attention
The guid field in wp_posts has a specific identity-related purpose and should not be treated as just another internal URL column.
Migration procedures should avoid indiscriminately rewriting every value that happens to resemble the old domain.
This reinforces the broader principle:
Looks like a URL
≠
should automatically be replaced
Migration should preserve data meaning, not merely replace strings
The objective is not:
zero occurrences of old.example.com
at any cost.
The objective is:
correct application data
+
correct environment references
+
valid structured values
+
working WordPress installation
Some historical occurrences may legitimately remain.
Export the database before modification
WP-CLI can export the WordPress database:
wp db export pre-migration.sql
The official WP-CLI db export documentation covers database exports through the command line.
Keep the original export unchanged so you can return to the pre-replacement state if validation fails.
A safe migration workflow
A practical database migration process can look like:
1. Inventory the site
2. Create a complete backup
3. Export the database
4. Inspect custom tables
5. Identify source URL variants
6. Import into staging or destination
7. Run serialization-aware dry run
8. Review replacement scope
9. Execute replacement
10. Clear caches
11. Validate WordPress
12. Search for unexpected old URLs
13. Test critical workflows
14. Perform production cutover
This process is covered more broadly in Planning a WordPress Site Migration: a Checklist.
Validate WordPress immediately after replacement
After the search-and-replace operation, do not jump directly to DNS cutover.
Test:
- homepage;
- representative pages;
- WordPress admin;
- login;
- Media Library;
- forms;
- custom post types;
- theme configuration;
- plugin settings;
- widgets;
- custom fields.
Inspect settings that commonly reveal serialization problems
Pay particular attention to complex settings screens.
Examples include:
- page-builder configuration;
- theme options;
- widget configuration;
- form-builder settings;
- SEO configuration;
- ecommerce settings;
- integration settings.
If these unexpectedly reset after migration, investigate the underlying stored data.
Check media after URL replacement
Open representative:
- recent images;
- old images;
- PDFs;
- featured images;
- gallery content;
- custom-field media;
- page-builder images.
A migration can correctly update ordinary post content while leaving a URL embedded inside structured metadata unchanged or damaged.
Check custom post types after migration
Custom post types often rely on plugin-specific metadata.
See WordPress Post Types vs. Custom Post Types for the underlying WordPress content model.
During migration, verify both the post records and the metadata or custom tables required by those content types.
Clear caches after migration
A correct database replacement can still appear unsuccessful if cached output contains old URLs.
Depending on the architecture, clear:
- page cache;
- object cache;
- Redis cache;
- CDN cache;
- page-builder cache;
- generated CSS;
- plugin caches.
Then test again.
Do not mistake cached data for database corruption
If an old URL remains visible after migration, determine whether it comes from:
database
filesystem
generated CSS
JavaScript
page cache
object cache
CDN
browser cache
Running increasingly aggressive database replacements against a cache problem can create new damage without fixing the actual source.
Search the database again after replacement
After migration, perform another search for the old hostname.
Remaining matches should be reviewed rather than automatically replaced.
Ask:
- Is this an active application reference?
- Is it historical data?
- Is it a log entry?
- Is it an external reference?
- Is it cached data?
- Does changing it affect meaning?
Test the migrated database before production cutover
The database should be considered ready only after application-level validation.
For a migration test, verify:
- frontend rendering;
- admin functionality;
- authentication;
- content editing;
- media;
- forms;
- custom functionality;
- ecommerce where applicable;
- scheduled tasks;
- external integrations.
Keep the pre-migration backup until validation is complete
Do not delete the source recovery point immediately after the new site starts loading.
A migration problem may only become visible when:
- a particular settings screen is opened;
- an old page is viewed;
- a scheduled task runs;
- a customer checks out;
- a plugin processes stored configuration;
- an administrator edits specific content.
Maintain the recovery point according to the migration rollback plan.
How to recover from a broken naive replacement
If a raw SQL replacement has corrupted serialized data, the safest recovery option is often restoring the database from the pre-migration backup and repeating the migration correctly.
The process may be:
Stop further modifications
↓
Preserve current database for investigation
↓
Restore valid pre-migration database
↓
Run serialization-aware replacement
↓
Validate application
↓
Resume migration
For recovery validation, see How to Test a WordPress Backup Restore.
Why restoring is often safer than repairing
Once a broad SQL operation has modified thousands of rows, determining which serialized values were damaged can be difficult.
You may not know:
- which values were serialized;
- which replacements changed lengths;
- which plugin settings are affected;
- which nested structures were damaged;
- whether every problem has been found.
A known-good database plus a controlled replacement process provides a much clearer recovery path.
Do not run another reverse SQL REPLACE() as your first recovery strategy
Suppose you performed:
old.example.com
→
production.example.com
and damaged serialization.
Running:
production.example.com
→
old.example.com
may appear to reverse the operation, but relying on another broad text transformation is risky, particularly if new data has been written since the first operation.
Restore from a verified recovery point when possible.
Serialization is not a reason to fear database migrations
The existence of serialized data does not make WordPress migrations inherently fragile.
It simply means the migration tool must understand WordPress data structures.
A controlled process using serialization-aware tools can safely move very large WordPress databases.
Serialization is also not a reason to avoid direct database work entirely
Direct database inspection and maintenance can be extremely useful.
TheOneWP’s Database Manager can help inspect tables and values, while database exports provide a recovery point before destructive operations.
The principle is:
Inspect directly when useful.
Modify directly only when
you understand the data model.
Common migration mistakes involving serialized data
Running SQL REPLACE() across wp_options
The options table can contain serialized structures, making arbitrary raw replacement dangerous.
Assuming postmeta contains only strings
Metadata can contain arrays and complex plugin data.
Updating only siteurl and home
Those settings do not cover every stored absolute URL.
Replacing every occurrence of the old domain
Some values may be historical or should remain unchanged.
Skipping the dry run
This removes an important opportunity to understand replacement scope before modifying production data.
Running migration directly on production
This reduces your ability to detect and correct problems before users encounter them.
Having no recoverable database backup
A destructive transformation without rollback turns a migration error into a recovery incident.
Assuming a working homepage proves success
Serialization problems often affect specific settings, metadata or plugin functionality that the homepage does not exercise.
A serialized-data-safe WordPress migration checklist
- Create a complete backup.
- Verify that the database can be restored.
- Export the original database separately.
- Identify the source and destination URLs.
- Check HTTP and HTTPS variants.
- Check www and non-www variants.
- Inventory WordPress tables.
- Identify plugin-specific tables.
- Identify custom tables.
- Inspect important option values.
- Expect serialized data in options and metadata.
- Do not run blind SQL
REPLACE()operations. - Use a serialization-aware migration tool.
- Run WP-CLI search-replace with
--dry-runfirst where appropriate. - Review the replacement scope.
- Do not indiscriminately rewrite GUID values.
- Test the migration on staging.
- Keep staging isolated from production services.
- Execute the controlled replacement.
- Clear caches.
- Search for remaining old-domain references.
- Review remaining matches individually.
- Test WordPress admin.
- Test theme settings.
- Test widgets.
- Test plugin settings.
- Test custom fields.
- Test custom post types.
- Test media.
- Test forms.
- Test ecommerce functionality where applicable.
- Inspect PHP logs.
- Keep the pre-migration recovery point.
- Perform production cutover only after validation.
How TheOneWP tools fit into a safer migration workflow
TheOneWP can support different stages of the migration process without treating them as the same operation.
Backup Manager
Backup Manager provides the recovery layer that should exist before database migration begins.
Create an appropriate backup before performing broad URL replacement or other destructive database operations.
Database Manager
Database Manager can help inspect the database before and after migration.
Use inspection to understand:
- table structure;
- plugin tables;
- custom tables;
- stored values;
- unexpected migration artifacts.
These tools complement rather than replace a serialization-aware URL migration process.
A practical WP-CLI migration example
A simplified workflow might begin by exporting the source database:
wp db export pre-migration.sql
Then inspect the intended replacement:
wp search-replace \
'https://old.example.com' \
'https://new.example.com' \
--all-tables-with-prefix \
--dry-run
Review the result carefully.
If the scope is correct, execute the replacement:
wp search-replace \
'https://old.example.com' \
'https://new.example.com' \
--all-tables-with-prefix
Then clear the appropriate caches and validate the application.
The exact commands and scope should be adapted to the site’s architecture rather than copied mechanically onto every WordPress installation.
Why a dry run matters even when serialization is handled
The dry run answers questions such as:
- How many replacements will occur?
- Which tables contain the value?
- Are unexpected tables involved?
- Is the old hostname present where expected?
- Is the operation much larger than anticipated?
Structural safety and operational safety are different layers.
Migration testing should include data integrity
After migration, do not merely check whether pages render.
Validate representative data structures:
Theme settings
Plugin settings
Widgets
Post metadata
User metadata
Custom fields
Page-builder layouts
Custom tables
These are precisely the areas where a serialization problem may appear.
Compare important settings before and after migration
For critical sites, record representative configuration before migration.
For example:
Active theme
Active plugins
Widget configuration
Payment settings
Shipping settings
Form configuration
Custom post type settings
Important integration settings
After migration, compare those values functionally rather than relying only on row counts.
Database row counts cannot prove serialized values are valid
A corrupted option still occupies a database row.
Therefore:
same number of rows
≠
same usable application state
Database-level validation and WordPress-level validation should both be part of the migration process.
Use WordPress APIs when application context matters
When writing custom migration code, prefer WordPress APIs where they provide the appropriate abstraction.
For options, for example:
$settings = get_option( 'example_settings' );
$settings['url'] = 'https://new.example.com';
update_option( 'example_settings', $settings );
WordPress handles the stored representation of the array.
This can be safer than manually modifying its serialized database string.
Be careful with double serialization
WordPress’s historical compatibility behavior means some already serialized strings can be serialized again when passed through certain storage functions.
The official maybe_serialize() reference documents the behavior developers should understand when handling serialized values.
Migration code should therefore work with the actual application value wherever possible rather than repeatedly encoding already encoded strings.
Do not use unserialize() indiscriminately on untrusted data
PHP object deserialization has security implications when applied to untrusted serialized values.
Migration code should not assume arbitrary external input is safe to deserialize.
For normal WordPress migration operations, prefer established WordPress-aware tools instead of building a generic unserialization pipeline around uncontrolled input.
Migration scripts should be tested on copies first
If a project requires custom transformation logic that WP-CLI search-replace cannot provide, test the script against a copy of the database.
Use a workflow such as:
production export
↓
isolated database
↓
custom migration script
↓
application tests
↓
database inspection
↓
repeat until deterministic
↓
controlled production migration
This approach is particularly important for applications with extensive custom tables or proprietary data structures.
Migration and backup restoration are closely related
A migration is effectively a controlled reconstruction of an application in another environment.
That makes backup restoration testing directly relevant.
If you cannot reliably reconstruct the source site from its backup, the migration already has an unresolved recovery risk.
See How to Test a WordPress Backup Restore.
Related guides
- How to Migrate WordPress URLs Safely
- Preparing a WordPress Database for Migration
- Planning a WordPress Site Migration: a Checklist
- How to Test a WordPress Backup Restore
- WordPress Staging Site Best Practices
Final recommendation
Never treat a WordPress database migration as a generic text replacement operation.
WordPress Core, themes and plugins can store arrays and other structured values as PHP serialized data. Those serialized strings contain structural metadata, including the byte length of stored strings. Replacing a URL with a differently sized URL without updating that structure can make the complete value unreadable.
Before migration, create a recoverable backup using an appropriate process such as Backup Manager, inspect the database and understand the tables involved. Database Manager can help examine database structures and values before broad changes are made.
For URL migration, use a serialization-aware tool such as WP-CLI search-replace. Start with a dry run, inspect the affected tables and make sure the replacement scope matches the actual migration plan.
Do not assume every occurrence of the old hostname should disappear. Historical records, logs and application-specific values may legitimately retain old references. The objective is correct application state, not an arbitrary zero-result database search.
After replacement, validate WordPress at the application level. Check theme settings, widgets, plugin configuration, custom fields, media, forms, authentication and critical business workflows. A database operation completing without an SQL error does not prove the stored application data remains valid.
Most importantly, preserve the original database until migration validation is complete. If a naive replacement corrupts serialized data, restoring a known-good database and repeating the migration with serialization-aware tooling is usually safer than attempting to repair thousands of modified values manually.
The principle behind safe WordPress migration is straightforward:
Do not modify the serialized representation
as though it were ordinary text.
Modify the underlying data
while preserving its structure.

