Patch Gap – Update Coverage & Licence Auditor
Your updates page says everything is fine. It might be lying to you.
WordPress.org plugins get a safety net: WordPress checks them for updates automatically, and security plugins warn you when one is abandoned.
Premium plugins get nothing.
When a premium plugin’s licence expires, its key goes missing, it was hand-uploaded from a zip, or its vendor quietly disappears, the plugin’s updater stops answering. And here is the dangerous part: a plugin that cannot be updated does not show a warning. It shows nothing at all — which looks identical to a plugin that is perfectly up to date.
So the plugin sits there, at the version it was when the licence lapsed, and never receives another security patch. Your dashboard stays green. Your fleet-management tool stays green. Nobody tells you.
Patch Gap closes that blind spot. It forces every update source on the site to answer, then reports who — if anyone — is actually patching each plugin and theme.
What it tells you
Every plugin and theme is sorted into one of these:
- Covered — WordPress.org. WordPress checks it for you.
- Covered — vendor updater active. A licensed premium plugin whose updater is registered and responding. Working correctly.
- GAP — updater present but silent. The component ships licence/updater code (Freemius, EDD Software Licensing, Plugin Update Checker, WooCommerce API Manager…) but registered no update source. Its licence has almost certainly expired, its key is missing, or it was installed outside the vendor’s channel. It will never be patched again.
- GAP — declares an update source that never answers. It advertises an Update URI, but nothing responds. The vendor may be gone.
- Abandoned upstream. Still on WordPress.org, but not updated in years — or closed entirely.
- No updater (bespoke). Custom or in-house code with no update source and no licence — expected, so Patch Gap lists it without treating it as a problem.
That last one matters: a naive «is it in the update list?» check would scream about every custom plugin an agency has ever written. Patch Gap looks at four independent signals before it calls something a gap, so it flags the components that are genuinely unpatchable — not the ones that are simply bespoke.
Why this is worth your attention
Patchstack’s 2026 security report attributes 29% of all valid WordPress vulnerability reports to premium and freemium components, and a majority of those are the kind attackers automate at scale. Premium components are simultaneously the ones nothing version-checks.
Also included, free
- Licence roster — the licence states Patch Gap can read from your own site (expired, active, expiry dates), without contacting any vendor.
- Weekly re-check with an email the moment a component loses its update source (that is usually the week a licence expired — the moment you can still fix it cheaply).
- Site Health integration and a dashboard summary.
- WP-CLI:
wp patch-gap scan— including--format=json. - Dismiss any finding with a note — useful as an audit record («this one is deliberate»).
The free plugin is complete for auditing a site: nothing above is limited, metered, or unlocked by payment.
Read-only, by design
Patch Gap never updates, deactivates, rolls back, or modifies any plugin, theme, or setting. It is strictly read-only: it asks every update source whether it is listening, and reports the answer.
Patch Gap Pro adds the things agencies need on top: a white-label client-facing coverage report (PDF/print), a licence-renewal roster you can invoice against, Slack/webhook alerts on new gaps, and a REST coverage endpoint for fleet dashboards. Sold and licensed through Freemius (see «External services»).
External services
The audit itself runs on your own server. Licence information is read from your own site’s options and is never transmitted anywhere.
WordPress.org (api.wordpress.org)
- A scan asks WordPress to run its normal update check — the same one your site already runs on a schedule. WordPress core contacts api.wordpress.org exactly as it always does, and any premium plugin’s own updater contacts its own vendor exactly as it always does (that is the mechanism Patch Gap observes; it adds no data of its own to those requests).
- Patch Gap additionally queries the public WordPress.org Plugin API (api.wordpress.org) to check whether a WordPress.org-hosted plugin has been abandoned or closed upstream. Only the plugin’s public slug is sent — nothing about your site, its users, or its configuration. Responses are cached for a day, and a circuit breaker stops these lookups entirely if wp.org is unreachable. WordPress.org privacy policy.
Freemius (freemius.com), who sell and license the Pro version
Freemius is contacted in four situations. Every one of them is something you click. It is never contacted in the background.
- If you opt in on the activation screen (or start a trial / activate a licence). Sent to api.freemius.com: your site URL, your WordPress and PHP versions, and the email address of the account you activate with. Skipping the opt-in is a first-class choice and the plugin is fully functional without it.
- If you open the «Upgrade» page under the plugin’s menu. Your own server (not your browser) asks api.freemius.com for current plan prices, sending your site URL. The page itself loads no third-party scripts — everything it renders is served from this plugin’s own folder. The payment SDK’s bundled pricing script used to inject Google Analytics and a remote checkout script into wp-admin on that page; this build removes both, along with the SDK’s remaining remote references (all modifications are listed under «Source code» below).
- If you open the «Contact Us» page, which is Freemius’s hosted support form (wp.freemius.com). The link carries your site URL and your WordPress login URL so the form knows which site you are writing about.
- If you click a plan to buy, you go to Freemius’s hosted checkout (checkout.freemius.com). It receives your site URL, site name, WordPress and PHP versions, and your WordPress administrator email address (pre-filled, sent whether or not you complete the purchase). Freemius is the merchant of record. Their checkout page loads its own third-party scripts (at the time of writing: Stripe, PayPal, Google Tag Manager, and Freemius’s own assets); we do not control that list. If you never click a plan, none of it loads.
Terms: https://freemius.com/terms/ — Privacy: https://freemius.com/privacy/
Installing, activating, skipping the opt-in, scanning, using every screen, deactivating (the SDK’s deactivation-feedback dialog is switched off in this build, so deactivation is one click and sends nothing), WordPress’s update cycle and all scheduled tasks complete without contacting Freemius at all. Free updates come from WordPress.org like any other plugin.
Source code
This plugin’s own PHP is unminified and readable in the plugin folder.
The one exception to «unminified» is the third-party payment SDK in vendor/freemius/, which ships pre-minified. Those files are the Freemius WordPress SDK, published under the GPL, and their unminified source and build tooling are public:
- Freemius WordPress SDK: https://github.com/Freemius/wordpress-sdk
- The pricing screen bundled at
vendor/freemius/assets/js/pricing/freemius-pricing.js: https://github.com/Freemius/pricing-page
This plugin ships four deliberate modifications to that SDK, all in assets/js/pricing/freemius-pricing.js, all removing remote references from wp-admin. Three are marked with a «Patch Gap:» comment at the patch site; the loader-image swap (3.) is a one-string replacement:
- The
appendScripts()method is emptied. Upstream it injectshttps://www.google-analytics.com/analytics.jsandhttps://checkout.freemius.com/checkout.jsinto wp-admin when the pricing screen renders. - The Google Analytics pageview tracker is stubbed out. Upstream it reports pricing-page views to Freemius’s Analytics property whenever a GA object is already present in wp-admin, stamping them with the Freemius user id.
- The remote loading spinner (
img.freemius.com/blue-loader.gif) is replaced with an inline data-URI equivalent. - Testimonial photos (Gravatar/remote) are forced to the bundled placeholder image, so the pricing page renders without any remote image requests.
