WP Stagecoach 03.3. Released
Posted on by Morgan KayWe just released a new version of WP Stagecoach Beta. This plugin fixes a bug that was preventing some users from importing database changes. We also made some changes to the import user interface, and fixed some other small bugs.
Review on WP Tavern
Posted on by Morgan KaySarah Gooding at WP Tavern just wrote a review of WP Stagecoach! Our favorite part:
At the moment, the service is very promising and offers a highly convenient way to create a staging site for a simple WordPress site on a standard LAMP stack.
Deleting Alpha staging sites
Posted on by Morgan KayWe’re getting close to launching version 1.0!
In preparation for launch, we need to tidy up old sites created by old versions of WP Stagecoach. We will shut down the Alpha server on December 23. All staging sites created with the alpha version of WP Stagecoach will be deleted on December 23. Continue reading →
WP Stagecoach Beta Launched!
Posted on by Morgan KayWe have launched the beta version of WP Stagecoach! The plugin has come a very long way since the first alpha versions a year ago. The beta version does lots of nifty new things:
- staging sites can be accessed via SSL-encryption
- you can password-protect staging sites
- advanced debug mode for tracking down problems
- much more reliable
- if importing gets interrupted, it can pick up where it left off
- ability to undo file import
WP Stagecoach is still free while it is in beta. Sign up to use WP Stagecoach beta!
And you’ve no doubt seen our fancy new website by now.
If you’ve been using the alpha version, you will need to sign up for a new API key. Your old alpha API key will still work with the alpha version, but we will phase out the alpha version soon.
Search Engine Optimization
Posted on by Jonathan KayUnlike most search engine optimization that goes on, I am trying to dissuade search engines from coming to staging sites hosting on WP Stagecoach. Prior to today, I just made a change in all staging sites that made WordPress discourage them, but many search bots, especially the less reputable ones, don’t tend to listen very well. So today I implemented a change that will make Apache return a 403 (Forbidden) error to search engines that use a User-Agent name that contains:
- bot
- crawler
- spider
(as well as a couple others).
I did this using Apache’s ability to set an environment variable with mod_setenvif, and the “Deny” directive.
I put the following in apache’s main config, httpd.conf:
LoadModule setenvif_module modules/mod_setenvif.so
SetEnvIfNoCase User-Agent "bot" search_bots
SetEnvIfNoCase User-Agent "crawler" search_bots
SetEnvIfNoCase User-Agent "spider" search_bots
and then in each of Apache’s vhosts, I already have the Directory set, so I just included the deny at the end:
...
Order allow,deny
Allow from all
Deny from env=search_bots
That should keep the staging sites off of the major search engines, but not stop anyone from actually visiting and using their staging site!
Conditional logic in a regular expression – Conditional Capture Group
Posted on by Jonathan KayI have been working on making WP Stagecoach work reliably with sites that are encrypted with TLS (that is, https://), and I wanted to make a single line of change for different URLs that may be in the database.
Let’s say we want to create a staging site from a live site running on https://example.com with the following local URLs stored in its database:
https://example.com
https://example.com/foo
http://example.com/
http://example.com/bar/
example.com/?p=123
example.com
These are all URLs which may stored in the database of a TLS encrypted site.
When WP Stagecoach creates the staging site, it needs to change all of these to be non-encrypted (as currently WP Stagecoach does not support encrypted staging sites):
http://example.wpstagecoach.com
http://example.wpstagecoach.com/foo
http://example.wpstagecoach.com/
http://example.wpstagecoach.com/bar/
example.wpstagecoach.com/?p=123
example.wpstagecoach.com
So I found that a pretty simple regular expression with a capture group got me really close to what I needed to do:
$search = 'example.com';
$replace = 'example.wpstagecoach.com';
foreach ($urls as $key => $url) {
$urls[$key] = preg_replace('#(https?://)?'.$search.'#i', '1'.$replace, $url);
}
So, some groundwork here. Regular Expressions are an incredibly powerful, but often hard to utilize method of matching (and replacing) a string. In this case, we are searching for elements of the database that match “example.com”, and we want to replace them with “example.wpstagecoach.com”.
preg_replace($pattern_we_want_to_match, $replacement_text, $string_to_check_for_match_in)
The PHP function preg_replace() takes 3 arguments, the pattern we want to match, the string we will replace what is matched with, and the string itself. The first argument here looks a little odd: ‘#(https?://)?’.$search.’#i’ — the ‘#’s here are used as delimiters–typically a ‘/’ is used, but as we are trying to match “//”, it is cleaner to just use a different delimiter. Then there is an ‘i’ at the end to indicate it can match a case-insensitive pattern (eg, Example.com, or example.COM).
Looking inside the delimiters, we notice two main elements, the “(https?://)?” and the ‘$search’ (which in this case is “example.com”). The latter is pretty self-explanatory–it will attempt to match database entries that have “example.com” in them. The former takes a little more effort.
There are a couple question marks in the first element, and notate that the preceding sub-element is not required to be matched. So in this case, on the inside, the element ‘s’ (a literal character ‘s’) is followed by ‘?’, so that will match both “http://” and “https://”. The outer element “(https?://)” is also followed by a ‘?’, so while we must match “example.com”, we don’t have to have “http://” in front of it for the match to succeed.
The parenthesis (https?://) mark what is called a capture group, that is, something we can reference later on. In this simpler case, we just prepend the capture group in front of the replacement string with the “1” in front of “$replace” in the function’s second argument.
However, there is a problem because the capture group will match either “http://” or “https://” and prepend that to “example.wpstagecoach.com”, and we want it only to prepend “http://” if either are present in the database.
So we need to use a slightly different PHP function which lets us call a function as the method of creating the replacement text. This PHP function is called “preg_replace_callback()”, and it takes three arguments, the only difference from the “preg_replace()” function is that it uses a function to calculate what the replacement text should be.
preg_replace_callback($pattern_we_want_to_match, function($match) {return $replacement_text}, $string_to_check_for_match_in)
The first and third arguments are the same as before, however, we want to utilize the function to create a replacement text based on whether the database entry has “http://” or “https://” in it.
preg_replace_callback(
'#(https?://)?'.$search.'#',
function($match) use($replace) {return empty($match[1]) ? $replace:'http://'.$replace;},
$url
);
To this function we pass the “$match” variable, which is (basically) an array of all the capture groups, in this case, we only have one, (and it is 1-based, like the capture group numbering), so inside the function, we do PHP shorthand to check if “$match[1]” is empty, and if so, only return “$replace”, but if it is not empty, we return “‘http://’.$replace”. Of note, the “use()” addition is needed if you want the function to have access to any external variables.
Startup Health Hazards
Posted on by Jonathan KayWP Stagecoach should have launched by now. I should have released beta in February, and the initial public version a few weeks ago. Unfortunately, doing a startup has taken a toll on my health. Many long hours of coding have led to a pinched nerve in my neck, and my left arm has been numb or tingling a lot of the time, and I’ve been in a lot of pain. Some days, I’m in enough pain that after just a few hours of work, my brain shuts down and I can’t get any more useful work done.
I can’t begin to tell you how frustrating this is for me!
I have the beta version of Stagecoach pretty much written in my head: I know what I need to do to finish it, but I haven’t had the physical or mental stamina to sit in front of a computer and get it done.
What makes this extra frustrating is that I’m pretty good about sitting properly in an ergonomic chair, stopping for regular stretch breaks, and (thanks to my active and ever-enthusiastic dog) getting lots of exercise. Despite all of those things, being the main developer for WP Stagecoach means I have been spending very long hours sitting in front of my computer – long, exciting, productive, enthusiastic hours, and I wish I could spend more, but my body apparently doesn’t want me to do that.
One advantage to this is that several extremely helpful alpha testers have found more bugs for me to squash, so ultimately the beta release will be more robust because of this delay.
Ultimately, this is just one of the hazards of doing a startup: startuppers often risk their financial and physical health to make their dreams come true. WP Stagecoach is still a very viable dream, and I still have every intention of continuing to make it come true, it just might take longer than I originally planned. I am slowly getting better – I have been to several specialists, and have been working hard to get better, but it just takes time.
I hope you all understand, and hope that I can get the beta version launched some time this Spring!
Using WP Stagecoach to develop a new theme
Posted on by Morgan KayThe website for my theme development business has gotten pretty stale, so I decided it was time to give it a facelift. I asked a graphic designer, Seth Vincent, to come up with a new design for me. Once I had the design files, I was ready to develop a new theme.
If I hadn’t had WP Stagecoach, there are a few ways I could have done this. The new design was pretty simple, so it only took a few days to create the new theme. The site doesn’t get much traffic, so I could have just put it in maintenance mode for a few days. Or I could have used a plugin that lets the logged-in administrator see a different theme than non-logged in users, but the problem with that is that I needed to make a bunch of changes to content and menus for the new theme, so the site still would have been a bit awkward. Or I could have created a copy of the site, but even using tools like Backup Buddy, that would take a while to set up, and then copying the changes back would be time-consuming too.
Luckily, I was able to use WP Stagecoach. I created a staging copy of the site with just one click. Then I developed the new theme on the staging site. I installed some plugins, deleted some others, created some pages, changed navigation menus, changed the content on several pages, and, of course, developed a new theme.
When I was done with all of that work, I went back to my live site and imported all of the changes from the staging site. All of those changes – plugins, pages, navigation menus, theme files – were merged onto my live site, and now my site has a refreshing new look. I didn’t have to compromise the live site while I was developing, and I could take my time developing on the staging site to make sure I got everything just right.
Performance Considerations in WP Stagecoach
Posted on by Jonathan KayOne of the big things I have thought about while writing WP Stagecoach is how to make the plugin run as quickly as possible.
I would rather spend extra time and code in making the end product perform better than writing shorter or sometimes more readable code. On several occasions while I have been developing WP Stagecoach, I have taken time to test different methods of doing something to see which is faster. I am impressed by how little difference there is in performance between using different methods of doing things, despite being an interpreted language (rather than a compiled one).
However, a good example of where this is not the case recently came up in the PHP scandir() function. It returns an array of all the files and directories in a given directory, and on a unix-like system (like most web-hosting servers) that includes the current directory (‘.’) and the parent directory (‘..’), which are usually not used.
In WP Stagecoach, when the plugin creates a staging site, it first needs to scan the entirety of the WordPress install, and it does that by crawling over the filesystem, which means it runs scandir() a lot! I wanted to make sure that this was as fast as possible, so I tested the performance of several ways of excluding ‘.’ and ‘..’ from a foreach() loop over the array of files the plugin gets from scandir().
The cleanest and perhaps most obvious way seems to be to use array_diff() to remove the two unneeded dirs before the foreach() loop:
$array = scandir('.');
for ($i=0; $i < 20000; $i++) {
$arr = array_diff($array, array('.','..'));
foreach( $arr as $file ){
echo $file;
}
}
An alternative is to do a simple if( $file != ‘.’ && $file != ‘..’ ) for each element in the foreach loop. I was surprised how much faster this was than using the array_diff().
$array = scandir('.');
for ($i=0; $i < 20000; $i++) {
foreach ($array as $file) {
if( $file != '.' && $file != '..' ){
echo $file;
}
}
As it turns out, a third option seems to be even faster–using array_search() and unset() to remove the ‘.’ and ‘..’ entries from the array gotten from scandir().
$array = scandir('.');
for ($i=0; $i < 20000; $i++) {
unset( $array[ array_search('.', $array) ]);
unset( $array[ array_search('..', $array) ]);
foreach( $array as $file ){
echo $file;
}
}
In a loop of 20,000, using array_diff() was the slowest, with the simple if() conditionals running it about 10% faster, and unsetting the results of array_search being about 25% faster. On average, in a directory with ~150 items over a loop of 20k, the array_diff took 4.12s, using if’s took 3.73s and unsetting the values in the array took 3.30s.
While that may not seem like much, but every little bit helps (especially on slower web hosts) to make WP Stagecoach a bit more reliable and quick!