WordPress: Moving your site to a new domain

As a preliminary note, always use relative URLs where possible.

Always use relative URLs where possible (it is worth repeating).

There are a lot of plugins that offer easy ways to move your site. I’m not going to go into great detail, but highlight that at the core all of these services do two things. They export your database contents to a file, and they archive your wordpress web root directory. Import the database to the new location, extract the archive to the new web root, and make any necessary updates to wp-config.php for database connectivity. Done!

If only it were that easy; often when I move a WordPress site to a new domain (or a testing environment), I find the following:

  • All of my images are suddenly “missing”
  • My menu systems and/or header/footer links go to the old domain
  • Random plugins have stopped working
  • Theme-specific data seems to point to the old domain

Ideally, I would never encounter these issues, because of the first two statements above. In practice, I encounter at least one of these frustrations with just about every WordPress site I move. Here are a few tips and SQL statements for resolving these issues.

Some common places where URL/domain issues occur are:

  • Theme files – These get updated to include full URLs instead of dynamically generated or relative
  • Theme options – Users often paste full URLs into theme options for image and file references, sometimes themes enforce absolute paths (they shouldn’t!)
  • Plugin options – Users often paste full URLs into Plugin options, sometimes plugins enforce absolute paths (they shouldn’t either!)
  • Post content – Users often paste full URLs into Post/Page content
  • Post meta data – Users often use full URLs to populate meta data provided by a theme/plugin
  • Links – Users populate link data (and link images) with full URLs
  • Redirects – Users populate link data used for redirection by popular plugins with full URLs

Theme files

Check your theme files and replace any absolute paths with a relative path or a path generated using one of WordPress’s built in url functions.
Wordpress.org has excellent details of these functions on their Codex: Function Reference/bloginfo page.

Database updates

Take a backup of your database, and make sure that your backup works (i.e., you can successfully restore it somewhere and it has all the tables/records that it should).

Everything else is stored in the database. You probably already know to update the database options for ‘home’ and ‘siteurl’. The more difficult options updates are for stray theme and plugin options that are likely more intricate than a simple url or domain name. We will use MySQL’s REPLACE function to address this and our other database updates.

I forgot to point out that you can override the home and siteurl db options in wp-config.php. This is good and bad; it means that you can keep database changes entirely out of the picture when moving your site. However, it may cause frustration for other developers/users down the road, as I don’t see this feature being used that often, and devs may forget about the functionality. With that noted, here are a couple of nice bits to add to your wp-config, should you elect to move all domain detail out of your database:

// Depending on your hosting provider and/or server config, a fully dynamic configuration may work for you.
//    You may need to use HTTP_HOST instead of SERVER_NAME - depending on server config.
define('WP_SITEURL', 'http://' . $_SERVER['SERVER_NAME'] . '/path/to/wordpress');
define('WP_HOME',    'http://' . $_SERVER['SERVER_NAME'] . '/path/to/wordpress');

// If the dynamic option doesn't work, or you want to be more explicit about things:
//define('WP_SITEURL', 'http://my-new-domain.com/path/to/wordpress');
//define('WP_HOME',    'http://my-new-domain.com/path/to/wordpress');


Our technique is to tell MySQL to look through particular columns of the database, and everytime it finds the domain name, replace it with something else – and update the column for that record. The queries look like this:

-- Update options
UPDATE wp_options SET option_value = REPLACE(option_value,'http://www.my-old-domain.com','');

-- Update posts content
UPDATE wp_posts SET post_content = REPLACE(post_content,'http://www.my-old-domain.com','');

-- Update any post meta content
UPDATE wp_postmeta SET meta_value = REPLACE(meta_value,'http://www.my-old-domain.com','');

-- Update link urls and link image urls (you may or may not have any images associated with your links
UPDATE wp_links SET link_url = REPLACE(link_url,'http://www.my-old-domain.com','');
UPDATE wp_links SET link_image = REPLACE(link_image,'http://www.my-old-domain.com','');

Redirects will be in a unique table, depending on what plugin you are using, but you get the idea. Keep in mind that REPLACE() is finding a full match to the string you supply. If you have some links that are using “http://www.my-old-domain.com” and some that are using “http://my-old-domain.com”, you will need to run these updates multiple times for each distinct value.

There are a lot of ways to optimize these queries and reduce database overhead – but for most WordPress installations, these optimizations just make the update statements less clear. These updates are easy to follow, understand, and modify; as long as your WordPress installation doesn’t have millions of records in any of these tables, this technique will work just fine.

Change domains again

Now when you want to change domains again, or create a new development area, just change the ‘home’ and ‘siteurl’ options in the wp_options table, and you will be ready to go. Happy WordPressing!

Nicholas Whittier

Nicholas Whittier

Nicholas is a developer who loves to figure out how things work. Whether it is an errant bash script, missing kernel drivers, CSS conflicts, a JRE incompatibility, an unsolved Rubik's cube, or anything in between, he wants to learn why it is broken and how to fix it. Additionally, Nicholas fancies GNU/Linux system administration, database administration, Java development, and web development. 

One Response

  1. Thanks for your post. Unfortunately it didn’t work for me and results in my theme customizations being reset from wordpress considering it being “corrupted” in the database. This is because the values are stored as a serialized array in the wp_options table that we update in the query:

    UPDATE wp_options SET option_value = REPLACE(option_value,’http://www.my-old-domain.com’,”);

    When you do this, the count of the string lengths will not not match the value. E.g.


    The 150 is does not match the length of the string.

    Refer here: https://wordpress.stackexchange.com/questions/267860/the-entire-wordpress-theme-reset-to-default-after-uploaded-to-live

Leave a Reply

Your email address will not be published. Required fields are marked *



Recent Posts

Most Common Tags