WordPress database migration

I’ve looked around the WordPress forums about this and didn’t find anything so I thought I might try here.

If you have a staging/dev WordPress setup used for testing new pluging and such, how do you go about migrating the data in the staging database back to the production database? Is there a “WordPress best practices” way to do this, or am I limited to having to manually migrate tables from one database to the other?

Related posts

Leave a Reply

6 comments

  1. I have a script that mysqldumps a copy of my production WordPress DB, restores it over my test WordPress install & then corrects all the “production” settings & urls in the test DB.

    Both my production & test databases live on the same server, but you could change the mysqldump settings to dump from a remote mysql server & restore to a local server quite easily.

    Here are my scripts:

    overwrite_test.coach_db_with_coache_db.sh

    #!/bin/bash 
    dbUser="co*******"
    dbPassword="*****"
    dbSource="coach_production"
    dbDest="coach_test"
    tmpDumpFile="/tmp/$dbSource.sql"
    
    mysqldump --add-drop-table --extended-insert --user=$dbUser --password=$dbPassword --routines --result-file=$tmpDumpFile $dbSource
    mysql --user=$dbUser --password=$dbPassword $dbDest < $tmpDumpFile
    mysql --user=$dbUser --password=$dbPassword $dbDest < /AdminScripts/change_coach_to_test.coach.sql
    

    change_coach_to_test.coach.sql

    -- Change all db references from @oldDomain to @newDomain
    
    SET @oldDomain = 'coach.co.za';
    SET @newDomain = 'test.coach.co.za';
    SET @testUsersPassword = 'password';
    
    UPDATE `wp_1_options` SET `option_value` = REPLACE(`option_value`,@oldDomain,@newDomain) WHERE `option_name` IN ('siteurl','home','fileupload_url');
    UPDATE `wp_1_posts` SET `post_content` = REPLACE(`post_content`,@oldDomain,@newDomain);
    UPDATE `wp_1_posts` SET `guid` = REPLACE(`guid`,@oldDomain,@newDomain);
    UPDATE `wp_blogs` SET `domain` = @newDomain WHERE `domain` = @oldDomain;
    UPDATE `wp_users` SET `user_pass` = MD5( @testUsersPassword );
    
    -- Only valid for main wpmu site
    UPDATE `wp_site` SET `domain` = @newDomain WHERE `domain` = @oldDomain;
    
  2. The two methods would be using the export/import feature under tools or copying the database. I email myself a copy of my production database weekly using the WordPress Database Backup plugin.

    The import feature can be problematic for moving a wordpress blog as you have to configure your php.ini file often because the default value of files you can upload on a hosted php implementation tends to be too small by default.

  3. I wanted to pull the database from my production wordpress website into an offline development copy of it on my desktop machine so I could modify the site and test it with a
    full set of the existing blog content and history.

    This proved to be problematic, as simply making an offline backup of the database and importing it into the local development database did not work.

    Overcoming these problems in moving data from the production to the dev database can probably be used to go the other way as well – so I think you can just use these guidelines for what you want to do as well – just start with dev data and move it to prod.

    The problems here were:

    1. the permalink designations for the
      blog posts are all stored in the
      database as they would be for the
      online version, but my offline copy
      isn’t at the domain address, instead
      it is in the localhost directory. So
      when I launch the site locally,
      although the css formatting and
      images are all in place (the image
      links being relative), the actual
      blog posts don’t show up.
    2. many of the links throughout the
      site link back out to the internet,
      so if you try to navigate to
      archives, or comments, or
      categories, or the main posts, you
      get sent back out to the internet
      instead of staying in the database
      on the local machine.

    To make sure I was doing this right, I blew away the wordpress install I had on my local machine and restarted from scratch.

    Once I had a clean, new wordpress install and brand new default freshly created local database for it, I opened up the database in phpMyAdmin and took a look at the wp_posts

    table. Inside there, each record (in other words, each post) has a column titled “guid”, which shows the location of that post. For example, the first one in a fresh, default

    install contains this “guid” value:

    http://localhost/wordpress/?p=1
    

    If you look in the wp_posts table of your online version, you’ll see instead in this location the url to your site online.

    You can’t just import the tables wholesale into your local install, because you’ll be importing all these outside references. It will make your local version impossible to navigate locally.

    So, I created a backup copy of my online site’s database and saved it locally as a .sql file. I then opened that file in a text editor (I used notepad++, a great piece of free software, but you could use any text editor). Things I needed to look out for:

    • For whatever reason, the tables on my
      online site aren’t just, for example,
      “wp_posts” – they are
      “wp_something_posts”… there are
      some extra letters in there in the
      table names.
    • Any references to http://… that contain my online url instead of localhost/wordpress

    To keep it simple let’s just do only the posts. In the backup copy of the .sql you’ve made of your online database, find the beginning of the wp_posts table. It will look something like this:

    --
    
    -- Table structure for table `wp_posts`
    
    --
    
    
    
    DROP TABLE IF EXISTS `wp_posts`;
    
    CREATE TABLE `wp_posts` (
    

    …and so on. Highlight everything above that up to just below the comment marking the beginning of the database at the top of the file (it will say — Database: ‘your database name’) and delete it. Then go to the end of your wp_posts table, and delete everything after then end of it down to the bottom of the file. Now your file only contains your posts, and nothing else.

    Save this as a separate document. Call it posts.sql or something like that.

    Now, in this posts.sql file, you need to do two find/replaces actions.

    1. Find every instance of the name of
      the table wp_something_posts and
      replace it with wp_posts. You only
      need to do this if your backup copy
      of your online database doesn’t
      match your clean local install as
      far as the table names go. You want
      whatever the table name is in this
      file to match what your locally
      installed wordpress database has as
      this table name. If you don’t make
      these names match, you are just
      going to end up importing the posts
      into a new, differently named table,
      which will be of no use to you at
      all.
    2. Find every instance of http://
      (replace the elipsis with your url)
      and replace it with
      http://localhost/wordpress (or
      whatever the local url to your dev
      version of the site is)

    Now save this file again, to make sure you’ve got these changes set.

    Now that you’ve done that, use phpMyAdmin to get into the wordpress database on your local machine, select the “import” tab and navigate the selector to the posts.sql file you just made, and then import it. This will pull all the data in that file into your local wp_posts table.

    When that finishes, browse your local wordpress site. You’ll see all your posts in there now. Hooray!

    You may need to do something similar for a few other tables if you want to bring in your comments, tags, categories, and static pages you’ve created, etc.

    I realize this is a convoluted process. There is probably a tool out there somewhere that makes this activity easier, and if someone knows of one I’d love to find out about it. If someone knows of a better way to do this manually than what I’ve described, I’d love to know that as well!

    Until then, this is the way I figured out how to do it. Hopefully it helps get you going in the right direction.

  4. You need to handle the serialized objects. Here is a client side HTML5 utility to handle it. Because it is all javascript, it’s quite fast.

    The alternative would be hooking a bash script into your deployment. So once the site is deployed, the db is backed up and deserialized with the new domain.

  5. This about sums up the problems with the wordpress core architecture… but I wrote a plugin that solves the problems with domain names and absolute urls being stored in the database:

    http://wordpress.org/extend/plugins/root-relative-urls/

    This will solve the problems outlined by @oddbill. Though don’t worry too much about the url being in the GUID column as that field is never used for link generation.

    @markratledge provides a couple links to some lengthy documents that basically say this:

    //export

    mysqldump -u[username] -p[password] [database] > backup.sql

    //import

    mysql -u[username] -p[password] [database] < backup.sql

    You’ll want to exclude the comments/comments_meta tables if you push to production from staging so you don’t lose all of your comments and trackbacks (@DavidLaing’s approach will wipe those out.) And this assumes you only make content changes in your staging environment. If you want to make changes in production and your staging environment, you’ll need to write scripts that sync the data instead of wholesale overwrite it… good luck on that task, may I suggest adding create & modified timestamp columns before you invest too much time with the current schema.

    And finally, @RussellStuever’s approach is suitable in most circumstances, just be sure to know when you are browsing your host mapped site versus your production site. And really be sure about it, because some browsers cache dns lookups for days until you physically close them and start a new process. At which point switching hosts may take some time, and switching frequently may get frustrating. And if you need to test with an iPhone, you’ll need to publish the site live first, or use a good router that can remap outbound internet requests to local servers because you cannot modify hosts files on most mobile devices.

    My plugin lets you develop and test from http://localhost/ or http://staging.server.local/ or http://www.production.com without any of the usual pitfalls. And then to migrate data, it’s as simple as exporting and importing the data, no search & replace step or database setting tweaks necessary.

    And don’t rely on the import/export tool, it doesn’t capture everything in typical wordpress installations, and still requires a needless search & replace step.