Repository navigation
Conversation
|
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. |
d6b7a10 to
086c519
Compare
…or does not visit. `data-wp-html` declines on these tags through `has_and_visits_its_closer_tag()`, so its tests rely on this one to cover the full list. It omitted `noembed`, `noframes`, `title` and `xmp`, and listed `iframe` twice.
Tests that reached the same code path with the same kind of value are merged, keeping every behaviour they checked: - The HTML strings with directives and with stray closers become data sets of the byte-for-byte test, and the six-host test now asserts the exact output instead of counting the HTML. - The children of a declining host move into the `null` and not-a-token tests, which replace the separate children test. - The cannot-hold-content, `data-wp-text` and `template` with `data-wp-each` tests, the not-evaluated test, and the two message tests become one structural test. It resolves the reference through a derived-state closure and asserts that nothing is listed, so the value cannot matter, and checks that the notice names the tag or directive. - The unserialized token's listing is asserted by the unserialization test. - The bind-only listing test keeps only its listing assertion, and the authored literals keep a JSON object and a namespaced integer. `test_calls_do_not_share_trusted_html` is removed, as it could not fail. Assertions that repeat an exact output comparison are removed. The forged placeholder test now also holds a lookalike of the extended marker. The context test is renamed to say it is the HTML string that declines. Helpers move before the tests, and `add_hooks()` is no longer called.
The class is private, and every behaviour its tests checked is what `data-wp-html` renders or declines, so they move into the directive tests and their file is removed: - The whitespace, null byte and multibyte strings become data sets of the byte-for-byte test, which now checks them in the rendered output. - The empty string and an array with an `html` key become values that are not tokens. - The unserialization test also renders the token that was serialized, so serializing a token cannot clear its HTML. The tests that only repeated directive tests are dropped: unserialization raising one notice, tokens created with `new` or `clone`, unserialization leaving other tokens alone, and JSON encoding, which the client data tests check.
On a page, directives are processed by `WP_Block::render()` once the root interactive block has rendered, not by a direct call. The new test renders two sibling root interactive blocks whose render callbacks set the same state property to different tokens, and checks that each renders its own HTML with no placeholder left.
- The render test is folded into the test that also checks `data-wp-bind` and the client data, which uses the same data sets and asserts the same output. - The negated reference moves into the full-path test, on a path no `data-wp-html` host references, so that test also checks that a token referenced only by another directive is listed. The separate bind-only, listed-once and unreferenced-token tests go: the full-path test lists repeated paths once, and the context test holds tokens in state that no `state` reference reaches. - The ignored-entries and default-entry tests become one page, where a host with only a suffix and a unique ID entry pointing at a token stays as it is. - The HTML string from context and the per-item decline in `data-wp-each` go, as they take the same paths as the not-a-token and `data-wp-each` tests. - The one-line `expect_html_notices()` and `notice_sources()` helpers are inlined.
Trac ticket: https://core.trac.wordpress.org/ticket/66246
Adds server-side processing for the
data-wp-htmldirective, whose client implementation was merged in WordPress/gutenberg#83092, so that trusted HTML produced in PHP is present in the server-rendered page, including insidedata-wp-eachitems (WordPress/gutenberg#70531).What it adds
wp_interactivity_as_dangerous_html( string $html ): returns aWP_Interactivity_Dangerous_HTMLtoken that marks the HTML as trusted. The token keeps the HTML in a private property, so encoding it as JSON never includes it.data-wp-htmldirective processor. When the reference resolves to a token, the element's content is replaced with the token's HTML, as given. The element keeps its tag and attributes, and its other directives are processed as usual.Behavior
data-wp-context, and anything produced byjson_decode()never render.__wakeup()clears the HTML and raises a_doing_it_wrong()notice, so a page that cached a token keeps working, and the unserialized token never renders.{}.stateis listed inderivedStateClosures, the same way a derived-state closure's path is, so the client keeps the server-rendered content until its store supplies a value. Tokens reached throughcontext, or through the result of a derived-state closure, are not listed._doing_it_wrong()notice is raised when the value is not a token, when the element cannot hold content (void elements andscript,style,textarea,title,iframe,noembed,noframes,xmp), or when the element also carriesdata-wp-textor is atemplatewithdata-wp-each.nulland unresolved references keep the content without a notice.Implementation notes
The processor writes an inert placeholder comment as the element's content, and
process_directives()swaps each placeholder for its HTML with a singlestrtr()pass once processing has finished. The trusted HTML is therefore never scanned, and the processing loop anddata-wp-eachare unchanged. The placeholder marker is chosen so that it never occurs in the input. A newset_raw_content_between_balanced_tags()helper writes the placeholder without escaping.Known limitations, left out of scope:
wp_interactivity_process_directives()starts a new call, so the outer call's placeholders are not substituted. Re-entrant processing is already broken in trunk, because the inner call resets the namespace and context stacks.data-wp-stylereferencing a token fails as it does for any object in trunk (a warning on PHP 7.4, aTypeErroron PHP 8 and later). The general fix, treating every non-scalardata-wp-stylevalue asnull, belongs in a separate ticket.Testing
PHPUnit only; hydration in the browser is covered by the Gutenberg PR.
New test classes:
Tests_WP_Interactivity_API_WP_HtmlandTests_Interactivity_API_WpInteractivityDangerousHtml.Use of AI Tools
AI assistance: Yes
Tool(s): OpenCode, 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, GPT-6.1 Sol
Used for: 100% of the code, tests, and comments in this PR were autonomously generated by AI and reviewed by @DAreRodz 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.