Debugging WordPress Migration Errors: Serialized Data Fixes
Back to articles

Debugging WordPress Migration Errors: Serialized Data Fixes

Practical guide to scanning and fixing database serialization errors, wp-config path mismatches, and URL replacement issues during local-to-live WordPress migration.

Moving a WordPress site from local to live hosting should be straightforward — export database, import, update wp-config.php, done. But anyone who has done more than a few migrations knows the reality: broken images, widget text showing raw serialized strings, white screens, and sidebars that mysteriously reset. The culprit is almost always serialized data corruption during the URL replacement step.

Based on experience handling 50+ WordPress migrations for clients in Bali — from Denpasar agencies to villa websites in Seminyak and restaurant sites in Canggu — this guide walks through the exact debugging steps to identify and fix serialized data issues. If you need professional migration help, see Jasa Website Bali.

Quick Answer

WordPress stores plugin settings and widget data as PHP serialized strings in the database. When you do a blind str_replace to swap URLs (e.g., http://localhost to https://example.com), the string lengths in the serialized data no longer match, corrupting the data. Fix it by using serialization-aware tools like WP-CLI search-replace, Interconnect/it's Search Replace DB, or the Better Search Replace plugin — never raw SQL REPLACE().

Table of Contents

What is serialized data in WordPress?

PHP's serialize() function converts complex data structures (arrays, objects) into a string representation that can be stored in a database. WordPress uses this extensively:

  • Widget settings — stored in the wp_options table under widget_* keys
  • Plugin configurations — many plugins store settings as serialized arrays in wp_options
  • Theme mods — customizer settings in the theme_mods_* option
  • Shortcode attributes — some page builders store complex layouts as serialized data

A serialized string looks like this:

a:2:{s:4:"home";s:17:"http://localhost";s:5:"title";s:7:"My Site";}

Notice the s:17 — that is the string length. The value http://localhost is exactly 17 characters. This length prefix is what makes naive replacement dangerous.

Why naive URL replacement breaks things

When you run a raw SQL REPLACE() or str_replace() in a script:

-- DO NOT DO THIS
UPDATE wp_options SET option_value = REPLACE(option_value, 'http://localhost', 'https://mysite.com');

The URL changes from http://localhost (17 chars) to https://mysite.com (18 chars). But the s:17 prefix stays the same. PHP's unserialize() sees a length mismatch and returns false. The widget, plugin setting, or theme mod becomes corrupted.

The same problem occurs with any string length change: domain name changes, path changes (/Users/jaya/Sites/project/ to /var/www/html/), or protocol changes (http to https).

This is why every WordPress migration guide warns against blind find-and-replace. The WordPress Codex documents this, but many developers still learn it the hard way.

Symptoms of corrupted serialized data

How do you know if your migration broke serialized data? Look for these signs:

  • Widgets disappeared or reset to defaults — the sidebar looks empty or shows default WordPress widgets instead of your configured ones
  • Plugin settings reset — SEO plugin loses all configuration, caching plugin reverts to defaults, contact form plugin loses email settings
  • Customizer changes lost — theme colors, header layout, background images revert to theme defaults
  • White screen of death — a critical plugin or theme fails to unserialize() its options and throws a fatal error
  • Broken shortcodes or page builder layouts — Elementor, Beaver Builder, or Divi layouts show raw shortcode text or incomplete sections
  • "The link you followed has expired" or redirect loops — the siteurl and home options are corrupted

If you see any of these after migration, stop making changes and use a serialization-aware replacement tool.

Fix 1: WP-CLI search-replace (recommended)

If your hosting environment has WP-CLI installed (most quality hosts do), this is the cleanest fix:

# Dry run first — see what will change without modifying
wp search-replace 'http://localhost' 'https://mysite.com' --dry-run

# Execute the replacement
wp search-replace 'http://localhost' 'https://mysite.com'

# Also handle www vs non-www, or http vs https
wp search-replace 'http://www.mysite.com' 'https://mysite.com'

WP-CLI's search-replace command is serialization-aware. It unserializes each value, replaces within the data structure, then re-serializes with correct lengths. This is the safest method because it also handles:

  • Serialized arrays nested multiple levels deep
  • Objects stored via maybe_serialize()
  • GUID values in wp_posts (these are safe to replace, despite old advice not to)

Additional flags worth knowing:

# Skip certain columns (e.g., don't touch transients)
wp search-replace 'http://old.com' 'https://new.com' --skip-columns=guid

# Verbose output to see exactly what changed
wp search-replace 'http://old.com' 'https://new.com' --verbose

# Export the fixed database to a file instead of modifying in place
wp search-replace 'http://old.com' 'https://new.com' --export=/tmp/fixed.sql

The --export flag is especially useful if you are migrating to shared hosting where WP-CLI is not available — run the replacement locally with WP-CLI, export the clean SQL, then import on the live server.

Fix 2: Interconnect/it Search Replace DB script

For shared hosting without WP-CLI, the Interconnect/it Search Replace DB script is the gold standard. It is a standalone PHP script that does serialization-aware replacement.

How to use it:

  1. Download the script from the GitHub repository
  2. Upload the Search-Replace-DB folder to your web server (NOT inside the WordPress directory for security)
  3. Navigate to https://mysite.com/Search-Replace-DB/ in your browser
  4. Enter old URL and new URL, database credentials
  5. Click "dry run" first to preview changes
  6. Click "live run" to execute
  7. Delete the folder immediately after — leaving it accessible is a security risk

This script handles serialized data correctly because it parses and re-serializes PHP data structures, not raw string replacement.

Fix 3: Better Search Replace plugin

If you already have WordPress admin access on the live site, the Better Search Replace plugin is the easiest option for non-developers.

  1. Install and activate the plugin
  2. Go to Tools → Better Search Replace
  3. Enter the old URL and new URL
  4. Select all tables (or specific tables if you know which ones need it)
  5. Check "Case-Insensitive" if needed
  6. Run a dry run first, then the live replacement

The free version handles unlimited replacements. The pro version adds multisite support and serializes object handling for edge cases.

Limitation: This plugin requires WordPress to be functional enough to access wp-admin. If your migration caused a white screen, use WP-CLI or the Interconnect/it script instead.

wp-config.php path mismatches

Beyond serialized data, the most common migration issue is wp-config.php pointing to wrong paths or credentials. Symptoms include "Error establishing a database connection" or 500 internal server errors.

Check these values in wp-config.php:

// Database credentials — must match live hosting
define('DB_NAME', 'live_db_name');
define('DB_USER', 'live_db_user');
define('DB_PASSWORD', 'live_db_password');
define('DB_HOST', 'localhost'); // Some hosts use 127.0.0.1 or a specific hostname

// URLs — define these explicitly to prevent database confusion
define('WP_HOME', 'https://mysite.com');
define('WP_SITEURL', 'https://mysite.com');

// If moving from subdirectory to root (or vice versa)
// WP_HOME and WP_SITEURL above handle this, but also check:
// .htaccess RewriteBase and index.php require_once path

Path mismatches are trickier on shared hosting. If your local setup had WordPress in /Users/jaya/Sites/project/ but live is in /var/www/html/, the wp-config.php itself usually does not hardcode paths (it uses __DIR__). But some plugins and themes cache absolute paths in the database — this is where wp search-replace comes in again:

wp search-replace '/Users/jaya/Sites/project/' '/var/www/html/'

For checking site health after migration, use the WP Site Info Checker or the built-in Site Health tool in WordPress admin.

Post-migration checklist

After fixing serialized data and paths, verify:

  • Permalinks work — go to Settings → Permalinks, click "Save Changes" once to flush rewrite rules (no need to change settings, just re-save)
  • Media uploads load — check that image URLs point to the new domain. If images are broken, run wp search-replace on the old uploads path
  • .htaccess is correct — if moving from subdirectory to root, update RewriteBase
  • SSL/HTTPS — if the live site uses HTTPS (it should), make sure WordPress Address and Site Address both use https://
  • Cron jobs and scheduled posts — check Tools → Scheduled Events (or use WP-CLI wp cron event list)
  • XML sitemap — regenerate and submit to Google Search Console
  • Plugin compatibility — some plugins store absolute paths or environment-specific settings. Deactivate and reactivate all plugins to force them to re-detect environment
  • Test forms — contact forms, especially those with email routing, often break after migration

For a full WordPress security audit post-migration, see WordPress Security Checker Guide or professional help at Jasa SEO Maintenance Bali.

FAQ

Can I just use phpMyAdmin's search and replace?

No. phpMyAdmin's SQL REPLACE() function does raw string replacement without serialization awareness. It will corrupt serialized plugin and widget data. Use WP-CLI or a serialization-aware tool instead.

What if I already ran naive REPLACE() and broke the site?

Restore from the pre-migration database backup and re-do the replacement with a proper tool. If no backup exists, the WP-CLI serialization fix can sometimes repair damage if you re-run search-replace with the correct old/new values — but prevention is always better.

Do I need to replace the GUID in wp_posts?

Yes, for modern WordPress. Old advice said not to touch GUIDs, but since WordPress 5.x, GUID replacement is safe and recommended. WP-CLI search-replace handles it correctly.

How do I migrate serialized data for Elementor or Divi?

Page builders store layout data as serialized arrays or JSON in post_content or postmeta. WP-CLI search-replace handles both formats correctly. For Elementor specifically, also run the "Regenerate CSS" tool in Elementor → Tools after migration.

Should I migrate with a plugin like Duplicator or All-in-One WP Migration?

Yes, for simple migrations. Both Duplicator and All-in-One WP Migration handle serialized data correctly during the replacement step. They are good options for non-developers. But for complex migrations (large databases, custom server configs, multisite), manual migration with WP-CLI gives more control and debugging capability.

Conclusion

Serialized data corruption is the number one cause of broken WordPress migrations. The fix is simple: never use raw SQL REPLACE(). Always use serialization-aware tools — WP-CLI search-replace for CLI access, Interconnect/it script for shared hosting, or Better Search Replace plugin for admin access.

The migration process becomes predictable and painless once you follow the right steps. For professional WordPress migration, development, and maintenance services in Bali, visit Jasa Website Bali, Jasa SEO Maintenance Bali, and AI Search Optimization GEO.

More Articles