# Why Images Aren't Detected as Orphans by the OpenMage Image Cleaner: 7 Common Causes

> Discover 7 common reasons why OpenMage Image Cleaner might not detect orphan images. Learn about sync actions, blacklist patterns, placeholder protections, path mismatches, and more.

- Repository: [Fabrizio Balliano/openmage-image-cleaner](https://github.com/fballiano/openmage-image-cleaner)
- Tags: troubleshooting
- Published: 2026-03-01

---

**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`](https://github.com/fballiano/openmage-image-cleaner/blob/main/system.xml). In [`app/code/community/Fballiano/ImageCleaner/Helper/Data.php`](https://github.com/fballiano/openmage-image-cleaner/blob/main/app/code/community/Fballiano/ImageCleaner/Helper/Data.php), the `scandirRecursive()` method checks each path against `isBlacklisted()` before adding it to the filesystem array.

```php
// 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:

```php
// 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):

```php
if ($db_images) $db_images = array_map([$this, 'removeLeadingSlash'], $db_images);

```

**Category sync** (lines 41-44):

```php
$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()`:

```php
// 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:

- `cache`
- `watermark`
- `optimized`
- `.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:

```php
// 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.php`](https://github.com/fballiano/openmage-image-cleaner/blob/main/Helper/Data.php) prevent 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 `.thumbs` are 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`](https://github.com/fballiano/openmage-image-cleaner/blob/main/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.