WordPress.org

Make WordPress Core

Ticket #21170: 21170.14.diff

File 21170.14.diff, 32.3 KB (added by adamsilverstein, 22 months ago)
  • Gruntfile.js

    diff --git Gruntfile.js Gruntfile.js
    index 0070a7cf77..384599bb7b 100644
    module.exports = function(grunt) { 
    369369                                        '!wp-includes/js/json2.js',
    370370                                        '!wp-includes/js/tw-sack.js',
    371371                                        '!wp-includes/js/twemoji.js',
    372                                         '!**/*.min.js'
     372                                        '!**/*.min.js',
     373                                        '!wp-includes/js/wp-hooks.js'
    373374                                ],
    374375                                // Remove once other JSHint errors are resolved
    375376                                options: {
  • new file src/wp-includes/js/wp-hooks.js

    diff --git src/wp-includes/js/wp-hooks.js src/wp-includes/js/wp-hooks.js
    new file mode 100644
    index 0000000000..9adb525ee9
    - +  
     1this["wp"] = this["wp"] || {}; this["wp"]["hooks"] =
     2/******/ (function(modules) { // webpackBootstrap
     3/******/        // The module cache
     4/******/        var installedModules = {};
     5/******/
     6/******/        // The require function
     7/******/        function __webpack_require__(moduleId) {
     8/******/
     9/******/                // Check if module is in cache
     10/******/                if(installedModules[moduleId]) {
     11/******/                        return installedModules[moduleId].exports;
     12/******/                }
     13/******/                // Create a new module (and put it into the cache)
     14/******/                var module = installedModules[moduleId] = {
     15/******/                        i: moduleId,
     16/******/                        l: false,
     17/******/                        exports: {}
     18/******/                };
     19/******/
     20/******/                // Execute the module function
     21/******/                modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
     22/******/
     23/******/                // Flag the module as loaded
     24/******/                module.l = true;
     25/******/
     26/******/                // Return the exports of the module
     27/******/                return module.exports;
     28/******/        }
     29/******/
     30/******/
     31/******/        // expose the modules object (__webpack_modules__)
     32/******/        __webpack_require__.m = modules;
     33/******/
     34/******/        // expose the module cache
     35/******/        __webpack_require__.c = installedModules;
     36/******/
     37/******/        // define getter function for harmony exports
     38/******/        __webpack_require__.d = function(exports, name, getter) {
     39/******/                if(!__webpack_require__.o(exports, name)) {
     40/******/                        Object.defineProperty(exports, name, {
     41/******/                                configurable: false,
     42/******/                                enumerable: true,
     43/******/                                get: getter
     44/******/                        });
     45/******/                }
     46/******/        };
     47/******/
     48/******/        // getDefaultExport function for compatibility with non-harmony modules
     49/******/        __webpack_require__.n = function(module) {
     50/******/                var getter = module && module.__esModule ?
     51/******/                        function getDefault() { return module['default']; } :
     52/******/                        function getModuleExports() { return module; };
     53/******/                __webpack_require__.d(getter, 'a', getter);
     54/******/                return getter;
     55/******/        };
     56/******/
     57/******/        // Object.prototype.hasOwnProperty.call
     58/******/        __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };
     59/******/
     60/******/        // __webpack_public_path__
     61/******/        __webpack_require__.p = "";
     62/******/
     63/******/        // Load entry module and return exports
     64/******/        return __webpack_require__(__webpack_require__.s = 13);
     65/******/ })
     66/************************************************************************/
     67/******/ ([
     68/* 0 */
     69/***/ (function(module, exports, __webpack_require__) {
     70
     71"use strict";
     72
     73
     74Object.defineProperty(exports, "__esModule", {
     75        value: true
     76});
     77/**
     78 * Validate a hookName string.
     79 *
     80 * @param  {string} hookName The hook name to validate. Should be a non empty string containing
     81 *                           only numbers, letters, dashes, periods and underscores. Also,
     82 *                           the hook name cannot begin with `__`.
     83 *
     84 * @return {bool}            Whether the hook name is valid.
     85 */
     86function validateHookName(hookName) {
     87
     88        if ('string' !== typeof hookName || '' === hookName) {
     89                console.error('The hook name must be a non-empty string.');
     90                return false;
     91        }
     92
     93        if (/^__/.test(hookName)) {
     94                console.error('The hook name cannot begin with `__`.');
     95                return false;
     96        }
     97
     98        if (!/^[a-zA-Z][a-zA-Z0-9_.-]*$/.test(hookName)) {
     99                console.error('The hook name can only contain numbers, letters, dashes, periods and underscores.');
     100                return false;
     101        }
     102
     103        return true;
     104}
     105
     106exports.default = validateHookName;
     107
     108/***/ }),
     109/* 1 */
     110/***/ (function(module, exports, __webpack_require__) {
     111
     112"use strict";
     113
     114
     115Object.defineProperty(exports, "__esModule", {
     116        value: true
     117});
     118/**
     119 * Validate a namespace string.
     120 *
     121 * @param  {string} namespace The namespace to validate - should take the form
     122 *                            `vendorName/pluginName/functionName`.
     123 *
     124 * @return {bool}             Whether the namespace is valid.
     125 */
     126function validateNamespace(namespace) {
     127
     128        if ('string' !== typeof namespace || '' === namespace) {
     129                console.error('The namespace must be a non-empty string.');
     130                return false;
     131        }
     132
     133        if (!/^[a-zA-Z][a-zA-Z0-9_.-/]*$/.test(namespace)) {
     134                console.error('The namespace can only contain numbers, letters, dashes, periods and underscores, plus the forward slash dividing slug and description in the namespace.');
     135                return false;
     136        }
     137
     138        if (!/^[a-zA-Z][a-zA-Z0-9_.-]*\/[a-zA-Z][a-zA-Z0-9_.-]*\/[a-zA-Z][a-zA-Z0-9_.-]*$/.test(namespace)) {
     139                console.error('The namespace must take the form `vendorName/pluginName/functionName`.');
     140                return false;
     141        }
     142
     143        return true;
     144}
     145
     146exports.default = validateNamespace;
     147
     148/***/ }),
     149/* 2 */,
     150/* 3 */,
     151/* 4 */,
     152/* 5 */,
     153/* 6 */,
     154/* 7 */,
     155/* 8 */,
     156/* 9 */,
     157/* 10 */,
     158/* 11 */,
     159/* 12 */,
     160/* 13 */
     161/***/ (function(module, exports, __webpack_require__) {
     162
     163"use strict";
     164
     165
     166Object.defineProperty(exports, "__esModule", {
     167  value: true
     168});
     169exports.didFilter = exports.didAction = exports.doingFilter = exports.doingAction = exports.currentFilter = exports.currentAction = exports.applyFilters = exports.doAction = exports.removeAllFilters = exports.removeAllActions = exports.hasFilter = exports.hasAction = exports.removeFilter = exports.removeAction = exports.addFilter = exports.addAction = undefined;
     170
     171var _hooks = __webpack_require__(14);
     172
     173var _hooks2 = _interopRequireDefault(_hooks);
     174
     175var _createAddHook = __webpack_require__(15);
     176
     177var _createAddHook2 = _interopRequireDefault(_createAddHook);
     178
     179var _createRemoveHook = __webpack_require__(16);
     180
     181var _createRemoveHook2 = _interopRequireDefault(_createRemoveHook);
     182
     183var _createHasHook = __webpack_require__(17);
     184
     185var _createHasHook2 = _interopRequireDefault(_createHasHook);
     186
     187var _createRunHook = __webpack_require__(18);
     188
     189var _createRunHook2 = _interopRequireDefault(_createRunHook);
     190
     191var _createCurrentHook = __webpack_require__(19);
     192
     193var _createCurrentHook2 = _interopRequireDefault(_createCurrentHook);
     194
     195var _createDoingHook = __webpack_require__(20);
     196
     197var _createDoingHook2 = _interopRequireDefault(_createDoingHook);
     198
     199var _createDidHook = __webpack_require__(21);
     200
     201var _createDidHook2 = _interopRequireDefault(_createDidHook);
     202
     203function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
     204
     205// Add action/filter functions.
     206var addAction = exports.addAction = (0, _createAddHook2.default)(_hooks2.default.actions);
     207var addFilter = exports.addFilter = (0, _createAddHook2.default)(_hooks2.default.filters);
     208
     209// Remove action/filter functions.
     210var removeAction = exports.removeAction = (0, _createRemoveHook2.default)(_hooks2.default.actions);
     211var removeFilter = exports.removeFilter = (0, _createRemoveHook2.default)(_hooks2.default.filters);
     212
     213// Has action/filter functions.
     214var hasAction = exports.hasAction = (0, _createHasHook2.default)(_hooks2.default.actions);
     215var hasFilter = exports.hasFilter = (0, _createHasHook2.default)(_hooks2.default.filters);
     216
     217// Remove all actions/filters functions.
     218var removeAllActions = exports.removeAllActions = (0, _createRemoveHook2.default)(_hooks2.default.actions, true);
     219var removeAllFilters = exports.removeAllFilters = (0, _createRemoveHook2.default)(_hooks2.default.filters, true);
     220
     221// Do action/apply filters functions.
     222var doAction = exports.doAction = (0, _createRunHook2.default)(_hooks2.default.actions);
     223var applyFilters = exports.applyFilters = (0, _createRunHook2.default)(_hooks2.default.filters, true);
     224
     225// Current action/filter functions.
     226var currentAction = exports.currentAction = (0, _createCurrentHook2.default)(_hooks2.default.actions);
     227var currentFilter = exports.currentFilter = (0, _createCurrentHook2.default)(_hooks2.default.filters);
     228
     229// Doing action/filter: true while a hook is being run.
     230var doingAction = exports.doingAction = (0, _createDoingHook2.default)(_hooks2.default.actions);
     231var doingFilter = exports.doingFilter = (0, _createDoingHook2.default)(_hooks2.default.filters);
     232
     233// Did action/filter functions.
     234var didAction = exports.didAction = (0, _createDidHook2.default)(_hooks2.default.actions);
     235var didFilter = exports.didFilter = (0, _createDidHook2.default)(_hooks2.default.filters);
     236
     237/***/ }),
     238/* 14 */
     239/***/ (function(module, exports, __webpack_require__) {
     240
     241"use strict";
     242
     243
     244Object.defineProperty(exports, "__esModule", {
     245  value: true
     246});
     247/**
     248 * Contains the registered hooks, keyed by hook type. Each hook type is an
     249 * array of objects with priority and callback of each registered hook.
     250 */
     251var HOOKS = {
     252  actions: {},
     253  filters: {}
     254};
     255
     256exports.default = HOOKS;
     257
     258/***/ }),
     259/* 15 */
     260/***/ (function(module, exports, __webpack_require__) {
     261
     262"use strict";
     263
     264
     265Object.defineProperty(exports, "__esModule", {
     266        value: true
     267});
     268
     269var _validateNamespace = __webpack_require__(1);
     270
     271var _validateNamespace2 = _interopRequireDefault(_validateNamespace);
     272
     273var _validateHookName = __webpack_require__(0);
     274
     275var _validateHookName2 = _interopRequireDefault(_validateHookName);
     276
     277function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
     278
     279/**
     280 * Returns a function which, when invoked, will add a hook.
     281 *
     282 * @param  {Object}   hooks Stored hooks, keyed by hook name.
     283 *
     284 * @return {Function}       Function that adds a new hook.
     285 */
     286function createAddHook(hooks) {
     287        /**
     288  * Adds the hook to the appropriate hooks container.
     289  *
     290  * @param {string}   hookName  Name of hook to add
     291  * @param {string}   namespace The unique namespace identifying the callback in the form `vendorName/pluginName/functionName`.
     292  * @param {Function} callback  Function to call when the hook is run
     293  * @param {?number}  priority  Priority of this hook (default=10)
     294  */
     295        return function addHook(hookName, namespace, callback) {
     296                var priority = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : 10;
     297
     298
     299                if (!(0, _validateHookName2.default)(hookName)) {
     300                        return;
     301                }
     302
     303                if (!(0, _validateNamespace2.default)(namespace)) {
     304                        return;
     305                }
     306
     307                if ('function' !== typeof callback) {
     308                        console.error('The hook callback must be a function.');
     309                        return;
     310                }
     311
     312                // Validate numeric priority
     313                if ('number' !== typeof priority) {
     314                        console.error('If specified, the hook priority must be a number.');
     315                        return;
     316                }
     317
     318                var handler = { callback: callback, priority: priority, namespace: namespace };
     319
     320                if (hooks.hasOwnProperty(hookName)) {
     321                        // Find the correct insert index of the new hook.
     322                        var handlers = hooks[hookName].handlers;
     323                        var i = 0;
     324                        while (i < handlers.length) {
     325                                if (handlers[i].priority > priority) {
     326                                        break;
     327                                }
     328                                i++;
     329                        }
     330                        // Insert (or append) the new hook.
     331                        handlers.splice(i, 0, handler);
     332                        // We may also be currently executing this hook.  If the callback
     333                        // we're adding would come after the current callback, there's no
     334                        // problem; otherwise we need to increase the execution index of
     335                        // any other runs by 1 to account for the added element.
     336                        (hooks.__current || []).forEach(function (hookInfo) {
     337                                if (hookInfo.name === hookName && hookInfo.currentIndex >= i) {
     338                                        hookInfo.currentIndex++;
     339                                }
     340                        });
     341                } else {
     342                        // This is the first hook of its type.
     343                        hooks[hookName] = {
     344                                handlers: [handler],
     345                                runs: 0
     346                        };
     347                }
     348        };
     349}
     350
     351exports.default = createAddHook;
     352
     353/***/ }),
     354/* 16 */
     355/***/ (function(module, exports, __webpack_require__) {
     356
     357"use strict";
     358
     359
     360Object.defineProperty(exports, "__esModule", {
     361        value: true
     362});
     363
     364var _validateNamespace = __webpack_require__(1);
     365
     366var _validateNamespace2 = _interopRequireDefault(_validateNamespace);
     367
     368var _validateHookName = __webpack_require__(0);
     369
     370var _validateHookName2 = _interopRequireDefault(_validateHookName);
     371
     372function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
     373
     374/**
     375 * Returns a function which, when invoked, will remove a specified hook or all
     376 * hooks by the given name.
     377 *
     378 * @param  {Object}   hooks      Stored hooks, keyed by hook name.
     379 * @param  {bool}     removeAll  Whether to remove all callbacks for a hookName, without regard to namespace. Used to create `removeAll*` functions.
     380 *
     381 * @return {Function}            Function that removes hooks.
     382 */
     383function createRemoveHook(hooks, removeAll) {
     384        /**
     385  * Removes the specified callback (or all callbacks) from the hook with a
     386  * given hookName and namespace.
     387  *
     388  * @param {string}    hookName  The name of the hook to modify.
     389  * @param {string}    namespace The unique namespace identifying the callback in the form `vendorName/pluginName/functionName`.
     390  *
     391  * @return {number}             The number of callbacks removed.
     392  */
     393        return function removeHook(hookName, namespace) {
     394
     395                if (!(0, _validateHookName2.default)(hookName)) {
     396                        return;
     397                }
     398
     399                if (!removeAll && !(0, _validateNamespace2.default)(namespace)) {
     400                        return;
     401                }
     402
     403                // Bail if no hooks exist by this name
     404                if (!hooks.hasOwnProperty(hookName)) {
     405                        return 0;
     406                }
     407
     408                var handlersRemoved = 0;
     409
     410                if (removeAll) {
     411                        handlersRemoved = hooks[hookName].handlers.length;
     412                        hooks[hookName] = {
     413                                runs: hooks[hookName].runs,
     414                                handlers: []
     415                        };
     416                } else {
     417                        // Try to find the specified callback to remove.
     418                        var handlers = hooks[hookName].handlers;
     419
     420                        var _loop = function _loop(i) {
     421                                if (handlers[i].namespace === namespace) {
     422                                        handlers.splice(i, 1);
     423                                        handlersRemoved++;
     424                                        // This callback may also be part of a hook that is
     425                                        // currently executing.  If the callback we're removing
     426                                        // comes after the current callback, there's no problem;
     427                                        // otherwise we need to decrease the execution index of any
     428                                        // other runs by 1 to account for the removed element.
     429                                        (hooks.__current || []).forEach(function (hookInfo) {
     430                                                if (hookInfo.name === hookName && hookInfo.currentIndex >= i) {
     431                                                        hookInfo.currentIndex--;
     432                                                }
     433                                        });
     434                                }
     435                        };
     436
     437                        for (var i = handlers.length - 1; i >= 0; i--) {
     438                                _loop(i);
     439                        }
     440                }
     441
     442                return handlersRemoved;
     443        };
     444}
     445
     446exports.default = createRemoveHook;
     447
     448/***/ }),
     449/* 17 */
     450/***/ (function(module, exports, __webpack_require__) {
     451
     452"use strict";
     453
     454
     455Object.defineProperty(exports, "__esModule", {
     456        value: true
     457});
     458/**
     459 * Returns a function which, when invoked, will return whether any handlers are
     460 * attached to a particular hook.
     461 *
     462 * @param  {Object}   hooks Stored hooks, keyed by hook name.
     463 *
     464 * @return {Function}       Function that returns whether any handlers are
     465 *                          attached to a particular hook.
     466 */
     467function createHasHook(hooks) {
     468        /**
     469  * Returns how many handlers are attached for the given hook.
     470  *
     471  * @param  {string}  hookName The name of the hook to check for.
     472  *
     473  * @return {number}           The number of handlers that are attached to
     474  *                            the given hook.
     475  */
     476        return function hasHook(hookName) {
     477                return hooks.hasOwnProperty(hookName) ? hooks[hookName].handlers.length : 0;
     478        };
     479}
     480
     481exports.default = createHasHook;
     482
     483/***/ }),
     484/* 18 */
     485/***/ (function(module, exports, __webpack_require__) {
     486
     487"use strict";
     488
     489
     490Object.defineProperty(exports, "__esModule", {
     491        value: true
     492});
     493
     494var _validateHookName = __webpack_require__(0);
     495
     496var _validateHookName2 = _interopRequireDefault(_validateHookName);
     497
     498function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
     499
     500/**
     501 * Returns a function which, when invoked, will execute all callbacks
     502 * registered to a hook of the specified type, optionally returning the final
     503 * value of the call chain.
     504 *
     505 * @param  {Object}   hooks          Stored hooks, keyed by hook name.
     506 * @param  {?bool}    returnFirstArg Whether each hook callback is expected to
     507 *                                   return its first argument.
     508 *
     509 * @return {Function}                Function that runs hook callbacks.
     510 */
     511function createRunHook(hooks, returnFirstArg) {
     512        /**
     513  * Runs all callbacks for the specified hook.
     514  *
     515  * @param  {string} hookName The name of the hook to run.
     516  * @param  {...*}   args     Arguments to pass to the hook callbacks.
     517  *
     518  * @return {*}               Return value of runner, if applicable.
     519  */
     520        return function runHooks(hookName) {
     521
     522                if (!(0, _validateHookName2.default)(hookName)) {
     523                        return;
     524                }
     525
     526                if (!hooks.hasOwnProperty(hookName)) {
     527                        hooks[hookName] = {
     528                                runs: 0,
     529                                handlers: []
     530                        };
     531                }
     532
     533                var handlers = hooks[hookName].handlers;
     534
     535                for (var _len = arguments.length, args = Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
     536                        args[_key - 1] = arguments[_key];
     537                }
     538
     539                if (!handlers.length) {
     540                        return returnFirstArg ? args[0] : undefined;
     541                }
     542
     543                var hookInfo = {
     544                        name: hookName,
     545                        currentIndex: 0
     546                };
     547
     548                hooks.__current = hooks.__current || [];
     549                hooks.__current.push(hookInfo);
     550                hooks[hookName].runs++;
     551
     552                var maybeReturnValue = args[0];
     553
     554                while (hookInfo.currentIndex < handlers.length) {
     555                        var handler = handlers[hookInfo.currentIndex];
     556                        maybeReturnValue = handler.callback.apply(null, args);
     557                        if (returnFirstArg) {
     558                                args[0] = maybeReturnValue;
     559                        }
     560                        hookInfo.currentIndex++;
     561                }
     562
     563                hooks.__current.pop();
     564
     565                if (returnFirstArg) {
     566                        return maybeReturnValue;
     567                }
     568        };
     569}
     570
     571exports.default = createRunHook;
     572
     573/***/ }),
     574/* 19 */
     575/***/ (function(module, exports, __webpack_require__) {
     576
     577"use strict";
     578
     579
     580Object.defineProperty(exports, "__esModule", {
     581        value: true
     582});
     583/**
     584 * Returns a function which, when invoked, will return the name of the
     585 * currently running hook, or `null` if no hook of the given type is currently
     586 * running.
     587 *
     588 * @param  {Object}   hooks          Stored hooks, keyed by hook name.
     589 *
     590 * @return {Function}                Function that returns the current hook.
     591 */
     592function createCurrentHook(hooks, returnFirstArg) {
     593        /**
     594  * Returns the name of the currently running hook, or `null` if no hook of
     595  * the given type is currently running.
     596  *
     597  * @return {?string}             The name of the currently running hook, or
     598  *                               `null` if no hook is currently running.
     599  */
     600        return function currentHook() {
     601                if (!hooks.__current || !hooks.__current.length) {
     602                        return null;
     603                }
     604
     605                return hooks.__current[hooks.__current.length - 1].name;
     606        };
     607}
     608
     609exports.default = createCurrentHook;
     610
     611/***/ }),
     612/* 20 */
     613/***/ (function(module, exports, __webpack_require__) {
     614
     615"use strict";
     616
     617
     618Object.defineProperty(exports, "__esModule", {
     619        value: true
     620});
     621/**
     622 * Returns a function which, when invoked, will return whether a hook is
     623 * currently being executed.
     624 *
     625 * @param  {Object}   hooks Stored hooks, keyed by hook name.
     626 *
     627 * @return {Function}       Function that returns whether a hook is currently
     628 *                          being executed.
     629 */
     630function createDoingHook(hooks) {
     631        /**
     632  * Returns whether a hook is currently being executed.
     633  *
     634  * @param  {?string} hookName The name of the hook to check for.  If
     635  *                            omitted, will check for any hook being executed.
     636  *
     637  * @return {bool}             Whether the hook is being executed.
     638  */
     639        return function doingHook(hookName) {
     640                // If the hookName was not passed, check for any current hook.
     641                if ('undefined' === typeof hookName) {
     642                        return 'undefined' !== typeof hooks.__current[0];
     643                }
     644
     645                // Return the __current hook.
     646                return hooks.__current[0] ? hookName === hooks.__current[0].name : false;
     647        };
     648}
     649
     650exports.default = createDoingHook;
     651
     652/***/ }),
     653/* 21 */
     654/***/ (function(module, exports, __webpack_require__) {
     655
     656"use strict";
     657
     658
     659Object.defineProperty(exports, "__esModule", {
     660        value: true
     661});
     662
     663var _validateHookName = __webpack_require__(0);
     664
     665var _validateHookName2 = _interopRequireDefault(_validateHookName);
     666
     667function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
     668
     669/**
     670 * Returns a function which, when invoked, will return the number of times a
     671 * hook has been called.
     672 *
     673 * @param  {Object}   hooks Stored hooks, keyed by hook name.
     674 *
     675 * @return {Function}       Function that returns a hook's call count.
     676 */
     677function createDidHook(hooks) {
     678        /**
     679  * Returns the number of times an action has been fired.
     680  *
     681  * @param  {string} hookName The hook name to check.
     682  *
     683  * @return {number}          The number of times the hook has run.
     684  */
     685        return function didHook(hookName) {
     686
     687                if (!(0, _validateHookName2.default)(hookName)) {
     688                        return;
     689                }
     690
     691                return hooks.hasOwnProperty(hookName) && hooks[hookName].runs ? hooks[hookName].runs : 0;
     692        };
     693}
     694
     695exports.default = createDidHook;
     696
     697/***/ })
     698/******/ ]);
  • src/wp-includes/plugin.php

    diff --git src/wp-includes/plugin.php src/wp-includes/plugin.php
    index 5a87e40635..c0c052a84a 100644
    function doing_filter( $filter = null ) { 
    363363}
    364364
    365365/**
    366  * Retrieve the name of an action currently being processed.
     366 * Retrieve whether action currently being processed.
    367367 *
    368368 * @since 3.9.0
    369369 *
  • src/wp-includes/script-loader.php

    diff --git src/wp-includes/script-loader.php src/wp-includes/script-loader.php
    index 6e83b57d84..e6532b6618 100644
    function wp_default_scripts( &$scripts ) { 
    8585
    8686        $scripts->add( 'wp-a11y', "/wp-includes/js/wp-a11y$suffix.js", array( 'jquery' ), false, 1 );
    8787
     88        $scripts->add( 'wp-hooks', "/wp-includes/js/wp-hooks$suffix.js", array(), false, 1 );
     89
    8890        $scripts->add( 'sack', "/wp-includes/js/tw-sack$suffix.js", array(), '1.6.1', 1 );
    8991
    9092        $scripts->add( 'quicktags', "/wp-includes/js/quicktags$suffix.js", array(), false, 1 );
  • tests/qunit/index.html

    diff --git tests/qunit/index.html tests/qunit/index.html
    index 2ca82b3cdd..c3dc94d46c 100644
     
    7777                <script src="../../src/wp-includes/js/customize-base.js"></script>
    7878                <script src="../../src/wp-includes/js/customize-models.js"></script>
    7979                <script src="../../src/wp-includes/js/shortcode.js"></script>
     80                <script src="../../src/wp-includes/js/wp-hooks.js"></script>
    8081                <script src="../../src/wp-admin/js/customize-controls.js"></script>
    8182                <script src="../../src/wp-includes/js/api-request.js"></script>
    8283                <script src="../../src/wp-includes/js/wp-api.js"></script>
     
    125126                <script src="wp-admin/js/customize-header.js"></script>
    126127                <script src="wp-includes/js/shortcode.js"></script>
    127128                <script src="wp-includes/js/api-request.js"></script>
     129                <script src="wp-includes/js/wp-hooks.js"></script>
    128130                <script src="wp-includes/js/wp-api.js"></script>
    129131                <script src="wp-admin/js/customize-controls.js"></script>
    130132                <script src="wp-admin/js/customize-controls-utils.js"></script>
  • new file tests/qunit/wp-includes/js/wp-hooks.js

    diff --git tests/qunit/wp-includes/js/wp-hooks.js tests/qunit/wp-includes/js/wp-hooks.js
    new file mode 100644
    index 0000000000..3b54ea4177
    - +  
     1/* global wp */
     2( function( QUnit ) {
     3        QUnit.module( 'wp-hooks' );
     4
     5        function filter_a( str ) {
     6                return str + 'a';
     7        }
     8
     9        function filter_b( str ) {
     10                return str + 'b';
     11        }
     12
     13        function filter_c( str ) {
     14                return str + 'c';
     15        }
     16
     17        function action_a() {
     18                window.actionValue += 'a';
     19        }
     20
     21        function action_b() {
     22                window.actionValue += 'b';
     23        }
     24
     25        function action_c() {
     26                window.actionValue += 'c';
     27        }
     28
     29        function filter_check( x ) {
     30                ok( wp.hooks.doingFilter( 'runtest_filter' ), 'The runtest_filter is running.' );
     31                return x;
     32        }
     33
     34        window.actionValue = '';
     35
     36        QUnit.test( 'add and remove a filter', function() {
     37                expect( 1 );
     38                wp.hooks.addFilter( 'test_filter', 'myPlugin/myNamespace/myCallback', filter_a );
     39                wp.hooks.removeFilter( 'test_filter', 'myPlugin/myNamespace/myCallback'  );
     40                equal( wp.hooks.applyFilters( 'test_filter', 'test' ), 'test' );
     41        } );
     42        QUnit.test( 'add a filter and run it', function() {
     43                expect( 1 );
     44                wp.hooks.addFilter( 'test_filter', 'myPlugin/myNamespace/myCallback_filter_a', filter_a );
     45                equal( wp.hooks.applyFilters( 'test_filter', 'test' ), 'testa' );
     46                wp.hooks.removeAllFilters( 'test_filter' );
     47        } );
     48
     49        QUnit.test( 'add 2 filters in a row and run them', function() {
     50                expect( 1 );
     51                wp.hooks.addFilter( 'test_filter', 'myPlugin/myNamespace/myCallback_filter_a', filter_a );
     52                wp.hooks.addFilter( 'test_filter', 'myPlugin/myNamespace/myCallback_filter_b', filter_b );
     53                equal( wp.hooks.applyFilters( 'test_filter', 'test' ), 'testab' );
     54                wp.hooks.removeAllFilters( 'test_filter' );
     55        } );
     56
     57        QUnit.test( 'add 3 filters with different priorities and run them', function() {
     58                expect( 1 );
     59                wp.hooks.addFilter( 'test_filter', 'myPlugin/myNamespace/myCallback_filter_a', filter_a );
     60                wp.hooks.addFilter( 'test_filter', 'myPlugin/myNamespace/myCallback_filter_b', filter_b, 2 );
     61                wp.hooks.addFilter( 'test_filter', 'myPlugin/myNamespace/myCallback_filter_c', filter_c, 8 );
     62                equal( wp.hooks.applyFilters( 'test_filter', 'test' ), 'testbca' );
     63                wp.hooks.removeAllFilters( 'test_filter' );
     64        } );
     65
     66        QUnit.test( 'add and remove an action', function() {
     67                expect( 1 );
     68                window.actionValue = '';
     69                wp.hooks.addAction( 'test_action', 'myPlugin/myNamespace/myCallback', action_a );
     70                wp.hooks.removeAction( 'test_action', 'myPlugin/myNamespace/myCallback' );
     71                wp.hooks.doAction( 'test_action' );
     72                equal( window.actionValue, '' );
     73        } );
     74
     75        QUnit.test( 'add an action and run it', function() {
     76                expect( 1 );
     77                window.actionValue = '';
     78                wp.hooks.addAction( 'test_action', 'myPlugin/myNamespace/myCallback', action_a );
     79                wp.hooks.doAction( 'test_action' );
     80                equal( window.actionValue, 'a' );
     81                wp.hooks.removeAllActions( 'test_action' );
     82        } );
     83
     84        QUnit.test( 'add 2 actions in a row and then run them', function() {
     85                expect( 1 );
     86                window.actionValue = '';
     87                wp.hooks.addAction( 'test_action', 'myPlugin/myNamespace/myCallback', action_a );
     88                wp.hooks.addAction( 'test_action', 'myPlugin/myNamespace/myCallback', action_b );
     89                wp.hooks.doAction( 'test_action' );
     90                equal( window.actionValue, 'ab' );
     91                wp.hooks.removeAllActions( 'test_action' );
     92        } );
     93
     94        QUnit.test( 'add 3 actions with different priorities and run them', function() {
     95                expect( 1 );
     96                window.actionValue = '';
     97                wp.hooks.addAction( 'test_action', 'myPlugin/myNamespace/myCallback', action_a );
     98                wp.hooks.addAction( 'test_action', 'myPlugin/myNamespace/myCallback', action_b, 2 );
     99                wp.hooks.addAction( 'test_action', 'myPlugin/myNamespace/myCallback', action_c, 8 );
     100                wp.hooks.doAction( 'test_action' );
     101                equal( window.actionValue, 'bca' );
     102                wp.hooks.removeAllActions( 'test_action' );
     103        } );
     104
     105        QUnit.test( 'pass in two arguments to an action', function() {
     106                var arg1 = 10,
     107                        arg2 = 20;
     108
     109                expect( 4 );
     110
     111                wp.hooks.addAction( 'test_action', 'myPlugin/myNamespace/myCallback', function( a, b ) {
     112                        equal( arg1, a );
     113                        equal( arg2, b );
     114                } );
     115                wp.hooks.doAction( 'test_action', arg1, arg2 );
     116                wp.hooks.removeAllActions( 'test_action' );
     117
     118                equal( arg1, 10 );
     119                equal( arg2, 20 );
     120        } );
     121
     122        QUnit.test( 'fire action multiple times', function() {
     123                var func;
     124                expect( 2 );
     125
     126                func = function() {
     127                        ok( true );
     128                };
     129
     130                wp.hooks.addAction( 'test_action', 'myPlugin/myNamespace/myCallback', func );
     131                wp.hooks.doAction( 'test_action' );
     132                wp.hooks.doAction( 'test_action' );
     133                wp.hooks.removeAllActions( 'test_action' );
     134        } );
     135
     136        QUnit.test( 'remove specific action callback', function() {
     137                window.actionValue = '';
     138                wp.hooks.addAction( 'test_action', 'myPlugin/myNamespace/myCallback_action_a', action_a );
     139                wp.hooks.addAction( 'test_action', 'myPlugin/myNamespace/myCallback_action_b', action_b, 2 );
     140                wp.hooks.addAction( 'test_action', 'myPlugin/myNamespace/myCallback_action_c', action_c, 8 );
     141
     142                wp.hooks.removeAction( 'test_action', 'myPlugin/myNamespace/myCallback_action_b' );
     143                wp.hooks.doAction( 'test_action' );
     144                equal( window.actionValue, 'ca' );
     145                wp.hooks.removeAllActions( 'test_action' );
     146        } );
     147
     148        QUnit.test( 'remove all action callbacks', function() {
     149                window.actionValue = '';
     150                wp.hooks.addAction( 'test_action', 'myPlugin/myNamespace/myCallback_action_a', action_a );
     151                wp.hooks.addAction( 'test_action', 'myPlugin/myNamespace/myCallback_action_b', action_b, 2 );
     152                wp.hooks.addAction( 'test_action', 'myPlugin/myNamespace/myCallback_action_c', action_c, 8 );
     153
     154                wp.hooks.removeAllActions( 'test_action' );
     155                wp.hooks.doAction( 'test_action' );
     156                equal( window.actionValue, '' );
     157        } );
     158
     159        QUnit.test( 'remove specific filter callback', function() {
     160                wp.hooks.addFilter( 'test_filter', 'myPlugin/myNamespace/myCallback_filter_a', filter_a );
     161                wp.hooks.addFilter( 'test_filter', 'myPlugin/myNamespace/myCallback_filter_b', filter_b, 2 );
     162                wp.hooks.addFilter( 'test_filter', 'myPlugin/myNamespace/myCallback_filter_c', filter_c, 8 );
     163
     164                wp.hooks.removeFilter( 'test_filter', 'myPlugin/myNamespace/myCallback_filter_b' );
     165                equal( wp.hooks.applyFilters( 'test_filter', 'test' ), 'testca' );
     166                wp.hooks.removeAllFilters( 'test_filter' );
     167        } );
     168
     169        QUnit.test( 'remove all filter callbacks', function() {
     170                wp.hooks.addFilter( 'test_filter', 'myPlugin/myNamespace/myCallback_filter_a', filter_a );
     171                wp.hooks.addFilter( 'test_filter', 'myPlugin/myNamespace/myCallback_filter_b', filter_b, 2 );
     172                wp.hooks.addFilter( 'test_filter', 'myPlugin/myNamespace/myCallback_filter_c', filter_c, 8 );
     173
     174                wp.hooks.removeAllFilters( 'test_filter' );
     175                equal( wp.hooks.applyFilters( 'test_filter', 'test' ), 'test' );
     176        } );
     177
     178        // Test doingAction, didAction, hasAction.
     179        QUnit.test( 'Test doingAction, didAction and hasAction.', function() {
     180
     181                // Reset state for testing.
     182                wp.hooks.removeAllActions( 'test_action' );
     183                wp.hooks.addAction( 'another_action', 'myPlugin/myNamespace/myCallback', function(){} );
     184                wp.hooks.doAction( 'another_action' );
     185
     186                // Verify no action is running yet.
     187                ok( ! wp.hooks.doingAction( 'newtest_action' ), 'The newtest_action is not running.' );
     188                equal( wp.hooks.didAction( 'newtest_action' ), 0, 'The newtest_action has not run.' );
     189                ok( ! wp.hooks.hasAction( 'newtest_action' ), 'The newtest_action is not registered.' );
     190
     191                wp.hooks.addAction( 'newtest_action', 'myPlugin/myNamespace/myCallback', action_a );
     192
     193                // Verify action added, not running yet.
     194                ok( ! wp.hooks.doingAction( 'newtest_action' ), 'The newtest_action is not running.' );
     195                equal( wp.hooks.didAction( 'newtest_action' ), 0, 'The newtest_action has not run.' );
     196                ok( wp.hooks.hasAction( 'newtest_action' ), 'The newtest_action is registered.' );
     197
     198                wp.hooks.doAction( 'newtest_action' );
     199
     200                // Verify action added and running.
     201                equal( wp.hooks.didAction( 'newtest_action' ), 1, 'The newtest_action has run once.' );
     202                ok( wp.hooks.hasAction( 'newtest_action' ), 'The newtest_action is registered.' );
     203
     204                wp.hooks.doAction( 'newtest_action' );
     205                equal( wp.hooks.didAction( 'newtest_action' ), 2, 'The newtest_action has run twice.' );
     206
     207                wp.hooks.removeAllActions( 'newtest_action' );
     208
     209                // Verify state is reset appropriately.
     210                equal( wp.hooks.didAction( 'newtest_action' ), 2, 'The newtest_action has run twice.' );
     211                ok( ! wp.hooks.hasAction( 'newtest_action' ), 'The newtest_action is not registered.' );
     212
     213                wp.hooks.doAction( 'another_action' );
     214                ok( ! wp.hooks.doingAction( 'newtest_action' ), 'The newtest_action is running.' );
     215
     216                // Verify hasAction returns false when no matching action.
     217                ok( ! wp.hooks.hasAction( 'notanewtest_action' ), 'The notanewtest_action is registered.' );
     218
     219        } );
     220
     221        QUnit.test( 'Verify doingFilter, didFilter and hasFilter.', function() {
     222                expect( 5 );
     223                wp.hooks.addFilter( 'runtest_filter', 'myPlugin/myNamespace/myCallback', filter_check );
     224                equal( wp.hooks.applyFilters( 'runtest_filter', 'test' ), 'test' );
     225
     226                // Verify filter added and running.
     227                equal( wp.hooks.didFilter( 'runtest_filter' ), 1, 'The runtest_filter has run once.' );
     228                ok( wp.hooks.hasFilter( 'runtest_filter' ), 'The runtest_filter is registered.' );
     229                ok( ! wp.hooks.hasFilter( 'notatest_filter' ), 'The notatest_filter is not registered.' );
     230
     231                wp.hooks.removeAllFilters( 'runtest_filter' );
     232        } );
     233/*
     234*/
     235} )( window.QUnit );