Freshet Studio Unused Media

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

GPL-2.0-or-later. This page documents 1.2.1.

Install

Upload the plugin and activate it. Nothing is scheduled and nothing runs on its own — a scan happens when you start one.

One table is created, {prefix}freshet_unusedmedia_refs. It is the scan's own working record of which attachment each piece of content names, which is what makes a scan of a large library finish at all; it holds no content of yours and can be thrown away and rebuilt by running a scan again. Everything else the plugin stores is post meta on the attachment and a handful of its own options — see Extending.

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 Unused Media, the plugin's own entry in the admin menu directly below Media, plus two additions to screens you already use:

Where What
Unused Media → Scan Start, resume, stop or reset a full-library scan; running totals of used, unused and not-yet-scanned, and the moment the site they describe was read
Unused Media → Unused The list of files nothing refers to, with filters, and the delete actions
Unused Media → Used Every place a used file is used [Pro feature]
Unused Media → 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

  1. Go to Unused Media.
  2. Press Start full scan. The page walks your library in batches and shows progress as it goes.
  3. 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. One exception, and it is deliberate: a scan left idle for more than a day reads the site's content again when you resume it, instead of finishing a listing onto a reading that old. The screen says when that has happened, and the window is configurable — freshet_unusedmedia_index_max_age.

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.

What it is not is incremental. Every scan is a full scan — a new one reads the whole library again rather than only what has changed since the last one, so the second scan of a library costs what the first did. The stored results are what the lists and the exports are drawn from between scans; they are not a starting point a later scan builds on.

Reading the result

Every scanned file ends up in one of three states:

The status shown against a file records what the last scan found, and the scan's verdicts describe the site as it was read at the start of that scan rather than as it is this second — on a large library the file phase runs for hours after that reading was taken. Three things follow, and they are worth keeping apart:

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.