TL;DR: The last release date is the strongest signal. "Tested up to" goes stale on its own. A closed listing means opposite things depending on the reason field. Support-thread ratios are noisy. Premium plugins sit outside the directory entirely. There is a script at the end that checks a list of plugins in one run.
Ask the WordPress.org plugin API about Display Widgets and you get this:
{
"error": "closed",
"description": "This plugin has been closed as of January 30, 2021 and is not available for download. This closure is permanent. Reason: Security Issue."
}
Ask it about Paid Memberships Pro and you get this:
{
"error": "closed",
"description": "This plugin has been closed as of October 17, 2024 and is not available for download. This closure is permanent. Reason: Author Request."
}
Same error, same wording, same word "permanent". But these are opposite situations. Display Widgets was pulled over a security issue. Paid Memberships Pro left the directory by its own authors' choice and kept shipping releases from its own site. It was still releasing updates in September 2026.
Any check that stops at "is it listed?" treats those two plugins the same way. So does any check that stops at "when was it last updated?", for different reasons.
There is no official definition of an abandoned plugin, and no single field that tells you. What you do have is a handful of facts the directory publishes, each of which means something narrower than it looks. Read them together and you get a reliable picture. This post goes through each one, then gives you a short script that checks a list of plugins in one run.
Get the facts yourself first
Everything below comes from one public endpoint. No key, no signup:
curl -s "https://api.wordpress.org/plugins/info/1.2/?action=plugin_information&request[slug]=akismet&request[fields][sections]=0"
The fields that matter for maintenance:
| Field | What it holds |
|---|---|
version |
The current release |
last_updated |
When a release last shipped, e.g. 2026-08-18 11:42pm GMT
|
tested |
The newest WordPress version the author says they tested against |
requires_php |
The minimum PHP version the plugin declares |
active_installs |
A rounded floor, not an exact count |
support_threads / support_threads_resolved
|
Forum threads in the recent window, and how many are marked resolved |
For a closed plugin you get closed: true, a closed_date, and a reason such as security-issue or author-request, instead of the fields above.
Signal 1: the last release date (the strongest one)
A release is the only thing in the list that proves someone recently did work on the plugin. A reasonable way to read it:
- Under 6 months: actively maintained by any sensible standard.
- 6 to 11 months: worth a look, especially for anything large.
- 12 to 23 months: ageing. Find out what you would replace it with.
- 24 months or more: treat it as unmaintained until you learn otherwise.
The nuance is plugin size. A small plugin that does one narrow thing may genuinely need no changes for two years, and WordPress is careful about backwards compatibility. A page builder, a checkout extension or a membership system that has not shipped in two years is a different story, because those plugins touch everything that changes around them.
The date is not the risk on its own. The risk is what happens when PHP or WordPress next ships a breaking change and nobody is there to fix the plugin. You want to know about that before your host upgrades PHP, not after.
Signal 2: "tested up to" (stale by design)
The tested field is the author telling you the newest WordPress version they checked the plugin against. It goes stale on its own. WordPress ships two or three major releases a year, so a plugin that nobody touches falls behind whether or not anything in it is broken.
WordPress.org shows a warning on a plugin's page once it has not been tested with the latest three major releases, which is a sensible line.
Read it alongside the release date:
- Recent release, old "tested up to": usually the author forgot to bump the header. Low concern, but test it on staging before a major WordPress upgrade.
- Old release, old "tested up to": both fields are telling you the same thing, and it is the release date that matters.
Do not add the two together as if they were separate problems. When the last release is over a year old, the "tested up to" gap is a symptom of the same fact.
Signal 3: closed does not mean one thing
This is the case from the top of the post. The reason field is what separates them:
-
security-issue(and the other reasons set by the plugin review team): the directory pulled the plugin. Take this seriously, find out why, and plan to replace it. -
author-request: the author asked for the listing to be removed. That can mean they gave up. It can also mean they moved distribution to their own site, which is exactly what happened with Paid Memberships Pro.
For author-request closures, the next step is to check the author's own site or repository for recent releases. If they are still shipping, the plugin is maintained. It simply is not in the directory any more.
Signal 4: support threads (noisy, use with care)
It is tempting to read support_threads_resolved / support_threads as a responsiveness score. Be careful.
A thread only counts as resolved when someone marks it resolved. Plenty of active authors answer every thread and never tick the box, and plenty of users never come back to close their own threads. The ratio also needs a reasonable sample. Five threads with two resolved tells you almost nothing.
Use it as a prompt to open the forum and read the last page of threads yourself. If recent questions have replies from the author, the plugin is supported, whatever the ratio says.
Signal 5: premium plugins sit outside all of this
Commercial plugins sold from the developer's own site are not in the directory, so none of the fields above exist for them. That is completely normal, and it carries its own risk.
Premium plugins usually only get updates while the licence is active. When a renewal lapses, the plugin keeps running and quietly stops receiving fixes, and nothing on the site tells you. No outside check can see that.
For premium plugins, the questions are not technical. Which licences are still active, and who is responsible for renewing them?
Putting it together
| What you see | How to read it |
|---|---|
| Recent release, current "tested up to" | Maintained |
| Recent release, old "tested up to" | Maintained, test before major upgrades |
| No release for 12+ months | Ageing, know your replacement |
| No release for 24+ months, large plugin | Treat as unmaintained |
Closed, security-issue
|
Replace it |
Closed, author-request
|
Check the author's own site before deciding |
| Not in the directory | Premium or custom, check the licence |
A script to check a list of plugins
Save this as check-plugins.mjs and run it with Node 18 or later: node check-plugins.mjs akismet contact-form-7 display-widgets.
const API = 'https://api.wordpress.org/plugins/info/1.2/';
function monthsSince(lastUpdated) {
const date = new Date(lastUpdated.replace(/(\d)(am|pm)/i, '$1 $2'));
if (Number.isNaN(date.getTime())) return null;
return Math.floor((Date.now() - date.getTime()) / (1000 * 60 * 60 * 24 * 30.44));
}
async function check(slug) {
const url = `${API}?action=plugin_information&request[slug]=${encodeURIComponent(slug)}&request[fields][sections]=0`;
const res = await fetch(url);
const data = await res.json();
if (data.closed) {
return `${slug}: closed on ${data.closed_date} (${data.reason})`;
}
if (data.error) {
return `${slug}: not in the directory (premium, custom, or a typo)`;
}
const months = monthsSince(data.last_updated);
const age = months === null ? 'unknown' : `${months} month${months === 1 ? '' : 's'} ago`;
return `${slug}: v${data.version}, last release ${age}, tested up to ${data.tested}`;
}
for (const slug of process.argv.slice(2)) {
console.log(await check(slug));
}
Two details in there are worth knowing. last_updated comes back in a format like 2026-08-18 11:42pm GMT, which JavaScript's date parser does not reliably accept until the space before pm is added. And a slug that has never existed also returns an error without closed, so "not in the directory" covers typos as well as premium plugins.
Doing this for a whole site
The script works when you already know the slugs. On a client's site you often do not, especially before you have a login.
That is the gap I built a free WordPress plugin checker to fill. You paste a URL, and it detects the plugins the site loads publicly and reads the same directory fields covered above for each one. It separates plugin-team closures from author requests, marks which installed versions are inferred, and says plainly what it could not see. It does not make vulnerability claims, because that data sits behind commercial APIs and guessing at it does more harm than good.
If you want the signals for one plugin at a time, there is also a plugin maintenance check covering widely installed plugins, with the date each one was read from the directory.
And if you are on the other side of this and maintain a plugin yourself, this guide to WordPress plugin development covers what keeping one healthy in the directory actually involves.
The standard I would suggest for any site you are responsible for is simple. For every plugin that has gone a year without a release, know what you would replace it with before you need to. The day you need that answer is usually the day a host upgrades PHP.
Top comments (0)