diff --git a/packages/e2e-tests/plugins/interactive-blocks/directive-on/render.php b/packages/e2e-tests/plugins/interactive-blocks/directive-on/render.php
index edb081922fc0e4..eb2de94ab58eea 100644
--- a/packages/e2e-tests/plugins/interactive-blocks/directive-on/render.php
+++ b/packages/e2e-tests/plugins/interactive-blocks/directive-on/render.php
@@ -51,4 +51,24 @@
data-wp-on--click="actions.clickHandler"
>Click me!
+
+
false
+
0
+
true
+
+
diff --git a/packages/e2e-tests/plugins/interactive-blocks/directive-on/view.js b/packages/e2e-tests/plugins/interactive-blocks/directive-on/view.js
index 69378b53e14c0a..8b0bcc0e115eca 100644
--- a/packages/e2e-tests/plugins/interactive-blocks/directive-on/view.js
+++ b/packages/e2e-tests/plugins/interactive-blocks/directive-on/view.js
@@ -26,5 +26,17 @@ const { state } = store( 'directive-on', {
const context = getContext();
context.customEvents += 1;
},
+ setClicked: () => {
+ const context = getContext();
+ context.clicked = true;
+ },
+ countClick: () => {
+ const context = getContext();
+ context.clickCount += 1;
+ },
+ toggle: () => {
+ const context = getContext();
+ context.isOpen = ! context.isOpen;
+ },
},
} );
diff --git a/packages/interactivity/src/directives.js b/packages/interactivity/src/directives.js
index b19067bdc1ad9a..c20ea3aec722d3 100644
--- a/packages/interactivity/src/directives.js
+++ b/packages/interactivity/src/directives.js
@@ -270,13 +270,22 @@ export default () => {
// data-wp-on--[event]
directive( 'on', ( { directives: { on }, element, evaluate } ) => {
+ const events = new Map();
on.filter( ( { suffix } ) => suffix !== 'default' ).forEach(
( entry ) => {
- element.props[ `on${ entry.suffix }` ] = ( event ) => {
- evaluate( entry, event );
- };
+ const event = entry.suffix.split( '--' )[ 0 ];
+ if ( ! events.has( event ) ) events.set( event, new Set() );
+ events.get( event ).add( entry );
}
);
+
+ events.forEach( ( entries, eventType ) => {
+ element.props[ `on${ eventType }` ] = ( event ) => {
+ entries.forEach( ( entry ) => {
+ evaluate( entry, event );
+ } );
+ };
+ } );
} );
// data-wp-on-window--[event]
diff --git a/test/e2e/specs/interactivity/directive-on.spec.ts b/test/e2e/specs/interactivity/directive-on.spec.ts
index 03dfe64462c567..886f74335e7aee 100644
--- a/test/e2e/specs/interactivity/directive-on.spec.ts
+++ b/test/e2e/specs/interactivity/directive-on.spec.ts
@@ -51,4 +51,29 @@ test.describe( 'data-wp-on', () => {
.click( { clickCount: 3, delay: 100 } );
await expect( counter ).toHaveText( '3' );
} );
+
+ test( 'should work with multiple event handlers on the same event type', async ( {
+ page,
+ } ) => {
+ const button = page.getByTestId( 'multiple handlers button' );
+ const isOpen = page.getByTestId( 'multiple handlers isOpen' );
+ const clicked = page.getByTestId( 'multiple handlers clicked' );
+ const clickCount = page.getByTestId( 'multiple handlers clickCount' );
+
+ await expect( clicked ).toHaveText( 'false' );
+ await expect( clickCount ).toHaveText( '0' );
+ await expect( isOpen ).toHaveText( 'true' );
+
+ await button.click();
+
+ await expect( clicked ).toHaveText( 'true' );
+ await expect( clickCount ).toHaveText( '1' );
+ await expect( isOpen ).toHaveText( 'false' );
+
+ await button.click();
+
+ await expect( clicked ).toHaveText( 'true' );
+ await expect( clickCount ).toHaveText( '2' );
+ await expect( isOpen ).toHaveText( 'true' );
+ } );
} );