Page tree
Skip to end of metadata
Go to start of metadata

Hooks can be explicitly requested inside a module by defining static functions:

public static function myGuiHooks() { return array(); }
public static function myDialplanHooks() { return array(); }
public static function myConfigPageInits() { return array(); }

Writing files (as part of retrieve_conf) can be requested by creating the functions

public function genConfig() { return Config; }
public function writeConfig($config) { $this->FreePBX->WriteConfig($config); }

GUI Hooks

See BMO/GuiHooks.class.php

Note that all the hook function must be 'public static function' (except for getConfig/writeConfig, documented further down)

Explicitly intercepting the output of a legacy module, and altering it.

This uses the magic 'INTERCEPT' key, which requests the function 'doGuiIntercept' is called when any of the pages returned are about to be displayed

public static function myGuiHooks() {
    return array("INTERCEPT" => "modules/modulename/pagename.modulename.php");
    // or
    return array("INTERCEPT" => array("modules/modulename/page.moduleame.php", "modules/module2/page.module2.php"));

public function doGuiIntercept($filename, &$output) {
    if ($filename == "modules/modulename/pagename.modulename.php") {
        $output = "<h2>I just added this to the top of the page</h2>\n".$output;
    } elseif ( $filename == "modules/anothermodule/anotherpagename.php") {
        $output = "This totally replaces the page<br>\n";

Intercepting a GUI Elements page

This is just an array of strings returned by myGuiHooks(). Returning 'core' means that your function doGuiHook will be handed the GUI Elements $currentcomponent after if has been processed by the page. Note that if the page you're requesting doesn't use GUI Elements, you'll need to use the INTERCEPT key, above.

This requires a reload to work.

    public static function myGuiHooks() {
        return array("core");
        // or
        return array("core", "INTERCEPT" => array("modules/modulename/page.moduleame.php", "modules/module2/page.module2.php"));

    public function doGuiHook(&$cc) {
        $cc->addguielem("_top", new gui_pageheading('', 'I added a header', false));

Dialplan Hooks

See BMO/DialplanHooks.class.php

public static function myDialplanHooks() { return true; }
// 'true' references the default priority of '500'
public function doDialplanHook(&$ext, $engine, $priority) {
    $ext->addGlobal('THIS_IS_A_GLOBAL', 'globalsrule');

Most modules don't specify a priority, however, to ensure you're run last, you can set your priority to 900 to ensure you're handed a complete $ext object before it is written. You can also return an array:

public static function myDialplanHooks() { return array(100, 900); }
public function doDialplanHook(&$ext, $engine, $priority) {
    if ($priority == 100) {
        // Do first things to $ext
    } elseif ($priority == 900) {
        // Do things after everything else

HTTP Hooks (Config Page Inits)

See BMO/GuiHooks.class.php

public static function myConfigPageInits() { return array("extensions", "users"); }
public function doConfigPageInit($display) {
    if ($display == "extensions") {
        // You have access to the $_REQUEST, and the callback from the page that requested it
        // has already run.
    } elseif ($display == "users") {
        // Do something slightly different if they're in device/user mode

Note that the 'owning' page will ALWAYS have its callbacks processed first. There is currently no way to hook in prior to the owning page having access to the $_REQUEST.

Writing Files (from retrieve_conf)

See BMO/FileHooks.class.php

public function genConfig() {
    return array("filename" => "Stuff to write to filename");
public function writeConfig($c) {
    // The output of genConfig is handed to writeConfig, after any hook requests have been processed.
    // Note: That hook hasn't actually been written yet. The code does $mod->writeConfig($mod->genConfig())

Both genConfig and writeConfig must be defined.

General Module Hooks

Say we created a module called SMS and we want other modules to be able to hook into a certain function from within SMS. The way to do that is as follows.

Setup the Hook Call

In SMS we need to add this function call to the method we want to expose (Usually in <modulename>.class.php, ex: Sms.class.php):

public function loadAdaptor($adaptor) {

We can pass processHooks any data we want as well:

public function loadAdaptor($adaptor) {
    $data = array("this is my data array");

Process Hooks will then call all modules which have requested to hook into SMS (see below). It will return an array like so:

public function loadAdaptor($adaptor) {
    $data = array("this is my data array");
    $out = \FreePBX::Hooks()->processHooks($data); 
     * $out will look like:
     * array(
     *     "FreePBX\Modules\Sipstation" => array("stuff"), //see below as to why this is output
     *     "calledModuleClassName1" => data,
     *     "calledModuleClassName2" => data

Setup the Hook Processor

To be able to hook into SMS you need to tell FreePBX about yourself and what you are trying to request. Here is an example from the SIPStation module

First start off by modifying module.xml

    <sms namespace="FreePBX\modules" class="Sms">
      <method namespace="FreePBX\Modules" class="Sipstation" callingMethod="loadAdaptor">smsAdaptor</method>

Let's break this apart, every hook will have a declaration, you define that with this line:

<sms namespace="FreePBX\modules" class="Sms">

If the module you are trying to hook into doesn't have a namespace you can omit that, however you can NOT omit class (which is case sensitive)

<sms class="Sms">

To add a priority to your call just add a "priority" attribute. If no priority attribute is added the priority will be set at 500

<sms class="Sms" priority="100">

Next we declare who we are and the method we want to hook into ("callingMethod").

  • namespace: The namespace of this module
  • class: The class of this module
  • callingMethod: The method we want to hook into
<method namespace="FreePBX\Modules" class="Sipstation" callingMethod="loadAdaptor">

Finally we add our method name (which is the method that will be called from within SMS), which we have named "smsAdaptor":

<method namespace="FreePBX\Modules" class="Sipstation" callingMethod="loadAdaptor">smsAdaptor</method>


In SIPStation we have now added our method:

public function smsAdaptor($data) {
    //From above, $data would be: array("this is my data array")
    return array("stuff");

After all of this is through you'll then need to run retrieve_conf so the caching engine will pickup on your changes.

  • No labels