<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>[60953] trunk: Interactivity API: Support lazy-loaded derived state props.</title>
</head>
<body>
<style type="text/css"><!--
#msg dl.meta { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; }
#msg dl.meta dt { float: left; width: 6em; font-weight: bold; }
#msg dt:after { content:':';}
#msg dl, #msg dt, #msg ul, #msg li, #header, #footer, #logmsg { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; }
#msg dl a { font-weight: bold}
#msg dl a:link { color:#fc3; }
#msg dl a:active { color:#ff0; }
#msg dl a:visited { color:#cc6; }
h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; }
#msg pre { white-space: pre-line; overflow: auto; background: #ffc; border: 1px #fa0 solid; padding: 6px; }
#logmsg { background: #ffc; border: 1px #fa0 solid; padding: 1em 1em 0 1em; }
#logmsg p, #logmsg pre, #logmsg blockquote { margin: 0 0 1em 0; }
#logmsg p, #logmsg li, #logmsg dt, #logmsg dd { line-height: 14pt; }
#logmsg h1, #logmsg h2, #logmsg h3, #logmsg h4, #logmsg h5, #logmsg h6 { margin: .5em 0; }
#logmsg h1:first-child, #logmsg h2:first-child, #logmsg h3:first-child, #logmsg h4:first-child, #logmsg h5:first-child, #logmsg h6:first-child { margin-top: 0; }
#logmsg ul, #logmsg ol { padding: 0; list-style-position: inside; margin: 0 0 0 1em; }
#logmsg ul { text-indent: -1em; padding-left: 1em; }#logmsg ol { text-indent: -1.5em; padding-left: 1.5em; }
#logmsg > ul, #logmsg > ol { margin: 0 0 1em 0; }
#logmsg pre { background: #eee; padding: 1em; }
#logmsg blockquote { border: 1px solid #fa0; border-left-width: 10px; padding: 1em 1em 0 1em; background: white;}
#logmsg dl { margin: 0; }
#logmsg dt { font-weight: bold; }
#logmsg dd { margin: 0; padding: 0 0 0.5em 0; }
#logmsg dd:before { content:'\00bb';}
#logmsg table { border-spacing: 0px; border-collapse: collapse; border-top: 4px solid #fa0; border-bottom: 1px solid #fa0; background: #fff; }
#logmsg table th { text-align: left; font-weight: normal; padding: 0.2em 0.5em; border-top: 1px dotted #fa0; }
#logmsg table td { text-align: right; border-top: 1px dotted #fa0; padding: 0.2em 0.5em; }
#logmsg table thead th { text-align: center; border-bottom: 1px solid #fa0; }
#logmsg table th.Corner { text-align: left; }
#logmsg hr { border: none 0; border-top: 2px dashed #fa0; height: 1px; }
#header, #footer { color: #fff; background: #636; border: 1px #300 solid; padding: 6px; }
#patch { width: 100%; }
#patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;}
#patch .propset h4, #patch .binary h4 {margin:0;}
#patch pre {padding:0;line-height:1.2em;margin:0;}
#patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;}
#patch .propset .diff, #patch .binary .diff {padding:10px 0;}
#patch span {display:block;padding:0 10px;}
#patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;}
#patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;}
#patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;}
#patch .lines, .info {color:#888;background:#fff;}
--></style>
<div id="msg">
<dl class="meta" style="font-size: 105%">
<dt style="float: left; width: 6em; font-weight: bold">Revision</dt> <dd><a style="font-weight: bold" href="https://core.trac.wordpress.org/changeset/60953">60953</a><script type="application/ld+json">{"@context":"http://schema.org","@type":"EmailMessage","description":"Review this Commit","action":{"@type":"ViewAction","url":"https://core.trac.wordpress.org/changeset/60953","name":"Review Commit"}}</script></dd>
<dt style="float: left; width: 6em; font-weight: bold">Author</dt> <dd>luisherranz</dd>
<dt style="float: left; width: 6em; font-weight: bold">Date</dt> <dd>2025-10-17 14:33:53 +0000 (Fri, 17 Oct 2025)</dd>
</dl>
<pre style='padding-left: 1em; margin: 2em 0; border-left: 2px solid #ccc; line-height: 1.25; font-size: 105%; font-family: sans-serif'>Interactivity API: Support lazy-loaded derived state props.
Serialize on the server the paths of derived state closures accessed during directive processing and include them in the serialized data. During the Interactivity API hydration, if a directive reads one of those paths before its JavaScript getter is available, keep the server-rendered value intact instead of replacing it with `undefined`.
props darerodz.
Fixes <a href="https://core.trac.wordpress.org/ticket/63898">#63898</a>.</pre>
<h3>Modified Paths</h3>
<ul>
<li><a href="#trunksrcwpincludesinteractivityapiclasswpinteractivityapiphp">trunk/src/wp-includes/interactivity-api/class-wp-interactivity-api.php</a></li>
<li><a href="#trunktestsphpunittestsinteractivityapiwpInteractivityAPIwpeachphp">trunk/tests/phpunit/tests/interactivity-api/wpInteractivityAPI-wp-each.php</a></li>
<li><a href="#trunktestsphpunittestsinteractivityapiwpInteractivityAPIphp">trunk/tests/phpunit/tests/interactivity-api/wpInteractivityAPI.php</a></li>
</ul>
</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunksrcwpincludesinteractivityapiclasswpinteractivityapiphp"></a>
<div class="modfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Modified: trunk/src/wp-includes/interactivity-api/class-wp-interactivity-api.php</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/src/wp-includes/interactivity-api/class-wp-interactivity-api.php 2025-10-17 10:10:49 UTC (rev 60952)
+++ trunk/src/wp-includes/interactivity-api/class-wp-interactivity-api.php 2025-10-17 14:33:53 UTC (rev 60953)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -59,6 +59,18 @@
</span><span class="cx" style="display: block; padding: 0 10px"> private $config_data = array();
</span><span class="cx" style="display: block; padding: 0 10px">
</span><span class="cx" style="display: block; padding: 0 10px"> /**
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ * Keeps track of all derived state closures accessed during server-side rendering.
+ *
+ * This data is serialized and sent to the client as part of the interactivity
+ * data, and is handled later in the client to support derived state props that
+ * are lazily hydrated.
+ *
+ * @since 6.9.0
+ * @var array
+ */
+ private $derived_state_closures = array();
+
+ /**
</ins><span class="cx" style="display: block; padding: 0 10px"> * Flag that indicates whether the `data-wp-router-region` directive has
</span><span class="cx" style="display: block; padding: 0 10px"> * been found in the HTML and processed.
</span><span class="cx" style="display: block; padding: 0 10px"> *
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -236,12 +248,17 @@
</span><span class="cx" style="display: block; padding: 0 10px"> * interactivity stores and the configuration will be available using a `getConfig` utility.
</span><span class="cx" style="display: block; padding: 0 10px"> *
</span><span class="cx" style="display: block; padding: 0 10px"> * @since 6.7.0
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ * @since 6.9.0 Serializes derived state props accessed during directive processing.
</ins><span class="cx" style="display: block; padding: 0 10px"> *
</span><span class="cx" style="display: block; padding: 0 10px"> * @param array $data Data to filter.
</span><span class="cx" style="display: block; padding: 0 10px"> * @return array Data for the Interactivity API script module.
</span><span class="cx" style="display: block; padding: 0 10px"> */
</span><span class="cx" style="display: block; padding: 0 10px"> public function filter_script_module_interactivity_data( array $data ): array {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- if ( empty( $this->state_data ) && empty( $this->config_data ) ) {
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ if (
+ empty( $this->state_data ) &&
+ empty( $this->config_data ) &&
+ empty( $this->derived_state_closures )
+ ) {
</ins><span class="cx" style="display: block; padding: 0 10px"> return $data;
</span><span class="cx" style="display: block; padding: 0 10px"> }
</span><span class="cx" style="display: block; padding: 0 10px">
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -265,6 +282,16 @@
</span><span class="cx" style="display: block; padding: 0 10px"> $data['state'] = $state;
</span><span class="cx" style="display: block; padding: 0 10px"> }
</span><span class="cx" style="display: block; padding: 0 10px">
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ $derived_props = array();
+ foreach ( $this->derived_state_closures as $key => $value ) {
+ if ( ! empty( $value ) ) {
+ $derived_props[ $key ] = $value;
+ }
+ }
+ if ( ! empty( $derived_props ) ) {
+ $data['derivedStateClosures'] = $derived_props;
+ }
+
</ins><span class="cx" style="display: block; padding: 0 10px"> return $data;
</span><span class="cx" style="display: block; padding: 0 10px"> }
</span><span class="cx" style="display: block; padding: 0 10px">
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -598,7 +625,7 @@
</span><span class="cx" style="display: block; padding: 0 10px"> // Extracts the value from the store using the reference path.
</span><span class="cx" style="display: block; padding: 0 10px"> $path_segments = explode( '.', $path );
</span><span class="cx" style="display: block; padding: 0 10px"> $current = $store;
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- foreach ( $path_segments as $path_segment ) {
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ foreach ( $path_segments as $index => $path_segment ) {
</ins><span class="cx" style="display: block; padding: 0 10px"> /*
</span><span class="cx" style="display: block; padding: 0 10px"> * Special case for numeric arrays and strings. Add length
</span><span class="cx" style="display: block; padding: 0 10px"> * property mimicking JavaScript behavior.
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -647,6 +674,20 @@
</span><span class="cx" style="display: block; padding: 0 10px"> array_push( $this->namespace_stack, $ns );
</span><span class="cx" style="display: block; padding: 0 10px"> try {
</span><span class="cx" style="display: block; padding: 0 10px"> $current = $current();
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+
+ /*
+ * Tracks derived state properties that are accessed during
+ * rendering.
+ *
+ * @since 6.9.0
+ */
+ $this->derived_state_closures[ $ns ] = $this->derived_state_closures[ $ns ] ?? array();
+
+ // Builds path for the current property and add it to tracking if not already present.
+ $current_path = implode( '.', array_slice( $path_segments, 0, $index + 1 ) );
+ if ( ! in_array( $current_path, $this->derived_state_closures[ $ns ], true ) ) {
+ $this->derived_state_closures[ $ns ][] = $current_path;
+ }
</ins><span class="cx" style="display: block; padding: 0 10px"> } catch ( Throwable $e ) {
</span><span class="cx" style="display: block; padding: 0 10px"> _doing_it_wrong(
</span><span class="cx" style="display: block; padding: 0 10px"> __METHOD__,
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -1160,6 +1201,7 @@
</span><span class="cx" style="display: block; padding: 0 10px"> * `template` tag.
</span><span class="cx" style="display: block; padding: 0 10px"> *
</span><span class="cx" style="display: block; padding: 0 10px"> * @since 6.5.0
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ * @since 6.9.0 Include the list path in the rendered `data-wp-each-child` directives.
</ins><span class="cx" style="display: block; padding: 0 10px"> *
</span><span class="cx" style="display: block; padding: 0 10px"> * @param WP_Interactivity_API_Directives_Processor $p The directives processor instance.
</span><span class="cx" style="display: block; padding: 0 10px"> * @param string $mode Whether the processing is entering or exiting the tag.
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -1205,8 +1247,8 @@
</span><span class="cx" style="display: block; padding: 0 10px"> }
</span><span class="cx" style="display: block; padding: 0 10px">
</span><span class="cx" style="display: block; padding: 0 10px"> // Extracts the namespace from the directive attribute value.
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- $namespace_value = end( $this->namespace_stack );
- list( $namespace_value ) = is_string( $attribute_value ) && ! empty( $attribute_value )
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ $namespace_value = end( $this->namespace_stack );
+ list( $namespace_value, $path ) = is_string( $attribute_value ) && ! empty( $attribute_value )
</ins><span class="cx" style="display: block; padding: 0 10px"> ? $this->extract_directive_value( $attribute_value, $namespace_value )
</span><span class="cx" style="display: block; padding: 0 10px"> : array( $namespace_value, null );
</span><span class="cx" style="display: block; padding: 0 10px">
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -1228,10 +1270,20 @@
</span><span class="cx" style="display: block; padding: 0 10px"> return;
</span><span class="cx" style="display: block; padding: 0 10px"> }
</span><span class="cx" style="display: block; padding: 0 10px">
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- // Adds the `data-wp-each-child` to each top-level tag.
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ /*
+ * Adds the `data-wp-each-child` directive to each top-level tag
+ * rendered by this `data-wp-each` directive. The value is the
+ * `data-wp-each` directive's namespace and path.
+ *
+ * Nested `data-wp-each` directives could render
+ * `data-wp-each-child` elements at the top level as well, and
+ * they should be overwritten.
+ *
+ * @since 6.9.0
+ */
</ins><span class="cx" style="display: block; padding: 0 10px"> $i = new WP_Interactivity_API_Directives_Processor( $processed_item );
</span><span class="cx" style="display: block; padding: 0 10px"> while ( $i->next_tag() ) {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- $i->set_attribute( 'data-wp-each-child', true );
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ $i->set_attribute( 'data-wp-each-child', $namespace_value . '::' . $path );
</ins><span class="cx" style="display: block; padding: 0 10px"> $i->next_balanced_tag_closer_tag();
</span><span class="cx" style="display: block; padding: 0 10px"> }
</span><span class="cx" style="display: block; padding: 0 10px"> $processed_content .= $i->get_updated_html();
</span></span></pre></div>
<a id="trunktestsphpunittestsinteractivityapiwpInteractivityAPIwpeachphp"></a>
<div class="modfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Modified: trunk/tests/phpunit/tests/interactivity-api/wpInteractivityAPI-wp-each.php</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/tests/phpunit/tests/interactivity-api/wpInteractivityAPI-wp-each.php 2025-10-17 10:10:49 UTC (rev 60952)
+++ trunk/tests/phpunit/tests/interactivity-api/wpInteractivityAPI-wp-each.php 2025-10-17 14:33:53 UTC (rev 60953)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -88,8 +88,8 @@
</span><span class="cx" style="display: block; padding: 0 10px"> '<template data-wp-each="myPlugin::state.list">' .
</span><span class="cx" style="display: block; padding: 0 10px"> '<span data-wp-text="myPlugin::context.item"></span>' .
</span><span class="cx" style="display: block; padding: 0 10px"> '</template>' .
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- '<span data-wp-each-child data-wp-text="myPlugin::context.item">1</span>' .
- '<span data-wp-each-child data-wp-text="myPlugin::context.item">2</span>' .
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ '<span data-wp-each-child="myPlugin::state.list" data-wp-text="myPlugin::context.item">1</span>' .
+ '<span data-wp-each-child="myPlugin::state.list" data-wp-text="myPlugin::context.item">2</span>' .
</ins><span class="cx" style="display: block; padding: 0 10px"> '<div id="after-wp-each" data-wp-bind--id="myPlugin::state.after">Text</div>';
</span><span class="cx" style="display: block; padding: 0 10px"> $new = $this->interactivity->process_directives( $original );
</span><span class="cx" style="display: block; padding: 0 10px"> $this->assertSame( $expected, $new );
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -140,8 +140,8 @@
</span><span class="cx" style="display: block; padding: 0 10px"> '<template data-wp-each="myPlugin::state.list">' .
</span><span class="cx" style="display: block; padding: 0 10px"> '<span data-wp-bind--id="myPlugin::context.id" data-wp-text="myPlugin::context.item"></span>' .
</span><span class="cx" style="display: block; padding: 0 10px"> '</template>' .
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- '<span data-wp-each-child id="some-id" data-wp-bind--id="myPlugin::context.id" data-wp-text="myPlugin::context.item">1</span>' .
- '<span data-wp-each-child id="some-id" data-wp-bind--id="myPlugin::context.id" data-wp-text="myPlugin::context.item">2</span>' .
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ '<span data-wp-each-child="myPlugin::state.list" id="some-id" data-wp-bind--id="myPlugin::context.id" data-wp-text="myPlugin::context.item">1</span>' .
+ '<span data-wp-each-child="myPlugin::state.list" id="some-id" data-wp-bind--id="myPlugin::context.id" data-wp-text="myPlugin::context.item">2</span>' .
</ins><span class="cx" style="display: block; padding: 0 10px"> '<div id="after-wp-each" data-wp-bind--id="myPlugin::context.after" data-wp-text="myPlugin::context.item">New text</div>' .
</span><span class="cx" style="display: block; padding: 0 10px"> '</div>';
</span><span class="cx" style="display: block; padding: 0 10px"> $new = $this->interactivity->process_directives( $original );
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -168,8 +168,8 @@
</span><span class="cx" style="display: block; padding: 0 10px"> '<template data-wp-each="myPlugin::context.list">' .
</span><span class="cx" style="display: block; padding: 0 10px"> '<span data-wp-text="myPlugin::context.item"></span>' .
</span><span class="cx" style="display: block; padding: 0 10px"> '</template>' .
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- '<span data-wp-each-child data-wp-text="myPlugin::context.item">1</span>' .
- '<span data-wp-each-child data-wp-text="myPlugin::context.item">2</span>' .
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ '<span data-wp-each-child="myPlugin::context.list" data-wp-text="myPlugin::context.item">1</span>' .
+ '<span data-wp-each-child="myPlugin::context.list" data-wp-text="myPlugin::context.item">2</span>' .
</ins><span class="cx" style="display: block; padding: 0 10px"> '<div id="after-wp-each" data-wp-bind--id="myPlugin::state.after">Text</div>' .
</span><span class="cx" style="display: block; padding: 0 10px"> '</div>';
</span><span class="cx" style="display: block; padding: 0 10px"> $new = $this->interactivity->process_directives( $original );
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -196,8 +196,8 @@
</span><span class="cx" style="display: block; padding: 0 10px"> '<template data-wp-each="state.list">' .
</span><span class="cx" style="display: block; padding: 0 10px"> '<span data-wp-text="context.item"></span>' .
</span><span class="cx" style="display: block; padding: 0 10px"> '</template>' .
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- '<span data-wp-each-child data-wp-text="context.item">1</span>' .
- '<span data-wp-each-child data-wp-text="context.item">2</span>' .
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ '<span data-wp-each-child="myPlugin::state.list" data-wp-text="context.item">1</span>' .
+ '<span data-wp-each-child="myPlugin::state.list" data-wp-text="context.item">2</span>' .
</ins><span class="cx" style="display: block; padding: 0 10px"> '<div id="after-wp-each" data-wp-bind--id="state.after">Text</div>' .
</span><span class="cx" style="display: block; padding: 0 10px"> '</div>';
</span><span class="cx" style="display: block; padding: 0 10px"> $new = $this->interactivity->process_directives( $original );
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -223,10 +223,10 @@
</span><span class="cx" style="display: block; padding: 0 10px"> '<span data-wp-text="myPlugin::context.item"></span>' .
</span><span class="cx" style="display: block; padding: 0 10px"> '<span data-wp-text="myPlugin::context.item"></span>' .
</span><span class="cx" style="display: block; padding: 0 10px"> '</template>' .
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- '<span data-wp-each-child data-wp-text="myPlugin::context.item">1</span>' .
- '<span data-wp-each-child data-wp-text="myPlugin::context.item">1</span>' .
- '<span data-wp-each-child data-wp-text="myPlugin::context.item">2</span>' .
- '<span data-wp-each-child data-wp-text="myPlugin::context.item">2</span>' .
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ '<span data-wp-each-child="myPlugin::state.list" data-wp-text="myPlugin::context.item">1</span>' .
+ '<span data-wp-each-child="myPlugin::state.list" data-wp-text="myPlugin::context.item">1</span>' .
+ '<span data-wp-each-child="myPlugin::state.list" data-wp-text="myPlugin::context.item">2</span>' .
+ '<span data-wp-each-child="myPlugin::state.list" data-wp-text="myPlugin::context.item">2</span>' .
</ins><span class="cx" style="display: block; padding: 0 10px"> '<div id="after-wp-each" data-wp-bind--id="myPlugin::state.after">Text</div>';
</span><span class="cx" style="display: block; padding: 0 10px"> $new = $this->interactivity->process_directives( $original );
</span><span class="cx" style="display: block; padding: 0 10px"> $this->assertSame( $expected, $new );
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -251,10 +251,10 @@
</span><span class="cx" style="display: block; padding: 0 10px"> '<img data-wp-bind--id="myPlugin::context.item">' .
</span><span class="cx" style="display: block; padding: 0 10px"> '<img data-wp-bind--id="myPlugin::context.item">' .
</span><span class="cx" style="display: block; padding: 0 10px"> '</template>' .
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- '<img data-wp-each-child id="1" data-wp-bind--id="myPlugin::context.item">' .
- '<img data-wp-each-child id="1" data-wp-bind--id="myPlugin::context.item">' .
- '<img data-wp-each-child id="2" data-wp-bind--id="myPlugin::context.item">' .
- '<img data-wp-each-child id="2" data-wp-bind--id="myPlugin::context.item">' .
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ '<img data-wp-each-child="myPlugin::state.list" id="1" data-wp-bind--id="myPlugin::context.item">' .
+ '<img data-wp-each-child="myPlugin::state.list" id="1" data-wp-bind--id="myPlugin::context.item">' .
+ '<img data-wp-each-child="myPlugin::state.list" id="2" data-wp-bind--id="myPlugin::context.item">' .
+ '<img data-wp-each-child="myPlugin::state.list" id="2" data-wp-bind--id="myPlugin::context.item">' .
</ins><span class="cx" style="display: block; padding: 0 10px"> '<div id="after-wp-each" data-wp-bind--id="myPlugin::state.after">Text</div>';
</span><span class="cx" style="display: block; padding: 0 10px"> $new = $this->interactivity->process_directives( $original );
</span><span class="cx" style="display: block; padding: 0 10px"> $this->assertSame( $expected, $new );
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -280,10 +280,10 @@
</span><span class="cx" style="display: block; padding: 0 10px"> '<img data-wp-bind--id="myPlugin::context.item">' .
</span><span class="cx" style="display: block; padding: 0 10px"> '<span data-wp-text="myPlugin::context.item"></span>' .
</span><span class="cx" style="display: block; padding: 0 10px"> '</template>' .
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- '<img data-wp-each-child id="1" data-wp-bind--id="myPlugin::context.item">' .
- '<span data-wp-each-child data-wp-text="myPlugin::context.item">1</span>' .
- '<img data-wp-each-child id="2" data-wp-bind--id="myPlugin::context.item">' .
- '<span data-wp-each-child data-wp-text="myPlugin::context.item">2</span>' .
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ '<img data-wp-each-child="myPlugin::state.list" id="1" data-wp-bind--id="myPlugin::context.item">' .
+ '<span data-wp-each-child="myPlugin::state.list" data-wp-text="myPlugin::context.item">1</span>' .
+ '<img data-wp-each-child="myPlugin::state.list" id="2" data-wp-bind--id="myPlugin::context.item">' .
+ '<span data-wp-each-child="myPlugin::state.list" data-wp-text="myPlugin::context.item">2</span>' .
</ins><span class="cx" style="display: block; padding: 0 10px"> '<div id="after-wp-each" data-wp-bind--id="myPlugin::state.after">Text</div>';
</span><span class="cx" style="display: block; padding: 0 10px"> $new = $this->interactivity->process_directives( $original );
</span><span class="cx" style="display: block; padding: 0 10px"> $this->assertSame( $expected, $new );
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -310,10 +310,10 @@
</span><span class="cx" style="display: block; padding: 0 10px"> 'id: <span data-wp-text="myPlugin::context.item"></span>' .
</span><span class="cx" style="display: block; padding: 0 10px"> '</div>' .
</span><span class="cx" style="display: block; padding: 0 10px"> '</template>' .
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- '<div data-wp-each-child id="1" data-wp-bind--id="myPlugin::context.item">' .
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ '<div data-wp-each-child="myPlugin::state.list" id="1" data-wp-bind--id="myPlugin::context.item">' .
</ins><span class="cx" style="display: block; padding: 0 10px"> 'id: <span data-wp-text="myPlugin::context.item">1</span>' .
</span><span class="cx" style="display: block; padding: 0 10px"> '</div>' .
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- '<div data-wp-each-child id="2" data-wp-bind--id="myPlugin::context.item">' .
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ '<div data-wp-each-child="myPlugin::state.list" id="2" data-wp-bind--id="myPlugin::context.item">' .
</ins><span class="cx" style="display: block; padding: 0 10px"> 'id: <span data-wp-text="myPlugin::context.item">2</span>' .
</span><span class="cx" style="display: block; padding: 0 10px"> '</div>' .
</span><span class="cx" style="display: block; padding: 0 10px"> '<div id="after-wp-each" data-wp-bind--id="myPlugin::state.after">Text</div>';
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -355,10 +355,10 @@
</span><span class="cx" style="display: block; padding: 0 10px"> '<span data-wp-text="myPlugin::context.item.id"></span>' .
</span><span class="cx" style="display: block; padding: 0 10px"> '<span data-wp-text="myPlugin::context.item.name"></span>' .
</span><span class="cx" style="display: block; padding: 0 10px"> '</template>' .
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- '<span data-wp-each-child data-wp-text="myPlugin::context.item.id">1</span>' .
- '<span data-wp-each-child data-wp-text="myPlugin::context.item.name">one</span>' .
- '<span data-wp-each-child data-wp-text="myPlugin::context.item.id">2</span>' .
- '<span data-wp-each-child data-wp-text="myPlugin::context.item.name">two</span>' .
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ '<span data-wp-each-child="myPlugin::state.list" data-wp-text="myPlugin::context.item.id">1</span>' .
+ '<span data-wp-each-child="myPlugin::state.list" data-wp-text="myPlugin::context.item.name">one</span>' .
+ '<span data-wp-each-child="myPlugin::state.list" data-wp-text="myPlugin::context.item.id">2</span>' .
+ '<span data-wp-each-child="myPlugin::state.list" data-wp-text="myPlugin::context.item.name">two</span>' .
</ins><span class="cx" style="display: block; padding: 0 10px"> '<div id="after-wp-each" data-wp-bind--id="myPlugin::state.after">Text</div>';
</span><span class="cx" style="display: block; padding: 0 10px"> $new = $this->interactivity->process_directives( $original );
</span><span class="cx" style="display: block; padding: 0 10px"> $this->assertSame( $expected, $new );
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -381,8 +381,8 @@
</span><span class="cx" style="display: block; padding: 0 10px"> '<template data-wp-each--myitem="myPlugin::state.list">' .
</span><span class="cx" style="display: block; padding: 0 10px"> '<span data-wp-text="myPlugin::context.myitem"></span>' .
</span><span class="cx" style="display: block; padding: 0 10px"> '</template>' .
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- '<span data-wp-each-child data-wp-text="myPlugin::context.myitem">1</span>' .
- '<span data-wp-each-child data-wp-text="myPlugin::context.myitem">2</span>' .
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ '<span data-wp-each-child="myPlugin::state.list" data-wp-text="myPlugin::context.myitem">1</span>' .
+ '<span data-wp-each-child="myPlugin::state.list" data-wp-text="myPlugin::context.myitem">2</span>' .
</ins><span class="cx" style="display: block; padding: 0 10px"> '<div id="after-wp-each" data-wp-bind--id="myPlugin::state.after">Text</div>';
</span><span class="cx" style="display: block; padding: 0 10px"> $new = $this->interactivity->process_directives( $original );
</span><span class="cx" style="display: block; padding: 0 10px"> $this->assertSame( $expected, $new );
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -406,8 +406,8 @@
</span><span class="cx" style="display: block; padding: 0 10px"> '<template data-wp-each--my-item="myPlugin::state.list">' .
</span><span class="cx" style="display: block; padding: 0 10px"> '<span data-wp-text="myPlugin::context.myItem"></span>' .
</span><span class="cx" style="display: block; padding: 0 10px"> '</template>' .
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- '<span data-wp-each-child data-wp-text="myPlugin::context.myItem">1</span>' .
- '<span data-wp-each-child data-wp-text="myPlugin::context.myItem">2</span>' .
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ '<span data-wp-each-child="myPlugin::state.list" data-wp-text="myPlugin::context.myItem">1</span>' .
+ '<span data-wp-each-child="myPlugin::state.list" data-wp-text="myPlugin::context.myItem">2</span>' .
</ins><span class="cx" style="display: block; padding: 0 10px"> '<div id="after-wp-each" data-wp-bind--id="myPlugin::state.after">Text</div>';
</span><span class="cx" style="display: block; padding: 0 10px"> $new = $this->interactivity->process_directives( $original );
</span><span class="cx" style="display: block; padding: 0 10px"> $this->assertSame( $expected, $new );
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -473,18 +473,18 @@
</span><span class="cx" style="display: block; padding: 0 10px"> '<span data-wp-text="myPlugin::context.item2"></span>' .
</span><span class="cx" style="display: block; padding: 0 10px"> '</template>' .
</span><span class="cx" style="display: block; padding: 0 10px"> '</template>' .
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- '<span data-wp-each-child data-wp-text="myPlugin::context.item1">1</span>' .
- '<template data-wp-each-child data-wp-each--item2="myPlugin::state.list2">' .
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ '<span data-wp-each-child="myPlugin::state.list" data-wp-text="myPlugin::context.item1">1</span>' .
+ '<template data-wp-each-child="myPlugin::state.list" data-wp-each--item2="myPlugin::state.list2">' .
</ins><span class="cx" style="display: block; padding: 0 10px"> '<span data-wp-text="myPlugin::context.item2"></span>' .
</span><span class="cx" style="display: block; padding: 0 10px"> '</template>' .
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- '<span data-wp-each-child data-wp-text="myPlugin::context.item2">3</span>' .
- '<span data-wp-each-child data-wp-text="myPlugin::context.item2">4</span>' .
- '<span data-wp-each-child data-wp-text="myPlugin::context.item1">2</span>' .
- '<template data-wp-each-child data-wp-each--item2="myPlugin::state.list2">' .
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ '<span data-wp-each-child="myPlugin::state.list" data-wp-text="myPlugin::context.item2">3</span>' .
+ '<span data-wp-each-child="myPlugin::state.list" data-wp-text="myPlugin::context.item2">4</span>' .
+ '<span data-wp-each-child="myPlugin::state.list" data-wp-text="myPlugin::context.item1">2</span>' .
+ '<template data-wp-each-child="myPlugin::state.list" data-wp-each--item2="myPlugin::state.list2">' .
</ins><span class="cx" style="display: block; padding: 0 10px"> '<span data-wp-text="myPlugin::context.item2"></span>' .
</span><span class="cx" style="display: block; padding: 0 10px"> '</template>' .
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- '<span data-wp-each-child data-wp-text="myPlugin::context.item2">3</span>' .
- '<span data-wp-each-child data-wp-text="myPlugin::context.item2">4</span>' .
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ '<span data-wp-each-child="myPlugin::state.list" data-wp-text="myPlugin::context.item2">3</span>' .
+ '<span data-wp-each-child="myPlugin::state.list" data-wp-text="myPlugin::context.item2">4</span>' .
</ins><span class="cx" style="display: block; padding: 0 10px"> '<div id="after-wp-each" data-wp-bind--id="myPlugin::state.after">Text</div>';
</span><span class="cx" style="display: block; padding: 0 10px"> $new = $this->interactivity->process_directives( $original );
</span><span class="cx" style="display: block; padding: 0 10px"> $this->assertSame( $expected, $new );
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -515,22 +515,22 @@
</span><span class="cx" style="display: block; padding: 0 10px"> '<span data-wp-text="myPlugin::context.item2"></span>' .
</span><span class="cx" style="display: block; padding: 0 10px"> '</template>' .
</span><span class="cx" style="display: block; padding: 0 10px"> '</template>' .
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- '<template data-wp-each-child data-wp-each--item2="myPlugin::state.list2">' .
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ '<template data-wp-each-child="myPlugin::state.list" data-wp-each--item2="myPlugin::state.list2">' .
</ins><span class="cx" style="display: block; padding: 0 10px"> '<span data-wp-text="myPlugin::context.item1"></span>' .
</span><span class="cx" style="display: block; padding: 0 10px"> '<span data-wp-text="myPlugin::context.item2"></span>' .
</span><span class="cx" style="display: block; padding: 0 10px"> '</template>' .
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- '<span data-wp-each-child data-wp-text="myPlugin::context.item1">1</span>' .
- '<span data-wp-each-child data-wp-text="myPlugin::context.item2">3</span>' .
- '<span data-wp-each-child data-wp-text="myPlugin::context.item1">1</span>' .
- '<span data-wp-each-child data-wp-text="myPlugin::context.item2">4</span>' .
- '<template data-wp-each-child data-wp-each--item2="myPlugin::state.list2">' .
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ '<span data-wp-each-child="myPlugin::state.list" data-wp-text="myPlugin::context.item1">1</span>' .
+ '<span data-wp-each-child="myPlugin::state.list" data-wp-text="myPlugin::context.item2">3</span>' .
+ '<span data-wp-each-child="myPlugin::state.list" data-wp-text="myPlugin::context.item1">1</span>' .
+ '<span data-wp-each-child="myPlugin::state.list" data-wp-text="myPlugin::context.item2">4</span>' .
+ '<template data-wp-each-child="myPlugin::state.list" data-wp-each--item2="myPlugin::state.list2">' .
</ins><span class="cx" style="display: block; padding: 0 10px"> '<span data-wp-text="myPlugin::context.item1"></span>' .
</span><span class="cx" style="display: block; padding: 0 10px"> '<span data-wp-text="myPlugin::context.item2"></span>' .
</span><span class="cx" style="display: block; padding: 0 10px"> '</template>' .
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- '<span data-wp-each-child data-wp-text="myPlugin::context.item1">2</span>' .
- '<span data-wp-each-child data-wp-text="myPlugin::context.item2">3</span>' .
- '<span data-wp-each-child data-wp-text="myPlugin::context.item1">2</span>' .
- '<span data-wp-each-child data-wp-text="myPlugin::context.item2">4</span>' .
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ '<span data-wp-each-child="myPlugin::state.list" data-wp-text="myPlugin::context.item1">2</span>' .
+ '<span data-wp-each-child="myPlugin::state.list" data-wp-text="myPlugin::context.item2">3</span>' .
+ '<span data-wp-each-child="myPlugin::state.list" data-wp-text="myPlugin::context.item1">2</span>' .
+ '<span data-wp-each-child="myPlugin::state.list" data-wp-text="myPlugin::context.item2">4</span>' .
</ins><span class="cx" style="display: block; padding: 0 10px"> '<div id="after-wp-each" data-wp-bind--id="myPlugin::state.after">Text</div>';
</span><span class="cx" style="display: block; padding: 0 10px"> $new = $this->interactivity->process_directives( $original );
</span><span class="cx" style="display: block; padding: 0 10px"> $this->assertSame( $expected, $new );
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -559,16 +559,16 @@
</span><span class="cx" style="display: block; padding: 0 10px"> '<span data-wp-text="myPlugin::context.number"></span>' .
</span><span class="cx" style="display: block; padding: 0 10px"> '</template>' .
</span><span class="cx" style="display: block; padding: 0 10px"> '</template>' .
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- '<template data-wp-each-child data-wp-each--number="myPlugin::context.list">' .
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ '<template data-wp-each-child="myPlugin::state.list2" data-wp-each--number="myPlugin::context.list">' .
</ins><span class="cx" style="display: block; padding: 0 10px"> '<span data-wp-text="myPlugin::context.number"></span>' .
</span><span class="cx" style="display: block; padding: 0 10px"> '</template>' .
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- '<span data-wp-each-child data-wp-text="myPlugin::context.number">1</span>' .
- '<span data-wp-each-child data-wp-text="myPlugin::context.number">2</span>' .
- '<template data-wp-each-child data-wp-each--number="myPlugin::context.list">' .
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ '<span data-wp-each-child="myPlugin::state.list2" data-wp-text="myPlugin::context.number">1</span>' .
+ '<span data-wp-each-child="myPlugin::state.list2" data-wp-text="myPlugin::context.number">2</span>' .
+ '<template data-wp-each-child="myPlugin::state.list2" data-wp-each--number="myPlugin::context.list">' .
</ins><span class="cx" style="display: block; padding: 0 10px"> '<span data-wp-text="myPlugin::context.number"></span>' .
</span><span class="cx" style="display: block; padding: 0 10px"> '</template>' .
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- '<span data-wp-each-child data-wp-text="myPlugin::context.number">3</span>' .
- '<span data-wp-each-child data-wp-text="myPlugin::context.number">4</span>' .
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ '<span data-wp-each-child="myPlugin::state.list2" data-wp-text="myPlugin::context.number">3</span>' .
+ '<span data-wp-each-child="myPlugin::state.list2" data-wp-text="myPlugin::context.number">4</span>' .
</ins><span class="cx" style="display: block; padding: 0 10px"> '<div id="after-wp-each" data-wp-bind--id="myPlugin::state.after">Text</div>';
</span><span class="cx" style="display: block; padding: 0 10px"> $new = $this->interactivity->process_directives( $original );
</span><span class="cx" style="display: block; padding: 0 10px"> $this->assertSame( $expected, $new );
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -671,15 +671,15 @@
</span><span class="cx" style="display: block; padding: 0 10px"> '<template data-wp-each="myPlugin::state.list">' .
</span><span class="cx" style="display: block; padding: 0 10px"> '<span data-wp-text="myPlugin::context.item"></span>' .
</span><span class="cx" style="display: block; padding: 0 10px"> '</template>' .
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- '<span data-wp-each-child data-wp-text="myPlugin::context.item">1</span>' .
- '<span data-wp-each-child data-wp-text="myPlugin::context.item">2</span>' .
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ '<span data-wp-each-child="myPlugin::state.list" data-wp-text="myPlugin::context.item">1</span>' .
+ '<span data-wp-each-child="myPlugin::state.list" data-wp-text="myPlugin::context.item">2</span>' .
</ins><span class="cx" style="display: block; padding: 0 10px"> '<div data-wp-bind--id="myPlugin::state.after">Text</div>';
</span><span class="cx" style="display: block; padding: 0 10px"> $expected = '' .
</span><span class="cx" style="display: block; padding: 0 10px"> '<template data-wp-each="myPlugin::state.list">' .
</span><span class="cx" style="display: block; padding: 0 10px"> '<span data-wp-text="myPlugin::context.item"></span>' .
</span><span class="cx" style="display: block; padding: 0 10px"> '</template>' .
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- '<span data-wp-each-child data-wp-text="myPlugin::context.item">1</span>' .
- '<span data-wp-each-child data-wp-text="myPlugin::context.item">2</span>' .
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ '<span data-wp-each-child="myPlugin::state.list" data-wp-text="myPlugin::context.item">1</span>' .
+ '<span data-wp-each-child="myPlugin::state.list" data-wp-text="myPlugin::context.item">2</span>' .
</ins><span class="cx" style="display: block; padding: 0 10px"> '<div id="after-wp-each" data-wp-bind--id="myPlugin::state.after">Text</div>';
</span><span class="cx" style="display: block; padding: 0 10px"> $new = $this->interactivity->process_directives( $original );
</span><span class="cx" style="display: block; padding: 0 10px"> $this->assertSame( $expected, $new );
</span></span></pre></div>
<a id="trunktestsphpunittestsinteractivityapiwpInteractivityAPIphp"></a>
<div class="modfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Modified: trunk/tests/phpunit/tests/interactivity-api/wpInteractivityAPI.php</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/tests/phpunit/tests/interactivity-api/wpInteractivityAPI.php 2025-10-17 10:10:49 UTC (rev 60952)
+++ trunk/tests/phpunit/tests/interactivity-api/wpInteractivityAPI.php 2025-10-17 14:33:53 UTC (rev 60953)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -25,6 +25,7 @@
</span><span class="cx" style="display: block; padding: 0 10px"> public function set_up() {
</span><span class="cx" style="display: block; padding: 0 10px"> parent::set_up();
</span><span class="cx" style="display: block; padding: 0 10px"> $this->interactivity = new WP_Interactivity_API();
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ wp_default_script_modules();
</ins><span class="cx" style="display: block; padding: 0 10px"> }
</span><span class="cx" style="display: block; padding: 0 10px">
</span><span class="cx" style="display: block; padding: 0 10px"> public function charset_iso_8859_1() {
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -315,7 +316,108 @@
</span><span class="cx" style="display: block; padding: 0 10px">
</span><span class="cx" style="display: block; padding: 0 10px"> $this->assertSame( array( 'state' => array( 'myPlugin' => array( 'emptyArray' => array() ) ) ), $filter->get_args()[0][0] );
</span><span class="cx" style="display: block; padding: 0 10px"> }
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ /**
+ * Tests that derived state props invoked during directive evaluation are
+ * serialized correctly.
+ *
+ * @ticket 63898
+ */
+ public function test_invoked_derived_state_props_are_serialized() {
+ $returns_whatever = function () {
+ return 'whatever';
+ };
</ins><span class="cx" style="display: block; padding: 0 10px">
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ $returns_array = function () {
+ return array( 'prop' => 'whatever' );
+ };
+
+ $filter = $this->get_script_data_filter_result(
+ function () use ( $returns_whatever, $returns_array ) {
+ $this->interactivity->state(
+ 'pluginWithInvokedDerivedState',
+ array(
+ 'derivedProp' => $returns_whatever,
+ 'nested' => array(
+ 'derivedProp' => $returns_whatever,
+ 'derivedPropReturnsArray' => $returns_array,
+ ),
+ )
+ );
+
+ $this->interactivity->state(
+ 'pluginWithInvokedDerivedStateReturningArray',
+ array(
+ 'derivedProp' => $returns_whatever,
+ 'nested' => array(
+ 'derivedProp' => $returns_whatever,
+ 'derivedPropReturnsArray' => $returns_array,
+ ),
+ )
+ );
+
+ $this->interactivity->state(
+ 'pluginWithoutInvokedDerivedState',
+ array(
+ 'derivedProp' => $returns_whatever,
+ 'nested' => array(
+ 'derivedProp' => $returns_whatever,
+ ),
+ )
+ );
+
+ $this->set_internal_context_stack( array() );
+
+ // Multiple evaluations should be serialized only once.
+ $this->set_internal_namespace_stack( 'pluginWithInvokedDerivedState' );
+ $this->evaluate( 'state.derivedProp' );
+ $this->evaluate( 'state.derivedProp' );
+ $this->evaluate( 'state.nested.derivedProp' );
+ $this->evaluate( 'state.nested.derivedProp' );
+
+ // Only the path part that points to a derived state prop should be serialized.
+ $this->set_internal_namespace_stack( 'pluginWithInvokedDerivedStateReturningArray' );
+ $this->evaluate( 'state.nested.derivedProp.prop' );
+ }
+ );
+
+ $this->assertSame(
+ array(
+ 'state' => array(
+ 'pluginWithInvokedDerivedState' => array(
+ 'derivedProp' => $returns_whatever,
+ 'nested' => array(
+ 'derivedProp' => $returns_whatever,
+ 'derivedPropReturnsArray' => $returns_array,
+ ),
+ ),
+ 'pluginWithInvokedDerivedStateReturningArray' => array(
+ 'derivedProp' => $returns_whatever,
+ 'nested' => array(
+ 'derivedProp' => $returns_whatever,
+ 'derivedPropReturnsArray' => $returns_array,
+ ),
+ ),
+ 'pluginWithoutInvokedDerivedState' => array(
+ 'derivedProp' => $returns_whatever,
+ 'nested' => array(
+ 'derivedProp' => $returns_whatever,
+ ),
+ ),
+ ),
+ 'derivedStateClosures' => array(
+ 'pluginWithInvokedDerivedState' => array(
+ 'state.derivedProp',
+ 'state.nested.derivedProp',
+ ),
+ 'pluginWithInvokedDerivedStateReturningArray' => array(
+ 'state.nested.derivedProp',
+ ),
+ ),
+ ),
+ $filter->get_args()[0][0]
+ );
+ }
+
</ins><span class="cx" style="display: block; padding: 0 10px"> /**
</span><span class="cx" style="display: block; padding: 0 10px"> * Tests that empty config objects are pruned from printed data.
</span><span class="cx" style="display: block; padding: 0 10px"> *
</span></span></pre>
</div>
</div>
</body>
</html>