Scatter, a deploy helper

Update: This project has been completely rewritten. The Github readme is up to date and there’s a post about some of the new features here.

Meet Scatter, a handy deploy helper I wrote this weekend.

Deploying web projects can be a bit of a pain, especially when you don’t manage them all the same way. I maintain a couple of sites, like this one — which uses Capistrano — and IsValid — which uses a good old fashioned git pull. It’s also frustrating not to have a good place to keep deploy-related code for open source projects (like IsValid).

At Automattic/WordPress.com, we have an awesome-yet-simple deploy tool that our systems team maintains. From a developer’s point of view, it’s as easy as typing deploy wpcom into a terminal. If I wanted to deploy another project I just change out the argument(s). For example, if I want to deploy our internal “Mission Control” site, I would type deploy mc.

Inspired by our deploy command and Mark Jaquith’s WP Stack, I decided to write a generic command line deploy tool; thus, Scatter was born.

The idea behind Scatter is to support whatever deploy “system” I wanted to use for a project. Scatter does that by letting you define a custom script for each project, called deploy (just an executable, extension-less file) and making it easy to access the one you want with some simple git repository parsing (or explicit arguments). It also supports a fallback to a basic cap deploy if you provide a Capfile, which is what I do for this site.

Scatter is designed to keep your deploy and web code separate and make it easy to access one while developing the other. I wrote a detailed Readme for Scatter, so if you want to know more I recommend you check it out.

Commercial plugins & the GPL

Brandon Dove did an awesome presentation at WordCamp San Diego this year on running a commercial plugin business while working with and respecting the GPL. I’ve mentioned it to several people since then because it’s the most informative and logical approach I’ve seen to a common challenge.

I just noticed it was posted on WordPress.tv, so here it is.

WordCamp Denver 2012

I’m doing a talk at WordCamp Denver today called “Demystifying the Black Box of WordPress Core”. It’s a collection of (hopefully) useful knowledge and tools to help understand how WordPress core works, and some examples of how to use and navigate WordPress more easily. Here are the slides.

Ask the negative in presentations

I see a lot of presentations where presenters stop in the middle of their talk to ask questions like, “Does this make sense to everybody?” That turns out to be a really bad question.

First, no one in the audience is actually empowered to answer it. Who am I to raise my hand and say it makes sense to everybody? Usually this question is followed about an awkward silence and a self-deprecating joke like, “Oh I guess I lost everyone.” No good.

Second, it’s a big social barrier to raise your hand — even when speaking only for yourself — and declare, “Yes, I totally got this.” Much more likely is being sort of in the middle, but hopefully knowing you just need to wrap your head around it a little longer to really grok the idea. Raising your hand in a room full of strangers to say that you understand everything is really intimidating. Doing it would probably makes most people feel like a jerk when they realize almost no one else is going to raise their hand.

Third, what’s important isn’t actually that everyone gets it. If you’re talking to more than five people about even a slightly complex idea, it’s basically impossible for everyone to understand it. A better question is, “Does anyone need to clarify anything before we move on?” You don’t require people to be 100% sure of something before raising their hand and you let the audience self-select for whether or not they think they would benefit from some more help. As a result, you save everyone that awkward 30 second silence. An even better option is to skip the question entirely, focus on what you came to talk about, and trust that the room full of adults will find a way to let you know on their own if they need help.

The best presentations maximize total learning. I think of total learning as multiplying information taught by the number of people that understood it. Everyone understanding everything seems nice but actually hurts your chance to do that because you end up catering to the lowest common denominator.

You’re better off asking about the opposite of what you really want.

Bash helper to check how much code you’re adding or removing

Less code is generally better than more code. If done correctly — avoiding cleverness for the sake of cleverness — it’s easier to maintain, more reliable, and easier for other people to learn from. It’s nice when you can add new features or improve existing features while removing code overall.

I wrote a very simple Bash helper function that I call redgreen to do this. It requires ack, which you should be using anyway.

I keep this in my .bashrc (Linux) or .profile (OSX) so I can easily use it from anywhere.

oEmbed in Comments

Last week I tried to embed a tweet in a comment reply here, and I was sad when I realized that comments don’t get the same oEmbed magic that posts do. I thought about making a core ticket to add this — and I still may do that eventually — but decided to make it a plugin first.

Over the weekend I wrote it, and earlier today I released oEmbed in Comments on the WordPress.org repository today. It’s also on Github.

It’s really simple. Once activated, if someone posts a comment with a stand-alone URL pointing to an approved oEmbed provider (like YouTube or Twitter) it will grab the media and replace the link with an embed. There’s no UI and no settings, just activate the plugin and it works.

If you search for this kind of thing, you may find an old plugin called oEmbed for Comments (lots of creative naming here). I originally thought I might just use that, but on closer inspection I didn’t like the way the plugin worked. It sort of used WordPress core’s oEmbed functionality, but it also rewrote a significant part of that on its own. On top of that, it hasn’t been updated in two and a half years, which isn’t a good sign.

In the end, I decided I’d be happier with something simpler and done from scratch.

WordPress themes on the command line: _sh

Last week we had a very fun hack day at Automattic. A couple Automatticians (Hugo and Konstantin) made underscores.me, an awesome and easy way to create custom forks of the _s starter theme that the Automattic theme team released earlier this year. Ian Stewart wrote a post about it on ThemeShaper and today I noticed an interesting discussion in the comments about forking _s from the command line. It seemed like a cool idea, so I spent a little while hacking together a Python script to do it, which I just released on Github.

I’m calling it _sh.

I wrote a detailed README, so I’m going to copy most of that here and let it play out the remainder of this post.

_sh (the _s shell)

_sh is a command line tool to generate forks of the _s WordPress starter theme. It uses underscores.me to create the fork, but lets you do it entirely from the command line.

It lives at https://github.com/evansolomon/_sh.

Installation

_sh is written in Python, so you’ll need to have it installed and have a way to interact with it on the command line, like in Terminal.app.

The easiest way to use _sh is to put it in a place that your PATH can access it. First, clone this repository.

git clone https://github.com/evansolomon/_sh.git /path/to/save/_sh

From the directory that you cloned _sh, you can run the setup.py installer script to create a symlink.

python setup.py

That will give you a prompt where you can type the directory that you want to link _sh to. Here I’ll set it up to live in my ~/bin directory.

Welcome to _sh.

Where do you want to symlink _sh? ~/bin



Running...

ln -s /Users/evan/code/_sh/_sh /Users/evan/bin

Usage

Assuming you’ve setup _sh to be accessible in your PATH, to use it you can just call _sh on the command line from anywhere.

When you call _sh you’ll get an interactive prompt that will walk you through setting up your theme. The new theme will get created in a child directory of wherever the command is run from. Here’s an example:

cd ~/code/themes && _sh

Once I run the _sh command I’ll get an interactive prompt with a few questions to setup my new theme. It’s hard to tell from here, but the introduction and questions all come from _sh, and the answers come from me, typed into an interactive prompt in Terminal. Most of these questions are optional; the only one you must answer is the theme’s name.

I'm going to ask you for some information about your theme.

You have to give your theme a name but you can leave the others blank if you want.

Let's get started.

Name? Stella and Mojo
Slug? stellaandmojo
Author? Evan Solomon
Author URI? http://evansolomon.me
Description? It's a theme named after dogs, because why the hell not.

At this point, _sh will make a request to underscores.me, download a ZIP file with my new theme, and unzip it. Then I’ll have a directory in ~/code/themes/stellaandmojo with my theme files.

That’s it, now I’ve got a new fork on _s with all of my customizations setup.

I updated the post to reflect the new setup.py installer.

“Premium Themes” are a lie

If you do almost anything with WordPress you’ll quickly find your way into discussion of “premium” themes. The name would suggest that these themes are the cream of the crop, vetted and verified as the themes to use to craft your soon-to-be-amazing WordPress site. The name lies.

Premium themes are just themes that are not free (as in beer). In Ryan Imel’s recent WordCamp SF talk called “The State of Themes” he suggested calling premium themes “commercial themes”, which I think is a good start to clarifying the real differences. I can’t count the people I’ve talked to that assume premium themes are good and free (as in beer) themes are bad. All things considered, it’s a rational assumption. Unfortunately it’s a really, really bad assumption and it leads to people having really bad experiences with WordPress that should have been avoided.

I am making a simple landing page for a project Beau Lebens and I worked on during a hack day at Automattic. I decided to browse Theme Forest and found a theme that, while not perfect, I came up with a way to tweak that I liked. I happily paid $8 and would have easily paid triple that for the time saved by not starting from scratch. In hindsight, it would have been a ripoff at half the price. Here’s the Skype conversation that followed, which really underscores how much I hate this theme.

Evan Solomon: this is very likely the worst $8 i’ve ever spent
Beau Lebens: you can just send me $8 if you like
Beau Lebens: i won’t even give you a shitty theme for it
Beau Lebens: then that’ll be the worst
Evan Solomon: this is way worse than just losing $8
Evan Solomon: it’s like spending $8 to get punched in the balls

This post really is not meant to pick on a particular theme, but the one I bought is called Under Construction page with twitter & pie graph. After reading the name, one wouldn’t have to work hard to argue that I got what I deserve.

Jokes aside — and there are many to be made — this is actually a substantive complaint. Let’s start with activating the theme. Here’s the first thing I saw:

Notice: Undefined index: id in /Users/evan/code/evansolomon.me/wp-content/themes/buddypig/var.php on line 6
Notice: get_settings is deprecated since version 2.1! Use get_option() instead. in /Users/evan/code/evansolomon.me/wp-includes/functions.php on line 2612
Notice: Undefined index: id in /Users/evan/code/evansolomon.me/wp-content/themes/buddypig/var.php on line 6
Notice: Undefined index: std in /Users/evan/code/evansolomon.me/wp-content/themes/buddypig/var.php on line 6
Notice: Undefined index: id in /Users/evan/code/evansolomon.me/wp-content/themes/buddypig/var.php on line 6
Notice: get_settings is deprecated since version 2.1! Use get_option() instead. in /Users/evan/code/evansolomon.me/wp-includes/functions.php on line 2612
Notice: Undefined index: id in /Users/evan/code/evansolomon.me/wp-content/themes/buddypig/var.php on line 6
Notice: Undefined index: std in /Users/evan/code/evansolomon.me/wp-content/themes/buddypig/var.php on line 6
Notice: get_settings is deprecated since version 2.1! Use get_option() instead. in /Users/evan/code/evansolomon.me/wp-includes/functions.php on line 2612
Notice: get_settings is deprecated since version 2.1! Use get_option() instead. in /Users/evan/code/evansolomon.me/wp-includes/functions.php on line 2612
Notice: Undefined index: std in /Users/evan/code/evansolomon.me/wp-content/themes/buddypig/var.php on line 6
Notice: get_settings is deprecated since version 2.1! Use get_option() instead. in /Users/evan/code/evansolomon.me/wp-includes/functions.php on line 2612
Notice: Undefined index: std in /Users/evan/code/evansolomon.me/wp-content/themes/buddypig/var.php on line 6
Notice: get_settings is deprecated since version 2.1! Use get_option() instead. in /Users/evan/code/evansolomon.me/wp-includes/functions.php on line 2612
Notice: Undefined index: std in /Users/evan/code/evansolomon.me/wp-content/themes/buddypig/var.php on line 6
Notice: get_settings is deprecated since version 2.1! Use get_option() instead. in /Users/evan/code/evansolomon.me/wp-includes/functions.php on line 2612
Notice: Undefined index: std in /Users/evan/code/evansolomon.me/wp-content/themes/buddypig/var.php on line 6
Notice: get_settings is deprecated since version 2.1! Use get_option() instead. in /Users/evan/code/evansolomon.me/wp-includes/functions.php on line 2612
Notice: Undefined index: std in /Users/evan/code/evansolomon.me/wp-content/themes/buddypig/var.php on line 6
Notice: get_settings is deprecated since version 2.1! Use get_option() instead. in /Users/evan/code/evansolomon.me/wp-includes/functions.php on line 2612
Notice: Undefined index: std in /Users/evan/code/evansolomon.me/wp-content/themes/buddypig/var.php on line 6
Notice: Undefined index: id in /Users/evan/code/evansolomon.me/wp-content/themes/buddypig/var.php on line 6
Notice: get_settings is deprecated since version 2.1! Use get_option() instead. in /Users/evan/code/evansolomon.me/wp-includes/functions.php on line 2612
Notice: Undefined index: id in /Users/evan/code/evansolomon.me/wp-content/themes/buddypig/var.php on line 6
Notice: Undefined index: std in /Users/evan/code/evansolomon.me/wp-content/themes/buddypig/var.php on line 6
Notice: Undefined variable: ts_portfolio_cat in /Users/evan/code/evansolomon.me/wp-content/themes/buddypig/var.php on line 12
Notice: Undefined variable: ts_blogpage in /Users/evan/code/evansolomon.me/wp-content/themes/buddypig/var.php on line 16
Notice: Undefined index: page in /Users/evan/code/evansolomon.me/wp-content/themes/buddypig/functions.php on line 98

That’s 28 PHP notices for those keeping score. It’s worth noting that at this point I still haven’t actually loaded a page running the theme. I noticed that there were quite a few errors (18) in a file called var.php. That’s notable because I’ve actually never seen a WordPress theme that had a file with that name. So I did what any developer would do when faced with a strange-sounding file generating lots of errors, I got a beer from my fridge. Next I opened the file.

I was surprised to find that the file was actually quite short. How short, you ask? 18 lines. 18. In a coincidence so incredible it made me question my own atheism, this file generated exactly one PHP notice PER LINE. Amazing, but far from the best part. The best part is that — ignoring comments, blank lines and PHP tags — I actually disliked every single line of the file. Even that is somewhat generous, because the file included a PHP closing tag, which you should not use. Thanks to the GPL I now have the right to redistribute this code, which I feel compelled to share with you.

Where to even start…

  • This code is running in the global scope already, because why the hell not, so there’s no need to global-ize $options
  • $options is possibly the worst name ever chosen for a global variable
  • …well, until we name one $value
  • get_settings() was deprecated in WordPress 2.1, which was released in January 2007. The function has actually been deprecated longer than it was valid.
  • Variable variables. Enough said.
  • Raw, un-sanitized database queries

So I hope we can all come to terms on the idea that this is a bad file. Maybe it’s not that important though, perhaps it’s used sparingly, right? Allow me two show you two lines from the theme’s index.php file. These are lines 10 and 96, and neither are inside of a conditional or any other code that would prevent them from running.

require(TEMPLATEPATH . "/var.php");
include(TEMPLATEPATH . "/var.php");

So you get this shit twice on every single page. Because — well, I have no idea.

Actually that’s a lie. Want to guess what functions.php does right before it ends with a PHP closing tag? Yup.

require(TEMPLATEPATH . "/var.php");

I guess at this point we might as well load up the actual theme. Upon visiting the front page, var.php outdoes itself by generating 47 PHP notices, for a staggering ratio of 2.6 notices per line of code.

I could go on, but I assume by this point you get the idea. This theme creates about a million global variables, does absolutely no sanitization of data, has SQL injection opportunities, misuses (or just ignores) countless WordPress core API’s, and who knows what else.

The point here isn’t just to criticize bad code. Everyone who’s written any code has written some bad code (though maybe not this bad). The point is that this is a “premium theme”. In fact, as I write this, it’s sold almost 1,000 copies and the feedback is almost universally positive.

Themes are a hugely important part of the WordPress ecosystem. For many people, their theme is synonymous with their site; they have no concept of the separation. For many of those same people, their site is synonymous with WordPress. If they have a bad experience with their site (or theme) that’s a bad experience with WordPress. And one of WordPress’ greatest strengths is how usable it is for non-experts. Those people need tools to make informed choices, and one of the tools that’s currently used most is the association of “premium” themes with high quality. It’s bullshit.

There are a few things I really hope this post can help inspire.

  • The WordPress community needs to take responsibility for communicating the idea that price is not a reliable predictor of quality. This isn’t to say that there are no good commercial themes, but it does mean that themes aren’t good just because they’re commercial.
  • The “premium theme” market needs to be more open. There are lots of very high quality companies and developers in the market, and they probably get hurt more by crap like this than anyone. They should be incentivized to educate users and educate each other, which starts with getting the code in commercial themes scrutinized the way the code in free themes is.

Simple function to add body classes in WordPress

I wrote this for one of our themes on WordPress.com and thought it might be useful to someone else. This is just a slight abstraction on top of the body_class filter in WordPress. We had a use case for adding body classes within theme files, and I wrote this as an alternative to adding function/filters to templates or adding more global variables.

The short saga of a W3 Total Cache victim

Before I start, I should say that the title is somewhat misleading — I’ve never actually installed W3 Total Cache on this site, or any other site outside my laptop for that matter. I have tested it a bit, and because of that decided not to use it. Someone in the comments of my post on Batcache, nginx and multisite asked me why I didn’t use it, and I decided to turn my response to that into a post.

Here is that comment, unedited. If you’d like to see it in context, you can check it out here.

To expand a bit on why I dislike W3 Total Cache, here is a short summary of my experience installing it.

First, because I know what’s coming, I made a new branch in my git repository.

Then I installed and activated W3 Total Cache. Let’s see what it did.

Oh, that’s interesting. That’s not the worst part though, the worst part is that because I am running Batcache it’s already broken my site. Here’s what the page you’re reading this on would look like if I activated W3 Total Cache on it.

Because of WordPress’ modular design, I’d hope to be able to fix this by deactivating the plugin. Not so much.

That’s what my repository looks like after the plugin is deactivated. Notably (though really, the whole thing is notable), it’s actually changed one file that wasn’t changed before, wp-config.php. What change did it make, you ask. Good question, I was curious too.

So after I deactivated W3 Total cache it decided to simply wipeout part of Batcache’s configuration. This sort of had the opportunity to be a good thing, because it had already broken Batcache to start with. Unfortunately they missed that parlay because they also edited wp-content/advanced-cache.php and destroyed the $batcache global, which means Batcache now throws a PHP notice because of an undefined variable.

That sucks. And if I were less responsible about versioning my code, I’d have a hell of a time getting my site back to a working state. I know a lot of people who love W3 Total Cache and I believe it does a lot of good things, but this is just a design I am not interested in working with.