Enano uses the concept of hooks to allow plugins to extend the core. A hook is a point in Enano's source code where plugin code can be run. Hooks give you the ability to change variables, manipulate settings, add new fields (and the associated validation code), and trigger events right from your plugin code, without ever having to force the user to edit Enano source code.

While Enano is GPL, we strive to avoid "mod-based" expansion systems because they involve patching different parts of the core. While patching allows slightly greater flexibility, we think that well-designed code can allow the same extensibility. Patching the core is bad for user experience because if more than one plugin needs to patch the same section of code, the patching process will fail, forcing the administrator to do 3-way merges and stare at diffs for several minutes trying to figure out what code needs to go where. Plugin conflicts are extremely rare in Enano thanks to the design of the hook system.

The plugin API

Most developers will only need two methods in the hook API: $plugins->setHook(), and $plugins->attachHook(), and in many cases, only the latter.

$plugins->attachHook(string $hook, string $code)

This method is used to insert code to be run at the specified hook. In almost all cases, $code will be put through eval() and no return is expected. There are a couple of individual hooks where a return value is expected; these are documented in phpDoc blocks above the hook.

A common (and recommended) practice to simplify code and reduce the amount of parsing that has to be done with eval() is to call a helper function from the hook, passing variables by reference when needed.

Simple example

  '$text = str_replace("Goodbye, Mr. Chips", "Hello, Mr. Carrots", $text);');

More complex example

$plugins->attachHook('render_wikiformat_pre', 'myplugin_parser_ext($text);');
// Notice that $text is passed by reference.
function myplugin_parser_ext(&$text)
  $text = str_replace("Goodbye, Mr. Chips", "Hello, Mr. Carrots", $text);

Unless it is specified in the hook documentation, never EVER use return in a hook. Otherwise, you will prevent any plugins that attach after yours from running at that hook. (Using return in a helper function is fine.)

$plugins->setHook(string $hook, bool $dont_merge = false)

As suggested, setHook() is the opposite of attachHook() - it returns all of the code that has been attached to the given hook so that you can eval() it.

The return from this method is always an array for backward compatibility reasons. In the past, this method returned an array, each value being a different hook. It was then discovered that implode()ing the array was a good way of optimizing execution because it reduced eval() calls. However we wanted to keep the code used to set hooks the same, so we left the return as an array.

The $dont_merge parameter, if true, will disable this new behavior and return each attached hook individually. You should do this only if you expect each hook to return something for you to check.

Why are we documenting this here? Plugins are encouraged to expand each other. For example, the Newsboy plugin can use Feed Me to add an additional RSS feed for news. The Gorilla pastebin plugin will use GeSHi to highlight pastes created with it. Use other plugins to advantage - and let other developers do the same with yours. It saves code meaning less effort for you as a developer.

Javascript API

Javascript hooks work in the exact same way as PHP hooks with the attachHook function. Like PHP hooks, Javascript hooks use eval(), which means you can access and change variables.

attachHook('login_build_form', 'yk_login_dlg_hook(table);');
// Here we have an example of an HTML table being appended through the DOM.
function yk_login_dlg_hook(table)
  window.yubikey_otp_current = false;
  var tr = document.createElement('tr');
  var td = document.createElement('td');
    .attr('colspan', '2')
    .css('text-align', 'center')
    .css('font-size', 'smaller')
    .css('font-weight', 'bold')
    .html('<a href="#" onclick="yk_mb_init(yk_login_validate_reqs); return false;"' +
             ' style="color: #6fa202">' + $lang.get('yubiauth_btn_enter_otp') + '</a>');
  $('a', td).blur(function(e)
      $('#messageBoxButtons input:button:first').focus();
  if ( window.yk_reg_require_otp || window.yk_user_enabled )
      }, 750);

Template hooks

Templates can define hook points where plugins can add their own HTML. The syntax within template files is:

<!-- HOOK hook_name -->

Then you can attach to the hook in both PHP and Javascript. (Do note that this depends on the compiler, e.g. you cannot attach to a template compiled with the PHP API via Javascript.


$plugins->attachHook('hook_name', "echo 'Hello world!';");

In Javascript

// Note the "thook_" prefix!
attachHook('thook_hook_name', 'do_stuff();');
function do_stuff()
    // Echo() is case sensitive.
    Echo('Hello world!');
    Echo('Value of the variable foo: ' + Template.tpl_strings['foo']);

Categories: (Uncategorized)