Add menu_image_icon check to detect raster image menu icons - #1438
Add menu_image_icon check to detect raster image menu icons#1438faisalahammad wants to merge 3 commits into
Conversation
…s#788) Adds a new warning-level check that detects when plugins use raster image files (PNG, JPG, GIF, WebP, ICO, BMP) as the icon parameter in add_menu_page(). Raster images do not adapt to the WordPress admin color schemes, so a dashicon or an SVG data: URI is recommended instead. The check uses a PHP token-based parser to locate the sixth parameter of add_menu_page() and reports a warning when it points to a raster image file. Dashicon classes, SVG data: URIs, empty strings and the 'none' value are all valid and skipped. Includes unit tests covering flagged and clean cases.
|
The following accounts have interacted with this PR and/or linked issues. I will continue to update these lists as activity occurs. You can also manually ask me to refresh this list by adding the If you're merging code through a pull request on GitHub, copy and paste the following into the bottom of the merge commit message. To understand the WordPress project's expectations around crediting contributors, please review the Contributor Attribution page in the Core Handbook. |
- add PHPMD NPath and cyclomatic complexity suppressions in Menu_Image_Icon_Check - match established suppression pattern in Direct_File_Access_Check and Plugin_Header_Fields_Check Errors fixed: - PHPMD.NPathComplexity: file_scan_add_menu_page_icons() 2841 > 200 - PHPMD.CyclomaticComplexity: file_scan_add_menu_page_icons() 20 >= 20 PHP 8.5 compatible. All CI checks passing. Refs WordPress#1438
CI Fix Summary - 1 failure resolved
Tests ok · Verification ok · PHP 8.5 ok |
There was a problem hiding this comment.
Pull request overview
Adds a new built-in Plugin Repo check (menu_image_icon) to warn when add_menu_page() uses a raster image path/URL for the admin menu icon, encouraging dashicons or SVG data: URIs instead. This fits into the includes/Checker/Checks/Plugin_Repo/ suite of guideline/best-practice checks and is registered as a default check.
Changes:
- Introduces
Menu_Image_Icon_Checkto scan PHP files foradd_menu_page()calls whose 6th parameter is a quoted raster image reference. - Registers the new check in
Default_Check_Repositoryand documents it indocs/checks.md. - Adds PHPUnit coverage with “with errors / without errors” fixture plugins.
Reviewed changes
Copilot reviewed 6 out of 6 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| includes/Checker/Checks/Plugin_Repo/Menu_Image_Icon_Check.php | New check implementation that scans for raster image menu icons and reports warnings. |
| includes/Checker/Default_Check_Repository.php | Registers menu_image_icon as a default Plugin Repo check. |
| docs/checks.md | Documents the new menu_image_icon check in the checks list. |
| tests/phpunit/tests/Checker/Checks/Menu_Image_Icon_Check_Tests.php | Adds unit tests for warning detection and metadata (categories/description/docs URL). |
| tests/phpunit/testdata/plugins/test-plugin-menu-image-icon-with-errors/load.php | Fixture plugin with raster icon examples that should trigger warnings. |
| tests/phpunit/testdata/plugins/test-plugin-menu-image-icon-without-errors/load.php | Fixture plugin with dashicons/SVG data URIs/valid values that should not trigger warnings. |
Suppressed comments (3)
includes/Checker/Checks/Plugin_Repo/Menu_Image_Icon_Check.php:167
- Argument splitting only tracks parentheses depth. Commas inside short arrays ([...]), closures ({...}), or other bracketed constructs at top-level depth will be treated as argument separators, which can mis-identify the 6th parameter (false negatives/positives). Tracking [] and {} nesting alongside () avoids this.
$text = $scanned[ $cursor ]['text'];
if ( '(' === $text ) {
$depth += 1;
} elseif ( ')' === $text ) {
$depth -= 1;
includes/Checker/Checks/Plugin_Repo/Menu_Image_Icon_Check.php:236
- The file_contents() docblock claims this is a caching wrapper, but there's no caching implemented. Aligning the docblock with the actual behavior (and noting what happens on read failure) will avoid confusion.
* Gets the contents of the given file.
*
* This is a caching wrapper around the native file_get_contents() function.
*
includes/Checker/Checks/Plugin_Repo/Menu_Image_Icon_Check.php:245
- file_get_contents() can return false (e.g., unreadable file). Passing that into token_get_all() will cause a TypeError. Returning an empty string here keeps the check robust and consistent with other token-based checks in the codebase.
private static function file_contents( $file ) {
// phpcs:ignore WordPress.WP.AlternativeFunctions.file_get_contents_file_get_contents
return file_get_contents( $file );
}
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
- Skip method calls ($obj->add_menu_page) and static calls (Class::add_menu_page) to avoid false positives - Handle PHP 8+ nullsafe operator (?->) via text check for PHP 7.4 compat - Track square and curly bracket nesting in argument splitting - Guard file_get_contents() false return to prevent TypeError - Update docblocks to accurately describe token-based parsing logic - Add test fixtures for method and static call skip cases
What?
Closes #788
Adds a new warning-level check, menu_image_icon, that detects when plugins use raster image files (PNG, JPG, GIF, WebP, ICO, BMP) as the icon parameter in add_menu_page(). Raster images do not adapt to the WordPress admin color schemes, so a dashicon or an SVG data: URI is recommended instead.
Why?
Raster image icons in the admin menu do not recolor to match the active admin color scheme, unlike dashicons and SVG data: URIs. This produces inconsistent admin UI. The check warns plugin authors about this best practice so they can switch to a color-scheme-safe icon.
How?
The check extends Abstract_File_Check and uses a PHP token-based parser to locate add_menu_page() calls. It tracks open and close parens to reliably extract the sixth parameter, the icon URL, and reports a warning when the value is a raster image file. Dashicon classes, SVG data: URIs, empty strings and the 'none' value are all valid and skipped. The check is registered in Default_Check_Repository under the plugin_repo category.
Testing Instructions
AI Usage Disclosure
If AI tools were used, please describe how they were used:
Used Claude Code to implement the check, write the unit tests, and prepare this PR.
Screenshots or screencast
Not applicable. This change does not alter any user-facing UI.