Creating a custom Magento module | Mementia

Creating a custom Magento module

Magento community provides us with a great variety of modules (free and paid), available for downloading and installing from Magento Connect catalog, and from 3rd party developers' websites. Together with the rich Magento functionality, this allows us to solve a lot of tasks without programming skills. But, what if there is no solution for your specific task? Or, what if the needed module doesn't quite work as you need. Unerstanding of Magento architecture will help you to make changes to the existing modules or create your own module from scratch.

In this post we will learn the basics of creating Magento modules and will create a simple Hello World-like sample. Let's start...

Where to put our module?

All Magento modules are located in /app/code/ folder and are split into three groups, called code pools: core, community, local.

/app/code
  |- /core/
  |- /community/
  |- /local/

core - 

All original Magento modules are placed here. They provide base functionality of system and prototypes of blocks, models, helpers, controllers for further extending. The standard modules are: Mage_Core, Mage_Adminhtml, Mage_Catalog, Mage_Customer, Mage_Sales, Mage_Payment, Mage_Shipping etc. As you have probably noticed, all of them have prefix "Mage_", we will talk about this a bit later. Unless you are sure about what you are doing (and even afterwards) never edit the code in the core modules.

community

As you can see from the name, this group dedicated for modules that are provided by 3rd party developers (i.e. not by Magento team). When you install this modules throught built-in installer (Magento Connect Manager) all of them will be put into the folder /app/code/community/.

local

This folder is created empty on a Magento installation. Or it can be absent in last versions 1.7.x of CMS, in this case you'll have to create it manually. Folder /app/code/local/ is used for your custom modules. All development, generally, is performed here.

Except logical splitting modules into groups, this architecture allows us to override any module or separate class in "local" folder without editing original files, which is important for further update of Magento. If we look to the file /app/Mage.php, we'll see this code:

$paths[] = BP . DS . 'app' . DS . 'code' . DS . 'local';
$paths[] = BP . DS . 'app' . DS . 'code' . DS . 'community';
$paths[] = BP . DS . 'app' . DS . 'code' . DS . 'core';
$paths[] = BP . DS . 'lib';

$appPath = implode(PS, $paths);
set_include_path($appPath . PS . Mage::registry('original_include_path'));

So, if we have two files with the same name but in different code pools (for example, /core/Mage/Core/Model/Config.php and /local/Mage/Core/Model/Config.php), then file from local pool will be loaded.

Now let's move to practice.

First steps

All further work assumes that you have installed and running Magento. Version doesn't matter. because the things we are giong to learn, look and work the same way in all versions and editions of Magento.

So, the first thing we need to do is disabling cache. Despite all pluses of caching on production servers,  it will disturb you during development, since it won't let you see all changed data immediately and will slow down the development. You can disable cache by going to Admin Panel -> System -> Cache Management -> Select All -> Action: Disable -> Submit.

Now we will start creating our module.

Magento module structure

All Magento modules consist of two main parts: module folder and basic configuration file. Lets start from module folder.

I have to say a few words about modules and classes naming rules at the start. Magento uses the same rules as Zend Framework 1.x does, i.e. class name indicates the file's path in folders' structure. For example, we have class MyCustomModule_HelloWorld_Helper_Data. If we replace underscores by directory separator and add ".php" to the end, we'll have a path to this file relative to the code pool or lib folder. That will be MyCustomModule/HelloWorld/Helper/Data.php.

The first folder we are going to create is a namespace. This can be any name you like, but it cannot contain spaces and underscores. Usually, a company name or developer's name is used as namespace  (as I have pointed before, all core Magento modules have namespace "Mage"). In out case we will call it "MyCustomModule". Now we have a folder  /app/code/local/MyCustomModule.

After this we need to choose the name of our module and create appropriate folder in out namespace. Lets call it "HelloWorld". When choosing module name, as well as namespace, you have to take into consideration that theese names are case-sensitive. And it is desirable to give the modules logical names. For example, if our module create navigation menu for catalog, the logical name could be "CatalogNavigation".

Now we should get folder structure like this:

/app
  |- /code
       |- /local
            |- /MyCustomModule
                 |- /HelloWorld

Typical Magento module structure is represented by six main folders: etc, Block, Model, Helper, controllers, sql.

etc - This is the only required foder. All modules configuration xml files have to be placed here. Each module has required file config.xml.

Block - This folder is used for storing View classes (is we use terms of MVC architecture). Main goal of theese classes if to link Models data with template files from Magento themes.

Model - Models are used to work with different data. Generally, they are designed for connecting to the database and processing data in\out it.

Helper - Here we can store helper classes, which contain different utility methods, that can be called from any point of Magento (blocks, models, controllers, template files etc.). Helper methods a called this way Mage::helper('modulename/helpername'). Also each module has default helper class Helper/Data.php (in out case it will be /MyCustomModule/HelloWorld/Helper/Data). It can be called just by module name  - Mage::helper('modulename').

controllers - This folder contains controller classes, that provide all business logics of out module.

sql - Files that are processed on module installation and upgrade, are located in this folder.

More detailed description of how to work with blocks, models, helpers I'll try to provide in future posts.

Configuring and activating module

Lets continue creating our HelloWorld module. For the next step will create etc/config.xml file. Its goal it to inform Magento about module name and version, files location, events observed, cron jobs, resources used by module etc. So, we will create etc folder and config.xml in it.

<?xml version="1.0" ?>
<!-- Root node for Magento configuration files -->
<config>
    <!-- modules node provides basic information about the module -->
    о модуле  -->
    <modules>
        <!-- This node's name has to be the same as module's full name
        including namespace -->
        <MyCustomModule_HelloWorld>
            <!-- Current version of module -->
            <version>0.0.1</version>
        </MyCustomModule_HelloWorld>
    </modules>
</config>

Then we need to activate our module. All files, indicating which modules are active and in what order do they have to be loaded, are located in /app/etc/modules. Lets create file  /app/etc/modules/MyCustomModule_HelloWorld.xml. Actually, file can have any name you like, this doesn't matter because Magento will read all files in this folder. Usually module's name is used for this purpose.

<?xml version="1.0"?>
<config>
    <!-- the same block we have in module's config.xml -->
    <modules>
        <!-- This node's name has to be the same as module's full name
        including namespace -->
        <MyCustomModule_HelloWorld>
            <!-- flag indicating weather module is active or not -->
            <active>true</active>
            <!-- code pool -->
            <codePool>local</codePool>
        </MyCustomModule_HelloWorld>
    </modules>
</config>

There also can be one more parameter "depends" in this file.

<?xml version="1.0"?>
<config>
    <modules>
        <MyCustomModule_HelloWorld>
            <active>true</active>
            <codePool>local</codePool>
            <!-- this node point to dependency from other modules -->
            <depends>
                <!-- specifying that out module should be loaded after Mage_Catalog -->
                <Mage_Catalog />
            </depends>
        </MyCustomModule_HelloWorld>
    </modules>
</config>

This parameter points to dependency of our module from others. In other words, with it's help we can control the modules loading order (or their config.xml files, to be more precise).

Modules configuration files and their structure will be described in more detail in future posts. And now lets check that our module is installed correctly. We can do this by going to Admin Panel -> System -> Configuration -> Advanced -> Advanced. Then you expand "Disable Modules Output" block and. if we did everything right on previous steps, we'll see our module in a list.

Controller

Now we will create controller /MyCustomModule/HelloWorld/controllers/IndexController.php

/*
 * Controller class has to be inherited from Mage_Core_Controller_action
 */
class MyCustomModule_HelloWorld_IndexController extends Mage_Core_Controller_Front_Action
{

    /*
     * this method privides default action.
     */
    public function indexAction()
    {
        /*
         * Initialization of Mage_Core_Model_Layout model
         */
        $this->loadLayout();

        /*
         * Building page according to layout confuration
         */
        $this->renderLayout();
    }
}

IndexController is called by default if we don't call any other controller, as well as indexAction will be called by default if we don't call any other action. As we can see, indexAction call only two methods, that initialize and render website page. This is quite enough for out simple example.  Now lets make link to our module's page more nice. In order to do this, we'll add some information to config.xml.

<?xml version="1.0" ?>
<config>
    <modules>
        <MyCustomModule_HelloWorld>
            <version>0.0.1</version>
        </MyCustomModule_HelloWorld>
    </modules>

    <!-- This node contains parameters, available on frontend -->
    <frontend>
        <!-- Module aliases are located in this block -->
        <routers>
            <!-- This node's name should be the same as our alias -->
            <helloworld>
                <!-- use parameter specifies which of basic routers needs to be used.
                This can be "standard" for frontend or "admin" for backend -->
                <use>standard</use>
                <!-- router arguments block -->
                <args>
                    <!-- This parameter specifies the full name of out module -->
                    <module>MyCustomModule_HelloWorld</module>
                    <!-- This parameter sets module alias -->
                    <frontName>helloworld</frontName>
                </args>
            </helloworld>
        </routers>

    </frontend>
</config>

So we have set an helloworld alias, and out page is now available at url _your_url_/helloworld or _your_url_/helloworld/index/index.

The next step will be adding content to our page.

Layout configuration

All templates and layout files are located in /app/design folder. Magento uses two design areas: "frontend" for public section and "adminhtml" for backend.

/app/design
  |-- /adminhtml
  |-- /frontend

Also there can be "install" area, which is used for installation pages. Themes are split into packages. By default there are two theme packages (base and default) in /app/design/frontend. If theme is not set in Magento configuration, default/default theme will be used by default. We are going to work with this theme.

Usually Magento theme consists of two main folders: "layout", where layout configuration files are stored, and "template", where all ".phtml" files are located. At first we need to create layout file /app/design/frontend/default/default/layout/helloworld.xml

<?xml version="1.0" ?>
<!-- Root node for Magento layout configuration -->
<layout version="0.1.0">
    <!--Page handle -->
    <helloworld_index_index>
        <!-- reference tag specifies the block where we a going to add child block -->
        <reference name="content">
            <!-- Our page content block -->
            <block type="core/template" name="helloworld" template="helloworld/view.phtml"></block>
        </reference>
    </helloworld_index_index>
</layout>

We have added simple "core/template" block to our page. It doesn't require creating separate block class, and just simply loads template file, specified in "template" attribute. Then we will create template file /app/design/frontend/default/default/template/helloworld/view.phtml with a simple message in it.

<p>Hello World!</p>

The last thing we need to do is to inform Magento that we want to load our helloworld.xml. Lets edit config.xml once more.

<?xml version="1.0" ?>
<config>
    <modules>
        <MyCustomModule_HelloWorld>
            <version>0.0.1</version>
        </MyCustomModule_HelloWorld>
    </modules>

    <frontend>
        <routers>
            <helloworld>
                <use>standard</use>
                <args>
                    <module>MyCustomModule_HelloWorld</module>
                    <frontName>helloworld</frontName>
                </args>
            </helloworld>
        </routers>

        <!-- This node contains module layout configuration -->
        <layout>
            <updates>
                <!-- module alias -->
                <helloworld>
                    <!-- File for loading -->
                    <file>helloworld.xml</file>
                </helloworld>
            </updates>
        </layout>
    </frontend>
</config>

We are done! Out simple module is ready to work. Now we can go to _your_url_/helloworld and see our page.

Share this post