Summary
We offer out-of-the-box the possibility to extend the functionality of the site by hooking on the execution of the functions on browser side. Although this feature was initially designed to allow different integrations (such as GA/GTM or New Relic), it is perfectly adapted to extend the functionality of the site as it may be needed. Be aware that using extensions requires development skills (mostly on Javascript). The level of the required skills depends on the complexity of the extension.
The basic principle of hooks is that are executed immediately after the execution of the target function (which has to be known in the global scope), it is aware of the result of the execution of the target function, it is aware of the arguments used to execute the target function and it can take additional parameters to further extend the functionality.
The possibility to extend the functionality on server side is provided by default by Jekyll plugins
Target function
The target function needs to be known in the global scope to be hookable. You may take a look to this document to see an example of how to make a function hookable.
The hook is set by hooks.addAction method which takes the following parameters:
hookable function: the name of the target functionadditional arguments: array of values which will be attached to the hook besides of the target function arguments which are passed by default to any hookpriority(0 is the highest): sets the order of execution for the hooks attached to the same target functionhook type: string which can beinitorpreorpost
Hook type
There are three types of hooks, depending on what target function is needed to be extended. There are three intervals in which the potential target functions are executed:
- Executed outside/before
document.ready(INIT-HOOKS). - Executed after
document.readyand before the document/page is fully loaded, including all async functions (PRE-HOOKS) - Executed on user action such as click on buttons (
POST-HOOKS)
The key of using hooks is to set them before the execution of the target function. If the hook is set after the execution of the target function, it has no effect since the target function execution cannot be captured anymore.
INIT-HOOKS
These hooks are ideally for inline functions executed within <script> tags and for functions executed outside document.ready blocks. These hooks are located in _includes/siteIncludes/partials/init-hooks.html.
INIT-HOOKS does not have access to any asset (variables, functions) since these are not available at the time of such target function execution. Only the super globals are available at the moment of the execution of the INIT-HOOKS target functions.
Example of an init hook:
<script id="init-hooks">
/*
* define here the actions that hooks into site init proces
* init process = any function executed before document.ready event
* can be useful to hook on any function called by <script> tag
* only settings superglobal is visible here
* HEADS UP!!!
* AT LEAST ONE INIT HOOK ACTION MUST BE SET IN ORDER TO ALLOW PRE AND POST HOOKS
*/
hooks.addAction('customiseTheme', (functionName, result, args) => {
console.log(`init hook after: ${functionName} on {{page.permalink}}`);
nrLog(
'loading page',
`executed ${functionName}`,
'info',
{
functionName: functionName,
result: result,
args: args
}
);
}, 0, 'init');
</script>
PRE_HOOKS
These hooks are ideally for functions executed after document.ready and before the document/page is fully loaded. These hooks are located in assets/js/pre-hooks.js.
PRE-HOOKS may not have access to some assets (variables, functions) since these may not be available at the time of such target function execution. When setting the hooks it is recommended to always test if the assets you want to use are available. Such test can be easily performed by a simple console.log(<asset>).
Examples of pre-hooks:
hooks.addAction('removeUselessElements', (functionName, result, args) => {
console.log(`sample pre-hook after: ${functionName} on ${$('page-data-permalink').text()}`)
}, 5, 'pre');
hooks.addAction('removeUselessElements', (functionName, result, args) => {
console.log(`sample pre-hook after: ${functionName} on ${$('page-data-permalink').text()} higher priority`)
}, 4, 'pre');
hooks.addAction('setPageButtonsFunctions', (functionName, result, args) => {
console.log(`sample pre-hook after: ${functionName} on ${$('page-data-permalink').text()}`)
}, 1, 'pre');
hooks.addAction('addCat', (functionName, result, args) => {
console.log(`sample pre-hook after: ${functionName} on ${$('page-data-permalink').text()} lower priority`)
},7, 'pre');
POST-HOOKS
These hooks are ideally for functions executed in user actions such as click on buttons (POST-HOOKS). These hooks are located in assets/js/post-hooks.js.
POST-HOOKS have access to all assets (variables, functions) since all of these are available at the time of such target function execution.
Examples of post-hooks:
postHooksActions = {
addNoteAction: (functionName, result, args, ...extraArgs) => {
const userToken = Cookies.get(settings.user.userTokenCookie);
gtmObject = {
'userToken': userToken,
'event': 'Add_Custom_Note'
};
fireGTMTag(gtmObject);
},
addTagAction: (functionName, result, args, ...extraArgs) => {
const userToken = Cookies.get(settings.user.userTokenCookie);
gtmObject = {
'userToken': userToken,
'event': 'Add_Custom_Tag'
};
fireGTMTag(gtmObject);
},
addCatAction: (functionName, result, args, ...extraArgs) => {
const userToken = Cookies.get(settings.user.userTokenCookie);
gtmObject = {
'userToken': userToken,
'event': 'Add_Custom_Cat'
};
fireGTMTag(gtmObject);
},
savedItemsToJsonAction: (functionName, result, args) => {
nrLog(
'savedItems to JSON',
'savedItems saved to JSON',
'info',
{
functionName: functionName,
result: result,
args: args
}
);
},
savedItemsFromJsonAction: (functionName, result, args, ...extraArgs) => {
nrLog(
'savedItems from JSON',
'savedItems loaded from JSON',
'info',
{
functionName: functionName,
result: result,
args: args,
argsExtra: extraArgs,
}
);
},
showToastAction: (functionName, result, args, ...extraArgs) => {
nrLog(
'toast was shown',
'show toast',
'warn',
{
functionName: functionName,
result: result,
args: args,
argsExtra: extraArgs,
}
);
}
}
hooks.addAction('addNote', globUtils.bindArgsAtEnd(postHooksActions.addNoteAction, ), 0, 'post'); // hook by function name
hooks.addAction('addTag', globUtils.bindArgsAtEnd(postHooksActions.addTagAction, ), 0, 'post');
hooks.addAction('addCat', globUtils.bindArgsAtEnd(postHooksActions.addCatAction, ), 0, 'post');
hooks.addAction('saveLocalStorageKeyAsJsonFile', postHooksActions.savedItemsToJsonAction, 0, 'post');
hooks.addAction('loadLocalStorageKeyFromJsonFile', globUtils.bindArgsAtEnd(postHooksActions.savedItemsFromJsonAction, ), 0, 'post');
hooks.addAction('showToast', postHooksActions.showToastAction, 0, 'post');
// the following hooks are tests, may be removed later
hooks.addActionEX(deleteNote, (functionName, result, args) => {
console.log(`sample post-hook by object after: ${functionName} on ${$('page-data-permalink').text()}`)
}, 0, 'post'); // hook by function object
hooks.addAction('addCat', (functionName, result, args) => {
console.log(`sample post-hook after: ${functionName} on ${$('page-data-permalink').text()}`)
},4, 'post');
hooks.addAction('addCat', (functionName, result, args) => {
console.log(`sample post-hook after: ${functionName} on ${$('page-data-permalink').text()} higher priority`)
},3, 'post')
On this page
