How to clone a WordPress site

So how do you clone a WordPress site?

At work, we are in the beta test phase of our new website, and for the first time ever, we are using WordPress as our platform.

I had been trying to figure out the right way to set up a staging server, so that we can test changes there before going live. Sounds reasonable enough. But it wasn’t turning out to be a simple task.

The procedure I came up on my first try looked like this:

1. Run UpDraftPlus Backup
2. Download backup files to my computer
3. Copy zip files
4. Unzip database file
5. Open database file in Sublime editor
6. Find/Replace all occurrences of website address to correct address
7. Find/Replace all occurrences of c:\\path\\WordPress\\_site_folder_
8. Find/Replace all occurrences of c:\\\\path\\\\WordPress\\\\_site_folder_\\\\
9. Copy db script and run it on staging db server
10. Test

Simple enough, right?

But there’s a problem! Apparently, this method will not work reliably, due to the presence of serialized data!

This problem first reared it’s ugly head with our Custom Post Types. We were using a plugin we found that makes it easy to create and maintain Custom Post Types. However, they use the options table to store their data, so when I cloned the site the first time using this method, the new version of the site didn’t see any of our Custom Post Types. I did some digging, and figured out that the cause was the function call trying to deserialize the data from the options table. At that point I thought that the issue was that the plugin used serialization. But…

Today I learned that the problem is with steps 6,7, and 8 in my first procedure. You cannot just do a blind find/replace in a WordPress DB. This is due to the presence of serialized data.

To understand why, let’s look at how serialization works.

When serializing a string in PHP, you get something that looks like this: s:size:value; Or, with actual data, it looks like this: s:5:"hello";  The s stands for string, the number is the number of characters in the string, and then finally, we have the string itself.

So the problem is that if we have s:17:”http://google.com”; and do a find/replace to make it look like this: s:17:”http://bing.com”; we will no longer be able to deserialize that string. Why? Because the new string is no longer 17 characters long!

What to do?

Enter the DATABASE SEARCH AND REPLACE SCRIPT IN PHP. This little gem will do the search and replace for you, but it will also unserialize the data first, then reserialize it afterward. That way, the string lengths will be updated too.

After running that, the correct data was in my staging DB, and all looked well. However, when I went to the front page, I got the dreaded “White screen of death”. Just a blank white screen staring at me. I could still get to the backend, and everything there looked just fine.

I tried going to the permalinks page, to see if that might do anything, but it didn’t.  Next I went to the plugins page where I was immediately greeted with three red boxes. Apparently, three plugins had been disabled because their files were missing. I’m not sure how that happened, but the fix was easy enough. I copied the missing items in, and reactivated the plugins.

Still, a white screen staring me down.  Nothing I seemed to do would make it work. The back end was now behaving as if all was well, but something was still not right.

Sigh

Ok, the only thing I could think to do next was to delete the whole thing and start over.  You see, I had already cloned the site once before, and manually modified the db, so at this point I was thinking I’d better start from scratch.

So, here’s what I did:

  1. Delete all files on staging server
  2. Delete all DB tables on staging server db
  3. Copy fresh WordPress files to staging server
  4. Copy wp-config.php from live site to staging server
  5. Copy web.conf file from live to staging server
  6. Copy additional folders and files, that we added manually, from root of live
  7. Backup live site
  8. Copy zip files over to a folder on my desktop
  9. Unzip all zip files
  10. Copy plugins, themes, uploads folders over to staging server wp-content folder, selecting to replace all existing content when prompted
  11. Copy “others” folder over to staging server wp-content folder
  12. Run DB Script on staging server db
  13. Copy searchreplacedb2.php (the script liked to above) to the root of the staging server folder (!! Not the root of the entire server!!)
  14. Run Find/Replace Script, replacing whatever you need to
  15. Test

I left out a couple details, such as what to find and replace. Basically, you want to convert from the live domain, to the staging one. But it’s not just http: paths we are concerned with here. There’s also local file paths to change. By searching for our domain name in the db, I found three different forms which needed to be changed. I’ll show an example of each:

  1. http://livesite.com —> http://stagingsite.com
  2. c:/webpath/Wordpress/livesite.com —> c:/webpath/Wordpress/stagingsite.com
  3. c://webpath//Wordpress//livesite.com —> c://webpath//Wordpress//stagingsite.com

There was only one occurrance of the one shown in #3, but I resisted the temptation to change it manually in the db. I let the script do it in case it was serialized.

Also, when I entered the find and replace terms for #2 and #3 in the script, I needed to double the forward slashes – to escape them. So #2 looked like c://webpath//Wordpress…  and #3 looked like c:////webpath////Wordpress… I know – crazy, but it didn’t work otherwise.

Once I had done all this, the staging server was a clone of the live site, at the moment of the backup at least. You want to make the backup as late as possible.

This procedure worked perfectly. If I learn anything new, or find anything I missed, I’ll post it here.

Update

We are now using Akeeba Backup for WordPress. This free tool does just what we want, and abstracts away most of the details.

 

Custom Admin Logo for WordPress 3.3.1 and newer

I found an article today with a bunch of tips for customizing WordPress, and tried to implement one to change the logo at the top left corner of the admin screen. There is normally a WordPress logo there. However, the code didn’t work. After poking around a bit, it became apparent that I must be using an out of date technique. After some further searching I found http://paulbredenberg.com/2012/01/changing-and-overriding-the-wordpress-admin-logo-since-3-3-1/

Here is what it looks like:

function my_custom_logo() {
echo '<style type="text/css">
#wp-admin-bar-wp-logo > .ab-item .ab-icon { 
	background-image: url(path to image) !important; 
	background-position: 0 0;
	}
#wpadminbar #wp-admin-bar-wp-logo.hover > .ab-item .ab-icon {
	background-position: 0 0;
	}	
</style>';
}

//hook into the administrative header output
add_action('admin_head', 'my_custom_logo');

Thanks to Paul for providing updated code for the original solution found on wpbeginner.com.