How detection works
A scan looks at one attachment at a time. It collects every name that file answers to, runs eight detectors over the places a reference can hide, and records what each one found. Any confirmed or possible reference makes the file used. Only a file with nothing at all against it lands on the Unused list.
What the file is known by
Before anything is searched for, the scan collects the file's identity: its attachment ID, its stored path, the original file where one was kept, every registered size (photo-300x200.jpg), the -scaled variant, and the alternate-format copies recorded in the attachment's metadata — the WebP and AVIF versions of the original and of each size.
So a reference to a thumbnail, or to the WebP of a thumbnail, resolves back to the original attachment and keeps it. Matching is on basenames, not URLs, which is also why a library served from external storage still matches: the filename is in the URL wherever the URL points.
Where it looks
| Detector | Reads | Finds, among other things |
|---|---|---|
| Post meta | postmeta |
Custom fields — image, gallery and file values, including serialized values and repeater/flexible sub-fields, verified against the field-key meta; featured images; product galleries; page-builder data |
| Post content | posts |
Image and gallery blocks, wp-image-N classes, [gallery] and [playlist], page-builder shortcodes carrying an ID (image="123"), raw file URLs, excerpts, custom-field values stored inside block markup, and unsaved edits held in autosaves |
| Options | options |
Site icon, custom logo, widgets, customizer settings and theme mods — serialized or JSON, at any depth |
| Term meta | termmeta |
Fields on categories, tags and custom taxonomies |
| User meta | usermeta |
Fields on profiles |
| Comments | comments, commentmeta |
A file linked in a reply, review photos |
| Recent upload | posts |
Files uploaded inside the grace window (24 hours by default) |
| Attached | posts |
The Uploaded to relation — recorded as information only |
IDs and URLs are found inside JSON stored under any key, including JSON nested inside serialized settings, and non-ASCII filenames are matched in their percent-encoded and JSON-escaped spellings as well as plainly.
Confidence, and what each level does
Every reference carries one of three confidence levels, and the meta box shows it:
- confirmed — an unambiguous reference. Counts as used.
- possible — a match that is real but not provably a content reference; a reference from a trashed post or comment, for instance, because a trashed object can be restored. Counts as used.
- record only — not a content reference — the Uploaded to relation. Shown as evidence, never counts as usage. That unreliable signal is exactly what this plugin exists to replace.
Each reference is also labelled with the kind of thing it is — Custom field, Block field, Featured image, Shortcode attribute, Image in content, Gallery, File URL, Widget, Customizer setting, Unsaved edit, Uploaded recently, and so on — with a link to the post, term, user, comment or Customizer it was found in.
Deliberately wrong in one direction
Deleting media is destructive, so where the scan cannot be certain it keeps the file.
- Ambiguity counts as used. A bare attachment ID in a meta key the plugin has never seen keeps the file.
- Matches are boundary-checked. Attachment 123 is never matched by
wp-image-1234, andphoto.jpgis never matched bymy-photo.jpg. - A reference in the trash still counts. A trashed post or comment can be restored, so the files it uses are kept.
- Files uploaded in the last 24 hours count as in use. An editor may still be placing them, so a clean-up never removes work in progress. The window is configurable, including down to zero — see Extending.
- Unsaved edits count; old revisions do not. An autosave holds an edit nobody has saved yet, so it protects its files. A file removed from a post in a past revision is meant to become findable.
- A saved draft protects its images —
draft,pending,privateandfutureare all read. Onlyauto-draftis skipped: a post that has never been saved has no reference anywhere in the database for any scanner to find, which is the case the upload grace covers.
What it cannot see, said plainly
The scan reads posts, post meta, options, term meta, user meta, comments and comment meta. Anything outside those tables is outside its reach, and the blind spot most worth knowing about is inside your own database:
References kept in a plugin's own custom database tables. Form entries, slider records, page-builder tables — any plugin that stores attachment IDs or file URLs in a table of its own shape. No query-based scanner can find a reference in a table it has never seen. If a plugin on your site works that way, check what it holds before deleting.
The same applies to references hard-coded in theme or plugin files, references held by an external service, references on other sites of a multisite network (network-wide options included), and the legacy Links manager. Multisite works per site; another site of the network embedding this site's file URL is not detected.
The evidence that is stored
Every reference found is recorded against the attachment, for used and unused files alike, with its detector, the object it lives in, the field or option it was found in, the kind of match and its confidence. The first twenty are kept; the true total is stored alongside them, so a heavily-referenced file shows twenty places and then says …and 43 more rather than pretending twenty is the count.
To see all of them for one file, use the Used view [Pro feature], which re-reads that single file on demand.
Next: Deleting safely.