Icons: Register the default icons lazily instead of on every request - #78
Draft
mukeshpanchal27 wants to merge 1 commit into
Draft
Icons: Register the default icons lazily instead of on every request#78mukeshpanchal27 wants to merge 1 commit into
mukeshpanchal27 wants to merge 1 commit into
Conversation
`_wp_register_default_icons()` was hooked to `init` unconditionally, so every request — including front-end requests that never render an icon — included the 88-entry core icon manifest and registered all of it. The manifest calls `_x()` for each label, so this also ran 88 gettext lookups per request. None of that data is used unless something reads the icons registry, which in practice means the editor, the REST API, or a rendered `core/icon` block. Registration now happens on first read of the registry, guarded by a flag on the registry instance. `_wp_register_default_icons()` additionally ensures the `core` collection exists, since a lazy load can now occur before `init`. Measured on trunk, per request: include manifest (88 `_x()` calls) 0.126 ms 88 `register()` calls 0.096 ms total 0.221 ms That cost is now zero for requests that never touch the registry. Verified that the default icons are absent after `init` and present after the first read, and that `wp_get_icon()` still returns valid SVG markup. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Defers registration of the 88 core icons until something actually reads the icons registry, instead of doing it on
initfor every request.Why
default-filters.phphooked registration unconditionally:_wp_register_default_icons()includes a 10.5 KB manifest and registers all 88 icons throughWP_Icons_Registry::register(), which per icon runs twopreg_matchvalidations, anarray_fill_keysallocation, and a key-by-key property check. The generated manifest also calls_x()for every label, so 88 gettext lookups run on every request.None of it is used unless something reads the registry — in practice the editor, the REST API, or a rendered
core/iconblock. A front-end page view that renders no icon pays the full cost and discards it.Measured on trunk, in a booted WordPress (PHP 8.3.2, 2000 iterations, warmed):
includemanifest (88_x()calls)register()callsHow
A
$default_icons_loadedflag on the registry, and aload_default_icons()guard called from the read paths —is_registered()andget_registered_icons().get_registered_icon()andunregister()both route throughis_registered(), so they are covered too._wp_register_default_icons()now also ensures thecorecollection exists, because a lazy load can occur beforeinitfires:Collection registration itself stays on
init— it registers one collection with two__()calls, which is not worth deferring.Behaviour notes
Worth reviewer attention, since these are real changes rather than pure optimisation:
register()still triggers the load, via its existingis_registered()duplicate check. This is deliberate: it keeps duplicate detection semantically identical to today. The trade-off is that a plugin registering its own icon oninitwill pull in the core defaults and forfeit the saving for that site. Makingregister()use a directisset()would avoid that, but would change which party gets the "already registered" notice, so I left it alone.WP_Icon_Collections_Registry::unregister()enumerates registered icons to drop the ones in that collection, and that read populates the defaults first. Unavoidable — you need the full list to know what to remove._wp_register_default_icons()no longer runs oninit. Anything depending on that specific timing would be affected. It remains callable directly and is@access private.Testing
Four tests added to
tests/phpunit/tests/icons/wpIconsRegistry.php, covering: defaults absent before a read, present after a read,is_registered()triggering the load, and the load working when thecorecollection has not been registered yet.They reset the registry singleton explicitly rather than relying on
set_up(), because the existingtear_down()unregisters a test collection after nulling the singleton — and that unregistration reads the registry, lazily populating the replacement instance. Without the explicit reset the assertions leak across tests.Existing suites — all green (MySQL 8.4, PHP 8.3.2), 1868 tests total:
tests/phpunit/tests/icons/tests/phpunit/tests/blocks/tests/phpunit/tests/rest-api/tests/phpunit/tests/block-supports/Behaviour verified directly. Reading
registered_iconsreflectively, so the check does not itself trigger the load:initwp_get_icon('core/arrow-left')Note for the committer
The new tests carry
@ticket 00000placeholders — these need the real Trac ticket number before landing.Context
From a 7.0.4 → 7.1 RC3 benchmark comparison showing a server-side regression on both Block and Classic themes (Block
wp-totalp50 +9.88% / +10.53 ms; Classic +7.92% / +3.99 ms), withLCP − TTFBflat on both — i.e. PHP execution time, not front-end or database. This was one of the fixed per-request costs identified; at 0.221 ms it is roughly 43% of the Classic theme's entirewp-before-templateregression.An alternative approach — moving
_x()out of the generated manifest and translating lazily at read time — was considered and rejected. The manifest is copied verbatim fromgutenberg/packages/icons/src/manifest.phpby aGruntfile.jstask, and those literal_x()calls are what the i18n tooling extracts. Turning them into plain data would silently drop all 88 strings from core's POT, and there is no icon equivalent ofblock-i18n.json/theme-i18n.jsonto declare them. Deferring the include keeps the_x()literals intact and avoids the problem entirely.