Find and delete unused WordPress media files: a plugin you can build today
· 5 min read
A WordPress site that has been running for a few years often has a media library that no longer reflects what is actually on the site. Images uploaded for posts that were later deleted, test uploads from campaigns that ran and ended, files imported from a previous platform. None of it gets removed automatically, and the disk usage climbs until someone has to deal with it.
The standard approach is a scan-and-delete plugin. Tools like Media Cleaner look through post content and flag attachments that appear to have no references. The gap is custom field data. ACF stores image selections as attachment IDs in post meta. A scanner that only reads post_content treats every ACF-attached image as unused and queues it for deletion. For a site using ACF for team photos, product galleries, or testimonials, that is a way to silently remove content that is actively in use.
What one build gives you
- Scanning post content across all post types for embedded attachment references
- Scanning post meta including serialized ACF gallery field values for attachment IDs
- An admin screen listing unreferenced attachments with thumbnails, file names, dates, and sizes
- Bulk deletion with a confirmation step and a summary of files and disk space freed
What it does not do
- Images referenced in widget content or theme customizer settings stored in wp_options
- Images stored in custom database tables created by third-party plugins
- Resized crop files generated by WordPress, which are not tracked as separate attachments
- Recovering accidentally deleted attachments: deletion is permanent, so take a backup first
Media Cleaner does these. This covers the part most sites use.
The prompt
Loads into the composer so you can edit it first. Nothing is built, and nothing is charged, until you send it.
Build a WordPress plugin that finds and displays unused media library attachments. Add an admin page under Media > Unused Media. Add a Scan button that queries the database for all attachment post IDs, then checks whether each ID appears in: the post_content of any post, page, or custom post type; any post meta value including serialized arrays, covering ACF image and gallery fields that store attachment IDs; or the _thumbnail_id post meta key used for featured images. After the scan, display unreferenced attachments in a table with columns for a small thumbnail, the file name, the upload date, and the file size in kilobytes. Add a checkbox on each row and a Select All checkbox in the header. Add a Delete Selected button below the table that shows a JavaScript confirmation dialog before deleting. After deletion, display a message with the count of deleted files and the total megabytes freed.
Why media libraries accumulate unused files
WordPress does not delete attachments when a post is deleted. The post goes to trash and then disappears, but every image uploaded to that post stays in the media library. Multiply that by years of publishing, staff turnover, theme changes, and staging site imports, and the library contains a lot of files with no connection to anything live.
The problem is that there is no visual signal. The media library shows all files in the same grid. An unused image from 2022 looks identical to the featured image on the homepage. Without scanning the database for references, there is no way to tell them apart.
What the plugin scans
A Steem build for this job adds a Media > Unused Media admin page with a Scan button. When the scan runs, it checks three locations for attachment references:
What the results page shows
After the scan, the admin page lists every attachment that appeared in no reference found across those three locations. The table shows a small thumbnail preview, the file name, the upload date, and the file size.
Checkboxes allow selecting individual files or the whole page at once. A Delete Selected button asks for confirmation before anything is removed. After deletion, the page reports how many files were deleted and the total disk space freed.
How to install and use it
Paste the prompt below into Steem and download the generated zip. Install it under Plugins > Add New > Upload Plugin. Once active, go to Media > Unused Media.
Before running the scan on a production site, take a backup. Deletion through this plugin is permanent. Run the scan, review the results, and delete in small batches rather than all at once until you are confident the scan is catching what you expect.
What the scan does not check
Three areas are outside the scope of a post meta and post content scan. Widget content stored in the wp_options table can reference image URLs without using an attachment ID. Theme customizer settings stored in wp_options can do the same. Custom plugin tables that live outside the standard WordPress schema are not scanned.
For a site that makes heavy use of widgets or theme customizer image settings, check those areas manually before bulk-deleting. The safest approach is to delete a small batch first, verify the site looks correct, and then continue.
Questions
- Will images stored in ACF fields be treated as unused?
- No. ACF stores image selections as attachment IDs in post meta. The scan checks post meta values for attachment IDs, including serialized arrays used by ACF gallery fields, so ACF-referenced images are marked as in use and excluded from the results.
- Is there a way to preview what will be deleted before committing?
- Yes. The results page shows a thumbnail and file details for every unreferenced attachment. You select which ones to delete; nothing is removed until you confirm the deletion.
- Will deleted files be recoverable?
- No. Attachment deletion in WordPress is permanent. Take a full backup before running any bulk deletions, and delete in small batches the first time you use it on a site.
- How long does the scan take on a large media library?
- Scan time scales with the number of posts and attachments. On a site with thousands of posts and a large media library, a scan can take several minutes. The page waits while the scan completes.
- Does this handle images added through the WordPress customizer or widgets?
- No. Customizer settings and widget content are stored in wp_options, not in post meta or post content. Images referenced only through those locations will appear as unused in the scan results. Check those areas manually before bulk-deleting.
The prompt
Loads into the composer so you can edit it first. Nothing is built, and nothing is charged, until you send it.
Build a WordPress plugin that finds and displays unused media library attachments. Add an admin page under Media > Unused Media. Add a Scan button that queries the database for all attachment post IDs, then checks whether each ID appears in: the post_content of any post, page, or custom post type; any post meta value including serialized arrays, covering ACF image and gallery fields that store attachment IDs; or the _thumbnail_id post meta key used for featured images. After the scan, display unreferenced attachments in a table with columns for a small thumbnail, the file name, the upload date, and the file size in kilobytes. Add a checkbox on each row and a Select All checkbox in the header. Add a Delete Selected button below the table that shows a JavaScript confirmation dialog before deleting. After deletion, display a message with the count of deleted files and the total megabytes freed.
Steem