Add wp media find-orphans subcommand#252
Conversation
|
Hello! 👋 Thanks for opening this pull request! Please check out our contributing guidelines. We appreciate you taking the initiative to contribute to this project. Contributing isn't limited to just code. We encourage you to contribute in the way that best fits your abilities, by writing tutorials, giving a demo at your local meetup, helping other users with their support questions, or revising our documentation. Here are some useful Composer commands to get you started:
To run a single Behat test, you can use the following command: # Run all tests in a single file
composer behat features/some-feature.feature
# Run only a specific scenario (where 123 is the line number of the "Scenario:" title)
composer behat features/some-feature.feature:123You can find a list of all available Behat steps in our handbook. |
Codecov Report❌ Patch coverage is
📢 Thoughts on this report? Let us know! |
Add a non-destructive subcommand that finds orphaned media candidates by
comparing the media library, the uploads directory, and content usage.
Detectors (via `--type`, all run by default):
- filesystem: files on disk not in the media library. Restricted to known
media extensions (get_allowed_mime_types) and skips generated
subdirectories (elementor, gravity_forms, cache, wpcf7_uploads)
via the `wp_cli_media_find_orphans_ignore_paths` filter, so
page-builder noise is excluded.
- database: attachments whose file is missing from disk (both the
get_attached_file() and raw _wp_attached_file paths checked
to avoid `-scaled` false positives).
- thumbnails: generated thumbnails whose parent attachment is gone.
- usage: attachments unreferenced in content (conservative; scans all
registered post types; O(M+N) precomputed path->id lookup).
Options: --type, --format (table/json/csv/yaml/ids/count), --fields,
--include-thumbnails, --limit, --error-on-orphans (exit 1 when found).
Usage detection is extensible via the `wp_cli_media_find_orphans_used_ids`
filter so plugins can declare postmeta/ACF/page-builder references.
Adds a Behat feature covering all four types, JSON output, and the
error-on-orphans exit code. Registers the command in composer.json.
Implements wp-cli/ideas#216.
c0a9910 to
10a55e4
Compare
|
I've tried my best to get a 100% coverage on Codecov, but the missing lines would imply a lot of fixtures and heavy coding for a small result. Is it mandatory ? |
No, not mandatory at all. Thanks for keeping an eye on it though! |
There was a problem hiding this comment.
Pull request overview
Adds a new read-only WP-CLI subcommand, wp media find-orphans, to audit a WordPress site for media “orphan” candidates across filesystem, database, thumbnails, and content-usage signals, with configurable output formats and CI-friendly exit behavior.
Changes:
- Implements
wp media find-orphansinMedia_Commandwith four detectors and two extensibility filters. - Adds Behat acceptance coverage for core scenarios, output formats, and flag validation.
- Registers the new subcommand in
composer.jsonso it’s discoverable/bundled with the command set.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
src/Media_Command.php |
Adds the find-orphans subcommand and the detector implementations (filesystem/database/thumbnails/usage) plus helper utilities. |
features/media-find-orphans.feature |
Adds end-to-end Behat scenarios covering expected detection behavior, output, and exit codes. |
composer.json |
Registers media find-orphans in the commands list. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
The post_parent scan collected parent post IDs into $used_ids, which is a set of attachment IDs. This could misclassify attachments uploaded to a post (but not referenced in content) as unused, and could shield an unrelated attachment whose ID collided with a parent post ID. Select the attachment IDs themselves instead, and cover the post_parent-only case in the usage scenario.
What it does
wp media find-orphansscans a WordPress site for "orphan" media — files and attachments that are out of sync between the filesystem and the media library — and reports them. It is read-only by design: it never deletes, moves, or modifies anything.It runs four independent detectors, selectable with
--type:wp-content/uploadsthat are not in the media library (File on disk not in media library)Attachment file missing from disk)-WxH) whose parent attachment no longer exists (Thumbnail parent attachment missing)Attachment appears unused in content); featured images are not flaggedWithout
--type, all detectors run. Output is a table by default and supports--format=table|json|csv|yaml|ids|count, plus--fields,--limit, and--include-thumbnails.The command always exits
0. Pass--error-on-orphansto exit1when any orphan is found — convenient for CI/cron checks.Extensibility
Two WordPress filters let themes/plugins teach the detectors about their own storage and references:
wp_cli_media_find_orphans_ignore_paths— upload subpaths to skip (defaults cover common generated dirs such as caches and form uploads), so plugin-generated assets aren't reported as filesystem orphans.wp_cli_media_find_orphans_used_ids— additional attachment IDs to treat as "used" (receives the scanned post IDs and known attachment IDs as context), so custom references (e.g. postmeta, custom fields) don't yield false positives in theusagedetector.Examples
Tests
Acceptance coverage lives in
features/media-find-orphans.feature— one scenario per capability, each following Arrange → Act → Assert on a fresh WP install (withuploads_use_yearmonth_foldersdisabled for deterministic paths):No orphan media foundand exits0.uploads/is detected.@require-wp-5.3) → an imported attachment whose file is thenrm'd is detected.-150x150file with no parent attachment is detected.--format=json→ output is valid JSON containing the expected fields (type,attachment_id,file,issue,path).--error-on-orphans→ returns a non-zero exit code when orphans exist.All 7 scenarios pass (72 steps) against the standard
wp-cli/wp-cli-testsBehat harness.Notes
composer.json.