Hooks and Joomla!

2011-05-15 15:27
Written by

One of the best things about CiviCRM 3.4 and 4 for Joomla! users is that hooks are now implemented using the Joomla! plugin system. This actually has always worked, but it was not documented and now it's implemented a lot more cleanly.


As Joomla! developers know, Joomla plugins are an implementation of the observer design pattern. They are part of the framework layer sitting next to the Joomla! Platform and external libraries and underneath the CMS application.  Plugins are incredibly powerful and can override almost anything that happens in Joomla. At the same time, basic plugins are simple to code, at base just requiring one php file and one xml file. They also should have two language files (I'm going to skip those) because I'm not  giving a plugin tutorial here but you can read more in the Joomla documentation


Plugins respond to events and context. So in the case of hooks we need to have extension specific plugins that will be listening when we are inside com_civicrm. Therefore the plugins implementing hooks will go into a plugin subfolder called civicrm (plugins/civicrm). Each plugin will have its own folder.


Plugins can implement as many hooks as you want in whatever combination you want, but for this post I'm going to show how to make a plugin implementing the example for hook_civicrm_tabs in the CiviCRM wiki. This hook is used when composing the tabs in a contact display. 


The example shows how to remove the contributions tab and then display a copy of it with a new name as the last tab.


I'm going to call the plugin tabs.  It's important to understand that Joomla! is strongly conventions driven so you should always follow the naming patterns to ensure that you are taking maximum advantage of the Joomla! framework. 


To make the plugin first, we make the xml file, tabs.xml. (I'm having trouble getting indenting to render properly so just imagine that part.)

<?xml version="1.0" encoding="UTF-8"?>
<extension version="1.6" type="plugin" group="civicrm">
<author>Joomla! Project</author>
<creationDate>November 2005</creationDate>
<copyright>Copyright (C) 2005 - 2011 Open Source Matters. All rights reserved.</copyright>
<license>GNU General Public License version 2 or later; see LICENSE.txt</license>

   <filename plugin="tabs">tabs.php</filename>


Notice a few things. First,<extension version="1.6" type="plugin" group="civicrm"> identifies this as a plugin and says what group it will belong to. The installer will use this to put it in the right location.

Second, notice the name of the plugin is plg_civicrm_tabs which reflects the file system location of the plugin. From Joomla 1.6 forward the php native ini parser is used and strings should have no spaces and should be named spaced. The same applies for the description.  These strings will be one of the language files (language/en-GB/en-GB.plg_civicrm_tabs.sys.ini). In Joomla we always include a blank index.html to keep nosey people from seeing what files you have. These strings will also work in Joomla! 1.5. 

Third, note <filename plugin="tabs">tabs.php</filename> this gives the plugin name and the name of the file with the code. Notice that they match. All files in the language folder are also included. Again following the naming and location conventions is important. 

Next we create tabs.php. 


 * @version 
 * @package Civicrm
 * @subpackage Joomla Plugin
 * @copyright Copyright (C) 2005 - 2011 Open Source Matters, Inc. All rights reserved.
 * @license GNU General Public License version 2 or later; see LICENSE.txt

// No direct access

defined('_JEXEC') or die;

class plgCivicrmTabs extends JPlugin


      * Example Civicrm Plugin
      * @package Civicrm
        * Joomla plugins
        * @since 1.5

     public function civicrm_tabs(&$tabs, $contactID)

        // unset the contribition tab, i.e. remove it from the page unset( $tabs[1] );
        // let's add a new "contribution" tab with a different name and put it last
        // this is just a demo, in the real world, you would create a url which would
        // return an html snippet etc.

         $url = CRM_Utils_System::url( 'civicrm/contact/view/contribution',
                                  "reset=1&snippet=1&force=1&cid=$contactID" );

          $tabs[] = array( 'id'    => 'mySupercoolTab',
                           'url'   => $url,
                           'title' => 'Contribution Tab Renamed',
                           'weight' => 300 );



First we use jimport to bring in the plugin class. Then we extend it using the appropriate naming convention:

 Then except for changing the name slightly to civicrm_tabs (instead of civitest_civicrm_tabs)  we just paste in the whole example from the wiki and close up the class. 
Now we are ready to install. You can zip up the files and use the normal Joomla extension installer or in Joomla! 1.6 you can put the files in the files in the appropriate location plugins/civicrm/tabs and use discover install. Don't forget to go to the plugin manager and enable it. 
A couple of notes. First, you can put all of your hooks into one big plugin if you want. And of course you can make your actual code as complex as you want. Plugins also have a Joomla! viewing access level associated with them. While normally these are left on public you can play around with them and (for example) make plugins that only run when the user is an administrator. Of course the ACL in Joomla! 1.6 makes these possibilities a lot more interesting. 
Okay, about the language files. I mentioned there are two. The first should be 

it contains:


; Joomla! Project
; Copyright (C) 2005 - 2011 Open Source Matters. All rights reserved.
; License GNU General Public License version 2 or later; see LICENSE.txt, see LICENSE.php
; Note : All ini files need to be saved as UTF-8

PLG_CIVICRM_TABS_XML_DESCRIPTION="Deletes the existing contribution tab and adds a new one with a different name."


The second should be




; Joomla! Project
; Copyright (C) 2005 - 2011 Open Source Matters. All rights reserved.
; License GNU General Public License version 2 or later; see LICENSE.txt, see LICENSE.php
; Note : All ini files need to be saved as UTF-8


Those will make your listing in the plugin manager and also the plugin edit form page look nice. 
You'll find some more example code in the civicrm zip file at /administrator/com_civicrm/admin/civicrm/joomla/plugins or in the civicrm/joomla/plugins folder of your administrator.
There is a lot more that you can do with plugins and CiviCRM (like responding to user, form, and content events) but implementing hook plugins is a great way to get started.


Filed under


Thanks for providing the documentation for this.

I've created a base plugin to help get people started. It implements the hook above and one other, and is a bit more refined than the example code that ships with core -- including implementing the language files. You can access it here (on the wiki).

Will (not verified)
2011-09-26 - 06:22

I know that I am likely missing something REALLY fundamentally simple, but, when I take the sample code as shown above, it works. I simply change the file names to ones that I like, also changing the XML... plugin="test" test.php. It no longer works. What stupid thing am I over looking?


its a lot easier to support folks on the forums. Also a lot more users read the forums than blog comments