How to add license keys to a WordPress plugin
Short answer: add a "License key" field to your plugin's settings, check the key with the SunLicense PHP SDK in the admin (cached in a transient for 12 hours, so pages stay fast), and when SunLicense says no, show an admin notice and stop serving the Pro features or updates. A network error is not a no: keep working and check later.
// composer require sunlicense/sunlicense, bundled (and prefixed, see below) in your plugin zip
add_action('admin_init', function () {
$key = trim((string) get_option('myplugin_license_key', ''));
if ($key === '' || get_transient('myplugin_license_ok') !== false) return;
try {
$client = new \SunLicense\SunLicenseClient('https://api.sunlicense.com', MYPLUGIN_API_KEY);
$r = $client->validate($key, ['host' => hash('sha256', home_url())]); // one site = one machine
if ($r->getStatusCode() === 400) { // EXPIRED, REVOKED, TOO_MANY_MACHINES…
update_option('myplugin_license_error', $r->toArray()['code'] ?? 'INVALID');
return;
}
delete_option('myplugin_license_error');
set_transient('myplugin_license_ok', 1, 12 * HOUR_IN_SECONDS);
} catch (\SunLicense\SunLicenseException $e) {
set_transient('myplugin_license_ok', 1, HOUR_IN_SECONDS); // unreachable: try again in an hour
}
});Your Pro features check get_option('myplugin_license_error') is empty; an admin_notices hook shows the error with a link to the settings page.
Or let your AI agent do it: paste the setup prompt into Claude Code, Cursor or Codex in your plugin's folder.
Free plan: 3 products, 100 licenses, no credit card. Create a free account.
Step by step
- In the dashboard: a product, a policy where a machine is a site (for example "Single site" with 1 machine, "Agency" with 25) and an API key, which can only validate.
- Sites, not servers. Send a hash of
home_url()ashost, so a site keeps its slot through server moves and a staging copy on another domain counts as another site (add an exclusion or a bigger policy if you allow staging). - Settings field.
register_setting('myplugin', 'myplugin_license_key')plus a field on your settings page; when the key changes,delete_transient('myplugin_license_ok')so it's checked at once. - Prefix the SDK. Every plugin shares one PHP process, so two plugins bundling different versions of
SunLicense\…would clash. Prefix vendor namespaces with Strauss or PHP-Scoper before you zip the plugin (YourPlugin\Vendor\SunLicense\…). The SDK needs PHP 8.0+ and uses cURL when the site has it. - Your API key as a constant in a generated file your release script writes (
MYPLUGIN_API_KEY), never in git. It can only validate licenses, so it's fine inside the zip. - Results: 200 enables Pro, 400 shows the reason in an admin notice (mask the key:
AX8P-XXXX-XXXX-XXXX), anything else keeps Pro running and retries in an hour. - Updates and support are what a key controls best on WordPress: check the license in your update server or download link too, so a revoked key stops getting new versions.
wordpress.org and the GPL
- Plugins hosted on wordpress.org can't lock features behind a license key: the directory's guidelines ban trialware and locked features. Keep the free plugin complete on wordpress.org and sell Pro as a separate add-on plugin from your own site (WooCommerce, Lemon Squeezy, Payhip, Envato). Only the add-on checks the key, and its readme says it connects to SunLicense.
- WordPress plugins are GPL, so buyers may share the code. A license key controls what you provide: updates, support and any service your plugin calls. PHP source is readable; SunLicense's obfuscation doesn't cover PHP.
Selling it
WooCommerce, Lemon Squeezy, Payhip, Gumroad and Envato (CodeCanyon purchase codes) issue a key per purchase and revoke it on a refund. More on licensing WordPress plugins. Selling a whole PHP application? See Laravel.
