How to write a WordPress plugin that I’ll use

I tend to be very fastidious about the WordPress plugins that I’ll install. I’ll often write my own simple version of a plugin rather than install one from someone else that does a bunch of stuff I don’t need. Here is my philosophy behind writing WordPress plugins, best witnessed through the plugins I’ve written lately, like Markdown on Save, Login Logo, Monitor Pages, and WP Help.

Fewer features as a feature

There are diminishing returns as you add features. That is, the more you add, the more likely you’re adding something that X % of your plugin’s users won’t ever use. Stick to the basics. I’ll often release a “0.1” version of my plugin with really obvious features missing. When I get a flurry of “You should add Y!” messages, that validates my assumption that Y is necessary. Start with the smallest version that gets the core job done. Iterate as needed.

Code the hell out of it

The best part of starting small is that you can code the hell out of the plugin. Do it right. Make each line of code beautiful. Make sure you’re using WordPress APIs properly, and while you’re at it, add i18n support (WP Help 0.2 shipped with support for Bulgarian, German, Spanish, Mexican Spanish, Macedonian, Dutch, Brazilian Portuguese, and Russian!)

Reduce UI

If you can do without UI, don’t make it. Make every bit of UI prove its necessity. As an example, look at my Login Logo plugin. It has zero UI. It looks for the presence of a file named login-logo.png in the wp-content directory. The rest is “magic.” It measures the image, generates appropriate CSS, and gives you an instantly and easily customized login screen. The plugin is invisible. It’s completely out of sight, and out of mind. Finally, UI screens are generally where plugin authors make security mistakes. By skipping them, you make it much more likely that your plugin is secure.

Code it for the future

Don’t use deprecated APIs. Plan features in future-forward ways. Implement it in such a way that a site that is using the plugin doesn’t break if the plugin suddenly goes away. One example of this is my Markdown on Save plugin, which offers per-post Markdown formatting. First, I decided that for performance reasons, I wanted to parse Markdown then the post was updated, not on display. The obvious place to store the generated HTML was in the post_content_filtered column that WordPress provides (but does not use). But then I considered what would happen if someone deactivated the plugin or deleted the plugin. The code that accessed post_content_filtered would not work. Their blog would spit out raw Markdown. And any exports they made would export raw Markdown. What if they were exporting to WordPress.com which doesn’t support Markdown? So I decided to store the Markdown in post_content_filtered, and store the generated HTML in post_content. When you edit a Markdown-formatted post, it swaps in the Markdown, so you can edit that. But if you deactivated the plugin, it would fall back to the HTML. So you can feel free to use this plugin and know that if one day you wake up and you hate Markdown, all you have to do is deactivate the plugin and all of your posts are back to HTML.

Secure it

Writing secure WordPress plugins isn’t hard. It just takes awareness. Take the time to do your research and code a plugin that will be an asset to its users, not a liability.

Web Hosts: WordPress is here to stay. Adapt!

WordPress is the number one user-installed web app, and its growth is showing no signs of slowing. If you are a web host, and you don’t have a specific strategy for WordPress, you’re likely operating your service inefficiently, and may be opening yourself up to security issues. This is the year to adapt, or be left behind by nimbler upstarts.

Performance

WordPress does not currently ship with any output caching. First, because most blogs never get enough traffic to need it, so it’s not worth the added complexity and configuration that it would add to our relatively nimble core. But also because every environment is different, and what works on one web host may actually degrade performance on another. So we leave it up to the WordPress user to choose whether they need a caching plugin, and which one to run.

As a web host, you know what caching strategies will work best with your server architecture. You have the ability to roll out things like Memcached or APC. You can route image requests to a lightweight web server or a CDN. These changes will result in a better user experience, and they’ll save you money.

Security

All code has bugs. WordPress has had its share of security issues through the years. As a web host, you can help keep your users out in front of security issues instead of just being reactive when someone gets hacked. First, by encouraging, or even demanding that users upgrade their sites to the newest available version of WordPress. In practice, there aren’t any widespread attacks against the current version of WordPress. The large scale attacks you see from time to time are against old versions of the software whose users haven’t updated in a while. It is in a web host’s interest to encourage upgrades and reduce the incidence of exploitation.

Because WordPress is so widespread, it also is often the victim of attacks that originated against other software or server misconfiguration. So a bad guy gets in using something else, and then once in, they look for WordPress installs to exploit. You can help users recover from these attacks by aggressively backing up their data and by looking for suspicious files or suspicious code that could indicate that a bad actor is exploiting their WordPress install.

What you can do

  • Get your company to abandon the mindset that you’re just a dumb host who doesn’t care what software your users are running. Users want and are willing to pay for a more specialized experience. If you tell them that it’s not your problem, they’re going to go find a service that will support their web hosting needs.
  • Offer WordPress-specific hosting. Specially optimized, prodigiously backed up, with a more locked-down environment. And because it is a specialty service, you can charge more than you do for your regular hosting products!
  • Build an internal WordPress Response Team that has in-depth training to help diagnose and fix WordPress bug, security and scaling issues. And in the meantime, hire a WordPress consultant like me or one of these fine consultancies to get your WordPress strategy rolling.

People ask me for hosting recommendations all the time. I have a few decent hosts that I’ll recommend, but I don’t have any hosts about which I can say “use them, because they know how to host WordPress, and they’ll support you.” I’d like nothing better than to have a dozen such hosts to recommend by this time next year. WordPress is here to stay, and it’s time for web hosts to adapt!

Interview with Deutsche Welle on WordPress Security

I recently did a short interview with Deutsche Welle about WordPress security. Listen to it here.

To expand on the topic, here are some of the details that didn’t make it into the final cut of the interview:

If your blog is compromised, you should install the latest version of WordPress, but first you should remove your old files. This is to prevent a hacker from leaving a back door (something like wp-give-hacker-access-forever.php in your WordPress directory. Just dropping the new version over the old version wouldn’t replace a new file that a hacker may have added, which is the reason for getting rid of the old files. Once you’ve done that (being careful to back up your wp-config.php and all your wp-content files), upload a clean install of WordPress. Restore your custom files. Next, look for any user accounts that weren’t there before, or that have higher access than they should. Sort that out. And lastly, scan through your theme/plugin files looking for backdoors or hidden links. This is mostly a manual process, but there are some common things to look for. Most backdoors use the eval() function, so be on the lookout for that!

The best way to keep your blog safe is to stay updated with the latest WordPress version! We’ve tried to make it as easy as possible to update (one-click!), and we have big plans for making it even easier in the future.

I’ve never had one of my WordPress blogs compromised, and I don’t do anything “fancy.” I just stay updated.

Reminder: if you’re using WordPress.com or another “hosted” blog solution, they take care of security updates for you. The only thing you need to worry about is choosing an unguessable, complex password.

Escaping API updates for WordPress 2.8

The WordPress escaping API functions have been updated. Escaping is a way of using untrusted text that “neuters” anything that could do damage. Escaping is used in WordPress to avoid SQL injection and cross-site scripting/script injection (XSS), among other things.

The old functions still work, so if you were using the old ones, you’re fine. The new ones just offer you an easier to remember, more concise, and more flexible way of securing your WordPress code.

Here’s an example. Say you wanted to translate a string, escape it for use in a quoted HTML attribute, and then echo it out. In WP 2.7, you’d have to do this:

<?php echo attribute_escape( __( 'Untranslated text' ) ); ?>

In WordPress 2.8, you can just do this:

<?php esc_attr_e( 'Untranslated text' ); ?>

Shorter, plus we killed the echo and the extra pair of parenthesis! But let’s break it down.

esc_ = 1, attr = 2, _e = 3

  1. esc_ is the prefix for the new WP escaping functions.
  2. attr is the context (in this case, attribute). The available contexts for 2.8 are attr, html, js, sql, url, and url_raw.
  3. _e is the optional translation suffix. The available suffixes for 2.8 are __, and _e. If you omit the suffix, no translation is performed, and your string is just returned.

More about contexts

  • attr means an HTML attribute.
  • html means text within an HTML node, but not within an attribute
  • sql is an alias to $wpdb->escape().
  • url means URLs for use in HTML attributes.
  • url_raw means URLs for use in redirects or storage in the database (does not entity-encode).
  • js means JS, for using PHP to populate a Javascript var.

More about suffixes

Suffixes work just like the function they’re named after.

  • __ translates the string and returns it.
  • _e translates the string and echoes it.
  • The suffix is optional. A blank suffix will just return.
  • Suffixes are currently only available for html and attr contexts.

Functions with translation suffixes also accept an option second parameter of a translation domain, for use in plugins.

Enjoy! Go forth and write more succinct code.