Why Images Aren't Detected as Orphans by the OpenMage Image Cleaner: 7 Common Causes
The Image Cleaner only flags files as orphans after a sync action compares the filesystem against database references, but blacklist patterns, placeholder protections, path formatting mismatches, and negative entity ID isolation can prevent detection even for apparently unused files.
The OpenMage Image Cleaner (fballiano/openmage-image-cleaner) identifies unused media by scanning directories and diffing them against database-stored references. If you notice images that appear unused but never appear in the Orphans grid, the module's conservative filtering logic is likely excluding them based on specific architectural safeguards.
How Orphan Detection Works
The detection algorithm relies on a comparison between two arrays: $fs_images (files found on disk via recursive scan) and $db_images (paths extracted from entity tables). The array_diff() between these sets produces the orphan list. However, multiple preprocessing filters can remove entries from either array before the comparison occurs.
Blacklist Patterns Exclude Matching Paths
The recursive filesystem scanner respects user-defined blacklist patterns configured in system.xml. In app/code/community/Fballiano/ImageCleaner/Helper/Data.php, the scandirRecursive() method checks each path against isBlacklisted() before adding it to the filesystem array.
// app/code/community/Fballiano/ImageCleaner/Helper/Data.php (lines 18-22)
$blacklist_patterns = $this->getBlacklistedPatterns();
if ($this->isBlacklisted("$dir/$value", $blacklist_patterns)) continue;
If an image resides in a blacklisted directory or matches a pattern, it never enters $fs_images, making it invisible to the orphan detection diff.
Placeholder Images Are Always Considered Used
Product placeholders are explicitly protected from deletion. During product sync (syncproductAction), the controller adds placeholder paths to the $db_images reference set:
// FbimagecleanerController.php (lines 85-89)
// Adds placeholder/{$placeholder} to $db_images
Even if the physical placeholder file is missing, it is treated as a used reference, preventing it from appearing in the orphan grid.
Category vs. Product Path Formatting Mismatches
A critical inconsistency exists in path normalization. Product sync calls removeLeadingSlash() on database values, while category sync does not.
Product sync (line 82):
if ($db_images) $db_images = array_map([$this, 'removeLeadingSlash'], $db_images);
Category sync (lines 41-44):
$db_images = $db->fetchCol(
"SELECT value FROM {$resource->getTableName('catalog_category_entity_varchar')} …"
);
// No removeLeadingSlash() call
This means a category image stored as /image.jpg in the database is compared against image.jpg from the filesystem, causing a mismatch that excludes it from orphan detection.
Product Cache Isolation via Negative Entity IDs
Cache images use negative entity type IDs to separate them from standard product images. In syncproductCacheAction():
// line 17
$entity_type_id = -Mage::getModel('catalog/product')->getResource()->getTypeId();
These entries are stored with negative IDs. When you run a regular product sync, these cache images are excluded because the entity type IDs differ, effectively isolating them from normal orphan detection until a cache-specific sync is run.
Protected Directory Exclusions
The scanner explicitly skips directories that typically contain generated or protected assets. In scandirRecursive() (line 21), the code performs an early continue for:
cachewatermarkoptimized.thumbs- Any directory matching blacklist patterns
Images located in these sub-folders are never listed in $fs_images and therefore cannot be detected as orphans.
WYSIWYG Reference Detection Limitations
The WYSIWYG sync (syncwysiwygAction) identifies used images by searching for filesystem paths within CMS content and CSS files:
// lines 84-99
foreach ($fs_images as $fs_image) {
foreach ($db_images as $db_image) {
if (stripos($db_image ?? '', $fs_image) !== false) $used_images[] = $fs_image;
}
foreach ($css_files as $css_file) {
if (stripos($css_file, $fs_image) !== false) $used_images[] = $fs_image;
}
}
Images referenced via hard-coded URLs, external CDNs, or custom HTML editors that store paths differently from the database content may be missed if the exact string isn't found in the scanned content.
Temporary Folders Are Flushed, Not Scanned
The cleaner treats media/tmp, media/import, and var/export as temporary storage rather than orphan candidates. The controller provides specific flush actions (flushmediatmpAction(), flushmediaimportAction(), flushvarexportAction()) that delete these directories entirely rather than scanning them for orphans. Files left in these locations remain invisible to the sync logic.
Summary
- Blacklist patterns in
Helper/Data.phpprevent matching paths from entering the filesystem scan array. - Placeholder images are automatically added to the used reference set during product sync.
- Leading slash mismatches between category storage (with slash) and filesystem listings (without) cause category images to be overlooked.
- Negative entity type IDs isolate product cache images from standard product orphan detection.
- Protected directories including
cache,watermark, and.thumbsare excluded from recursive scanning. - WYSIWYG detection relies on string matching against CMS content and CSS, missing externally referenced images.
- Temporary folders are handled via bulk flush operations rather than orphan scanning.
Frequently Asked Questions
Why do my category images never appear as orphans even after deletion?
Category image paths stored in catalog_category_entity_varchar retain leading slashes (e.g., /image.jpg), while the filesystem scanner strips leading slashes for comparison. Because the category sync action does not call removeLeadingSlash() unlike the product sync, the paths never match, preventing detection.
Why aren't product cache images detected during a regular product sync?
Cache images are stored with negative entity type IDs (e.g., -4) via syncproductCacheAction(), while regular product sync queries for positive IDs. This architectural separation ensures cache cleanup doesn't interfere with product orphan detection, requiring you to run the specific cache sync action to evaluate those files.
Can I configure the cleaner to scan excluded directories like cache or watermark?
These exclusions are hardcoded in scandirRecursive() at line 21 of Helper/Data.php and cannot be overridden via configuration. To scan these directories, you would need to modify the core helper code or relocate the images to standard media folders not matching the exclusion patterns.
Why does the cleaner ignore images I know are unused in WYSIWYG content?
The WYSIWYG sync performs substring matching (stripos) against database content and CSS files. If the image path in your HTML differs from the filesystem path (e.g., absolute URLs, CDN paths, or encoded strings), the matcher fails to identify the reference, treating the file as potentially unused when it is actually referenced, or vice versa.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →