Skip to main content
WordPressPlugin DevelopmentLicensingBackend

How WordPress Plugin Licensing and Updates Actually Work

ZsTechLabs Team·April 2, 2026·5 min read

Most people only think about how plugin licensing works the moment it stops working — a site migration trips an activation limit, or updates silently stop arriving after a renewal lapses. If you're evaluating a commercial plugin, or building one yourself, it's worth understanding what's actually happening behind the "Enter your license key" field. This isn't a specification exercise — it's the same model we use for our own WordPress plugin catalog.

A license key is an identifier, not a lock

The instinct when building plugin licensing is to reach for something that feels like DRM — obfuscated code, phone-home checks that break the site if they fail, aggressive kill switches. In practice, none of that serves the customer or the business well. A license key is better understood as an identifier tied to an entitlement record: which plugin, which plan, which customer, how many sites, and until when.

A minimal license record looks something like:

licenseKey:          human-readable, unique
plugin + plan:        which product, which tier
siteActivationLimit:  how many domains can run it
activations:          list of {siteUrl, activatedAt, lastSeenAt}
supportExpiresAt:     when the update/support window ends
status:               active | revoked

Everything else — activation checks, update eligibility, renewal reminders — is just logic layered on top of that record. Keep the record itself simple and the rest stays easy to reason about.

Site activations should be domain-tracked, not device-tracked

WordPress plugins run on servers, not on personal devices, so activation limits should track domains, not machine fingerprints. A Single plan might allow one production site plus a staging copy; a Team plan might allow five; an Agency plan might allow twenty-five across different clients. The important design decision is what happens when a customer hits the limit while legitimately migrating a site: a hard block frustrates real customers far more often than it stops real abuse. The better pattern is to let a customer deactivate an old domain to free a slot, and log deactivation/reactivation events so support can spot actual abuse patterns (the same domain cycling in and out dozens of times a day looks nothing like a normal migration).

Update eligibility is a separate question from activation

It's tempting to conflate "is this install allowed to run the plugin" with "is this install allowed to receive updates," but they're different questions with different failure modes. An expired license shouldn't necessarily break the plugin outright — a site owner who let their renewal lapse for two weeks while switching payment methods still deserves a working site. What should stop is the flow of new versions and premium support access. A clean way to model this: the plugin continues to run at whatever version is already installed, but the update-manifest endpoint that ordinarily serves new versions and changelogs starts returning "no update available, license inactive" instead of a new package, and any lightweight validation ping the plugin makes on a schedule reflects that back into the admin UI so the site owner sees a clear, non-alarming notice rather than a broken feature.

Renewal reminders need a "tightest match wins" rule, not "first match wins"

Renewal reminder emails are usually specified as something like "send at 30, 7, and 1 days before expiry." The natural-looking implementation checks those thresholds in the order they're written and fires on the first one that matches — but if you write [30, 7, 1] and check in that order, a customer whose license expires in exactly 1 day can still match the 30-day threshold on a later run if the 30-day reminder was somehow delayed or reprocessed, resulting in a stale "renews in a month" email one day before it actually lapses. Two changes fix this cleanly:

  1. Check thresholds from tightest to loosest ([1, 7, 30]), and take the first match — the nearest deadline is the one that matters.
  2. Track which thresholds have already been sent per license, so a customer who renews right after the 7-day email doesn't also get the 1-day one, and one who's overdue doesn't get re-spammed with a looser threshold after a tighter one already went out.

It's a small ordering detail, but it's exactly the kind of bug that only shows up in production, weeks later, as a confused support ticket — worth catching with a test that asserts the nearest threshold wins, not just that a threshold matches.

What to actually look for when evaluating a commercial plugin

If you're the one buying, not building, a few practical questions cut through most licensing frustration before you pay for a plan:

  • Does deactivating a license on an old domain actually free up an activation slot, or do you need to email support?
  • What exactly happens when a license lapses — does the site break, or just stop receiving updates?
  • Is there a customer portal where you can see your activations and licenses without digging through old purchase emails?

We built our own customer portal around exactly these answers, because we'd rather a customer self-serve a domain swap in thirty seconds than open a ticket for something a licensing system should just handle.

If you're building a commercial WordPress plugin yourself and want help designing the licensing, activation, and update-delivery layer — or productizing an internal tool into something you can actually sell — that's work we do directly, and we're happy to talk through the tradeoffs above in more detail for your specific case. Get in touch.