diff --git a/packages/e2e-tests/plugins/interactive-blocks/directive-ignore/block.json b/packages/e2e-tests/plugins/interactive-blocks/directive-ignore/block.json
new file mode 100644
index 0000000000000..a6089a224692f
--- /dev/null
+++ b/packages/e2e-tests/plugins/interactive-blocks/directive-ignore/block.json
@@ -0,0 +1,15 @@
+{
+ "$schema": "https://schemas.wp.org/trunk/block.json",
+ "apiVersion": 2,
+ "name": "test/directive-ignore",
+ "title": "E2E Interactivity tests - directive ignore",
+ "category": "text",
+ "icon": "heart",
+ "description": "",
+ "supports": {
+ "interactivity": true
+ },
+ "textdomain": "e2e-interactivity",
+ "viewScriptModule": "file:./view.js",
+ "render": "file:./render.php"
+}
diff --git a/packages/e2e-tests/plugins/interactive-blocks/directive-ignore/render.php b/packages/e2e-tests/plugins/interactive-blocks/directive-ignore/render.php
new file mode 100644
index 0000000000000..7593d211d6975
--- /dev/null
+++ b/packages/e2e-tests/plugins/interactive-blocks/directive-ignore/render.php
@@ -0,0 +1,33 @@
+ 0 ) );
+?>
+
+
'the letter a',
+ 'b' => 'the letter b',
+ 'one' => 'the number one',
+ 'two' => 'the number two',
+ )
+ );
+ ?>
+>
+
+
+
+
No processing should occur here.
+
+
+
+
diff --git a/packages/e2e-tests/plugins/interactive-blocks/directive-ignore/view.asset.php b/packages/e2e-tests/plugins/interactive-blocks/directive-ignore/view.asset.php
new file mode 100644
index 0000000000000..db23afdf657a1
--- /dev/null
+++ b/packages/e2e-tests/plugins/interactive-blocks/directive-ignore/view.asset.php
@@ -0,0 +1 @@
+ array( '@wordpress/interactivity' ) );
diff --git a/packages/e2e-tests/plugins/interactive-blocks/directive-ignore/view.js b/packages/e2e-tests/plugins/interactive-blocks/directive-ignore/view.js
new file mode 100644
index 0000000000000..27d44d9da00b7
--- /dev/null
+++ b/packages/e2e-tests/plugins/interactive-blocks/directive-ignore/view.js
@@ -0,0 +1,16 @@
+/**
+ * WordPress dependencies
+ */
+import { store, getContext } from '@wordpress/interactivity';
+
+const { state } = store( 'directive-ignore', {
+ actions: {
+ run() {
+ getContext().one = '1';
+ getContext().two = '2';
+ },
+ click() {
+ state.clicks += 1;
+ },
+ },
+} );
diff --git a/packages/interactivity/src/directives.js b/packages/interactivity/src/directives.js
index c20ea3aec722d..3f8b61db49732 100644
--- a/packages/interactivity/src/directives.js
+++ b/packages/interactivity/src/directives.js
@@ -3,7 +3,7 @@
/**
* External dependencies
*/
-import { h as createElement } from 'preact';
+import { h as createElement, Component } from 'preact';
import { useContext, useMemo, useRef } from 'preact/hooks';
import { deepSignal, peek } from 'deepsignal';
@@ -221,6 +221,30 @@ const getGlobalEventDirective =
} );
};
+/**
+ * @augments {Component}
+ */
+class IgnoredComponent extends Component {
+ shouldComponentUpdate() {
+ return false;
+ }
+
+ render( props ) {
+ const {
+ element: {
+ type: Type,
+ props: { innerHTML, ...rest },
+ },
+ } = props;
+ return (
+
+ );
+ }
+}
+
export default () => {
// data-wp-context
directive(
@@ -440,24 +464,9 @@ export default () => {
} );
// data-wp-ignore
- directive(
- 'ignore',
- ( {
- element: {
- type: Type,
- props: { innerHTML, ...rest },
- },
- } ) => {
- // Preserve the initial inner HTML.
- const cached = useMemo( () => innerHTML, [] );
- return (
-
- );
- }
- );
+ directive( 'ignore', ( args ) => {
+ return ;
+ } );
// data-wp-text
directive( 'text', ( { directives: { text }, element, evaluate } ) => {
diff --git a/packages/interactivity/src/hooks.tsx b/packages/interactivity/src/hooks.tsx
index 00c3c0d6d1729..5cb3091bf9558 100644
--- a/packages/interactivity/src/hooks.tsx
+++ b/packages/interactivity/src/hooks.tsx
@@ -24,7 +24,7 @@ interface DirectiveEntry {
type DirectiveEntries = Record< string, DirectiveEntry[] >;
-interface DirectiveArgs {
+export interface DirectiveArgs {
/**
* Object map with the defined directives of the element being evaluated.
*/
@@ -347,7 +347,7 @@ const Directives = ( {
);
const props = { ...originalProps, children };
- const directiveArgs = {
+ const directiveArgs: DirectiveArgs = {
directives,
props,
element,
diff --git a/test/e2e/specs/interactivity/directive-each.spec.ts b/test/e2e/specs/interactivity/directive-each.spec.ts
index a9f09191685a3..0de9056d91af9 100644
--- a/test/e2e/specs/interactivity/directive-each.spec.ts
+++ b/test/e2e/specs/interactivity/directive-each.spec.ts
@@ -18,7 +18,7 @@ test.describe( 'data-wp-each', () => {
await utils.deleteAllPosts();
} );
- test( 'should use `item` as the defaul item name in the context', async ( {
+ test( 'should use `item` as the default item name in the context', async ( {
page,
} ) => {
const elements = page.getByTestId( 'letters' ).getByTestId( 'item' );
diff --git a/test/e2e/specs/interactivity/directive-ignore.spec.ts b/test/e2e/specs/interactivity/directive-ignore.spec.ts
new file mode 100644
index 0000000000000..2612fc7be040a
--- /dev/null
+++ b/test/e2e/specs/interactivity/directive-ignore.spec.ts
@@ -0,0 +1,47 @@
+/**
+ * Internal dependencies
+ */
+import { test, expect } from './fixtures';
+
+test.describe( 'data-wp-ignore', () => {
+ test.beforeAll( async ( { interactivityUtils: utils } ) => {
+ await utils.activatePlugins();
+ await utils.addPostWithBlock( 'test/directive-ignore' );
+ } );
+
+ test.beforeEach( async ( { interactivityUtils: utils, page } ) => {
+ await page.goto( utils.getLink( 'test/directive-ignore' ) );
+ } );
+
+ test.afterAll( async ( { interactivityUtils: utils } ) => {
+ await utils.deactivatePlugins();
+ await utils.deleteAllPosts();
+ } );
+
+ test( 'ignored directives should never update the DOM', async ( {
+ page,
+ } ) => {
+ const block = page.getByTestId( 'block' );
+
+ const ignoredElement = await block
+ .getByTestId( 'ignored' )
+ .evaluate( ( el ) => el );
+ const ignoredChildElement = await block
+ .getByTestId( 'ignored-child' )
+ .evaluate( ( el ) => el );
+
+ await expect( block.getByTestId( 'ignored-child' ) ).toHaveText(
+ 'No processing should occur here.'
+ );
+
+ await expect( block.getByTestId( 'counter' ) ).toHaveText( '0' );
+ await block.getByTestId( 'click-me' ).click();
+ await expect( block.getByTestId( 'counter' ) ).toHaveText( '1' );
+ expect( ignoredElement ).toBe(
+ await block.getByTestId( 'ignored' ).evaluate( ( el ) => el )
+ );
+ expect( ignoredChildElement ).toBe(
+ await block.getByTestId( 'ignored-child' ).evaluate( ( el ) => el )
+ );
+ } );
+} );