Automating Backups to Amazon S3

My Setup & Prerequisites

I’ve got a LEMP stack, that is Linux (ubuntu), Nginx, MySQL, and PHP. It’s pretty common, but this should also work just fine for other LAMP stacks.

I want to backup some databases as well as web files, including some non-WordPress stuff.

There are tools out there like BackupBuddy that might be perfectly sufficient for your needs, especially if you want access to support forums and such.

But I like to dig into server-y stuff. Doing it this way will require a few things

  • ssh access to your server
  • sudo permissions (usually…)
  • amazon s3 account
  • some basic familiarity with the command line


Getting Started with WP-CLI

By getting started, I mean really just getting started. I’m just going to show you how to get WP-CLI running. I think once you do, you’ll take off on your own.

If your local development environment is on VVV, then stop reading, you’ve already got WP-CLI installed!

Here’s a summary of what we’re going to do:

  1. Download the application
  2. Make it executable from the command line
  3. Move and rename it
  4. In case of XAMPP (or MAMP), add its binary directory to PATH (need to make sure XAMPP’s php is used, and not your machine’s)

Yes, the instructions for installing WP-CLI can be found on its site, but sometimes I just like to reiterate and expand.

The publish_post hook

The publish_post hook is one I’ve seen a lot in tutorials and such. Even has its own page in the codex.

But surprise! That hook doesn’t actually exist, at least not if you search for do_action\(\s?.publish_post.

When I was learning to dig into core, this baffled me. What was this publish_post sorcery? Why wouldn’t it work on my custom post types???

Here’s a secret: The actual hook in core looks like this "{$new_status}_{$post->post_type}". It’s part of a small function in wp-includes/post.php (line 3321 at the time of writing), and there’s another equally useful variable hook right before it.

function wp_transition_post_status($new_status, $old_status, $post) {
	do_action('transition_post_status', $new_status, $old_status, $post);
	do_action("{$old_status}_to_{$new_status}", $post);
	do_action("{$new_status}_{$post->post_type}", $post->ID, $post);

There are quite a few of these variable hooks in core, I encourage you to go look at them, here’s a list I scraped together:


Stronger than dirt… I mean Ajax

I first learned about Ajax at a WordCamp (yay!), but I didn’t fully grasp how to implement it. There was a helper script provided, and I figured out how to make it work for my plugins, but all I really knew was copy & paste.

It was at least a good 6 months before I dug in and looked at the WordPress Ajax API. Getting a closer look helped me understand what I was writing, and how I could simplify and/or make improvements when necessary.

So let’s start.


Screencast: Coding a plugin, start to finish*

This screencast is an experiment I wanted to try and if well-received, I may do more in this style.

This recording is in realtime, not sped up (I may do a timelapsed version in the future), so you can see what I’m doing. I try to narrate it to make it easier to follow, but sometimes the cat in the background throws me off.

Unedited. Exporting and uploading took long enough as it is, as my first screencast of this type, consider it a rough draft.

The final result of this screencast can be found here:

However, the goal of this isn’t so much for the code at the end as the how I got there. Feedback and questions welcome.

Props to @dougal for the plugin idea. It might not be exactly what was had in mind, but that’s beside the point 🙂

* I know, plugins are never really finished

Removing ms-files.php Dependency

WordPress networks that were in place prior to the 3.5 update are dependent on wp-includes/ms-files.php and have that fun blogs.dir directory.

Upgrading your network to no longer have that dependency requires moving some files and making a whole bunch of database updates (mostly to reflect the changes from moving those files…)

This was my guide: And to reiterate what is said there, this is not something you have to do.

This post assumes certain technical ability and WordPress familiarity. Read everything, including the Half-Elf post, before proceeding to make sure you’re not going to get stuck partway through.

First, move (or copy, and delete later when you’re sure) your images from blogs.dir/BLOG_ID/files/ to /uploads/sites/BLOG_ID/.
Something like this

mkdir /path/to/wp-content/sites
cd /path/to/wp-content/sites

Then for each site

cp -r /path/to/wp-content/blogs.dir/BLOG_ID/files .
mv files BLOG_ID

For my 15-site network, doing this manually was fine. There is no doubt a script that can save you from doing this manually, but believe me when I say you don’t want me writing that for you.

Then you want to start making the database changes. Obvious are the image URLs, primarily in post_content, but also in other places, like theme_mods (custom headers, background images)

Then there are a couple other changes needed so that WordPress knows how to build the URLs, as well as where to put new uploads. So in each site’s options table, you can empty out upload_path, upload_url_path, and fileupload_url

And lastly, trip the ms_files_rewriting flag so that WordPress knows to stop treating your network like it still uses ms-files.php. ms_files_rewriting is a site option, so there’s only one place to set it (or insert it, since it may not be in the database already), and it should be false.

Once you’ve confirmed that nothing has exploded, you can remove the ms-files.php rules from your htaccess or nginx config files

To help out with the database edits, I wrote a plugin. It helped me get this network away from ms-files.php, but I haven’t done a fresh run on any other pre-3.5 network. READ THE SOURCE, USE WITH CAUTION, DON’T DO IT IN PRODUCTION LIKE ME.

Got it? I mean really. If you blow up your site, don’t come crying to me. Check it out on Github.

Send a weird postcard from Russia (by proxy)!

My mother will be traveling in Russia this summer. Part of her adventures will be a road trip! You know what that means? Small no-one’s-heard-of-them towns.

If you want to weird-out a friend, my mom will send a postcard for you.

Use my donate form to buy a postcard. In the ‘Any particular reason?’ field, provide your email address, the recipient’s name and address, as well as 2-3 little details to be mentioned in the postcard. Do they have a dog named Spot? My mom will ask how Spot is doing in the postcard. Only requirement: must be family friendly!

(She’ll also be in Scotland briefly, if you definitely do/don’t want a Scottish postcard, let me know.)

In order to cover materials, postage, time, and labor, this will cost $10 per card. Start thinking now, and get your request in over the next few weeks! She leaves on June 25th, but she’ll be able to receive new request via email (don’t worry, I’ll be sending her the info).

There is no set limit right now, as I’m not expecting heaps of interest, but I reserve the right to stop accepting requests if demand becomes too much. So don’t delay!

Where’s my mom going? See the map below. She’ll be in the 4 locations marked below, and traveling between them either by train or car.

View Larger Map