Warning
This package is in early development and may break your website or cause data loss. Use with caution and test thoroughly before running on production sites.
Detect and remove orphaned files in WordPress uploads directories.
Scans the uploads directory and cross-references against the WordPress attachment database to identify files not tracked as media library items. Supports local filesystem scanning and S3 object listings.
WordPress stores uploaded media as files in wp-content/uploads/ and tracks each one as an attachment post in the database. Over time, the two get out of sync: attachments get deleted through the admin but their files stay on disk, plugins drop temporary or generated files into uploads, and files land there via FTP or deployment scripts without ever being registered in the media library. The result is a steadily growing pool of orphaned files that waste storage, inflate backups, and make it harder to audit what's actually in use.
There's no built-in way to reconcile the filesystem against the database. This plugin scans every file in uploads, checks whether it belongs to a known attachment (including thumbnails, scaled originals, and editor variants), and reports or removes anything that doesn't.
- PHP 8.1+
- WP-CLI 2.12+
wp package install built-fast/wp-cli-lost-and-foundOr load directly:
wp --require=wp-cli-lost-and-found-command.php media find-orphansScan for orphaned files without modifying anything.
# JSON output (default)
wp media find-orphans
# Human-readable table
wp media find-orphans --format=table
# Scan S3 object listing
wp media find-orphans --file-list=/tmp/s3-objects.txt
# Custom exclude directories
wp media find-orphans --exclude-dirs=cache,woocommerce_uploads,gravity_forms| Option | Default | Description |
|---|---|---|
--format=<format> |
json |
Output format: json or table |
--exclude-dirs=<dirs> |
cache |
Comma-separated directory names to skip |
--file-list=<path> |
— | Path to file listing (enables S3 mode) |
Remove orphaned files from the uploads directory.
# Preview what would be removed
wp media remove-orphans --dry-run
# Remove orphans (with confirmation prompt)
wp media remove-orphans
# Remove without confirmation
wp media remove-orphans --yes
# Move to quarantine directory instead of deleting
wp media remove-orphans --yes --quarantine-dir=/tmp/quarantine
# JSON output for scripting
wp media remove-orphans --yes --format=json| Option | Default | Description |
|---|---|---|
--dry-run |
false |
Show what would be removed, touch nothing |
--yes |
false |
Skip interactive confirmation |
--quarantine-dir=<path> |
— | Move files here instead of deleting; preserves directory structure |
--format=<format> |
table |
Output format: json or table |
--exclude-dirs=<dirs> |
cache |
Comma-separated directory names to skip |
- Files left behind after attachments are deleted from the database
- Files uploaded via FTP/SFTP never registered in the media library
- Plugin artifacts in uploads (Gravity Forms, Elementor, WooCommerce, etc.)
- Original attachment files
- All thumbnail/size variants from attachment metadata
- WP 5.3+ scaled originals (
original_image) - WordPress image editor variants (
-e{timestamp}files) - PDF-generated preview thumbnails
index.phpand.htaccessfiles- Files inside directories specified by
--exclude-dirs
composer install
# Unit tests
composer phpunit
# Integration tests (requires MySQL)
composer prepare-tests
composer behat
# All tests
composer testMIT