Why CSS Files in /skin/frontend Are Scanned for WYSIWYG Image Detection
The fballiano/openmage-image-cleaner module scans CSS files within /skin/frontend directories to detect image references in stylesheets, ensuring that background images and icons loaded via CSS rules are not mistakenly deleted as orphaned WYSIWYG files.
The fballiano/openmage-image-cleaner repository provides a utility to safely identify and remove unused WYSIWYG images from Magento and OpenMage installations. While the module primarily checks database tables such as cms_page, cms_block, and core_email_template for image references, it must also account for assets loaded through frontend CSS. Scanning CSS files within /skin/frontend directories is essential because themes frequently reference WYSIWYG images using background-image, content, or similar CSS properties rather than direct HTML.
The Risk of CSS-Referenced Images
Magento themes and custom designs often load visual assets exclusively through CSS rules. A store might display a banner, icon, or background texture using code similar to:
.hero-banner {
background-image: url(/media/wysiwyg/banner.jpg);
}
If the cleanup utility only inspected database content, these files would appear unused and be flagged for deletion. By scanning CSS files within /skin/frontend for WYSIWYG image detection, the module avoids false positives and prevents breaking the storefront appearance.
How the Detection Works
The detection process involves two distinct phases: collecting all CSS contents from the frontend skin directory, then performing substring searches against every file found in the media/wysiwyg directory.
Step 1 – Collecting CSS Contents
The helper method getAllCSSFilesContents() in Helper/Data.php (lines 46–55) recursively gathers every .css file under the frontend skin directory and loads their contents into memory.
// app/code/community/Fballiano/ImageCleaner/Helper/Data.php
public function getAllCSSFilesContents()
{
$files = $this->getAllCSSFiles(Mage::getBaseDir('skin') . '/frontend');
foreach ($files as $k=>$css_file_path) {
$files[$k] = file_get_contents($css_file_path);
}
return $files;
}
This method returns an array of strings, where each element contains the full text content of a CSS file found within /skin/frontend.
Step 2 – Cross-Referencing WYSIWYG Files
During the syncwysiwyg action, the controller iterates through every image file in the media directory and checks if its filename appears within any of the loaded CSS strings. This logic appears in controllers/Adminhtml/FbimagecleanerController.php (lines 177–199).
// app/code/community/Fballiano/ImageCleaner/controllers/Adminhtml/FbimagecleanerController.php
$css_files = $helper->getAllCSSFilesContents();
foreach ($fs_images as $fs_image) {
// ... database checks omitted ...
foreach ($css_files as $css_file) {
if (stripos($css_file, $fs_image) !== false) {
$used_images[] = $fs_image;
break;
}
}
}
The stripos() function performs a case-insensitive search. If the image filename (e.g., wysiwyg/banner.jpg) exists anywhere within a CSS file's content, the image is marked as used and excluded from the orphan deletion list.
Practical Implementation Examples
To manually verify if a specific WYSIWYG image is referenced in your theme's CSS, you can leverage the helper directly:
$helper = Mage::helper('fballiano_imagecleaner');
$cssContents = $helper->getAllCSSFilesContents();
$image = 'wysiwyg/banner.jpg';
$isUsed = false;
foreach ($cssContents as $css) {
if (stripos($css, $image) !== false) {
$isUsed = true;
break;
}
}
echo $isUsed ? 'Image is actively used in CSS' : 'Image may be orphaned';
The complete workflow executed during a sync operation follows this pattern:
$helper = Mage::helper('fballiano_imagecleaner');
$css_files = $helper->getAllCSSFilesContents();
$mediaDir = Mage::getBaseDir('media') . '/wysiwyg';
$fs_images = $helper->scandirRecursive($mediaDir);
$fs_images = str_replace(Mage::getBaseDir('media') . '/', '', $fs_images);
$used_images = [];
foreach ($fs_images as $fs_image) {
// Check against CSS files
foreach ($css_files as $css_file) {
if (stripos($css_file, $fs_image) !== false) {
$used_images[] = $fs_image;
break;
}
}
}
$orphan_images = array_diff($fs_images, $used_images);
// $orphan_images now contains only files not referenced in DB or CSS
Summary
- CSS files in
/skin/frontendcontain image references that are not stored in the database, making filesystem scanning necessary for complete orphan detection. - The
getAllCSSFilesContents()method recursively reads all CSS files into an array of strings to enable fast substring searching. - Case-insensitive matching via
stripos()identifies images referenced throughurl()functions regardless of CSS formatting. - Images found in CSS are excluded from deletion, ensuring that theme assets referenced via
background-imageorcontentproperties remain intact.
Frequently Asked Questions
What specific CSS properties are detected when scanning these files?
The module does not parse CSS properties specifically; instead, it performs a substring search across the entire file content using stripos(). This means any image filename appearing inside a CSS file—whether within background-image, content, list-style-image, or any other property utilizing url()—will be detected as a reference.
Does the scanner check CSS files in the adminhtml or backend skin directories?
No, the implementation specifically targets the frontend skin directory only. The path is hardcoded in getAllCSSFilesContents() as Mage::getBaseDir('skin') . '/frontend', which excludes /skin/adminhtml and other backend theme directories from the WYSIWYG image detection process.
How does the module handle minified or aggregated CSS files?
Because the detection relies on simple string matching rather than CSS parsing, minified or concatenated CSS files are processed identically to standard formatted files. The file_get_contents() call reads the entire file as a string, and stripos() searches that string for image filenames, making the detection method agnostic to formatting, whitespace, or file structure.
Is there a performance impact when scanning large theme directories?
The scan occurs during the administrative syncwysiwyg action rather than on every page load. While the operation loads all CSS file contents into memory (an array of strings), this is a necessary trade-off to ensure accurate orphan detection. For sites with extensive theme libraries, this process runs only when the administrator manually triggers a synchronization.
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 →