Getting started
Freshet Unused Media answers one question about every file in your media library: is this still used anywhere? — and lets you delete the files that provably aren't.
WordPress' own Uploaded to column only records where a file was first attached. It says nothing about where a file is actually used, so an image referenced from a custom field, a page builder, a widget or a plain URL looks exactly like a file nothing needs. This plugin looks in all those places instead, and shows you the evidence for each answer.
Requirements
- WordPress 6.5+
- PHP 8.1+
GPL-2.0-or-later. This page documents 1.0.1.
Install
Upload the plugin and activate it. Nothing is scheduled, nothing runs on its own, and no tables are created — a scan happens when you start one.
Before your first run, consider adding a trash safety net to wp-config.php:
define( 'MEDIA_TRASH', true );
With that set, a deletion here goes to the media trash and can be restored. Without it, deletion is permanent — see Deleting safely.
The screens
Everything lives under Media → Usage, plus two additions to screens you already use:
| Where | What |
|---|---|
| Media → Usage → Scan | Start, resume, stop or reset a full-library scan; running totals of used, unused and not-yet-scanned |
| Media → Usage → Unused | The list of files nothing refers to, with filters, and the delete actions |
| Media → Usage → Used | Every place a used file is used [Pro feature] |
| Media → Usage → License | Enter or remove a key (only in the build downloaded from freshet.studio) |
| Media Library, list mode | A Usage column with a badge, a per-file Check usage action, and a status filter |
| The attachment screen | A Usage meta box listing the references found, each with a link to go and look |
Your first scan
- Go to Media → Usage.
- Press Start full scan. The page walks your library in batches and shows progress as it goes.
- Leave the tab open, or don't — the scan records its position after every batch. Resume scan picks up from the last completed file rather than starting over.
Each batch stops before PHP's time limit is reached, so a batch can never run out of time mid-file and retry the same IDs forever. That is what makes a large library safe to scan in a browser at all.
It takes as long as it takes
Thoroughness is the point rather than speed: a first full scan of a large library is measured in hours, not minutes. Cost tracks the total volume of content the scan has to read through rather than the number of files — a library of a few thousand attachments on a site with a few thousand page-builder posts is an afternoon's work, not a coffee break. A scanner that only reads the Uploaded to column is much faster and answers a much weaker question.
Nothing is lost to that time. The scan always makes progress, it can be stopped and picked up later, and the results are stored per file as they are computed — so the second scan of a library only has to catch up on what has changed.
Reading the result
Every scanned file ends up in one of three states:
- Used — at least one reference was found. The Usage meta box on that attachment lists them: which post, which field, which option, with a link to each.
- Unused — nothing anywhere refers to it. It appears on the Unused tab and is offered for deletion.
- Not scanned — the scan hasn't reached it yet, or it was uploaded since.
The status shown against a file records what the last scan found. If the content has changed since, the Scan tab and the meta box both say so rather than presenting a stale answer as current.
A file being used is never a judgement about whether you want it — it means something on the site still points at it. What counts as a reference, and the deliberate places the plugin errs towards keeping a file, are on How detection works.
Next: How detection works.