This post is dedicated to WPEngine, who donated to help me get to WCSF. While I don’t use them, I think that if you’ve outgrown WordPress.com and aren’t quite ready to host everything yourself, but you still want the plugins and themes, then you should check these guys out. They aren’t cheap, but then again, I firmly believe in paying for what’s important.
Read the comments before you comment. Otto haz the smartz.
One of the many rules of WordPress.org hosted plugins is you can’t phone home. Actually you can, and the rule really is ‘Don’t phone home without a damn good reason.’ To use Akismet as an example, it phones home with information to help verify who posted on your site, and are they a damn dirty spammer. That’s a damn good reason. But phoning home to check “Did Bob pay for a license?” is not. That’s considered abuse of the “serviceware” guideline, and essentially making an API just to make sure a license is okay isn’t okay. Now making money on your plugins is an awesome thing. But when your code is open source and anyone can see it, how do you keep people honest?
To get down to brass tacks, I’m going to take a little jounrey the wrong way, before I get to some suggestions on how you can provide ‘free’ and ‘pay’ versions of a plugin on the WordPress repository, and not cause any guideline issues.
Let’s start out with the most common way people restrict you: A license key. If you put in a plain license key check like this, it’s easy to crack:
if ( $license == "yes" ) { // Licensed! }
Okay, you say, I want to encrypt things so that I tell someone ‘your license is ipstenuisreallyneatsheismadeofturtlemeat’ but when I look at my code, it shows ‘774ffc4efce8da294dff77f35f75df98
‘ instead (that’s md5(ipstenuisreallyneatsheismadeofturtlemeat)
as it happens). Wait. We can’t encrpyt code. Or rather, we can’t include encrypted code in a plugin, it’s against the no-obfuscation rule. We’d want to decrypt that instead. So I give you the code string instead and run it this way instead (Just pretend that $options['license']
is a site option.):
if ( md5(ipstenuisreallyneatsheismadeofturtlemeat) == $options['license'] ) { // Licensed! }
But then I have the problem of anyone can just look and see what’s going on again. You could go the extra step like putting ipstenuisreallyneatsheismadeofturtlemeat
in a file and then pull off something like this:
$md5file = file_get_contents("md5file.txt"); if (md5_file("test.txt") == $options['license'] )
Is this easily decrypted? Yes. Is this easily circumvented by editing the code and removing the if? Again, yes. In fact the only way to really do this would be to use an API on your server to check the validity of the license (which you can’t do if you want to be hosted on WordPress.org anyway – no APIs just to check licenses), and even then I can strip mine your plugin and remove all checks like that. So why bother? Because you want to make a living on your code, and that’s certainly a fair-go! But as Otto rightly says, we can’t stop piracy, so why are we trying? DRM doesn’t work, and reverse engineering hasn’t proven sustainable. Maybe we’re building the wrong mousetrap.
If we throw the code solutions out the window, because we know they won’t work, where are we left? The next most common thing I see is people offering two plugins. A free, totally open GPL one on the WordPress repository and then a version behind a pay-wall that you would ‘replace’ that free one with. For example, I have a Rickroll plugin, and let’s say I wanted to make a Rickroll Pro version that let you change the video to anything you want, just put in the YouTube URL. I would have a settings page on my free version that pretty much says “Hi, if you want to change the video, visit halfelf.org/plugins/rickroll-pro/ to download.” And now I have to code Rickroll Pro to check if Rickroll (free) is installed and active, and refuse to activate if so. Furthermore, my users have to be told to delete the free Rickroll.
You know what? That’s a pain in the butt. What if instead I coded a Rickroll Pro add-on. No, I don’t mean ‘add this file to your plugin’ but ‘Install this second plugin, which will add functionality to Rickroll.’
It’s a second plugin, yes, but now I can have Rickroll free look for Rickroll pro. Not active? The settings page (which I would keep in Rickroll free) would tell you ‘Hey, you don’t have Rickroll pro! Install it and get more things!’ or ‘Hi, you have Rickroll pro installed by not active. Don’t you know it’ll never give you up? Activate it and have fun!’
Now the code muscle becomes a question of ‘How do I ensure my dependency checks work?’ First, Scribu wrote an awesome plugin dependency plugin, and the only flaw with it, is you’d have to install a third plugin. We don’t want that here, since yet another plugin is problematic. But looking back, that code grew out of a trac ticket about handling plugin dependencies. Now there’s a nice way to check: is_plugin_active()
if (!is_plugin_active('rickroll/rickroll.php')) { // do not activate. Provide message why. }
You could go to town with the checks in there. Like if the plugin isn’t active, deactivate the child and so on and so forth. I’m not going to write it all for you (though Otto wrote a lot about it for themes)
Now going back in your parent plugin, you can run the same check:
if (!is_plugin_active('rickroll-pro/rickroll.php')) { // Rickroll pro isn't active, prompt the user to buy it. } else { // Include rickroll-pro/adminsettings.php so they can use it }
The one last thought I had on this was how to handle pro upgrades. Since I don’t like to upgrade a plugin a lot unless I have to, I’d make it an ‘upgrade both’. In Rickroll Pro I’d set a version constant, and then in that check to see if it’s active call, reference that version. So Rickroll, after verifying Rickroll Pro is active, would come back and say ‘My current supported version of Rickroll Pro is 1.5 and the constant is set to 1.0. You should upgrade!’ Then every time I write a new version of Rickroll Pro, I’d update Rickroll to point to the new version, and when they upgrade from WP, they would get notified about Rickroll Pro needing an update too.
Probably not the most efficient or effective way about it, but the other option is a self hosted plugin update API.
Bear in mind, because of GPL, all these hoops and ladders can be circumvented. Your plugin can and will be taken away for free. Don’t fight the pirates with registration circuses, and limit the weight of your code by selling the right thing. It’s a strange idea to think that giving your code away for free will help you earn money, but at the very least, not fighting against the pirates will give you time to write better, more secure, code. And that certainly will earn you more money. Then sell your support, because that time is money.