How to Build a WordPress Plugin Licensing System from Scratch (Without Freemius)
If you're shipping a commercial WordPress plugin, sooner or later you'll need a licensing system. Something that lets paying customers activate the plugin on their site, locks it to that domain, and stops people from sharing the same key across fifty sites. The default answer in the WordPress world is Freemius or EDD Software Licensing. They're great. They're also a revenue share, a third-party dependency, and a black box you don't control. When we built RideCab WP , a commercial WooCommerce taxi booking plugin, we decided to build our own. Here's the architecture, the code, and the gotchas we hit along the way. What a Licensing System Actually Needs to Do Before writing any code, get clear on the requirements. A real plugin licensing system needs to: Generate unique license keys when someone buys Let the customer activate the key on their site Bind that key to one (or N) domains Validate the key periodically so revoked or expired keys stop working Handle deactivation when a customer moves to a new domain Fail gracefully — never lock a paying customer out because your license server hiccuped Optionally: deliver plugin updates only to valid license holders We'll cover 1 through 6 in this post. Update delivery is a separate beast and I'll write it up next. The Architecture The system has two halves that live in two different places. The license server runs on your own infrastructure — for us, it's a WordPress must-use plugin (mu-plugin) on the same WordPress install that powers our marketing site. It: Stores license keys in a custom database table Exposes a small REST API for activate, deactivate, and validate calls Provides an admin dashboard to view, create, and revoke keys The client is a PHP class shipped inside the commercial plugin (RideCab WP, in our case). It: Adds a license settings page to the plugin Calls home on activation Caches the validation result Re-validates quietly in the background Two pieces, talking over HTTPS, with the customer's domain as the b