Hooks.js
The Hooks.js file adds the ability to hook into methods and functions just like in PHP.
The Hooks.js file can be loaded both in the backend and in the frontend of your site! To make loading the global ProcessWire object as efficient as possible, it is split up into several components, like this one.
File structure
The file is structured as follows:
// create global ProcessWire object if it doesn't exist
if (typeof ProcessWire == "undefined") ProcessWire = {};
// function for custom scope to not pollute global namespace
(() => {
// ##### Public ProcessWire API #####
ProcessWire.addHookAfter = addHookAfter;
ProcessWire.addHookBefore = addHookBefore;
ProcessWire.wire = wire;
// ##### Internal code to support hooks #####
// hooks storage
const hooks = { ... };
// HookEvent class to use in hooks
// eg event.arguments() or event.return
class HookEvent { ... }
// addHookAfter
function addHookAfter(name, fn, priority = 100) { ... }
// addHookBefore
function addHookBefore(name, fn, priority = 100) { ... }
// executeHooks
// this executes all attached before and after hooks
function executeHooks(type, hookName, hookEvent) { ... }
// wire() method to apply HookHandler to an object
// this is all we need to make any object hookable :)
function wire(object, name = null) { ... }
})();
Explanation
If the Hooks.js file is loaded on the frontend, the ProcessWire
object will not be available. In this case it will create an empty object on the fly, which will then be enriched with some hook-related methods.
Next, we add an auto-executed function. All code inside this function has its own scope, so it doesn't pollute the global namespace. Only some of the features are exposed globally via the ProcessWire
object:
ProcessWire.addHookAfter()
ProcessWire.addHookBefore()
ProcessWire.wire()
Next, we define the hooks
object, which will store all hooks. This is the object that users can add hooks to via ProcessWire.addHookAfter()
and ProcessWire.addHookBefore()
.
Then we define the HookEvent
class that will be available in every hook via the event
parameter as you know it from ProcessWire's core. This class basically only adds the event.arguments(...) syntax to make JS hooks match PHP hooks as much as possible.
After that, we implement the addHookAfter()
and addHookBefore()
methods that users can use to add hooks and we implement the executeHooks()
method, which will execute any attached hooks whenever a hookable method is called.
Finally, the wire()
method is used to make any object hookable. It takes an object and a name (optional) and returns an object with the same methods as the original object, but with added hooking functionality.