keyagency / statamic-asset-usage
See where every asset is used across entries, globals, taxonomy terms, navs, users and form submissions, and find the ones that aren't used at all
Package info
github.com/keyagency/statamic-asset-usage
Type:statamic-addon
pkg:composer/keyagency/statamic-asset-usage
Requires
- php: ^8.2
- pixelfear/composer-dist-plugin: ^0.1.6
- statamic/cms: ^6.0
Requires (Dev)
- laravel/pint: ^1.13
- orchestra/testbench: ^10.8
README
See where every asset is used, and find the ones that aren't used at all.
A Statamic 6 Control Panel addon that answers the question the asset library never does: is this file actually used anywhere? Like WordPress's "Uploaded to", but across your whole site and aware of multiple sites.
- "Used in" panel in the asset editor — the entries, globals, terms, navs, users and form submissions that reference this asset, as links, grouped by site.
- A "Used" column in the asset browser — a tick or a cross, so one glance tells you which files are orphans.
- A Used / Unused filter in the browser.
- An overview under Tools — filter by container, site, usage and path, sort by name or by how much an asset is used, expand any asset to see where it's used, and delete the ones nothing needs.
pleasecommands for reporting and cleaning up from the CLI.
Works on flat-file and database sites alike
Content is read exclusively through Statamic's repositories (Entry::query(), Term::query(), GlobalSet::all(), …) — never by scanning the content/ directory. So on a site using the eloquent driver, where entries live in the database rather than on disk, everything is found just the same. And rather than only telling you whether an asset is used, it tells you where.
Installation
composer require keyagency/statamic-asset-usage php please asset-usage:index
The second command builds the usage index. After that the addon keeps itself up to date as you edit content.
What counts as "used"
Every reference format Statamic itself understands, found anywhere in your content — top level, or nested inside Grid, Replicator, Group and Bard sets:
| Where | What it looks like |
|---|---|
| Asset / file fields | img/photo.jpg (a path relative to the container) |
| Link fields, Bard images, Bard link marks | asset::main::img/photo.jpg |
| Markdown and Bard HTML | statamic://asset::main::img/photo.jpg |
| Any text, textarea, markdown or HTML field | /assets/img/photo.jpg, https://example.com/assets/img/photo.jpg |
That last row is off in Statamic's own reference tracking but on by default here (scan_urls), because a hand-typed URL is exactly the case where you'd otherwise delete a file that was in use.
Scanned content types: entries (including unpublished working copies), global sets, taxonomy terms, navigations, users, other assets' own fields, and form submissions. scanned_types is the complete set, so listing only the types you want is enough — anything left out is off.
What it doesn't see
- References in Antlers/Blade templates or in config — this is a content scanner, not a codebase scanner. Protect those files with the
ignoreconfig. - Glide-transformed URLs (
/img/asset/…), which live in templates rather than content. - A bare path that exists in two enabled containers is counted as used in both. Over-reporting is deliberate: you should never lose a file because the addon guessed wrong.
Where the column appears
The column arrives through the container's blueprint, and Statamic renders blueprint columns before its own File / Size / Last Modified — there's no hook to change that. If you'd rather have it at the end, use Customize Columns in the browser and drag it there; Statamic remembers the order per user.
The column deliberately shows only a tick or a cross. A count or a list of sites made rows wide enough to push the filename off screen; the numbers live in the editor panel and on the Tools page.
Multisite
Every usage records the site of the item it was found in, so an asset used only in your Dutch entries shows Nederlands and nothing else. An asset counts as unused only when no site uses it. Items that have no site of their own — users, other assets, form submissions — are grouped under "All sites".
The index
Scanning a whole site per page load isn't viable, so usage lives in an index at storage/statamic/asset-usage/index.json. It is:
- built by
php please asset-usage:index, or from the Refresh usage data button on the Tools page; - patched incrementally whenever content is saved or deleted, so it stays accurate on its own;
- marked out of date automatically when you change a setting it was built with: the enabled containers,
scanned_types,scan_urlsorinclude_working_copies. While it's out of date the CP says so, the browser filter hides itself, and nothing can be deleted; - never built implicitly while rendering a page. Before the first build the column and the panel say "not checked yet" rather than pretending everything is unused.
Which assets exist is read through the container's asset query, the same source the asset browser uses — not through the container's file listing, which on the eloquent driver reports the container root only.
The incremental updates run through a queued listener (like Statamic's own reference updating). On the sync queue that means inline; with a real queue connection you need a worker running, or set auto_update to false and rebuild on a schedule instead.
Commands
# Rebuild the whole index php please asset-usage:index php please asset-usage:index --queue # hand it to a worker # Diagnose what the addon sees per container php please asset-usage:doctor php please asset-usage:doctor --folders # Report unused assets php please asset-usage:unused php please asset-usage:unused --container=main --json php please asset-usage:unused --older-than=30 --ignore='*.pdf' # Clean up php please asset-usage:unused --delete # asks first php please asset-usage:unused --delete --force # doesn't php please asset-usage:unused --fresh --delete # rebuild the index first
--delete refuses to run against an out-of-date index, and re-checks every asset immediately before removing it.
asset-usage:doctor is for when the numbers look wrong. Per container it prints what the filesystem holds (split into root and subfolders), what the asset query finds, what Statamic's own file listing reports, how many paths resolve to an actual asset and how many are recorded as used. It also flags files that exist on disk but aren't known as assets: on the eloquent driver those have no row in the assets table, so nothing can report on them until php please eloquent:import-assets brings them in.
Deleting
Deleting is available from the Tools page — per row, for a checkbox selection, and as Delete all unused, which covers every unused asset the active filters match rather than only the page you're looking at (up to 500 per click, so a big cleanup takes a few) — and from the CLI. Everything goes through the same rails:
- the
delete unused assetspermission, on top of Statamic's own per-container asset permissions; - the index must be current;
- the asset must have zero usages — a used asset can't be deleted from here at all;
ignorepatterns andminimum_age_in_daysare enforced server-side, not just in the UI.
Configuration
php artisan vendor:publish --tag=asset-usage-config
return [ // '*' for all containers, or ['main', 'documents'] 'containers' => '*', // The complete set: a type you leave out is not scanned 'scanned_types' => [ 'entries' => true, 'globals' => true, 'terms' => true, 'navs' => true, 'users' => true, 'assets' => true, 'form_submissions' => true, ], // Also count plain /assets/… URLs typed into text fields 'scan_urls' => true, // An asset in an unpublished draft counts as used 'include_working_copies' => true, // Keep the index in sync on content saves 'auto_update' => true, 'editor_panel' => true, 'listing_column' => true, // Never reported as unused, e.g. ['*.pdf', 'downloads/*'] 'ignore' => [], // Assets younger than this are never reported as unused 'minimum_age_in_days' => 0, ];
Permissions
- View asset usage — the Tools page.
- Delete unused assets — the delete buttons and the destroy endpoint.
The "Used in" panel and the browser column follow Statamic's normal asset permissions; if you can see the asset, you can see its usage.
License
Proprietary. © Key Agency.