Skip to content

Editor: Cache the theme.json data merged from all origins - #14071

Closed
sirreal wants to merge 15 commits into
WordPress:trunkfrom
sirreal:theme-json/cache-merged-data
Closed

sirreal wants to merge 15 commits into
WordPress:trunkfrom
sirreal:theme-json/cache-merged-data

Conversation

@sirreal

@sirreal sirreal commented Oct 7, 2026 •

Copy link
Copy Markdown
Member

WP_Theme_JSON_Resolver::get_merged_data() repeats the same merges on every call, including once per block with an is-style-* class. Cache the merged data per origin for the request, and return a clone so callers can modify their copy.

Backport of WordPress/gutenberg#81979.

In Gutenberg on WordPress 7.2-alpha with WP_DEBUG off, a Twenty Twenty-Four front page spent 6.6 ms in 24 merges per request; a post with 52 styled blocks spent 12.9 ms in 58 merges. With the resolver cache, total time in get_merged_data() was about 1.9 ms for either page, including the initial merge. These are Gutenberg measurements, not a separate Core benchmark (method and results).

The cache uses the resolver's existing block-registration check and resets on clean_cached_data(). Remove the redundant wp_get_global_settings() cache so it reads the resolver's current data, including after late block registration. Both caches are per-request; the removed cache's theme development mode bypass did not affect data freshness across requests. This also makes the accessor cache proposed in #13214 unnecessary.

Theme supports changed after the first merge require wp_clean_theme_json_cache(). The wp_theme_json_data_* filters already require a reset after their origin has been cached; see Trac #62249. The block-registration check still detects additions only.

Tests cover per-origin caching, independent returned instances, changes to returned data, late block registration, cache clearing, theme switching, and settings accessor invalidation. Reported local validation: themes, blocks, block-supports and global-styles groups passed (2,118 tests, 15 skipped); phpcs and git diff --check passed.

Trac ticket: https://core.trac.wordpress.org/ticket/66280
Related: https://core.trac.wordpress.org/ticket/62249

Closes #13214.

Use of AI Tools

Claude Code (Claude Fable 5.1) for implementation and tests. Codex (GPT-6) checked the diff and edited the description.


This pull request is for code review only. Keep other discussion in the Trac ticket. Do not merge. See GitHub Pull Requests for Code Review in the Core Handbook.

@github-actions

github-actions Bot commented Oct 7, 2026

Copy link
Copy Markdown

Test using WordPress Playground

The changes in this pull request can previewed and tested using a WordPress Playground instance.

WordPress Playground is an experimental project that creates a full WordPress instance entirely within the browser.

Some things to be aware of

  • All changes will be lost when closing a tab with a Playground instance.
  • All changes will be lost when refreshing the page.
  • A fresh instance is created each time the link below is clicked.
  • Every time this pull request is updated, a new ZIP file containing all changes is created. If changes are not reflected in the Playground instance,
    it's possible that the most recent build failed, or has not completed. Check the list of workflow runs to be sure.

For more details about these limitations and more, check out the Limitations page in the WordPress Playground documentation.

Test this pull request with WordPress Playground.

WP_Theme_JSON_Resolver::get_merged_data() merged the four origins on
every call. Block style variations call it once per block carrying an
is-style-* class, and the stylesheet, settings, duotone and REST callers
add more merges per request.

Cache the merged data per origin for the request, return a clone so
callers can modify the result, discard it when new blocks are
registered, and clear it in clean_cached_data().
The resolver now caches the merged data, so this cache saved one array
read per call. Read through to the resolver on every call and drop the
two cache keys from wp_clean_theme_json_cache().
…a().

Merge each origin behind a condition so the method stores the result once and clones once, matching the Gutenberg pull request.
@sirreal
sirreal force-pushed the theme-json/cache-merged-data branch from 54fdea9 to 75a6e42 Compare October 7, 2026 14:50
… old cache keys.

Match the Gutenberg test from WordPress/gutenberg#81979: the key assertions forbid one past implementation by name and fail only if those exact keys return. Keep the assertion that the accessor reflects resolver data refreshed after a previous call.
@tellthemachines

Copy link
Copy Markdown
Contributor

If we're going with this as alternative to #13214 we should copy the changes from src/wp-includes/block-supports/layout.php from there too.

Match the test name and assertion message from WordPress/gutenberg#81979.
The Gutenberg suite defines WP_DEBUG, which bypassed the plugin's removed
cache, so the test there cannot show that cache's absence. Core's removed
cache was bypassed only in theme development mode, so this test still
fails against it.
@sirreal
sirreal marked this pull request as ready for review October 9, 2026 12:04
@github-actions

github-actions Bot commented Oct 9, 2026 •

Copy link
Copy Markdown

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 props-bot label.

Core Committers: Use this line as a base for the props when committing in SVN:

Props jonsurrell, peterwilsoncc, isabel_brison, ramonopoly, mamaduka.

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

@tellthemachines tellthemachines 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.

Changes match the respective files in Gutenberg PR. Do we also want to bring the tests from phpunit/wp-theme-json-test.php across?

Also let's copy the changes to src/wp-includes/block-supports/layout.php from #13214.

@ramonjd ramonjd left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Ran some tests (local so probably take them with a grain of salt)

Page Request time, median (trunk → PR) Peak memory (trunk → PR) Origins cached Memory the cache adds
Plain post 49.3 → 44.5 ms (−4.8, −10%) 6,141 → 5,968 KB (−172 KB) custom 10.9 KB
Post with 50 section-styled groups 89.4 → 68.2 ms (−21.2, −24%) 6,477 → 6,389 KB (−88 KB) custom 10.9 KB
Post editor 184.8 → 145.5 ms (−39.4, −21%) 11,295 → 11,561 KB (+265 KB) custom, theme 28.3 KB

Comment thread tests/phpunit/tests/theme/wpGetGlobalSettings.php
Comment thread tests/phpunit/tests/theme/wpThemeJsonResolver.php Outdated
@Mamaduka

Copy link
Copy Markdown
Member

Hey, folks

Just wanted to check if there are any blockers here and if we will commit this enhancement before next week's beta 1.

Tag the tests added for the resolver cache and the settings accessor with Trac ticket 66280.
…tion.

Port the styles accessor test from WordPress/gutenberg#81979. The accessor reads the resolver's current data, so a block registered after a previous call appears in the next result.
Remove the static that held the first wp_get_global_styles() result in wp_render_layout_support_flag(). The resolver now caches the merged data, so each read is a cached lookup, and a block registered after the first layout render is reflected in later renders.
@sirreal

sirreal commented Oct 14, 2026

Copy link
Copy Markdown
Member Author

Also let's copy the changes to src/wp-includes/block-supports/layout.php from #13214.

Done in 1458bb3.

Add native parameter and return types to the tests, the data provider, the sentinel helper and the filter closures this change adds, and type the provider's rows in its docblock. Make the data provider static, as the other providers in this directory are.

@tellthemachines tellthemachines 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 updating, LGTM now!

@peterwilsoncc

Copy link
Copy Markdown
Contributor

I've taken the liberty of merging in trunk and removing some unnecessary tear downs in the tests (filters are reset by the test suite's base tear down).

Otherwise let's ship.

@peterwilsoncc peterwilsoncc added the props-bot Adding this label triggers the Props Bot workflow for a PR. label Oct 15, 2026
@github-actions github-actions Bot removed the props-bot Adding this label triggers the Props Bot workflow for a PR. label Oct 15, 2026
wporg-sync pushed a commit that referenced this pull request Oct 15, 2026
`WP_Theme_JSON_Resolver::get_merged_data()` merged all origins on every call, including once for each rendered block with an `is-style-*` class. Cache the result until a block is registered or `wp_clean_theme_json_cache()` is called, and remove the redundant cache in `wp_get_global_settings()`. Theme support changes made after the first merge require `wp_clean_theme_json_cache()`.

Backports WordPress/gutenberg#81979.

Developed in: #14071

Props jonsurrell, peterwilsoncc, isabel_brison, ramonopoly.
Fixes #66280. See #62249.


git-svn-id: https://develop.svn.wordpress.org/trunk@64354 602fd350-edb4-49c9-b593-d223f7449a82
@github-actions

Copy link
Copy Markdown

A commit was made that fixes the Trac ticket referenced in the description of this pull request.

SVN changeset: 64354
GitHub commit: 84b4736

This PR will be closed, but please confirm the accuracy of this and reopen if there is more work to be done.

@github-actions github-actions Bot closed this Oct 15, 2026
wporg-sync pushed a commit to WordPress/WordPress that referenced this pull request Oct 15, 2026
`WP_Theme_JSON_Resolver::get_merged_data()` merged all origins on every call, including once for each rendered block with an `is-style-*` class. Cache the result until a block is registered or `wp_clean_theme_json_cache()` is called, and remove the redundant cache in `wp_get_global_settings()`. Theme support changes made after the first merge require `wp_clean_theme_json_cache()`.

Backports WordPress/gutenberg#81979.

Developed in: WordPress/wordpress-develop#14071

Props jonsurrell, peterwilsoncc, isabel_brison, ramonopoly.
Fixes #66280. See #62249.

Built from https://develop.svn.wordpress.org/trunk@64354


git-svn-id: http://core.svn.wordpress.org/trunk@63504 1a063a9b-81f0-0310-95a4-ce76da25c4cd
@sirreal
sirreal deleted the theme-json/cache-merged-data branch October 15, 2026 07:58
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants