Skip to content

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.

php
// 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 ​

  1. 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.
  2. Sites, not servers. Send a hash of home_url() as host, 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).
  3. 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.
  4. 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.
  5. 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.
  6. 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.
  7. 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.

Send feedback

Found something broken, or have an idea? It goes straight to our board.

The first line becomes the title.
Images (optional, up to 5: paste, drop or capture)
Check each image before sending, and remove any that show something private.

We also receive this page's address and your browser version.

Ctrl Enter to send