Repository navigation
Interactivity API: Print data-wp-html tokens as the wpServerHtml marker. - #14489
SantosGuillamot wants to merge 1 commit into
Conversation
…marker.
Encode `WP_Interactivity_Dangerous_HTML` tokens as `{"wpServerHtml":true}` on both paths of `wp_json_encode()`, so the client keeps the server-rendered content of a `data-wp-html` host wherever the reference reaches the token, including `data-wp-each` items read from context. Stop listing tokens reached through state in `derivedStateClosures`, which the marker makes unnecessary.
See #66246.
|
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 Core Committers: Use this line as a base for the props when committing in SVN: To understand the WordPress project's expectations around crediting contributors, please review the Contributor Attribution page in the Core Handbook. |
Test using WordPress PlaygroundThe 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
For more details about these limitations and more, check out the Limitations page in the WordPress Playground documentation. |
Follow-up to #14301 (r64386), which added server-side processing of the
data-wp-htmldirective. The client side of this change is Gutenberg #84889; both sides share the{"wpServerHtml":true}representation.What
A
WP_Interactivity_Dangerous_HTMLtoken now prints as the marker{"wpServerHtml":true}wherever the server sends it to the browser: in the Interactivity client data and in the attributewp_interactivity_data_wp_context()prints, at any depth. The server stops listing token paths underderivedStateClosures; derived-state closures are listed as before.Why
Before this change a token printed as
{}, and the server listed each token'sstatepath underderivedStateClosuresso the client would keep the server-rendered content of the host element. That could not cover a token reached throughcontext, such ascontext.item.htmlinside adata-wp-eachloop: the client received a plain{}and, with the client-sidedata-wp-htmldirective from Gutenberg #84652, emptied the element on hydration.With the marker, the client (Gutenberg #84889) recognizes a token's place wherever the reference reaches it and keeps the element's content until the client store supplies a value. The marker carries no HTML, and the
derivedStateClosuresworkaround is no longer needed.How
WP_Interactivity_Dangerous_HTMLimplementsJsonSerializable, sojson_encode()prints the marker, andIteratorAggregate, so the fallback path ofwp_json_encode(), which rebuilds objects withforeachwhen a string is not valid UTF-8, prints it too. The HTML stays in a private property and never reaches JSON.WP_Interactivity_API::evaluate()drops the step that listed token state paths, together with its flag and@sinceline. Closure tracking is unchanged.data-wp-contextattribute,json_decode()output in state) is an array orstdClass, not a token, so it never renders anddata-wp-htmlraises its existing non-token notice.Tests
tests/phpunit/tests/interactivity-api/wpInteractivityAPI-wp-html.php: the{}expectations become the marker, the path-listing assertions go away with the listing, and new coverage checks the marker on both encoding paths ofwp_json_encode(), iteration of a token, and a marker decoded from JSON being refused as a non-token.Testing instructions
Tested with a block temporarily modified to render three
data-wp-htmlelements: one bound to a token in state, two generated bydata-wp-eachover items whosehtmlis a token (context.item.html), and one bound to a token passed through adata-wp-contextattribute generated withwp_interactivity_data_wp_context(). The same page was loaded ontrunkand on this branch.Server HTML (view source, or JavaScript disabled)
data-wp-eachitemsdata-wp-context{"h":{}}{"h":{"wpServerHtml":true}}After hydration (JavaScript enabled)
derivedStateClosuresworkarounddata-wp-eachitemsSCRIPT_DEBUGdata-wp-contextThe
data-wp-eachitems are the bug this fixes. The element bound throughdata-wp-contextshows that a forged marker is harmless: it can only keep content the element already has.Trac ticket: https://core.trac.wordpress.org/ticket/66246
Use of AI Tools
AI assistance: Yes
Tool(s): OpenCode and Claude Code, running an autonomous multi-agent pipeline (Radical Pipelines) that wrote and reviewed each stage separately
Model(s): Claude Opus 5.5, Claude Sonnet 5.5, Claude Fable 5.1, GPT-6 Luna, GPT-6.1 Sol
Used for: 100% of the code, tests, and comments in this PR were autonomously generated by AI and reviewed by @SantosGuillamot before the PR was opened.
This Pull Request is for code review only. Please keep all other discussion in the Trac ticket. Do not merge this Pull Request. See GitHub Pull Requests for Code Review in the Core Handbook for more details.