Tag Archives: WordPress

The Challenge for WordPress Plugin Businesses

A few days ago Pippin Williamson wrote a post about the WordPress plugins business. It’s worth reading, but I’ll paraphrase its main ideas:

  • WordPress plugins are getting more powerful and sophisticated
  • Plugin-based businesses are growing
  • Requirements that used to fall to custom themes are now being solved more granularly with plugins

I agree with these ideas in general. Plugins are certainly getting more powerful and mature. The best examples of this are the plugins-as-platforms that are becoming significantly more popular, like BuddyPress and Pippin’s own Easy Digital Downloads.

At the end of his post, Pippin makes a prediction:

If you are on the edge about entering the world of commercial plugin development, now is the time.

Here’s where I disagree. We got to talking about it on Twitter earlier and I decided that I’d rather take a few extra characters to explain my opinion.

@ I don’t think WP consumers are sophisticated enough yet to support plugins businesses on the scale of theme businesses


Evan Solomon

First, I’ll start with a premise. The WordPress theme market is a success. It has high end agencies like 10up and Range, consumer-facing marketplaces like ThemeForest, developer ecosystems like Genesis, and great tools like _s. The commercial WordPress theme market is large and growing.

Conversely, the commercial WordPress plugin market is significantly smaller and I think will face a much more difficult path to success.

Themes have a natural source of demand because the easiest thing to understand about a website is the way it looks, which is the primary thing a theme controls. Most technical products have consumers that are much less knowledgable about the products than the creators, and often the creators that win are the ones that market the products in a way that matches the consumers’ understanding of it — even when that understanding is drastically flawed. Themes fit this model perfectly because of the natural tendency to express what you want in your website primarily by its interface.

Plugins tend to be much more abstract. I think understanding a plugin often requires understanding how it works in addition to what it does. The reason is that plugins are a lot less standardized and are naturally suited to do a lot more things, so basic descriptions of what they do are likely to cause more confusion than they solve. In addition to doing a wider variety of things, plugins also tend to do them in a relatively granular way. While you can only have one theme, you can have countless plugins and plugins can interact with (and even require) each other. Again, to make sense of that you need a deeper understanding of the system than just a list of features — you need to be able to make sense of how that interaction works.

In short, plugins are complicated, and complicated things have a smaller market for natural demand, even if they’re ultimately a better solution for customers.

That brings us to customers. WordPress’ greatest strength and source of growth is its usefulness to non-technical people. It can be hard to remember, but in the not-too-distant past it was nearly impossible for a non-technical person to make their own website. While I think it’s still probably not an awesome idea for a lot of people to do it, it’s now incredibly easy and a lot of that is due to the WordPress ecosystem. Despite this being one of WordPress’ greatest strengths, it’s also one of its biggest problems because it creates a market full of people who often don’t really understand what they’re doing. This lack of understanding has actually been a real value to the commercial theme market because its resulted in themes being the hammer to an “every WordPress problem is a nail” syndrome. Themes are often chosen irresponsibly and forced to solve ill-suited problems — see every theme that bundles 15 image sliders and 25 shortcodes. When presented a WordPress requirement, it’s incredibly common for the solution to start with a trip to a “premium theme” website, almost regardless of whether a theme is a logical way to solve the problem.

There are obvious reasons this benefits theme businesses. Similarly, there are obvious reasons this hinders plugin businesses. Here are the assumptions I’m making:

  1. WordPress theme businesses are, in aggregate, a success
  2. Theme business success has been significantly driven by customers’ overfitting WordPress demands to theme solutions
  3. Plugins require sophisticated customers that can think about problems granularly and understand multi-part solutions
  4. The conditions that drive #2 also hinder #3

As I mentioned to Pippin on Twitter, I’d like to be proven wrong. I think a growing plugin market is important to WordPress. There are some outliers, for sure. Ecommerce plugins, an example Pippin chose, are an early success story, as are some strong brands. This might even be a good thing for customers because it’s harder to build a business with bad plugins than bad themes. And it’s certainly a good thing for those people and companies that have found a way to build successful plugin businesses. As a result, I think they’re a lot more defensible than theme businesses. But it’s bad for the market as a whole.

The plugin market needs more demand and more supply to grow to a scale where it can support more businesses. WordPress’ economic moat is driven significantly by the number of people that earn their income from it. That market creates a lot more people that are incentivized to improve WordPress than would otherwise exist. Right now that moat is mostly composed of the businesses that make themes successful — agencies, marketplaces, etc. WordPress would benefit greatly by expanding the pool to plugins, which is why I hope that I am wrong and Pippin is right.

Bots, passwords, short strings, and simple characters

About a month ago I got curious about bots that target WordPress sites. I use the Limit Login Attempts plugin and every time I got an alert that an IP had been limited it was always for the username ‘admin’. I had never thought much about it, but it makes sense as an attack vector given how many people probably do use that name. What I wondered was what sorts of attacks they were trying. In particular, the passwords they used seemed most interesting.

So I started writing a new plugin, Admin Login Notifier, which you can also fork it on Github if you’re into that kind of thing. Admin Login Notifier does pretty much what it sounds like — it grabs the password when someone tries to login as ‘admin’ and notifies you. Originally it sent an email for each attempt, now it saves them in a dashboard page and sends a daily email digest.

It’s been running on my site for a couple weeks and, as of this morning, has caught over 1,000 attempts. I decided it would be interesting to look at the list and see what these bots are up to. Until recently, the passwords were all in emails (and not saved elsewhere) so aggregating them was a bit of a pain. Because of some different formats I used in the emails, I ended up only exporting 920 of them, which you can see here.

I was especially curious about the strength of passwords used by bots, which I decided to break down into four really basic metrics:

  • Length — Just the number of characters in a password
  • Uniqueness — The number of unique characters in a password
  • Complexity — The number of character types in a password, like uppercase letters, or symbols
  • Repetition — How often bots tried the same passwords as other bots (or as themselves)

Here is the script I used.

And here are the results. You can do this yourself by saving the password list as sample.txt in the same directory as this script.

Average length: 6.2 characters
Average unique characters: 4.8 characters
Average character types: 1.2 types
Repetition: 17% of password attempts were repeats of other attempts

Hopefully you can learn a few things of this. First, you should learn not to use the username ‘admin’. Beyond there, here are a couple of conclusions. None of these are particularly noteworthy, and each ought to sound familiar if you’ve read any other password advice on the web.

  • Use long passwords. Bots try pretty short passwords, so you should use long passwords. There are mathematical reasons for doing this, too. But we’re sticking to empirical data for this post.
  • Use lots of characters. Although the average pasword attempt was just over 6 characters, they contained 25% fewer unique characters. Bots try a lot of repeated characters, likely because people repeat characters to make their passwords easier to remember. Don’t do that.
  • Use multiple character types. 80% of all attempts used only one character type.
  • Don’t use passwords found on things like “Most commonly used passwords” lists. 1 in 6 passwords that bots attempt are repeats. Don’t make their jobs easier.

Admin Login Notifier isn’t terribly useful, but it is kind of fun and I’m glad it helped me get a look at this data.

Faster WordPress: Multisite, nginx, and Batcache

A couple weeks ago I decided to move this site to a new server. With the help of Pete Mall and Mark Jaquith I settled on the following setup:

  • Linode 512 MB
  • Debian 6 32-bit
  • APC (for opcode and object cache)
  • nginx
  • WordPress Multisite
  • Batcache

I documented my setup and after testing it with another friend (it worked!) and mentioning it to a couple others, decided to post it here. I’m going to assume you’re familiar with the basics of administering a VPS, especially SSH.


I did this on Linode, but it will probably work fine on pretty much any VPS (or dedicated server). It won’t work on a shared host because it depends on installing specific software that requires root access. My server needs are not very extravagant so I chose Linode’s cheapest plan, a 512 MB VPS. You’ll need to choose a location for your server, and since I have no idea what the practical differences are, I went with Dallas based on a recommendation. For the purposes of this tutorial, it doesn’t matter which one you choose.

Go through the Linode setup, choose the Debian 6 32-bit distribution, get your ssh information, and login to your new server. If you use a larger VPS you might want the 64-bit distribution, but on a 512 MB server that’s going to cause problems.


Linode has a very good tutorial on the first few things you’ll want to setup with your new Linux install. Once you’re logged in you can skip to the security section in Linode’s “Getting Started” tutorial. That will walk you through:

  • Updating your package installer
  • Setting your server’s hostname
  • Setting the timezone

Your settings here can be unique to you. In my case I like to name computing devices after Yankees players (see my external hard drive named Mattingly) so I called my Linode server dimaggio. I like to use my local time, which is America/Los_Angeles in the Linux world. Some people like to use UTC, which we do at Automattic. Pick your poison.

Before you go any further, you should install sudo because you’ll need it soon and your server won’t have it by default. You can do it with this one liner:

apt-get install sudo

Now that you have the basics setup, it’s time to move onto the real stuff — users, permissions, firewalls, and software. Slicehost has two great tutorials on this: Debian part 1, and Debian part 2. We’ll go through these now.

You don’t want to be logged in as root any longer than you absolutely have to. The first thing Slicehost will walk you through doing is creating a new user account. They use the username demo but you’ll probably want to use your first name. In my case I skipped the additional group management steps; I don’t plan on managing a large number of users and it’s easier to have fewer moving parts. If you don’t assign your user to a group, it will be automatically put in a group with its own name — my user is in a group called evan. Slicehost will walk you through the details, but I’ll add one suggestion: do not log out of your root SSH session until you’ve successfully logged into your user account and confirmed that your sudo access works. Otherwise you’ll need to reset your whole server and start from the beginning. Once you’re setup, move onto part 2.

Part 2 mainly covers Bash and the Aptitude package installer. I am pretty particular about my bash prompt. You can grab the key parts of mine here. This does a few things:

  • Shorten long directory names by replacing the middle with an ellipse
  • Add the git branch name to the prompt (if you’re in a git repo)
  • Use up and down arrows to search your bash history using whatever you’ve already entered as a search prefix
  • Make tab cycle through available commands instead of listing them
  • Add tab-completion for git commands

The git pieces rely on this git auto-complete script.

Once you’ve got your .bashrc setup and your package repositories updated, it’s time to move onto the the next step: PHP-FPM.

The stack: PHP-FPM

Debian’s default package repository has an outdated version of PHP-FPM, so first we’re going to add a new repository to our list. Aptitude’s repository list is kept in /etc/apt/sources.list and we want to add a new line with this repo: deb http://packages.dotdeb.org stable all. You’ll need to use sudo to edit this file and save it. When you’re finished, it should look something like this. Now go back to your home directory and setup your new repository.

cd ~
wget http://www.dotdeb.org/dotdeb.gpg
cat dotdeb.gpg | sudo apt-key add -
rm dotdeb.gpg
sudo apt-get update
sudo apt-get upgrade

Now we can install PHP and its siblings:

sudo apt-get install php5 php5-fpm php-pear php5-common php5-mcrypt php5-mysql php5-cli php5-gd php5-apc

We’ll be using PHP-FPM to handle all of the PHP requests that come in through nginx. To do that, we’ll need to update the PHP-FPM config at /etc/php5/fpm/pool.d/www.conf. We will set PHP-FPM to decide how many processes it will run and how it will listen for requests from nginx. My config file is here. It will set PHP-FPM to spawn a reasonable number of children and servers for 512 MB VPS and configure it to listen over a Unix socket instead of a TCP port. These settings may not be perfect for you, but they should get you started.

Restart PHP to make sure your new settings are in effect.

sudo /etc/init.d/php5-fpm restart

The stack: nginx

We’re going to use nginx as our web server, so first we’ll install it.

sudo apt-get install nginx

Now we’ll setup our nginx config at /etc/nginx/nginx.conf to tell nginx how to serve our data. This file is pretty straightforward, but it does assume you’re using the 512 Linode server (or another one like it). You can grab mine here.

Once you have your config in place, restart nginx to use the new settings.

sudo /etc/init.d/nginx restart

The stack: MySQL

The last part of your stack is MySQL, which we will install now:

sudo apt-get install mysql-server php5-mysql

Once you complete the MySQL installer you can head over to Linode’s low memory settings tutorial to configure some settings for MySQL geared toward low memory servers (which a 512 MB VPS is). I followed their guidelines in my config, so I won’t copy it here. The last two items won’t be in your default my.cnf file, so you can add them at the bottom.


One last thing you’ll want to install here, even though it’s not a part of the traditional L(A|E)MP stack, is an email server. Again, Linode has a great send-only mail server tutorial. If you want to configure a mail server to actually receive email, that’s outside the scope of this post. In my case my server’s only interaction with mail is to send it — for example, when you need to reset your WordPress password.


There are lots of ways to get WordPress installed. In my case, I had a few requirements that guided my choices:

  • I’m using WordPress multisite
  • I’m using the multisite domain mapping plugin
  • WordPress will manage my whole site
  • My site will be version controlled with git

After experimenting with lots of different options, I decided on this setup:

  • My public directory will just be a copy of my git repository
  • WordPress will be installed in my git repository as an svn export
  • Local development will use Mark Jaquith’s local config setup

At this point, you’ll want to install git on your server so that you can pull in your repository. Again, a one-liner will do it for you:

sudo apt-get install git-core

I setup my git repository and exported WordPress trunk, then setup my local-config.php per Mark’s instructions. Next I setup my .gitignore file to make sure I didn’t accidentally commit any of the local-specific data.


I won’t walk through the WordPress multisite installation. If you need help with that, there’s a great Codex article that covers it. The only part specific to this tutorial is that you won’t want to use the .htaccess file (notice how I .gitignore‘d it?) because we aren’t using Apache. Instead, you’ll use a nginx config file to handle this. In my case, I put a file called .nginx-config into the root of my git repo and symlink it to nginx’s sites-enabled directory. You can grab my config file here — obviously you’ll want to replace domain.com with your actual domain. I have a couple other rewrite rules specific to my site, but this should cover the basics.

Again, that config goes into your git repo, which means nginx has no idea it exists yet. Once you’ve pulled your git repo onto your server, you can symlink it to the place nginx will look (/etc/nginx/sites-enabled). In my case my web sites are being served from /srv/www/domain.com/public, so that’s where my git repo will be pulled. This directory won’t exist by default, so you’ll need to create it as well as /srv/www/domain.com/log, which is where nginx will store your access and error logs. You can put your website content in another directory if you want, but you’ll need to change the nginx config file to make it work. Now you can symlink your config by running:

sudo ln -s /srv/www/domain.com/public/.nginx-conf /etc/nginx/sites-enabled/domain.com

This will take care of copying your rules to nginx, and it will also block nginx from serving that file publicly because it starts with a dot.

Restart nginx to make sure it uses your new virtual host.

sudo /etc/init.d/nginx restart


Last, you’ll want to setup caching for WordPress. I’m using Batcache, which uses the WordPress object cache for all of its page caching. We use it on WordPress.com and it’s super-configurable, but I’m using it with the out-of-the-box settings for now. Batcache requires a persistent object cache backend, which Mark Jaquith’s APC plugin is perfect for on a one-server setup. If you’re running multiple servers you should use Ryan’s Memcached plugin (and you should also have stopped reading this a while ago). We already installed php5-apc (along with the rest of PHP) so there’s no server config needed here.

The Batcache installation is pretty straightforward. You will put Batcache’s batcache.php into /wp-content/mu-plugins (which you’ll probably need to create). Then you’ll put Batcache’s advanced-cache.php into /wp-content. Finally, you’ll put APC’s object-cache.php into /wp-content (the same place as advanced-cache.php). You’re almost there, you just need one line in your wp-config.php to tell WordPress to use the cache:

define( 'WP_CACHE', true );


That’s it. You should be good to go with a very fast and easy (relatively speaking) WordPress setup. There is some other house keeping you might want to do, like hardening WordPress, but I’ll skip that for now because there is plenty of good information about it on the Codex. You’ll also need to setup your DNS, both within Linode and in your domain registrar. This is no different than any other setup so I’ll skip that as well. Finally, you may want to configure other server-specific settings, like rotating logs. You should check out Linode’s tutorials on those.

For a bit of fun, you can run Apache’s benchmark test to see how many requests your server can (in theory) serve per second. First you’ll want to install Apache’s dev tools. Once you do that, from your server, we can throw a bunch of traffic at WordPress:

sudo apt-get install apache2-dev
ab -n 10000 -c 1000 -H 'Host: domain.com'

The output will include a “Requests per second” line, and in my experience you should be able to hit the mid-6000’s.

Edit: I really do want to clarify this is mostly for fun, and not a useful metric of how much traffic you’ll be able to handle. The one place this is actually useful is comparing your new server to an old server, purely on a relative basis. For example, my old site running Apache with mod_php came in around 200-300 requests per second. So I can get a sense of how much faster the new server is, but it does not mean I’ll be able to serve 500m page views per day from one VPS.

Again, I owe many thanks to Pete Mall and Mark Jaquith for helping me figure this out.