Module Tutorial

Naming Your Module

The first step before even creating a single script is to choose a name for your module. Usually a single word or two is sufficient and for this example we are going to simply call our module 'Fortunes', and it will allow an administrator to submit fortune cookie-like messages via the Control Panel and then have users view a different fortune cookie message every day.

Create Module Folder

Once we have the name of our module, we need to create a folder for it in ExpressionEngines's module folder in the system directory. The name of this folder should be a lowercased and space-less version of the module's name. Instead of spaces, you should either use a single word for your module or underscores. For our example, we will create a folder called 'fortunes' that would be located like so:

/system/modules/fortunes/

Create Control Panel and Core Module files

Inside this folder will be two files, one which will control the Control Panel side of the module (installing, uninstalling, and submitting content into the database) and the other which will be used for front-end stuff like form processing and the displaying of content from the database. Their names have to be very specific in order for the system to read them correctly. The Control Panel file must have a prefix of 'mcp', a 'php' suffix, and the name of the module folder. So, for our example the module's Control Panel file would be 'mcp.fortunes.php'. The core module file must have a prefix of 'mod', a 'php' suffix, and the name of the module folder. So, for our example the core module file would be named 'mod.fortunes.php'.

/system/modules/fortunes/mcp.fortunes.php
/system/modules/fortunes/mod.fortunes.php

Create Language File

Every module requires a language file as well, which is used for displaying text in the Control Panel side of the module and displaying the details of each module in the MODULES section of the Control Panel. This file will be located in your default language folder in the /system/language/ directory, and it will have a prefix of 'lang', the 'php' suffix, and use the same name as the module folder. So, for our example, the language file will be called 'lang.fortunes.php' and will be located in the /system/language/english/ directory.

/system/language/english/lang.fortunes.php

Required Language Lines

The Language file contains an array named $L, which is used along with the Language class to display text on a page in whatever language is selected in the user's account settings, if a translation for the module is available in that language of course. There are two required lines in the language file for each module, which allows the name and description of the module to be viewable on the MODULES page:

<?php

$L = array(

//----------------------------------------
// Required for MODULES page
//----------------------------------------

"fortunes_module_name" =>
"Fortunes",

"fortunes_module_description" =>
"Fortune cookie displaying",

//----------------------------------------

// END
''=>''
);
?>

The Control Panel file (mcp.fortunes.php)

The Control Panel file for a module includes a class with a name that is a combination of the modules name with '_CP' tacked on the end. So, for our fortunes module, we will create a class called 'Fortunes_CP'. There is only one required class variable for this class and that is var $version = '1.0'; that should indicate the current version of this module.

Note:  If your module name contains two or more words, then the class name should have the first letter uppercased but all other characters in the name lowercased: Your_module_name_CP

Each Control Panel class has at a minimum two functions, which are used by ExpressionEngine to install or uninstall the module. These functions are required even if your module has no Control Panel side functionality. The names of these two functions are the lower-cased name of the module followed by '_module_install' and '_module_deinstall'. So, for our Fortunes module, they will be called 'fortunes_module_install' and 'fortunes_module_deinstall', respectively.

Installation Function

Here is what our Fortunes module's installation function will look like. Basically, it inserts the module's name, version, and whether it has a backend into the exp_modules table. Since our module will have a Control Panel backend, we set the fourth field to 'y', otherwise it should be set to 'n'. Also, the installation function will create the database table that we will use to store the fortunes in the database.

    // ----------------------------------------
    //  Module installer
    // ----------------------------------------

    function fortunes_module_install()
    {
        global $DB;        
        
        $sql[] = "INSERT INTO exp_modules (module_id, 
                                           module_name, 
                                           module_version, 
                                           has_cp_backend) 
                                           VALUES 
                                           ('', 
                                           'Fortunes', 
                                           '$this->version', 
                                           'y')";
                                           
        $sql[] = "CREATE TABLE IF NOT EXISTS `exp_fortunes` (
                 `fortune_id` INT(6) UNSIGNED NOT NULL AUTO_INCREMENT,
                 `fortune_text` TEXT NOT NULL ,
                 PRIMARY KEY (`fortune_id`));";
    
        foreach ($sql as $query)
        {
            $DB->query($query);
        }
        
        return true;
    }
    // END

Occasionally, a module will require that certain actions be performed on the user side of the site. An example of this is when a form is being submitted and the module needs to gather and process the data. When this is required, the module needs to enter the class and method that the system needs to call to perform into the exp_actions database table during the installation of the module. Here is an example from the mcp.comments.php file.

    // --------------------------------
    //  Module installer
    // --------------------------------

    function comment_module_install()
    {
        global $DB;        
        
        $sql[] = "INSERT INTO exp_modules (module_id, 
                                           module_name, 
                                           module_version, 
                                           has_cp_backend) 
                                           VALUES 
                                           ('', 
                                           'Comment', 
                                           '$this->version', 
                                           'n')";
                                           
        $sql[] = "INSERT INTO exp_actions (action_id, 
                                           class, 
                                           method) 
                                           VALUES 
                                           ('', 
                                           'Comment', 
                                           'insert_new_comment')";
                                           
        $sql[] = "INSERT INTO exp_actions (action_id, 
                                           class, 
                                           method) 
                                           VALUES 
                                           ('', 
                                           'Comment_CP',
                                           'delete_comment_notification')";    
    
        foreach ($sql as $query)
        {
            $DB->query($query);
        }
        
        return true;
    }
    // END

When the actions are entered into the exp_actions database table, they are given a unique action_id that the system will recognize and use to call the class and function required. To discover this action id for use in for a URL or form action, you can usethe Functions class fetch_action_id() function.

$action_id  = $FNS->fetch_action_id('Comment_CP', 'insert_new_comment');

Deinstallation Function

The deinstallation function in the Control Panel class for the module should be pretty standard for every module. Basically, it just clears out all mention of the module in the standard ExpressionEngine database tables. If the module created tables for its own usage, then those will also be deleted in this function.

    // ----------------------------------------
    //  Module de-installer
    // ----------------------------------------

    function fortunes_module_deinstall()
    {
        global $DB;    

        $query = $DB->query("SELECT module_id
                             FROM exp_modules 
                             WHERE module_name = 'Fortunes'"); 
                
        $sql[] = "DELETE FROM exp_module_member_groups 
                  WHERE module_id = '".$query->row['module_id']."'";      
                  
        $sql[] = "DELETE FROM exp_modules 
                  WHERE module_name = 'Fortunes'";
                  
        $sql[] = "DELETE FROM exp_actions 
                  WHERE class = 'Fortunes'";
                  
        $sql[] = "DELETE FROM exp_actions 
                  WHERE class = 'Fortunes_CP'";
                  
        $sql[] = "DROP TABLE IF EXISTS exp_fortunes";

        foreach ($sql as $query)
        {
            $DB->query($query);
        }

        return true;
    }
    // END

Controller Function

Since our module is going to have a Control Panel interface and ExpressionEngine knows this from the installation query, we need to create a menu with various options and then tell ExpressionEngine where to go when those menu options are selected. For this module, the obvious menu options are when a user wants to add, modify, delete, or view fortunes. The menu will go in the constructor function for the Control Panel file's class (i.e. Fortunes_CP) and will use the 'P' global from the URL to determine which function to call in the class.

    // -------------------------
    //  Constructor
    // -------------------------
    
    function Fortunes_CP( $switch = TRUE )
    {
        global $IN;
        
        if ($switch)
        {
            switch($IN->GBL('P'))
            {
                 case 'view'            :	$this->view_fortunes();
                     break;	
                 case 'delete'          :	$this->delete_fortune();
                     break;
                 case 'add'             :	$this->modify_fortune();
                     break;
                 case 'modify'          :	$this->modify_fortune();
                     break;
                 case 'update'          :	$this->update_fortune();
                     break;
                 default                :	$this->fortunes_home();
                     break;
            }
        }
    }
    // END

Module's Control Panel Homepage

In order to make a menu visible when a person first views the module through the Control Panel, we set the default switch option to be a function called fortunes_home(), which will contain a list of the menu options for this module. Remember when creating any text that is displayed on a page to create it in the language file array for this module, and then display it using the Language class.

    // ----------------------------------------
    //  Module Homepage
    // ----------------------------------------

    function fortunes_home()
    {
        global $DSP, $LANG;

        $DSP->title = $LANG->line('fortunes_module_name');
        $DSP->crumb = $DSP->anchor(BASE.
                                   AMP.'C=modules'.
                                   AMP.'M=fortunes',
                                   $LANG->line('fortunes_module_name'));
        $DSP->crumb .= $DSP->crumb_item($LANG->line('fortunes_menu')); 

        $DSP->body .= $DSP->heading($LANG->line('fortunes_menu'));

        $DSP->body .= $DSP->qdiv('itemWrapper', $DSP->heading($DSP->anchor(BASE.
                                                                           AMP.'C=modules'.
                                                                           AMP.'M=fortunes'.
                                                                           AMP.'P=add', 
                                                                           $LANG->line('add_fortune')),
                                                                           5));

        $DSP->body .= $DSP->qdiv('itemWrapper', $DSP->heading($DSP->anchor(BASE.
                                                                           AMP.'C=modules'.
                                                                           AMP.'M=fortunes'.
                                                                           AMP.'P=view', 
                                                                           $LANG->line('view_fortunes')),
                                                                           5));
    }
    // END

Everything Else

The remaining functions in the Control Panel file are up to your own devising, and we suggest you examine this example module and the rest of the module documentation to see how we create them.

The Core Module file (mod.fortunes.php)

The Core Module file is used for outputting content via the Templates and doing any processing that is required by both the Control Panel and any module tags contained in a template. Inside this file should be a class using the same name of the module and containing at least one class variable, $return_data, which will contain the module's outputted content and is retrieved by the Template parser after the module is done processing.

class Fortunes {

    var $return_data	= ''; 

    // -------------------------------------
    //  Constructor
    // -------------------------------------

    function Fortunes()
    {
    }
    
}

In ExpressionEngine, a typical module or plugin tag has an appearance similar to this:

{exp:weblog:weblog_name}

The first part of the tag, exp:, tells ExpressionEngine that this is a tag. The second part, weblog, is the module or the plugin that the tag belongs to, in this case the "weblog" module. The third part (modules only) is the specific function from within the Core Module file's class that is being called; in the above example the function called is named "weblog_name". The third part can be optional for a module and ExpressionEngine will simply call the constructor function for the Core Module class. Since our Fortunes module is not overly complex, we will take advantage of this and our module will simply use the ExpressionEngine tag {exp:fortunes}.

Template parameters and output for Core Module functions are covered in the section regarding the Template class, so we suggest you examine this example module and that area of the Developer Documentation for more information about creating functions within the Core Module file for your module tags.

Top of Page