You are on page 1of 12

Creating a simple Joomla 3 module

Introduction
Joomla! 3.x is constructed using three different applications:
installation (used for installing Joomla)
administrator (used for managing content)
public (used for displaying content)
The installation application is used once. The administrator and public are used through the
concept of components with modules. Each module has a single entry point located in the
modules directory. This is called mod_modulename/modulename.php (the mod_ prefix is a
historical trace)
Requirements
You need the latest version of Joomla! 3.x (with PHP, MySQL, Apache and Microsoft II) for this
tutorial (as of writing currently 3.1.1)

Developing a Basic Module
A module is a lightweight and flexible extension. They are used for small bits of the page that
are generally less complex and are able to be seen across different components.
You can see many examples of modules in the standard Joomla! install: - menus - Latest News -
Login form - and many more.
This tutorial will explain how to go about creating a simple Hello World module. Through this
tutorial you will learn the basic file structure of a module. This basic structure can then be
expanded to produce more elaborate modules.
File Structure
There are four basic files that are used in the standard pattern of module development:
mod_helloworld.php - This file is the main entry point for the module. It will perform
any necessary initialization routines, call helper routines to collect any necessary data,
and include the template which will display the module output.
mod_helloworld.xml - This file contains information about the module. It defines the
files that need to be installed by the Joomla! installer and specifies configuration
parameters for the module.
helper.php - This file contains the helper class which is used to do the actual work in
retrieving the information to be displayed in the module (usually from the database or
some other source).
tmpl/default.php - This is the module template. This file will take the data collected
by mod_helloworld.php and generate the HTML to be displayed on the page.
Creating mod_helloworld.php
The mod_helloworld.php file will perform three tasks:
include the helper.php file which contains the class to be used to collect the necessary
data
invoke the appropriate helper class method to retrieve the data
include the template to display the output.
The helper class is defined in our helper.php file. This file is included with a require_once
statement:
require_once( dirname(__FILE__).'/helper.php' );
require_once is used because our helper functions are defined within a class, and we only want
the class defined once.
Our helper class has not been defined yet, but when it is, it will contain one method: getHello().
For our basic example, it is not really necessary to do this - the Hello, World message that this
method returns could simply be included in the template. We use a helper class here to
demonstrate this basic technique.
Our module currently does not use any parameters, but we will pass them to the helper method
anyway so that it can be used later if we decide to expand the functionality of our module.
The helper class method is invoked in the following way:
$hello = modHelloWorldHelper::getHello( $params );
Completed mod_helloworld.php file
The complete mod_helloworld.php file is as follows:
<?php
/**
* Hello World! Module Entry Point
*
* @package Joomla.Tutorials
* @subpackage Modules
* @link http://dev.joomla.org/component/option,com_jd-
wiki/Itemid,31/id,tutorials:modules/
* @license GNU/GPL, see LICENSE.php
* mod_helloworld is free software. This version may have been modified
pursuant
* to the GNU General Public License, and as distributed it includes or
* is derivative of works licensed under the GNU General Public License or
* other free or open source software licenses.
*/

// no direct access
defined( '_JEXEC' ) or die( 'Restricted access' );
// Include the syndicate functions only once
require_once( dirname(__FILE__).'/helper.php' );

$hello = modHelloWorldHelper::getHello( $params );
require( JModuleHelper::getLayoutPath( 'mod_helloworld' ) );
?>
The one line that we havent explained so far is the first line. This line checks to make sure that
this file is being included from the Joomla! application. This is necessary to prevent variable
injection and other potential security concerns.
Creating helper.php
The helper.php file contains that helper class that is used to retrieve the data to be displayed in
the module output. As stated earlier, our helper class will have one method: getHello(). This
method will return the Hello, World message.
Here is the code for the helper.php file:
<?php
/**
* Helper class for Hello World! module
*
* @package Joomla.Tutorials
* @subpackage Modules
* @link http://dev.joomla.org/component/option,com_jd-
wiki/Itemid,31/id,tutorials:modules/
* @license GNU/GPL, see LICENSE.php
* mod_helloworld is free software. This version may have been modified
pursuant
* to the GNU General Public License, and as distributed it includes or
* is derivative of works licensed under the GNU General Public License or
* other free or open source software licenses.
*/
class modHelloWorldHelper
{
/**
* Retrieves the hello message
*
* @param array $params An object containing the module parameters
* @access public
*/
public static function getHello( $params )
{
return 'Hello, World!';
}
}
?>
There is no rule stating that we must name our helper class as we have, but it is helpful to do this
so that it is easily identifiable and locateable. Note that it is required to be in this format if you
plan to use the com_ajax plugin.
More advanced modules might include database requests or other functionality in the helper
class method.
Creating tmpl/default.php
The default.php file is the template which displays the module output.
The code for the default.php file is as follows:
<?php // no direct access
defined( '_JEXEC' ) or die( 'Restricted access' ); ?>
<?php echo $hello; ?>
An important point to note is that the template file has the same scope as the
mod_helloworld.php file. What this means is that the variable $hello can be defined in the
mod_helloworld.php file and then used in the template file without any extra declarations or
function calls.
Creating mod_helloworld.xml
The mod_helloworld.xml is used to specify which files the installer needs to copy and is used by
the Module Manager to determine which parameters are used to configure the module. Other
information about the module is also specified in this file.
The code for mod_helloworld.xml is as follows:
<?xml version="1.0" encoding="utf-8"?>
<extension type="module" version="3.1.0" client="site" method="upgrade">
<name>Hello, World!</name>
<author>John Doe</author>
<version>1.0.0</version>
<description>A simple Hello, World! module.</description>
<files>
<filename>mod_helloworld.xml</filename>
<filename module="mod_helloworld">mod_helloworld.php</filename>
<filename>index.html</filename>
<filename>helper.php</filename>
<filename>tmpl/default.php</filename>
<filename>tmpl/index.html</filename>
</files>
<config>
</config>
</extension>
Manifest files explains the technical details of the elements used in the XML file.
You will notice that there are two additional files that we have not yet mentioned: index.html and
tmpl/index.html. These files are included so that these directories cannot be browsed. If a user
attempts to point their browser to these folders, the index.html file will be displayed. These files
can be left empty or can contain the simple line:
<html><body bgcolor="#FFFFFF"></body></html>
which will display an empty page.
Since our module does not use any form fields, the config section is empty.

Using the Database
Many modules in Joomla require using a database. It is assumed in this tutorial that you already
understand the basics of using the JDatabase class. If you don't please read the documentation on
accessing the database using JDatabase before continuing this tutorial
Creating a table on install
To create the xml table on install we are going to add the following lines into
mod_helloworld.xml:
<install>
<sql>
<file driver="mysql"
charset="utf8">sql/mysql/install.mysql.utf8.sql</file>
<file driver="sqlazure"
charset="utf8">sql/sqlazure/install.sqlazure.utf8.sql</file>
</sql>
</install>

<uninstall>
<sql>
<file driver="mysql"
charset="utf8">sql/mysql/uninstall.mysql.utf8.sql</file>
<file driver="sqlazure"
charset="utf8">sql/sqlazure/uninstall.sqlazure.utf8.sql</file>
</sql>
</uninstall>

<update>
<schemas>
<schemapath type="mysql">sql/mysql/updates</schemapath>
<schemapath type="sqlazure">sql/sqlazure/updates</schemapath>
</schemas>
</update>
There are 3 sections to this code:
The install tag adds the database table
The uninstall tag removes the database table if the module is uninstalled. Note that not all
modules will want to use this feature (and it's not required).
The update tag will update the databases if a database needs to be amended when
updating the module.
Note that we have both schemas for MySQL and Microsoft SQL - again you can choose to tailor
your module for one or both of these systems.
In this example we will just show the example files for the MySQL database. Creating the
Microsoft SQL Server will be left as an exercise for the reader.
In our install.mysql.utf8.sql file we will create the table and place some hellos into it
CREATE TABLE IF NOT EXISTS `#__helloworld` (
`id` int(10) NOT NULL AUTO_INCREMENT,
`hello` text NOT NULL,
`lang` varchar(25) NOT NULL,

PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=1;

INSERT INTO `#__helloworld` (`hello`, `lang`) VALUES ('Hello World', 'en-
GB');
INSERT INTO `#__helloworld` (`hello`, `lang`) VALUES ('Hola Mundo', 'es-ES');
INSERT INTO `#__helloworld` (`hello`, `lang`) VALUES ('Bonjour tout le
monde', 'fr-FR');
In the uninstall file we'll just remove the table.
DROP TABLE IF EXISTS `#__helloworld`
Finally we'll just leave a placeholder in the updates file. There is an SQL file for each component
version. Each file name must match the version string in the manifest file for that version.
Joomla uses this string to determine which SQL files(s) to execute, and in what order they will
be executed.
Important Note: These files are also used to set the version number in the #__schemas table. This
version number must be present in the current version of the component in order for the new
SQL files to be run during the update. For example, if you have version 1.0 and are updating to
version 1.1, the 1.1.sql file will not be executed if there was no 1.0.sql file in the 1.0 release. For
this reason, it is good practice to have a SQL update file for each version, even if there is no SQL
change in that version.
# Placeholder file for database changes for version 1.0.0
Making the request in the helper file
Now on installing our module we should find that there is a helloworld database set up in our
database schema with our hello's in. We must now retrieve this from the database to display to
the user. We will now amend the getHello function we placed in the helper file in the last part.
For now we'll ignore using form fields to choose a hello and just retrieve the English shout
//Obtain a database connection
$db = JFactory::getDbo();
//Retrieve the shout
$query = $db->getQuery(true)
->select($db->quoteName('hello'))
->from($db->quoteName('#__helloworld'))
->where('lang = '. $db->Quote('en-GB'));
//Prepare the query
$db->setQuery($query);
// Load the row.
$result = $db->loadResult();
//Return the Hello
return $result;

Adding Form Fields
Form fields give a great deal of customisation in Joomla and for modules are the sole way of
allowing the user to tweak the module to the needs of their site.
Adding Form Fields to the module
In this case we are going to extend our previous example using the database to provide a list of
languages for the user to select from. To allow this to happen we will use the SQL form field
type (full details for this on the SQL Form Field docs page).
First of all we are going to add a form field into our xml file. Remember those config tags that
we added in earlier? Well now inside these tags we are going to add the following code:
<fields name="params">
<fieldset name="basic">
<field name="lang" type="sql" default="1" label="Select a language"
query="SELECT id AS value, lang FROM #__helloworld" />
</fieldset>
</fields>
This selects the languages from the database table and allows the user to choose which one from
a select element.
If you were to install the module as it is now you would see if you were to access the module in
the backend of Joomla that a dropdown had appeared (although picking an option won't affect
the module at the moment).
Note: The form field parameters are stored for each module in the #__modules table under the
params field as json encoded string.
Now lets make the form field do something!
Lets go into the mod_helloworld.php and retrieve the parameter (note you cannot retrieve the
parameter in the helper), and then pass it into the helper function.
/**
* This retrieves the lang parameter we stored earlier. Note the second part
* which states to use the default value of 1 if the parameter cannot be
* retrieved for some reason
**/
$language = $params->get('lang', '1');
$hello = modHelloWorldHelper::getHello( $language );
Now lets edit our database query in the helper file to reflect our parameter choice
//Obtain a database connection
$db = JFactory::getDbo();
//Retrieve the shout - note we are now retrieving the id not the lang field.
$query = $db->getQuery(true)
->select($db->quoteName('hello'))
->from($db->quoteName('#__helloworld'))
->where('id = '. $db->Quote($params));
//Prepare the query
$db->setQuery($query);
// Load the row.
$result = $db->loadResult();
//Return the Hello
return $result;

Adding Auto Update
This section of the tutorial will help you create an update server so that your module can utilize
the Joomla one-click-upgrade system.
Introduction & Pre-reading
The first thing to do is to read the Managing Component Upgrades with Joomla 2.5 - Part 1
tutorial to give an idea of how the upgrade process works in Joomla. Whilst written for 2.5 the
process hasn't changed for Joomla 3.x. Also read Deploying an update server - this is what we'll
be implementing in this tutorial.
Remember that sql update file we mentioned in the Using the database section? That will be used
to update our database still. Whilst a new zipped version of our module will be used to update all
the php files. To keep this simple for now we will update the files and sql database without any
checks for Joomla version and the version of the module that is currently installed (it is
recommended these are used in a production module).
Updating our module
The only way to update our existing module is to add in a update server into the xml file.
<updateservers>
<server type="extension" name="Helloworld"
priority="1">http://www.example.com/helloworld_update.xml</server>
</updateservers>
Joomla will now search http://www.example.com/helloworld_update.xml for updates with a
frequency set in the extension manager options.
Creating an update
So now that Joomla is searching for updates to our extension - lets create one to test out our
process.
Create a copy of the module as it is now. Then lets update the version number to 1.0.1, and also
we'll add something into our Update SQL file - in this case an extra German Language file
<version>1.0.1</version>
INSERT INTO `#__helloworld` (`hello`, `lang`) VALUES ('Hallo Welt', 'de-DE');
Note we can also edit any of our php files - all the existing php files will be overridden by the
ones in the update file (Note: This is the reason why core hacks of any extension are discouraged
- they will be lost on the extension update).
Now we must create the xml file at http://www.example.com/helloworld_update.xml to let
Joomla know an update is available.
<updates>
<update>
<name>Helloworld</name>
<description>This is mod_helloworld 1.0.1</description>
<element>mod_helloworld</element>
<type>module</type>
<version>1.0.1</version>
<downloads>
<downloadurl type="full"
format="zip">http://www.example.com/mod_helloworld_101.zip</downloadurl>
</downloads>
<maintainer>Joomla</maintainer>
<maintainerurl>http://www.example.com</maintainerurl>
<targetplatform name="joomla" version="3.1"/>
<client>0</client>
<client_id>0</client_id>
</update>
</updates>
where http://www.example.com/mod_helloworld_101.zip is the zip of our newly created update.
If you now log into the backend of Joomla you should now see in the control panel that an
automatic update is available (if not you may need to purge your cache in the update section of
the extension manager). Simply click update and you'll find your module has been updated to
version 1.0.1.
Commercial Modules
Note that in our files we have linked to the extensions updates xml file. And from that xml file
we have a location for the zip of the module. This means that if someone were to track this
backwards they could find the physical source of your modules zip file (and make it
available/use it after a subscription has expired etc.). For this reason generally commercial
modules do not contain automatic updates (although they often will inform you of updates in
some alternative way).

Adding an install-uninstall-update script file
Introduction
Installing, updating and uninstalling a module may require additional operations that cannot be
achieved by the basic operations described in the main xml file. Joomla offers a new approach to
solve this problem. It consists in using a php script file containing a class using five methods:
preflight which is executed before install and update
install
update
uninstall
postflight which is executed after install and update
Creating the extension script file
Writing an extension script consists in declaring an class whose name is
mod_ModuleNameInstallerScript with these 5 methods.
script.php
<?php
// No direct access to this file
defined('_JEXEC') or die('Restricted access');

/**
* Script file of HelloWorld module
*/
class mod_helloWorldInstallerScript
{
/**
* Method to install the extension
* $parent is the class calling this method
*
* @return void
*/
function install($parent)
{
echo '<p>The module has been installed</p>';
}

/**
* Method to uninstall the extension
* $parent is the class calling this method
*
* @return void
*/
function uninstall($parent)
{
echo '<p>The module has been uninstalled</p>';
}

/**
* Method to update the extension
* $parent is the class calling this method
*
* @return void
*/
function update($parent)
{
echo '<p>The module has been updated to version' . $parent-
>get('manifest')->version) . '</p>';
}

/**
* Method to run before an install/update/uninstall method
* $parent is the class calling this method
* $type is the type of change (install, update or discover_install)
*
* @return void
*/
function preflight($type, $parent)
{
echo '<p>Anything here happens before the
installation/update/uninstallation of the module</p>';
}

/**
* Method to run after an install/update/uninstall method
* $parent is the class calling this method
* $type is the type of change (install, update or discover_install)
*
* @return void
*/
function postflight($type, $parent)
{
echo '<p>Anything here happens after the
installation/update/uninstallation of the module</p>';
}
}
In the update method we show the new version using $parent->get('manifest')->version.
You can also redirect to a page of choice with $parent->getParent()-
>setRedirectURL('index.php?option=com_modules');.