Writing a Joomla plugin

I’ve been working on a Joomla! project recently & have needed to write several plugins so I thought I’d write about how I wrote one that notified administrator when a user updates their JomSocial profile.

About Plugins

Joomla! plugins are code that implements additional features without the need to hack core code. Often they ‘plugin’ into system events (or hooks) & therefore enable developers to fire custom code at certain points in the execution cycle.

If you look under the plugins folder of your Joomla! installation, you’ll see that Joomla! ships with quite a few plugins, under folders such as ‘authentication’, ‘search’, ‘system’, etc. Each folder groups similar types of plugins & you’ll often find that a component will install its own plugins and/or folder of plugins.

Look within these folders and you’ll see that plugins follow a convention. There is a minimum of two files: a .php & a .xml file. Sometimes there is a blank index.html file (to prevent directory browsing) and sometimes a language file. We will deal with these files when we look at our example below.

The Requirement

The website I’ve been developing uses JomSocial & the administrator wanted to be alerted every time a member updated their JomSocial profile. Joomla! plugins are well suited to satisfy this type of requirement. The key is to find if JomSocial has any event or hook that we can call when the user saves their profile update.

Fortunately JomSocial has such an event: onAfterProfileUpdate($userId, $saveSuccess). So, the next stage is to figure out how to write a plugin that calls this code.

When you install JomSocial it creates a ‘community’ sub-folder with the plugin directory. There you will find several plugins, depending on the JomSocial feature set you have included.

So that’s the obvious place for us to include our plugin. I named my plugin notify, so it will sit under joomla/plugins/community/notify. It consists of 5 files: notify.php, notify.xml. index.html & then two language files under joomla/plugins/community/language/en-GB called en-GB.plg_community_notify.ini &  en-GB.plg_community_notify.sys.ini. These two ini files are not mandatory, but they provide a way of translating message strings if required.

So, to the two essential files: notify.php & notify.xml. The xml file is the easiest to create, since it follows a standard convention. It’s a file that tells Joomla! how & where to install your plugin & what files are dependencies of the plugin. Here’s the code within notify.xml:

<?xml version="1.0"?>
<extension version="2.5" type="plugin" group="community" method="upgrade">
 <name>Notify Administrator Jom Social Community Plugin</name>
 <version>1.1.1</version>
 <creationDate>Sept 2012</creationDate>
 <author>Eddie May</author>
 <authorEmail>ecm@freshwebservices.com</authorEmail>
 <authorUrl>http://www.freshwebservices.com/</authorUrl>
 <copyright>@freshwebservices</copyright>
 <license>GNU GPL v2.0</license>
 <description>This plugin alerts admin each time a user updates their JomSocial profile.</description>
 <files> 
 <filename plugin="notify">notify.php</filename>
 <filename>index.html</filename>
 <folder>language</folder>
 </files>
 <config>
 <fields name="params">
 <fieldset name="basic">
 <field
 name="admin_id"
 type="text"
 default=""
 label="PLG_COMMUNITY_NOTIFY_ADMIN_ID_LABEL"
 description="PLG_COMMUNITY_NOTIFY_ADMIN_ID_DESC"
 required="true"
 filter="string"
 size="50" />
 <field
 name="email_subject"
 type="text"
 default=""
 label="PLG_COMMUNITY_NOTIFY_EMAIL_SUBJECT_LABEL"
 description="PLG_COMMUNITY_NOTIFY_EMAIL_SUBJECT_DESC"
 required="true"
 filter="string"
 size="50" />
<field
 name="email_text"
 type="text"
 default=""
 label="PLG_COMMUNITY_NOTIFY_ADMIN_EMAIL_TEXT_LABEL"
 description="PLG_COMMUNITY_NOTIFY_ADMIN_EMAIL_TEXT_DESC"
 required="true"
 filter="string"
 size="50" />
 </fieldset>
 </fields>
 </config>
</extension>

Essentially this file tells Joomla! and the administrator what it is, who wrote it, what it does, what dependencies the plugin has (under the files bit) and that it has three fields that the administrator must complete: admin_id, email_subject, email_text. This is data that will be passed to the plugin to use when it executes.

You’ll notice that the convention is that required files have the same naming convention: notify in this example. They sit under a folder called notify, & there is notify.xml & notify.php. Let’s look at notify.php.

<?php
/**
 * This class notifies named site administrator who/when a profile is updated
 * 
 * @author Eddie May
 * @date Sept 20212
 */
// no direct access
defined('_JEXEC') or die;
jimport( 'joomla.plugin.plugin' );
jimport('joomla.mail.helper');
class plgCommunitynotify extends JPlugin{
 function onAfterProfileUpdate($userId, $saveSuccess){
 if(empty($saveSuccess)){
 return;
 }

 $adminID = $this->params->get('admin_id');
 $subject = $this->params->get('email_subject');
 $emailText = $this->params->get('email_text');

 if ($adminID == null || $adminID == '')
 {
 throw new Exception(JText::_('No Admin User ID - cannot send email notification without it'));
 }

 $user = JFactory::getUser($adminID);
 $userEmail = $user->get('email');
 $fromName = $user->get('username');
 $updatedUser = JFactory::getUser($userId);
 $updatedName = $updatedUser->get('username');
 $body = 'Hi, the following user ' . $updatedName .' with user id of ' . $userId .' ';
 $body .= 'has just updated their profile. ';
 $body .= 'Please review and update their public fields accordingly. ';
 $body .= ' '. $emailText . ' ';
 JFactory::getMailer()->sendMail($userEmail, $fromName, $userEmail, $subject, $body);
 return true; 
 }
}//eof class

So, we’ll examine this class is a little more detail. We start with a non-mandatory comment section, telling any future developer about the file. Then we have the  security call: defined(‘_JEXEC’) or die; This prevents the file from being called outside of the Joomla! application.

The next lines import dependencies the class requires. As I want to email the administrator, I import the Joomla! mailer functionality. Then I declare or create the class itself: class plgCommunitynotify extends JPlugin{ Note the naming convention – plg+folder+class name.

Then we’re into the functionality of the class. Essentially we build a function that calls the JomSocial event onAfterProfileUpdate($userId, $saveSuccess) which gives us two variables that we can work with. The id of the user who is updating their profile & a boolean to tell us if the update was successful.

So, we do a couple of checks – if $saveSuccess is false, it means the update failed & we don’t need to do anything else. So we exit.

If all is well, we then retrieve the information that the administrator entered when s/he installed the plugin

$adminID = $this->params->get('admin_id');
$subject = $this->params->get('email_subject');
$emailText = $this->params->get('email_text');

We bailout if the admin_id is missing: if ($adminID == null || $adminID == ”). If the information is there, we can use that later to get the administrator user.

In the next couple of lines we get the admin user, their email, etc:

$user = JFactory::getUser($adminID);
$userEmail = $user->get('email');
$fromName = $user->get('username');

& also the details of the JomSocial user:

$updatedUser = JFactory::getUser($userId);
$updatedName = $updatedUser->get('username');

Then we can construct the email that will be sent to the administrator:

$body = 'Hi, the following user ' . $updatedName .' with user id of ' . $userId .' ';
 $body .= 'has just updated their profile. ';
 $body .= 'Please review and update their public fields accordingly. ';
 $body .= ' '. $emailText . ' ';

Then we use the standard Joomla! mailer functionality to send the email:

JFactory::getMailer()->sendMail($userEmail, $fromName, $userEmail, $subject, $body);

Finally we exit our class by calling return true;

To deploy your plugin you just zip your notify folder up & install it using the Joomla! installer. You then need to publish the plugin within the Joomla! backend.

Conclusion

The key to writing such a plugin is to find the correct system or component event to call or hook into. Its worth looking at component APIs before you buy if you think that you may need to extend them with a plugin. A quick email to the component developer is a good tip – if s/he takes an age to respond, then it might be a signal that their support is not so good. If there’s no published API, that’s also a cause for concern – good software has good documentation!