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
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 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.
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:
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:
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.
We are now using Akeeba Backup for WordPress. This free tool does just what we want, and abstracts away most of the details.