diff --git a/packages/hooks/CHANGELOG.md b/packages/hooks/CHANGELOG.md index cb1625c912898..5e11d271d2441 100644 --- a/packages/hooks/CHANGELOG.md +++ b/packages/hooks/CHANGELOG.md @@ -1,8 +1,14 @@ +## Master + +### New Feature + + - Enable an optional namespace parameter for `hasAction` & `hasFilter`. When checking if an action or filter exists, `hasAction` and `hasFilter` now accept an optional paramter to limit matches by namespace. + ## 2.4.0 (2019-06-12) ### New Feature -- Enable support for the 'all' hook in non production environments. +- Enable support for the 'all' hook in non production environments. ## 2.0.4 (2019-01-03) diff --git a/packages/hooks/README.md b/packages/hooks/README.md index 952931c393bd1..4698580f4b4ed 100644 --- a/packages/hooks/README.md +++ b/packages/hooks/README.md @@ -39,8 +39,8 @@ In the WordPress context, API functions can be called via the global `wp.hooks` * `doingFilter( 'hookName' )` * `didAction( 'hookName' )` * `didFilter( 'hookName' )` -* `hasAction( 'hookName' )` -* `hasFilter( 'hookName' )` +* `hasAction( 'hookName', 'namespace' )` +* `hasFilter( 'hookName', 'namespace' )` * `actions` * `filters` diff --git a/packages/hooks/src/createHasHook.js b/packages/hooks/src/createHasHook.js index de4ee3c17a793..7e2474ccf8ae0 100644 --- a/packages/hooks/src/createHasHook.js +++ b/packages/hooks/src/createHasHook.js @@ -5,17 +5,25 @@ * @param {Object} hooks Stored hooks, keyed by hook name. * * @return {Function} Function that returns whether any handlers are - * attached to a particular hook. + * attached to a particular hook and optional namespace. */ function createHasHook( hooks ) { /** - * Returns how many handlers are attached for the given hook. + * Returns whether any handlers are attached for the given hookName and optional namespace. * - * @param {string} hookName The name of the hook to check for. + * @param {string} hookName The name of the hook to check for. + * @param {?string} namespace Optional. The unique namespace identifying the callback + * in the form `vendor/plugin/function`. * * @return {boolean} Whether there are handlers that are attached to the given hook. */ - return function hasHook( hookName ) { + return function hasHook( hookName, namespace ) { + // Use the namespace if provided. + if ( 'undefined' !== typeof namespace ) { + return hookName in hooks && + hooks[ hookName ].handlers.some( ( hook ) => hook.namespace === namespace ); + } + return hookName in hooks; }; } diff --git a/packages/hooks/src/test/index.test.js b/packages/hooks/src/test/index.test.js index f8b1c736f55b4..26d04853ede06 100644 --- a/packages/hooks/src/test/index.test.js +++ b/packages/hooks/src/test/index.test.js @@ -740,3 +740,38 @@ test( 'add multiple all actions and run it any hook to trigger them by priority' expect( window.actionValue ).toBe( 'ba' ); } ); +test( 'checking hasAction with named callbacks and removing', () => { + addAction( 'test.action', 'my_callback', () => {} ); + expect( hasAction( 'test.action', 'not_my_callback' ) ).toBe( false ); + expect( hasAction( 'test.action', 'my_callback' ) ).toBe( true ); + removeAction( 'test.action', 'my_callback' ); + expect( hasAction( 'test.action', 'my_callback' ) ).toBe( false ); +} ); + +test( 'checking hasAction with named callbacks and removeAllActions', () => { + addAction( 'test.action', 'my_callback', () => {} ); + addAction( 'test.action', 'my_second_callback', () => {} ); + expect( hasAction( 'test.action', 'my_callback' ) ).toBe( true ); + expect( hasAction( 'test.action', 'my_callback' ) ).toBe( true ); + removeAllActions( 'test.action' ); + expect( hasAction( 'test.action', 'my_callback' ) ).toBe( false ); + expect( hasAction( 'test.action', 'my_callback' ) ).toBe( false ); +} ); + +test( 'checking hasFilter with named callbacks and removing', () => { + addFilter( 'test.filter', 'my_callback', () => {} ); + expect( hasFilter( 'test.filter', 'not_my_callback' ) ).toBe( false ); + expect( hasFilter( 'test.filter', 'my_callback' ) ).toBe( true ); + removeFilter( 'test.filter', 'my_callback' ); + expect( hasFilter( 'test.filter', 'my_callback' ) ).toBe( false ); +} ); + +test( 'checking hasFilter with named callbacks and removeAllActions', () => { + addFilter( 'test.filter', 'my_callback', () => {} ); + addFilter( 'test.filter', 'my_second_callback', () => {} ); + expect( hasFilter( 'test.filter', 'my_callback' ) ).toBe( true ); + expect( hasFilter( 'test.filter', 'my_second_callback' ) ).toBe( true ); + removeAllFilters( 'test.filter' ); + expect( hasFilter( 'test.filter', 'my_callback' ) ).toBe( false ); + expect( hasFilter( 'test.filter', 'my_second_callback' ) ).toBe( false ); +} );