Skip to content

Icons: Skip sanitizing the core icons - #85083

Open
fushar wants to merge 1 commit into
trunkfrom
icons-skip-kses-bundled
Open

fushar wants to merge 1 commit into
trunkfrom
icons-skip-kses-bundled

Conversation

@fushar

@fushar fushar commented Oct 19, 2026 •

Copy link
Copy Markdown
Contributor

What?

Skips the wp_kses() sanitization of the core icons bundled with the plugin, in packages/icons/src/library.

Core backport: WordPress/wordpress-develop#14492

Why?

WordPress/wordpress-develop#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 the plugin and are as trusted as its PHP files, so sanitizing them does not really protect anything.

How?

WP_Icons_Registry_Gutenberg::get_content() skips sanitize_icon_content() when the icon file is inside the core icon library.

Testing Instructions

npm run test:unit:php:base -- --filter WP_Test_Icons_Registry_Gutenberg

Use of AI Tools

AI assistance: Yes
Tool(s): Claude Code
Model(s): Claude Opus 5.5
Used for: code generation, with my supervision.

@fushar fushar added [Type] Performance Related to performance efforts [Feature] Icons Related to Icon registration API and Icon REST API labels Oct 19, 2026
@github-actions

github-actions Bot commented Oct 19, 2026 •

Copy link
Copy Markdown

🤖 PR meta 🤖

Preview in WordPress Playground

🎉 Props

If you're merging code through a pull request on GitHub, copy and paste the following into the bottom of the merge commit message.

Co-authored-by: fushar <fushar@git.wordpress.org>
Co-authored-by: t-hamano <wildworks@git.wordpress.org>

To understand the WordPress project's expectations around crediting contributors, please review the Contributor Attribution page in the Core Handbook.

Updated as activity occurs, without notifying anyone named here. Add the props-bot label to refresh.

⚡ Performance

Show the results

Client side metrics exclude the server response time.

front-end-block-theme

Metric 54d5d2b trunk % Change
timeToFirstByte 52.1 ms +15.07% -3.84% 52.4 ms +10.21% -5.15% -0.57%
largestContentfulPaint 92 ms +4.35% -6.52% 86 ms +6.98% -2.33% 6.98%
lcpMinusTtfb 34.65 ms +21.79% -4.04% 34.3 ms +1.17% -4.52% 1.02%
wpBeforeTemplate 27.09 ms +23.37% -1.11% 27.08 ms +22.97% -1.96% 0.04%
wpTemplate 20.92 ms +3.49% -6.21% 20.59 ms +5.73% -5.88% 1.6%
wpTotal 48.12 ms +15.11% -3.76% 48.7 ms +9.59% -5.69% -1.19%
wpMemoryUsage 7.64 MB +0% -0% 7.61 MB +0% -0% 0.46%
wpDbQueries 16 +0% -0% 16 +0% -0% 0%

front-end-classic-theme

Metric 54d5d2b trunk % Change
timeToFirstByte 43.9 ms +12.07% -3.99% 42.45 ms +8.48% -0.82% 3.42%
largestContentfulPaint 102 ms +3.92% -1.96% 96 ms +4.17% -0% 6.25%
lcpMinusTtfb 57.05 ms +1.58% -5.08% 53.9 ms +0.83% -0.65% 5.84%
wpBeforeTemplate 24.14 ms +20.3% -1.82% 23.69 ms +2.87% -1.39% 1.9%
wpTemplate 15.85 ms +5.8% -3.72% 15.68 ms +8.99% -1.4% 1.08%
wpTotal 40.62 ms +12.63% -3.91% 39.39 ms +8.2% -1.19% 3.12%
wpMemoryUsage 6.32 MB +0% -0% 6.29 MB +0% -0% 0.57%
wpDbQueries 13 +0% -0% 13 +0% -0% 0%

media-processing

Metric 54d5d2b trunk % Change
mediaProcessingJpeg 418.3 ms +4.54% -0.7% 414.86 ms +0.81% -0.88% 0.83%
mediaProcessingAvif 6145.91 ms +0.41% -0.26% 6134.4 ms +0.24% -0.15% 0.19%
mediaProcessingJpegToAvif 4296.44 ms +0.16% -0.03% 4303.37 ms +0.11% -0.24% -0.16%

media-upload

Metric 54d5d2b trunk % Change
jpegUploadProcessing 1427.36 ms +2.22% -1.29% 1414.56 ms +0.61% -0.25% 0.9%
pngUploadProcessing 205.91 ms +3.39% -15.84% 212.99 ms +1.51% -4.81% -3.32%
largeJpegUploadProcessing 1406.07 ms +1.38% -0.61% 1412.6 ms +1.49% -1.1% -0.46%
multipleImageUploadProcessing 1564.25 ms +2.08% -1.14% 1560.86 ms +1.27% -0.69% 0.22%

post-editor

Metric 54d5d2b trunk % Change
serverResponse 268.81 ms +7.21% -6.83% 267.51 ms +5.01% -8.35% 0.49%
firstPaint 264.65 ms +51.03% -28.82% 359.2 ms +2.01% -48.18% -26.32%
domContentLoaded 827.9 ms +6.89% -3.24% 767.78 ms +2.17% -1.26% 7.83%
loaded 829.15 ms +6.89% -3.26% 768.87 ms +2.19% -1.25% 7.84%
firstContentfulPaint 397.29 ms +5.96% -2.07% 360.39 ms +3.12% -2.02% 10.24%
firstBlock 2376.86 ms +5.31% -4.68% 2242.56 ms +2.82% -2.72% 5.99%
type 17.68 ms +10.41% -5.37% 14.81 ms +9.66% -2.7% 19.38%
typeWithoutInspector 16.55 ms +2.24% -2.78% 16.02 ms +4.12% -6.87% 3.31%
typeWithTopToolbar 19.78 ms +10.72% -4.8% 17.79 ms +24.51% -4.16% 11.19%
typeContainer 7.21 ms +7.77% -2.64% 6.46 ms +7.28% -1.39% 11.61%
focus 95.29 ms +7.99% -7.42% 70.82 ms +19.36% -2.63% 34.55%
firstFocus 157.96 ms +0% -0% 151.07 ms +0% -0% 4.56%
selectAll 352.04 ms +9.2% -2.4% 405.89 ms +13.2% -3.9% -13.27%
listViewOpen 49.24 ms +7.6% -2.62% 48.48 ms +4.46% -7.9% 1.57%
inserterOpen 31.31 ms +7.92% -12.65% 24.18 ms +14.02% -8.06% 29.49%
inserterHover 10.19 ms +5.3% -5.4% 8.85 ms +6.78% -6.33% 15.14%
inserterSearch 7.2 ms +11.39% -7.64% 6.4 ms +5% -6.09% 12.5%
loadPatterns 446.3 ms +4.92% -2.28% 416.81 ms +3.4% -0.97% 7.08%
wpTotal 261.6 ms +7.37% -6.95% 260.27 ms +4.47% -8.5% 0.51%
wpMemoryUsage 13.58 MB +0% -0% 13.55 MB +0% -0% 0.24%
wpDbQueries 55 +0% -0% 55 +0% -0% 0%

site-editor

Metric 54d5d2b trunk % Change
serverResponse 494.55 ms +1.64% -4.59% 492.3 ms +0.91% -6.2% 0.46%
firstPaint 255.86 ms +5.52% -12.15% 254.08 ms +13.99% -8.27% 0.7%
domContentLoaded 1265.55 ms +2.01% -1.25% 1259.96 ms +1.66% -0.39% 0.44%
loaded 1266.61 ms +2.03% -1.24% 1261.11 ms +1.67% -0.41% 0.44%
firstContentfulPaint 525.27 ms +1.31% -3.31% 525.25 ms +0.55% -1.17% 0%
firstBlock 4680.87 ms +1.07% -0.67% 4668.52 ms +0.33% -0.28% 0.26%
type 18.77 ms +5.27% -2.98% 17.77 ms +3.71% -3.49% 5.63%
navigate 111.9 ms +2.96% -1.49% 118.62 ms +19.73% -1.08% -5.67%
loadPatterns 1248.58 ms +4.45% -3.52% 1228.43 ms +1.47% -1.19% 1.64%
loadPages 1023.7 ms +1.82% -1.86% 1015.27 ms +1.98% -0.97% 0.83%
wpTotal 484.82 ms +1.64% -4.68% 482.34 ms +0.93% -6.18% 0.51%
wpMemoryUsage 12.63 MB +0% -0% 12.59 MB +0% -0% 0.29%
wpDbQueries 44 +2.27% -0% 44 +2.27% -0% 0%

f6c20f8 Run

🏁 Flaky tests

Some tests passed with failed attempts. The failures may not be related to this commit but are still reported for visibility. See the documentation for more information.

As a site builder, I want to insert a core navigation overlay pattern with CTA and see it on the frontend in /test/e2e/specs/site-editor/navigation-overlay-template-part.spec.js, passed after 1 failed attempt.
Error: expect(locator).toBeVisible() failed

Locator:  getByRole('option', { name: /Overlay with site info and CTA/i })
Expected: visible
Received: hidden
Timeout:  5000ms

Call log:
  - Expect "toBeVisible" getByRole('option', { name: /Overlay with site info and CTA/i }) with timeout 5000ms
  - waiting for getByRole('option', { name: /Overlay with site info and CTA/i })
    14 × locator resolved to <div role="option" tabindex="-1" data-base-ui-tooltip-trigger="" aria-label="Overlay with site info and CTA" class="block-editor-block-patterns-list__item" id="core/navigation-overlay-centered-with-extras" aria-describedby="block-editor-block-patterns-list__item-description-4">…</div>
       - unexpected value "hidden"

    at /home/runner/work/gutenberg/gutenberg/test/e2e/specs/site-editor/navigation-overlay-template-part.spec.js:254:31
Regression: updating a specific option will only change its value and will not corrupt others in /test/e2e/specs/editor/various/core-settings.spec.js, passed after 1 failed attempt.
Error: expect(received).toStrictEqual(expected) // deep equality

- Expected  - 1
+ Received  + 1

  Array [
    "rewrite_rules",
-   "SERIALIZED DATA",
+   "",
  ]
    at forEach (/home/runner/work/gutenberg/gutenberg/test/e2e/specs/editor/various/core-settings.spec.js:46:26)
    at /home/runner/work/gutenberg/gutenberg/test/e2e/specs/editor/various/core-settings.spec.js:43:35
keeps the blocks selected after dropping a multi-selection in /test/e2e/specs/editor/various/draggable-blocks.spec.js, passed after 1 failed attempt.
TypeError: Cannot read properties of null (reading 'y')
    at /home/runner/work/gutenberg/gutenberg/test/e2e/specs/editor/various/draggable-blocks.spec.js:824:57
    at dragSelectionBelowLanding (/home/runner/work/gutenberg/gutenberg/test/e2e/specs/editor/various/draggable-blocks.spec.js:823:3)
    at /home/runner/work/gutenberg/gutenberg/test/e2e/specs/editor/various/draggable-blocks.spec.js:908:3
refuses the drop and uploads nothing in /test/e2e/specs/editor/various/single-file-placeholder-drop.spec.js, passed after 1 failed attempt.
Error: expect(received).toHaveLength(expected)

Expected length: 0
Received length: 1
Received array:  [{"_links": {"about": [{"href": "http://localhost:8889/wp-json/wp/v2/types/attachment"}], "author": [{"embeddable": true, "href": "http://localhost:8889/wp-json/wp/v2/users/1"}], "collection": [{"href": "http://localhost:8889/wp-json/wp/v2/media"}], "curies": [{"href": "https://api.w.org/{rel}", "name": "wp", "templated": true}], "replies": [{"embeddable": true, "href": "http://localhost:8889/wp-json/wp/v2/comments?post=280"}], "self": [{"href": "http://localhost:8889/wp-json/wp/v2/media/280", "targetHints": {"allow": ["GET", "POST", "PUT", "PATCH", "DELETE"]}}], "wp:attached-to": [{"embeddable": true, "href": "http://localhost:8889/wp-json/wp/v2/posts/279", "id": 279, "post_type": "post"}]}, "alt_text": "", "author": 1, "caption": {"rendered": ""}, "class_list": ["post-280", "attachment", "type-attachment", "status-inherit", "hentry", "entry"], "comment_status": "open", "date": "2026-10-19T11:27:29", "date_gmt": "2026-10-19T11:27:29", "description": {"rendered": "<p class=\"attachment\"><a href='http://localhost:8889/wp-content/uploads/2026/10/8d038799-3ea1-406c-9fd2-4ef0053b7520.png'><img loading=\"lazy\" decoding=\"async\" width=\"10\" height=\"10\" src=\"http://localhost:8889/wp-content/uploads/2026/10/8d038799-3ea1-406c-9fd2-4ef0053b7520.png\" class=\"attachment-medium size-medium\" alt=\"\" style=\"width:100%;height:100%;max-width:10px;\" /></a></p>
"}, "featured_media": 0, "filename": "8d038799-3ea1-406c-9fd2-4ef0053b7520.png", "filesize": 80, "guid": {"rendered": "http://localhost:8889/wp-content/uploads/2026/10/8d038799-3ea1-406c-9fd2-4ef0053b7520.png"}, "id": 280, "link": "http://localhost:8889/?attachment_id=280", "media_details": {"file": "2026/10/8d038799-3ea1-406c-9fd2-4ef0053b7520.png", "filesize": 80, "height": 10, "image_meta": {"alt": "", "aperture": "0", "camera": "", "caption": "", "copyright": "", "created_timestamp": "0", "credit": "", "focal_length": "0", "iso": "0", "keywords": [], "orientation": "0", "shutter_speed": "0", "title": ""}, "sizes": {}, "width": 10}, "media_type": "image", "meta": [], "mime_type": "image/png", "modified": "2026-10-19T11:27:29", "modified_gmt": "2026-10-19T11:27:29", "ping_status": "closed", "post": 279, "slug": "8d038799-3ea1-406c-9fd2-4ef0053b7520", "source_url": "http://localhost:8889/wp-content/uploads/2026/10/8d038799-3ea1-406c-9fd2-4ef0053b7520.png", "status": "inherit", "template": "", "title": {"rendered": "8d038799-3ea1-406c-9fd2-4ef0053b7520"}, "type": "attachment"}]
    at /home/runner/work/gutenberg/gutenberg/test/e2e/specs/editor/various/single-file-placeholder-drop.spec.js:71:45
should restore an older revision in /test/e2e/specs/editor/various/revisions.spec.js, passed after 1 failed attempt.
Error: expect(received).toMatchObject(expected)

- Expected  - 1
+ Received  + 1

  Array [
    Object {
      "attributes": Object {
-       "content": "Original content - Updated content - Autosaved",
+       "content": "Original content<ins aria-describedby=\"revision-diff-added-desc\" class=\"revision-diff-added\"> - Updated content</ins>",
      },
      "name": "core/paragraph",
    },
  ]

Call Log:
- Timeout 5000ms exceeded while waiting on the predicate
    at /home/runner/work/gutenberg/gutenberg/test/e2e/specs/editor/various/revisions.spec.js:146:5

f6c20f8 Run

The core icons bundled with the plugin are trusted, and sanitizing them with
wp_kses() is the main cost of rendering them.
@fushar
fushar force-pushed the icons-skip-kses-bundled branch from f01a194 to f6c20f8 Compare October 19, 2026 11:08
@fushar
fushar marked this pull request as ready for review October 19, 2026 11:30
@fushar
fushar requested a review from spacedmonkey as a code owner October 19, 2026 11:30
@fushar
fushar requested review from mcsf and t-hamano October 19, 2026 11:30
@github-project-automation github-project-automation Bot moved this to 🔎 Needs Review in WordPress 7.2 Editor Tasks Oct 23, 2026

@t-hamano t-hamano left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the PR! This is essentially a performance improvement that speeds up loading the core SVG icons, and it doesn't introduce any new APIs, so it would be nice to get it into the 7.2 release.

Overall, it looks good. I left two comments on the core PR:

As a side note, the core icons are already guaranteed to be safe by a unit test. If any harmful code were ever introduced into a core icon, this test would fail:

/**
* Should preserve every element and attribute of a library icon.
*
* @dataProvider data_library_icons
* @covers WP_Icons_Registry_Gutenberg::sanitize_icon_content
*
* @param string $file_path Absolute path to the library SVG file.
*/
public function test_sanitize_icon_content_preserves_library_icons( string $file_path ) {
$content = file_get_contents( $file_path );
$this->assertEqualHTML( $content, $this->sanitize_icon_content( $content ) );
}

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

[Feature] Icons Related to Icon registration API and Icon REST API [Type] Performance Related to performance efforts

Projects

Status: 🔎 Needs Review

Development

Successfully merging this pull request may close these issues.

2 participants