Commit bca7ceac1f for wordpress.org
commit bca7ceac1f6922c2c0851ee638c73b4eedc1912b
Author: luisherranz <luisherranz@git.wordpress.org>
Date: Mon Oct 19 12:38:51 2026 +0000
Interactivity API: Print `data-wp-html` tokens as the `wpServerHtml` 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.
Follow-up to [64386].
Props santosguillamot.
Fixes #66246.
Built from https://develop.svn.wordpress.org/trunk@64501
git-svn-id: http://core.svn.wordpress.org/trunk@63651 1a063a9b-81f0-0310-95a4-ce76da25c4cd
diff --git a/wp-includes/interactivity-api/class-wp-interactivity-api.php b/wp-includes/interactivity-api/class-wp-interactivity-api.php
index 6ec333401b..ad6ef564bc 100644
--- a/wp-includes/interactivity-api/class-wp-interactivity-api.php
+++ b/wp-includes/interactivity-api/class-wp-interactivity-api.php
@@ -706,7 +706,6 @@ final class WP_Interactivity_API {
* @since 6.6.0 Removed `default_namespace` and `context` arguments.
* @since 6.6.0 Add support for derived state.
* @since 6.9.0 Receive $entry as an argument instead of the directive value string.
- * @since 7.2.0 Tracks the path of a token that marks HTML as trusted, reached through state.
*
* @param array $entry An array containing a whole directive entry with its namespace, value, suffix, or unique ID.
* @return mixed|null The result of the evaluation. Null if the reference path doesn't exist or the namespace is falsy.
@@ -732,9 +731,8 @@ final class WP_Interactivity_API {
$path = $should_negate_value ? substr( $path, 1 ) : $path;
// Extracts the value from the store using the reference path.
- $path_segments = explode( '.', $path );
- $current = $store;
- $called_closure = false;
+ $path_segments = explode( '.', $path );
+ $current = $store;
foreach ( $path_segments as $index => $path_segment ) {
/*
* Special case for numeric arrays and strings. Add length
@@ -783,8 +781,7 @@ final class WP_Interactivity_API {
*/
array_push( $this->namespace_stack, $ns );
try {
- $called_closure = true;
- $current = $current();
+ $current = $current();
/*
* Tracks derived state properties that are accessed during
@@ -818,28 +815,6 @@ final class WP_Interactivity_API {
}
}
- /*
- * Tracks the tokens that mark HTML as trusted and that a reference
- * reaches through state, the way derived state closures are tracked, so
- * the client keeps the server-rendered content of a token until its
- * store supplies a value. A token reached through context, or through
- * the result of a derived state closure, is not tracked: the client has
- * no context store to resolve it from, and the closure is tracked
- * instead.
- *
- * @since 7.2.0
- */
- if (
- 'state' === $path_segments[0] &&
- ! $called_closure &&
- $current instanceof WP_Interactivity_Dangerous_HTML
- ) {
- $this->derived_state_closures[ $ns ] ??= array();
- if ( ! in_array( $path, $this->derived_state_closures[ $ns ], true ) ) {
- $this->derived_state_closures[ $ns ][] = $path;
- }
- }
-
// Returns the opposite if it contains a negation operator (!).
return $should_negate_value ? ! $current : $current;
}
diff --git a/wp-includes/interactivity-api/class-wp-interactivity-dangerous-html.php b/wp-includes/interactivity-api/class-wp-interactivity-dangerous-html.php
index bcfc8334d7..17ef1b6777 100644
--- a/wp-includes/interactivity-api/class-wp-interactivity-dangerous-html.php
+++ b/wp-includes/interactivity-api/class-wp-interactivity-dangerous-html.php
@@ -14,15 +14,22 @@
* Create tokens with {@see wp_interactivity_as_dangerous_html()}, which
* documents the risks of marking HTML as trusted.
*
- * The HTML is kept in a private property, so encoding a token as JSON never
- * includes it. A token restored by unserialization is inert: it holds no HTML,
- * so it never renders.
+ * The HTML is kept in a private property, so it never reaches JSON: a token
+ * encodes as the marker `{"wpServerHtml":true}`, which tells the client to
+ * keep the content the element already has. The marker holds no HTML. A token
+ * restored by unserialization is inert: it holds no HTML, so it never renders,
+ * and it encodes as the marker too.
+ *
+ * Both JSON encoding paths of `wp_json_encode()` print the marker: `json_encode()`
+ * uses {@see WP_Interactivity_Dangerous_HTML::jsonSerialize()}, and the fallback
+ * for data that is not valid UTF-8 rebuilds the object by iterating it with
+ * {@see WP_Interactivity_Dangerous_HTML::getIterator()}.
*
* @since 7.2.0
*
* @access private
*/
-final class WP_Interactivity_Dangerous_HTML {
+final class WP_Interactivity_Dangerous_HTML implements JsonSerializable, IteratorAggregate {
/**
* The trusted HTML. It is `null` for a token restored by unserialization,
* which never renders.
@@ -73,4 +80,32 @@ final class WP_Interactivity_Dangerous_HTML {
'7.2.0'
);
}
+
+ /**
+ * Gets the value that JSON encoding prints in place of the token.
+ *
+ * It is the same for every token and holds none of its HTML.
+ *
+ * @since 7.2.0
+ *
+ * @return array<string, bool> The marker: a single `wpServerHtml` entry set to `true`,
+ * which `json_encode()` prints as `{"wpServerHtml":true}`.
+ */
+ public function jsonSerialize(): array {
+ return array( 'wpServerHtml' => true );
+ }
+
+ /**
+ * Gets the iterator that `foreach` and the fallback of `wp_json_encode()` read.
+ *
+ * It yields the same single entry as {@see WP_Interactivity_Dangerous_HTML::jsonSerialize()}
+ * and none of the token's HTML.
+ *
+ * @since 7.2.0
+ *
+ * @return Traversable<string, bool> An iterator yielding `wpServerHtml` => `true`, once.
+ */
+ public function getIterator(): Traversable {
+ return new ArrayIterator( $this->jsonSerialize() );
+ }
}
diff --git a/wp-includes/version.php b/wp-includes/version.php
index 4c97486fbf..145bda233f 100644
--- a/wp-includes/version.php
+++ b/wp-includes/version.php
@@ -16,7 +16,7 @@
*
* @global string $wp_version
*/
-$wp_version = '7.2-alpha-64500';
+$wp_version = '7.2-alpha-64501';
/**
* Holds the WordPress DB revision, increments when changes are made to the WordPress DB schema.