Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
172 commits
Select commit Hold shift + click to select a range
b57409e
interactivity-router: preserve dynamically-injected and runtime-activ…
Mar 7, 2026
4685420
Update CHANGELOG for interactivity-router (#76289)
Mar 7, 2026
e00016e
Add unit tests for dynamic stylesheet and deferred media preservation…
Mar 7, 2026
187eeeb
Add E2E tests for dynamic stylesheet preservation (#76289)
Mar 7, 2026
e14388f
line break fixed
Mar 8, 2026
adbd3ff
Fix prettier formatting in router-dynamic-styles spec
Mar 8, 2026
435af0f
feat(e2e): register test/router-dynamic-styles block metadata
Mar 8, 2026
c51a354
feat(e2e): add deferred stylesheet fixture for router-dynamic-styles …
Mar 8, 2026
9ab8d3d
feat(e2e): add interactivity store for test/router-dynamic-styles block
Mar 8, 2026
d3e6ae6
feat(e2e): add render template for test/router-dynamic-styles block
Mar 8, 2026
a79e8c7
fix(e2e): fix lint errors in router-dynamic-styles view.js
Mar 8, 2026
1345e91
fix(e2e): fix prettier formatting in router-dynamic-styles view.js
Mar 8, 2026
14f455a
fix(e2e): remove unused store destructuring in router-dynamic-styles …
Mar 8, 2026
def3a6a
fix(e2e): rewrite router-dynamic-styles view.js - remove getComputedS…
Mar 8, 2026
6e0ee59
refactor(e2e): replace nested ternary with if/else in router-dynamic-…
Mar 8, 2026
18b97dd
feat(e2e): add view.asset.php to declare @wordpress/interactivity mod…
Mar 8, 2026
b612a10
fix(e2e): multi-item array associative keys in view.asset.php
Mar 8, 2026
adfc45a
feat(e2e): register router region in test/router-dynamic-styles block
Mar 8, 2026
9f169f4
docs(interactivity-router): expand CHANGELOG entries for #76289 Bug A…
Mar 8, 2026
eab168a
fix(interactivity-router): match styles by equivalence in applyStyles…
Mar 8, 2026
a66bf4d
fix(interactivity-router): normalize media="not all" and widen router…
Mar 8, 2026
f359af6
fix(interactivity-router): use normalised equality in applyStyles for…
Mar 8, 2026
a535bf1
fix(e2e): Update test to verify CSS application directly
Mar 8, 2026
0bf96cc
fix(interactivity-router): Style matching and management in router
Mar 8, 2026
4464a81
fix(interactivity-router): Unit test to verify href normalization
Mar 8, 2026
414342c
fix(e2e): additional indents complained about by Prettier
Mar 8, 2026
82fc66c
fix(router): update unit test expectation for href normalization
Mar 8, 2026
5fb4cfd
refactor(interactivity-router): seed routerManagedStyles from all ini…
Mar 8, 2026
8ffce45
refactor(e2e): treat null deferred sheet as preserved in router-dynam…
Mar 8, 2026
c17b8af
fix(e2e): revert deferred-style check from toHaveCSS to toHaveText
Mar 8, 2026
79d704d
fix(tests): restore upstream href assertion in normalizeMedia unit test
Mar 8, 2026
a02e511
fix(e2e): changed textdomain to organic
Mar 8, 2026
c776602
fix(e2e): align router-dynamic-styles block.json with e2e-interactivi…
Mar 8, 2026
02b43f3
fix(e2e): move deferred style enqueue into wp_enqueue_scripts hook in…
Mar 8, 2026
38cca72
refactor(e2e): clean up view.js comments in router-dynamic-styles fix…
Mar 8, 2026
b0974e6
fix(e2e): register deferred stylesheet via viewStyle in block.json
Mar 8, 2026
2230182
fix(e2e): set media=not-all via wp_style_add_data in render.php
Mar 8, 2026
607d203
fix(e2e): update deferred link selector to match viewStyle-generated id
Mar 8, 2026
6692aa5
refactor(interactivity-router): fix style normalization and managed s…
Mar 8, 2026
0f1e0f3
test(interactivity-router): fix stylesheet management and plugin sty…
Mar 8, 2026
e712ab3
test2(interactivity-router): fix stylesheet management and plugin sty…
Mar 8, 2026
6bd8971
test3(interactivity-router): fix stylesheet management and plugin st…
Mar 8, 2026
8fa1213
refactor(interactivity-router): clean up applyStyles — remove normali…
Mar 8, 2026
b031a50
refactor(e2e): remove viewStyle from router-dynamic-styles block.json
Mar 8, 2026
4067f13
refactor(e2e): remove wp_style_add_data from router-dynamic-styles re…
Mar 8, 2026
9577974
refactor(e2e): inject deferred style inline in router-dynamic-styles …
Mar 8, 2026
a8842f5
test(e2e): rewrite router-dynamic-styles spec with inline style fixtures
Mar 8, 2026
d631535
test(e2e): rewrite router-dynamic-styles spec with inline style fixtures
Mar 8, 2026
1dfb6e2
refactor(e2e): inject deferred style inline in router-dynamic-styles …
Mar 8, 2026
9306030
refactor(e2e): inject deferred style inline in router-dynamic-styles …
Mar 8, 2026
501dbe9
fix(interactivity-router): preserve deferred and plugin-injected styl…
Mar 8, 2026
46bdccb
test(e2e): inline deferred style fixture for router-dynamic-styles
Mar 8, 2026
cffcf5c
test(e2e): inline plugin and deferred style fixtures in view.js
Mar 8, 2026
b3b582b
test(e2e): Fix PHP fatal error in router-dynamic-styles render
Mar 8, 2026
473d62c
test(e2e): replace module-level refs with DOM getters and stable id i…
Mar 8, 2026
112a132
test(e2e): Updated the Bug B description comment to accurately reflect
Mar 8, 2026
32a5730
test(e2e): Updated JS the Bug B description comment to accurately ref…
Mar 8, 2026
6840a22
fix(test/router-dynamic-styles): use reactive state fields instead of…
Mar 8, 2026
706ffa1
final(e2e): fix preserve runtime-activated and plugin-injected styles…
Mar 8, 2026
016b597
final(interactivity-router): fix preserve runtime-activated and plugi…
Mar 8, 2026
09df3a0
final(interactivity-router): fix JSDoc and preserve runtime-activated…
Mar 8, 2026
8afa169
final(e2e): preserve runtime-activated and plugin-injected styles ren…
Mar 9, 2026
c1210cb
Merge branch 'WordPress:trunk' into fix/spa-navigate-deactivate-dynam…
Mar 9, 2026
b592822
Merge branch 'WordPress:trunk' into fix/spa-navigate-deactivate-dynam…
Mar 9, 2026
b877904
final(e2e): fix view.js therefore, init() is not restarted after navi…
Mar 9, 2026
6d4200c
test(e2e): wire navigation links to iAPI router in router-dynamic-sty…
Mar 9, 2026
8fedc40
test(e2e): add iAPI router navigate action to router-dynamic-styles f…
Mar 9, 2026
2cde888
Merge branch 'WordPress:trunk' into fix/spa-navigate-deactivate-dynam…
Mar 9, 2026
e4fda4c
fix(e2e): fix generator-star-spacing lint error in router-dynamic-sty…
Mar 9, 2026
6ec23f4
fix(e2e): fix PHPCS line-length error in router-dynamic-styles render…
Mar 9, 2026
67d06a5
Merge branch 'WordPress:trunk' into fix/spa-navigate-deactivate-dynam…
Mar 9, 2026
dd60ba9
fix(e2e): Error - Invalid JSDoc tag name
Mar 9, 2026
7f6a9dd
fix(e2e): prettier error view.js
Mar 9, 2026
489e82a
fix(e2e): prettier spacing in router-dynamic-styles view.js
Mar 9, 2026
870a1f0
fix(e2e): call actions.navigate without yield in router-dynamic-style…
Mar 9, 2026
0157c20
fix(e2e): await waitForURL after goBack in back-navigation test
Mar 9, 2026
614990f
Merge branch 'WordPress:trunk' into fix/spa-navigate-deactivate-dynam…
Mar 9, 2026
5b370e6
fix(e2e): replace waitForURL with waitForFunction for SPA back-naviga…
Mar 9, 2026
aaf61f6
fix(e2e): use history.back + toHaveURL for SPA back-navigation in spec
Mar 9, 2026
b0926af
fix(e2e): fix prettier formatting for toHaveURL calls in back-navigat…
Mar 9, 2026
9610479
test(e2e): add nav-to-a link to router-dynamic-styles fixture
Mar 9, 2026
b39c5e9
fix(e2e): replace browser back-navigation with explicit nav-to-a SPA …
Mar 9, 2026
53cd6ef
Merge branch 'WordPress:trunk' into fix/spa-navigate-deactivate-dynam…
Mar 9, 2026
7882744
Merge branch 'WordPress:trunk' into fix/spa-navigate-deactivate-dynam…
markusfoo Mar 9, 2026
96d59dc
Merge branch 'WordPress:trunk' into fix/spa-navigate-deactivate-dynam…
markusfoo Mar 10, 2026
bc157ed
Merge branch 'WordPress:trunk' into fix/spa-navigate-deactivate-dynam…
markusfoo Mar 10, 2026
dd55034
Merge branch 'WordPress:trunk' into fix/spa-navigate-deactivate-dynam…
markusfoo Mar 10, 2026
1661d33
Merge branch 'WordPress:trunk' into fix/spa-navigate-deactivate-dynam…
markusfoo Mar 10, 2026
1a77b2a
Merge branch 'WordPress:trunk' into fix/spa-navigate-deactivate-dynam…
markusfoo Mar 10, 2026
748ff42
Merge branch 'WordPress:trunk' into fix/spa-navigate-deactivate-dynam…
markusfoo Mar 10, 2026
b05e1c3
Merge branch 'WordPress:trunk' into fix/spa-navigate-deactivate-dynam…
markusfoo Mar 11, 2026
cb0a0f2
Merge branch 'WordPress:trunk' into fix/spa-navigate-deactivate-dynam…
markusfoo Mar 11, 2026
c13ee52
Merge branch 'WordPress:trunk' into fix/spa-navigate-deactivate-dynam…
markusfoo Mar 11, 2026
53322ac
fix(interactivity-router): revert areNodesEqual to plain isEqualNode
markusfoo Mar 11, 2026
350aded
test(interactivity-router): update areNodesEqual test comment
markusfoo Mar 11, 2026
ddf0983
Merge branch 'WordPress:trunk' into fix/spa-navigate-deactivate-dynam…
markusfoo Mar 11, 2026
a75db33
Merge branch 'WordPress:trunk' into fix/spa-navigate-deactivate-dynam…
markusfoo Mar 12, 2026
828e917
Merge branch 'WordPress:trunk' into fix/spa-navigate-deactivate-dynam…
markusfoo Mar 12, 2026
42c42e8
Merge branch 'WordPress:trunk' into fix/spa-navigate-deactivate-dynam…
markusfoo Mar 12, 2026
63bbb04
Merge branch 'WordPress:trunk' into fix/spa-navigate-deactivate-dynam…
markusfoo Mar 12, 2026
b346998
Merge branch 'WordPress:trunk' into fix/spa-navigate-deactivate-dynam…
markusfoo Mar 12, 2026
0ae2cc8
Merge branch 'WordPress:trunk' into fix/spa-navigate-deactivate-dynam…
markusfoo Mar 12, 2026
5a0368b
Merge branch 'WordPress:trunk' into fix/spa-navigate-deactivate-dynam…
markusfoo Mar 13, 2026
970e87e
Merge branch 'WordPress:trunk' into fix/spa-navigate-deactivate-dynam…
markusfoo Mar 13, 2026
a42f1ba
Merge branch 'WordPress:trunk' into fix/spa-navigate-deactivate-dynam…
markusfoo Mar 13, 2026
c755985
Merge branch 'WordPress:trunk' into fix/spa-navigate-deactivate-dynam…
markusfoo Mar 13, 2026
a0c8ea0
Merge branch 'WordPress:trunk' into fix/spa-navigate-deactivate-dynam…
markusfoo Mar 13, 2026
51f99ae
Merge branch 'WordPress:trunk' into fix/spa-navigate-deactivate-dynam…
markusfoo Mar 13, 2026
7db29c3
Merge branch 'WordPress:trunk' into fix/spa-navigate-deactivate-dynam…
markusfoo Mar 14, 2026
d7be885
Merge branch 'WordPress:trunk' into fix/spa-navigate-deactivate-dynam…
markusfoo Mar 14, 2026
d982c0d
Merge branch 'WordPress:trunk' into fix/spa-navigate-deactivate-dynam…
markusfoo Mar 16, 2026
240c3b7
Merge branch 'WordPress:trunk' into fix/spa-navigate-deactivate-dynam…
markusfoo Mar 16, 2026
b41bde1
Merge branch 'WordPress:trunk' into fix/spa-navigate-deactivate-dynam…
markusfoo Mar 16, 2026
52c5ad8
Merge branch 'WordPress:trunk' into fix/spa-navigate-deactivate-dynam…
markusfoo Mar 16, 2026
5acc2c5
Merge branch 'WordPress:trunk' into fix/spa-navigate-deactivate-dynam…
markusfoo Mar 17, 2026
c9303ea
Merge branch 'WordPress:trunk' into fix/spa-navigate-deactivate-dynam…
markusfoo Mar 17, 2026
2a9988a
Merge branch 'WordPress:trunk' into fix/spa-navigate-deactivate-dynam…
markusfoo Mar 17, 2026
611dc50
Merge branch 'WordPress:trunk' into fix/spa-navigate-deactivate-dynam…
markusfoo Mar 18, 2026
33663f9
Merge branch 'WordPress:trunk' into fix/spa-navigate-deactivate-dynam…
markusfoo Mar 19, 2026
25b280f
Merge branch 'WordPress:trunk' into fix/spa-navigate-deactivate-dynam…
markusfoo Mar 19, 2026
e85cd05
Merge branch 'WordPress:trunk' into fix/spa-navigate-deactivate-dynam…
markusfoo Mar 19, 2026
b53c00b
Merge branch 'WordPress:trunk' into fix/spa-navigate-deactivate-dynam…
markusfoo Mar 20, 2026
9cb1eec
Merge branch 'WordPress:trunk' into fix/spa-navigate-deactivate-dynam…
markusfoo Mar 20, 2026
ec81224
Merge branch 'WordPress:trunk' into fix/spa-navigate-deactivate-dynam…
markusfoo Mar 21, 2026
2db8144
Merge branch 'WordPress:trunk' into fix/spa-navigate-deactivate-dynam…
markusfoo Mar 23, 2026
92db615
Merge branch 'WordPress:trunk' into fix/spa-navigate-deactivate-dynam…
markusfoo Mar 23, 2026
8d30da5
Merge branch 'WordPress:trunk' into fix/spa-navigate-deactivate-dynam…
markusfoo Mar 24, 2026
623e1d9
Merge branch 'WordPress:trunk' into fix/spa-navigate-deactivate-dynam…
markusfoo Mar 24, 2026
5b4cfa8
Merge branch 'WordPress:trunk' into fix/spa-navigate-deactivate-dynam…
markusfoo Mar 25, 2026
26540b8
Merge branch 'WordPress:trunk' into fix/spa-navigate-deactivate-dynam…
markusfoo Mar 25, 2026
0f124b9
Merge branch 'WordPress:trunk' into fix/spa-navigate-deactivate-dynam…
markusfoo Mar 26, 2026
1122fd7
Merge branch 'WordPress:trunk' into fix/spa-navigate-deactivate-dynam…
markusfoo Mar 26, 2026
cacb3c0
Merge branch 'WordPress:trunk' into fix/spa-navigate-deactivate-dynam…
markusfoo Mar 26, 2026
0c90cb4
Merge branch 'WordPress:trunk' into fix/spa-navigate-deactivate-dynam…
markusfoo Mar 26, 2026
d357044
Merge branch 'WordPress:trunk' into fix/spa-navigate-deactivate-dynam…
markusfoo Mar 26, 2026
2df66a8
Merge branch 'WordPress:trunk' into fix/spa-navigate-deactivate-dynam…
markusfoo Mar 27, 2026
6da4b23
Merge branch 'WordPress:trunk' into fix/spa-navigate-deactivate-dynam…
markusfoo Mar 27, 2026
9f18c83
Merge branch 'WordPress:trunk' into fix/spa-navigate-deactivate-dynam…
markusfoo Mar 28, 2026
92c267e
Merge branch 'WordPress:trunk' into fix/spa-navigate-deactivate-dynam…
markusfoo Mar 30, 2026
5e7107e
Merge branch 'WordPress:trunk' into fix/spa-navigate-deactivate-dynam…
markusfoo Mar 31, 2026
b50b9c9
Merge branch 'WordPress:trunk' into fix/spa-navigate-deactivate-dynam…
markusfoo Apr 1, 2026
021d8ce
Merge branch 'WordPress:trunk' into fix/spa-navigate-deactivate-dynam…
markusfoo Apr 1, 2026
f431b2d
Merge branch 'WordPress:trunk' into fix/spa-navigate-deactivate-dynam…
markusfoo Apr 2, 2026
2e58363
Merge branch 'WordPress:trunk' into fix/spa-navigate-deactivate-dynam…
markusfoo Apr 2, 2026
38dad0e
Merge branch 'WordPress:trunk' into fix/spa-navigate-deactivate-dynam…
markusfoo Apr 3, 2026
314976b
Merge branch 'WordPress:trunk' into fix/spa-navigate-deactivate-dynam…
markusfoo Apr 3, 2026
bf4d8ce
Merge branch 'WordPress:trunk' into fix/spa-navigate-deactivate-dynam…
markusfoo Apr 6, 2026
dccb50d
Merge branch 'WordPress:trunk' into fix/spa-navigate-deactivate-dynam…
markusfoo Apr 7, 2026
b5917f0
Merge branch 'WordPress:trunk' into fix/spa-navigate-deactivate-dynam…
markusfoo Apr 8, 2026
af24ff3
Merge branch 'WordPress:trunk' into fix/spa-navigate-deactivate-dynam…
markusfoo Apr 12, 2026
3b3fe69
Merge branch 'WordPress:trunk' into fix/spa-navigate-deactivate-dynam…
markusfoo Apr 14, 2026
d985b74
Merge branch 'WordPress:trunk' into fix/spa-navigate-deactivate-dynam…
markusfoo Apr 16, 2026
70ba745
Merge branch 'WordPress:trunk' into fix/spa-navigate-deactivate-dynam…
markusfoo Apr 21, 2026
ad314dc
Merge branch 'WordPress:trunk' into fix/spa-navigate-deactivate-dynam…
markusfoo Apr 26, 2026
8c446f4
Merge branch 'WordPress:trunk' into fix/spa-navigate-deactivate-dynam…
markusfoo May 2, 2026
0b43374
Merge branch 'trunk' into fix/spa-navigate-deactivate-dynamic-styles
markusfoo May 4, 2026
f573751
Merge branch 'WordPress:trunk' into fix/spa-navigate-deactivate-dynam…
markusfoo May 4, 2026
96e8114
Merge branch 'trunk' into fix/spa-navigate-deactivate-dynamic-styles
markusfoo May 5, 2026
8e7589d
Merge branch 'WordPress:trunk' into fix/spa-navigate-deactivate-dynam…
markusfoo May 7, 2026
01a2623
Merge branch 'WordPress:trunk' into fix/spa-navigate-deactivate-dynam…
markusfoo May 9, 2026
0a5a250
Merge branch 'trunk' into fix/spa-navigate-deactivate-dynamic-styles
markusfoo May 14, 2026
158ad4c
Merge branch 'trunk' into fix/spa-navigate-deactivate-dynamic-styles
markusfoo May 14, 2026
0aa1d87
Merge branch 'trunk' into fix/spa-navigate-deactivate-dynamic-styles
markusfoo May 16, 2026
4dee1d6
Merge branch 'WordPress:trunk' into fix/spa-navigate-deactivate-dynam…
markusfoo May 18, 2026
3dd78cf
Merge branch 'trunk' into fix/spa-navigate-deactivate-dynamic-styles
markusfoo May 27, 2026
404abc7
Merge branch 'trunk' into fix/spa-navigate-deactivate-dynamic-styles
markusfoo Jun 3, 2026
8cc6428
Merge branch 'trunk' into fix/spa-navigate-deactivate-dynamic-styles
markusfoo Jun 3, 2026
a126571
Merge branch 'WordPress:trunk' into fix/spa-navigate-deactivate-dynam…
markusfoo Jun 4, 2026
96951d9
Merge branch 'trunk' into fix/spa-navigate-deactivate-dynamic-styles
markusfoo Jun 5, 2026
03b7341
Merge branch 'trunk' into fix/spa-navigate-deactivate-dynamic-styles
markusfoo Jun 5, 2026
a0f594d
Merge branch 'trunk' into fix/spa-navigate-deactivate-dynamic-styles
markusfoo Jun 6, 2026
0c16858
Merge branch 'trunk' into fix/spa-navigate-deactivate-dynamic-styles
markusfoo Jun 8, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{
"$schema": "https://schemas.wp.org/trunk/block.json",
"apiVersion": 3,
"name": "test/router-dynamic-styles",
"title": "Test Router Dynamic Styles",
"category": "text",
"description": "",
"supports": {
"interactivity": true
},
"textdomain": "e2e-interactivity",
"viewScriptModule": "file:./view.js",
"render": "file:./render.php"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
/**
* Deferred stylesheet for the test/router-dynamic-styles block.
*
* Enqueued by render.php with media="not all" — the browser fetches the file
* but does not apply it until an iAPI store activates it by mutating
* link.media to "all" (see activateDeferredStyle action in view.js).
*
* The custom property lets the view script detect activation without relying
* on visual-style inspection: getComputedStyle(body) returns "--test-deferred-active: 1"
* only when this sheet is active (media matches AND sheet.disabled === false).
*/
body {
--test-deferred-active: 1;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
<?php
/**
* Test block render template for test/router-dynamic-styles.
*
* Provides deterministic style-scenario fixtures for two router bugs:
*
* Bug A — runtime-activated deferred stylesheets:
* A <style id="test-router-deferred-style" media="not all"> element is
* output server-side on every page request.
* This mirrors the real WordPress pattern of wp_enqueue_style() with
* media="not all". view.js finds it by id and the activateDeferredStyle
* action sets element.media = "all".
*
* Because the element is server-rendered it also appears in the fetched
* page HTML during SPA navigation. normalizeMedia() maps "not all" → "all"
* so the SCS algorithm matches the live activated element (media="all")
* against the server-returned element (media="not all"), keeps it in
* page.styles, and applyStyles() leaves it enabled.
*
* No external CSS file is required — the declaration is inlined.
*
* Bug B — dynamically-injected plugin stylesheets:
* view.js init() appends a <style> element with a stable id attribute,
* simulating plugins like Complianz GDPR that bypass wp_enqueue_style().
* The router must never disable it across any navigation path.
*
* Navigation links use data-wp-on--click="actions.navigate" to trigger
* iAPI router SPA navigation. Without this directive the plain <a> clicks
* would cause full page reloads, resetting all state and making the test
* unable to verify that styles survive navigation.
*
* Navigation links nav-to-a, nav-to-b and nav-to-c resolve sibling posts by title so
* the spec's addPostWithBlock( …, { alias } ) pattern works out of the box.
*
* @package gutenberg-test-interactive-blocks
*/

// Resolve sibling post URLs by alias (post title set by addPostWithBlock).
$current_title = (string) get_the_title();
$base_alias = (string) preg_replace( '/-[a-z]$/', '', $current_title );

$find_url = static function ( string $alias ): string {
$posts = get_posts(
array(
'post_type' => 'post',
'post_status' => 'publish',
'title' => $alias,
'posts_per_page' => 1,
'no_found_rows' => true,
'fields' => 'ids',
)
);
return $posts ? (string) get_permalink( $posts[0] ) : '#';
};

$link_a = $find_url( $base_alias . '-a' );
$link_b = $find_url( $base_alias . '-b' );
$link_c = $find_url( $base_alias . '-c' );
?>

<!-- Bug A fixture: deferred style outside router region, survives navigation. -->
<style id="test-router-deferred-style" media="not all">body { --test-deferred-active: 1; }</style>

<div
data-wp-interactive="test/router-dynamic-styles"
data-wp-router-region="test-router-dynamic-styles"
<?php echo get_block_wrapper_attributes(); ?>
>
<p>
Deferred style:
<span
data-testid="deferred-style-active"
data-wp-text="state.deferredStyleStatus"
>inactive</span>
</p>
<p>
Plugin style:
<span
data-testid="plugin-style-active"
data-wp-text="state.pluginStyleStatus"
>inactive</span>
</p>
<button
type="button"
data-testid="activate-deferred-style"
data-wp-on--click="actions.activateDeferredStyle"
>
Activate deferred style
</button>
<nav>
<a
data-testid="nav-to-a"
href="<?php echo esc_url( $link_a ); ?>"
data-wp-on--click="actions.navigate"
>Page A</a>
<a
data-testid="nav-to-b"
href="<?php echo esc_url( $link_b ); ?>"
data-wp-on--click="actions.navigate"
>Page B</a>
<a
data-testid="nav-to-c"
href="<?php echo esc_url( $link_c ); ?>"
data-wp-on--click="actions.navigate"
>Page C</a>
</nav>
<div data-wp-init="callbacks.init"></div>
</div>
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<?php return array(
'dependencies' => array(
'@wordpress/interactivity',
array(
'id' => '@wordpress/interactivity-router',
'import' => 'dynamic',
),
),
);
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
/**
* WordPress dependencies
*/
import { store, getElement } from '@wordpress/interactivity';

const PLUGIN_STYLE_ID = 'test-router-plugin-style';

const { state } = store( 'test/router-dynamic-styles', {
state: {
/**
* "active" | "inactive". Written by activateDeferredStyle() and
* re-synchronised from the real DOM by init() on every SPA mount.
*
* Must be a plain reactive field, not a DOM getter: raw DOM reads are
* not tracked by Preact's signal system, so a getter would be evaluated
* once at hydration and never again, leaving the span stuck at "inactive".
*/
deferredStyleStatus: 'inactive',

/**
* "active" | "inactive". Written by init() on every SPA mount.
* Plain reactive field for the same reason as deferredStyleStatus.
*/
pluginStyleStatus: 'inactive',
},

actions: {
/**
* Bug A fixture — activates the deferred stylesheet.
*
* Mutates media from "not all" to "all" on the inline style element, then
* writes the reactive signal so data-wp-text re-renders immediately.
*/
activateDeferredStyle() {
const el = document.getElementById( 'test-router-deferred-style' );
if ( el ) {
el.media = 'all';
state.deferredStyleStatus = 'active';
}
},

/**
* SPA navigation action — intercepts the anchor click and delegates to
* the iAPI router's navigate() so the router performs a client-side
* navigation instead of a full page reload.
*
* Without this, plain <a href="..."> links inside the router region
* would cause a full page reload, resetting all reactive state and
* making it impossible to verify that applyStyles() preserved the
* activated stylesheet across navigation.
*
* Uses a generator function to yield the dynamic import.
* actions.navigate() is called without yield (fire-and-forget),
* matching the pattern used in full-page.ts.
*
* @param {MouseEvent} event The click event from data-wp-on--click.
*/
*navigate( event ) {
event.preventDefault();
const { ref } = getElement();
const { actions } = yield import(
'@wordpress/interactivity-router'
);
actions.navigate( ref.href );
},
},

callbacks: {
/**
* Runs on every SPA page mount (data-wp-init).
*
* Execution order per navigation:
* 1. applyStyles() — router enables / disables sheets.
* 2. iAPI re-initialises directives, calling this callback.
*
* Reading the DOM here therefore always reflects the post-applyStyles
* state, allowing both signals to be synchronised accurately.
*
* Bug B: injects the plugin-style element on first mount; subsequent
* mounts confirm it survived applyStyles() without being disabled.
*
* Bug A: re-reads sheet.disabled so deferredStyleStatus reflects whether
* applyStyles() correctly preserved the activated sheet.
*/
init() {
// Bug B — idempotent plugin-style injection.
if ( ! document.getElementById( PLUGIN_STYLE_ID ) ) {
const style = document.createElement( 'style' );
style.id = PLUGIN_STYLE_ID;
style.textContent = 'body { --test-plugin-style: 1; }';
document.head.appendChild( style );
}
state.pluginStyleStatus = 'active';

// Bug A — re-sync deferred status after applyStyles().
const el = document.getElementById( 'test-router-deferred-style' );
state.deferredStyleStatus =
el?.sheet && ! el.sheet.disabled && el.media !== 'not all'
? 'active'
: 'inactive';
},
},
} );
3 changes: 2 additions & 1 deletion packages/interactivity-router/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@
## 2.42.0 (2026-03-18)

### Bug Fixes

- Preserve runtime-activated deferred stylesheets (`media="not all"` → `"all"`) across client-side navigations. Previously, `areNodesEqual()` used `isEqualNode()` which compared the `media` attribute, causing `applyStyles()` to disable the activated sheet on the next navigation. ([#76289](https://github.com/WordPress/gutenberg/pull/76289))
- Preserve dynamically-injected stylesheets (e.g. Complianz GDPR consent CSS) across client-side navigations. Previously, `applyStyles()` disabled every stylesheet absent from the fetched page, including elements injected at runtime via `document.head.appendChild()` which carry no `id` attribute. ([#76289](https://github.com/WordPress/gutenberg/pull/76289))
- Fix race condition where router evaluates before `hydrateRegions()` completes on Safari and Firefox, causing interactive regions to be permanently non-functional (dead DOM). ([#76053](https://github.com/WordPress/gutenberg/pull/76053))
## 2.41.0 (2026-03-04)

Expand Down
Loading
Loading