Opened 9 days ago
Closed 21 hours ago
#66338 closed enhancement (fixed)
Icons: Optimization: Skip sanitizing the icons bundled with WordPress
| Reported by: | fushar | Owned by: | wildworks |
|---|---|---|---|
| Priority: | normal | Milestone: | 7.2 |
| Component: | General | Version: | |
| Severity: | normal | Keywords: | has-patch has-unit-tests |
| Cc: | Focuses: | performance |
Description
Follow-up to https://github.com/WordPress/wordpress-develop/pull/12270#discussion_r4257564282.
Proposal
In WP_Icons_Registry::get_content(), skip sanitize_icon_content() for icons shipped in Core.
It is costly as it calls wp_kses(). See the linked discussion above for numbers.
I believe it's safe to skip it, as we control what gets shipped to Core. The SVGs are checked in the version control and they were reviewed as PRs.
Change History (6)
This ticket was mentioned in PR #14492 on WordPress/wordpress-develop by @fushar.
9 days ago
#1
- Keywords has-patch has-unit-tests added
#2
@
5 days ago
- Milestone Awaiting Review → 7.2
Although this ticket is labeled as an enhancement, it is essentially a performance improvement aimed at speeding up the loading of core SVG icons and does not introduce any new APIs. Therefore, I propose addressing this ticket in the 7.2 release.
@fushar commented on PR #14492:
5 days ago
#3
@t-hamano Thanks for the review and welcome back! All make sense, I've applied them and re-test this PR.
#4
@
5 days ago
Test Report
Description
This report validates whether the indicated patch works as expected.
Patch tested: https://github.com/WordPress/wordpress-develop/pull/14492 (head fa2f8de)
Environment
- WordPress: 7.2-beta1-64606-src (wordpress-develop local environment in Docker)
- PHP: 8.3.32
- Server: nginx/1.31.3
- Database: MySQL 9.7.1
- Browser: none, requests made with curl
- OS: Windows 11 Pro
- Theme: Warqa
- MU Plugins: one test-only helper (see Steps)
- Plugins: TestFlow Console 1.0.2
Steps
- A test-only mu-plugin registers an icon collection
tests66338and an icon whose file sits outside the core icon library and contains<script>alert(1)</script>and anonloadattribute. - On
wp_loadedit loads every registered icon once throughWP_Icons_Registry::get_registered_icon()(126 core icons plus the plugin icon), times the loop and saves every icon's content. - Separately, over 5 rounds of the 126 core icons, it times the file checks and read (
realpath(),is_file(),is_readable(),file_get_contents()) andsanitize_icon_content()on the content already in memory. - 15 requests on trunk, with the patch, and with the patch reverted. Run the
iconstest group at each stage.
Actual Results
| Trunk | With patch | Patch reverted (control) | |
| Plugin icon | <script> and onload removed | <script> and onload removed (same output) | same as trunk |
| Core icons, compared with trunk | 126 of 126 have the same elements, attributes and values | identical to trunk | |
| Load all 127 icons, median of 15 requests | 731.6 ms | 778.7 ms | 660.9 ms |
icons test group | OK (171 tests, 623 assertions) | OK (173 tests, 626 assertions) |
Cost per core icon, median of 10 requests (5 rounds each):
| Part | Time per icon | With the patch |
| File checks and read | 6.773 ms | kept |
sanitize_icon_content() | 0.061 ms | skipped |
- ✅ Patch works as expected: core icons skip sanitization with equivalent output, and plugin icons are still sanitized.
Additional Notes
- The core icon output changes only in form: the raw files keep their attribute order and
viewBox, while the sanitized version reorders the attributes and lowercasesviewbox. Compared element by element, ignoring attribute order and case, all 126 core icons are the same. This matches the switch toassertStringContainsStringIgnoringCase()in the PR. - In this setup the patch saves 0.061 ms per core icon, about 1.2 ms for the roughly 20 icons on a wp-admin page and 7.7 ms for all 126. The full-load timings above do not show it because the file checks and reads take about 6.8 ms per icon on this Docker-on-Windows volume, which hides the difference. On a native filesystem the reads are much cheaper, so the sanitization would be a larger share of the time.
- On trunk and with the patch, the plugin icon keeps the text of the removed script element (
alert(1)) as plain text inside the SVG. It cannot run, and it is the same before and after.
Thanks @fushar for the patch, and @wildworks and @t-hamano for the reviews.
![(please configure the [header_logo] section in trac.ini)](/chrome/site/your_project_logo.png)
Trac ticket: https://core.trac.wordpress.org/ticket/66338.
Backport of https://github.com/WordPress/gutenberg/pull/85083.
Skips the
wp_kses()sanitization of the core icons bundled with WordPress, inwp-includes/images/icon-library/.https://github.com/WordPress/wordpress-develop/pull/12270 renders the admin bar and admin menu icons with
wp_get_icon(), so every wp-admin page now loads about 20 icons through the registry. Measurements on that PR show about +3.5 ms of server time per wp-admin page, and most of the icon cost iswp_kses(). The core icons ship with WordPress and are as trusted as the rest ofwp-includes, so sanitizing does not really protect anything.Use of AI Tools
AI assistance: Yes
Tool(s): Claude Code
Model(s): Claude Opus 5.5
Used for: code generation, with my supervision.