Make WordPress Core

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

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, in wp-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 is wp_kses(). The core icons ship with WordPress and are as trusted as the rest of wp-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.

#2 @wildworks
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 @softglaze
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

  1. A test-only mu-plugin registers an icon collection tests66338 and an icon whose file sits outside the core icon library and contains <script>alert(1)</script> and an onload attribute.
  2. On wp_loaded it loads every registered icon once through WP_Icons_Registry::get_registered_icon() (126 core icons plus the plugin icon), times the loop and saves every icon's content.
  3. Separately, over 5 rounds of the 126 core icons, it times the file checks and read (realpath(), is_file(), is_readable(), file_get_contents()) and sanitize_icon_content() on the content already in memory.
  4. 15 requests on trunk, with the patch, and with the patch reverted. Run the icons test 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
  1. ✅ 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 lowercases viewbox. Compared element by element, ignoring attribute order and case, all 126 core icons are the same. This matches the switch to assertStringContainsStringIgnoringCase() 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.

This ticket was mentioned in ​Slack in #core-performance by softglaze. ​View the logs.


5 days ago

#6 @wildworks
21 hours ago

  • Owner set to wildworks
  • Resolution → fixed
  • Status new → closed

In 64800:

Icons: Skip sanitizing the icons bundled with WordPress

Icons that ship with WordPress in the core icon library are no longer sanitized when they are loaded, because they are reviewed and versioned like the rest of core. This cuts the server time it takes to render the admin bar and admin menu icons on every admin screen. Icons registered by plugins and themes are still sanitized.

Developed in: ​https://github.com/WordPress/wordpress-develop/pull/14492

Props fushar, softglaze, wildworks.
Fixes #66338.

Note: See TracTickets for help on using tickets.