diff --git a/packages/hooks/CHANGELOG.md b/packages/hooks/CHANGELOG.md
index 4e0dbdce40e7d..0b070a6d3c0db 100644
--- a/packages/hooks/CHANGELOG.md
+++ b/packages/hooks/CHANGELOG.md
@@ -1,3 +1,9 @@
+## Master
+
+### New Feature
+
+- Enable support for the 'all' hook in non production environments.
+
## 2.0.4 (2019-01-03)
## 2.0.0 (2018-09-05)
diff --git a/packages/hooks/README.md b/packages/hooks/README.md
index be0148f3747a0..952931c393bd1 100644
--- a/packages/hooks/README.md
+++ b/packages/hooks/README.md
@@ -52,4 +52,8 @@ Whenever an action or filter is added or removed, a matching `hookAdded` or `hoo
* `hookAdded` action is triggered when `addFilter()` or `addAction()` method is called, passing values for `hookName`, `functionName`, `callback` and `priority`.
* `hookRemoved` action is triggered when `removeFilter()` or `removeAction()` method is called, passing values for `hookName` and `functionName`.
+### The `all` hook
+
+In non-minified builds developers can register a filter or action that will be called on *all* hooks, for example: `addAction( 'all', 'namespace', callbackFunction );`. Useful for debugging, the code supporting the `all` hook is stripped from the production code for performance reasons.
+
diff --git a/packages/hooks/src/createRunHook.js b/packages/hooks/src/createRunHook.js
index 66baaaa3e208c..d9c909b734af7 100644
--- a/packages/hooks/src/createRunHook.js
+++ b/packages/hooks/src/createRunHook.js
@@ -30,6 +30,14 @@ function createRunHook( hooks, returnFirstArg ) {
const handlers = hooks[ hookName ].handlers;
+ // The following code is stripped from production builds.
+ if ( 'production' !== process.env.NODE_ENV ) {
+ // Handle any 'all' hooks registered.
+ if ( 'hookAdded' !== hookName && hooks.all ) {
+ handlers.push( ...hooks.all.handlers );
+ }
+ }
+
if ( ! handlers || ! handlers.length ) {
return returnFirstArg ?
args[ 0 ] :
diff --git a/packages/hooks/src/test/index.test.js b/packages/hooks/src/test/index.test.js
index a31a0d2d113ce..20f27a30b9ae3 100644
--- a/packages/hooks/src/test/index.test.js
+++ b/packages/hooks/src/test/index.test.js
@@ -77,6 +77,7 @@ beforeEach( () => {
delete hooks[ k ];
}
+ delete hooks.all;
} );
} );
@@ -697,3 +698,47 @@ test( 'removing a filter triggers a hookRemoved action passing all callback deta
'my_callback3'
);
} );
+
+test( 'add an all filter and run it any hook to trigger it', () => {
+ addFilter( 'all', 'my_callback', filterA );
+ expect( applyFilters( 'test.filter', 'test' ) ).toBe( 'testa' );
+ expect( applyFilters( 'test.filter-anything', 'test' ) ).toBe( 'testa' );
+} );
+
+test( 'add an all action and run it any hook to trigger it', () => {
+ addAction( 'all', 'my_callback', actionA );
+ addAction( 'test.action', 'my_callback', actionA );// Doesn't get triggered.
+ doAction( 'test.action-anything' );
+ expect( window.actionValue ).toBe( 'a' );
+} );
+
+test( 'add multiple all filters and run it any hook to trigger them', () => {
+ addFilter( 'all', 'my_callback', filterA );
+ addFilter( 'all', 'my_callback', filterB );
+ expect( applyFilters( 'test.filter', 'test' ) ).toBe( 'testab' );
+ expect( applyFilters( 'test.filter-anything', 'test' ) ).toBe( 'testab' );
+} );
+
+test( 'add multiple all actions and run it any hook to trigger them', () => {
+ addAction( 'all', 'my_callback', actionA );
+ addAction( 'all', 'my_callback', actionB );
+ addAction( 'test.action', 'my_callback', actionA ); // Doesn't get triggered.
+ doAction( 'test.action-anything' );
+ expect( window.actionValue ).toBe( 'ab' );
+} );
+
+test( 'add multiple all filters and run it any hook to trigger them by priority', () => {
+ addFilter( 'all', 'my_callback', filterA, 11 );
+ addFilter( 'all', 'my_callback', filterB, 10 );
+ expect( applyFilters( 'test.filter', 'test' ) ).toBe( 'testba' );
+ expect( applyFilters( 'test.filter-anything', 'test' ) ).toBe( 'testba' );
+} );
+
+test( 'add multiple all actions and run it any hook to trigger them by priority', () => {
+ addAction( 'all', 'my_callback', actionA, 11 );
+ addAction( 'all', 'my_callback', actionB, 10 );
+ addAction( 'test.action', 'my_callback', actionA ); // Doesn't get triggered.
+ doAction( 'test.action-anything' );
+ expect( window.actionValue ).toBe( 'ba' );
+} );
+