Fixing URLs after a site migration
Swap stale dev URLs across your whole WordPress database, safely.
We’ve all done it. The development database is ready for production, the client has populated all the fields and everything is ready to move to the live server. All runs smoothly but then, what’s this? Why are those images not loading? Why, that’s because they’re referencing your local development server. Silly billy.
These days, I have a checklist of items to run through prior to setting a site live, but it wasn’t always such plain sailing.
One of the biggest hiccups I’ve encountered in the past is in ensuring that the content populated on a development site is transferred to live complete with all necessary changes made to the data so that links still work and images are properly referenced.
Using WordPress, within theme and template files, you can make use of helper functions such as bloginfo() to
ensure that theme code always references the current site. No links to urls are ever hardcoded within the template.
echo get_bloginfo('url'); // prints out the site URL
However, the populated content is another matter. Clients or developers may well drop absolute links to images or pages into the backend WYSIWYG. These will pretty much always be referencing the local development URL, leaving strings such as these lying around.
http://dev.stagingenvironment.client.com/site_a/img/hello.jpg
But, no fear. Help is at hand. This handy little PHP script will let you swap out text strings and replace with new.
Heads up If you have shell access, the 2026 default is WP-CLI:
wp search-replace 'old-url' 'new-url'. It’s serialization-safe (it unpacks and repacks serialized
arrays/objects, which a naive SQL find-and-replace will corrupt), supports --dry-run, and can skip GUIDs with
--skip-columns=guid. No script to upload or delete afterwards.
wp search-replace 'dev.stagingenvironment.client.com/site_a' 'www.client.com' --dry-run --skip-columns=guid
No terminal on the host? The Better Search Replace plugin, or WP Migrate, do the same serialization-safe job from the admin UI. The standalone Search Replace DB script below still works, but reach for these first.
You can use this for various purposes, such as
The latter there is the one I find myself doing most. Installation is straightforward, just follow the instructions on the site and within a few minutes you’ll be good to go.
The tool cleverly picks up on your WordPress’ installation’s database credentials (as long as you place it within the site’s root directory) and also gives you the option to do a dry run through your database before making any changes (recommended!)
You’ll then be prompted to enter the text you wish to replace, and what you want to replace it with. In our example above, we might provide the following as our source string:
dev.stagingenvironment.client.com/site_a
And this as our destination string, to replace the source string across all instances throughout the database
www.client.com
Be aware when making these adjustments that you have considered how the replacement will function. If you, for
example, try replacing http://dev.stagingenvironment.client.com then this may not pick up any instances of
https. You may have to run two or three replacements to catch all variations of a string.
Take note as well, that the script will offer to leave WordPress’ GUID fields untouched. This is
important for live/production servers which have had content indexed. The GUID is important for RSS purposes, and
shouldn’t be changed without a good deal of thinking first.
A couple of other important points – these hopefully don’t need saying, but just incase,
I help content-rich organisations understand their data and pull it back into one place. Tell me what specific problems you're having and I'll be happy to talk solutions with you.
Tell me what specific problems you’re having and I’ll be happy to talk solutions with you.