Anatomy of a Magento extension
Magento Commerce has been on the OSS “market” for a while now and I see more and more developers, designers and of course store owners migrating their ecommerce sites to Magento or installing it for their new stores. I’ve been coding on Magento since its beta 0.6 version, actually my first integration was based on this beta. I’ve been advised not to use the beta and they were right. However, I had my reasons for recommending it, using it and somehow advocating for that fresh, promising open source piece of software. In the meanwhile, it turned out I was right – it’s one of the most complete, scalable & feature-rich free ecommerce solution. Not the easiest to integrate or use, not the smoothest or lightweight, but it’s come a long way and it still have room for improvements.
One of the things I liked from the start (as a developer) was the ability to extend it in a very simple and loosely coupled way (unlike other solutions). Adding the OOP and design patterns made it perfect for my way of thinking. And I think this is the way to go for any major application, even if it might seem cluttered or with a steep learning curve at a first glance. I remember one of the first problems I faced was module creation – I was adding all my code in the core/Mage folder, I was overwriting a lot of the core code although I knew it was bad and so on. However, once I understood how to create a module, things became clearer and much simpler. So here’s a beginner’s guide to creating a new module. Although it’s meant for beginners, you should know the basic folder layout (skins, library, js, apps).
All Magento code resides in app/code
and the lib
folder. If you check app/code
you’ll notice three subfolders: community
, core
, local
. You should be adding your stuff in local or community (usually only when it is a community contribution). So let’s create our first module. I’ll use the namespace mandagreen and the module will be called HelloWorld. For this I need to create the following folders under app/code/local
:
Mandagreen/HelloWorld
To keep things simple, in this example we’ll be creating one Block, one Helper and one Model – no controllers & no Resource Models. Here’s where each of these will reside:
blocks – app/code/local/Mandagreen/HelloWorld/Block
helpers – app/code/local/Mandagreen/HelloWorld/Helper
models – app/code/local/Mandagreen/HelloWorld/Model
Create these three folders and then also create a new etc
folder. The structure will then look like this:
app/code/local/Mandagreen/HelloWorld/Block app/code/local/Mandagreen/HelloWorld/etc app/code/local/Mandagreen/HelloWorld/Helper app/code/local/Mandagreen/HelloWorld/Model
The etc
folder holds configuration information – in this case we’ll focus only on the module configuration file, which is config.xml
. Let’s create it and start adding some xml into it:
<?xml version="1.0"?> <config> <modules> <Mandagreen_HelloWorld> <version>0.0.1</version> </Mandagreen_HelloWorld> </modules> <global> <models> <helloworld> <class>Mandagreen_HelloWorld_Model</class> </helloworld> </models> <blocks> <helloworld> <class>Mandagreen_HelloWorld_Block</class> </helloworld> </blocks> <helpers> <helloworld> <class>Mandagreen_HelloWorld_Helper</class> </helloworld> </helpers> </global> <frontend> <layout> <updates> <helloworld> <file>mg_helloworld.xml</file> </helloworld> </updates> </layout> <translate> <modules> <Mandagreen_HelloWorld> <files> <default>Mandagreen_HelloWorld.csv</default> </files> </Mandagreen_HelloWorld> </modules> </translate> </frontend> </config>
That’s a lot, isn’t it? ? No worries, I’ll explain. Under the main node (config
), youll usually need the global node. The modules
node is being used to hold mode info about the current module, maybe dependencies and so on. The frontend
node is usually used for defining layout handlers and translation files, but they can do more than that. In this example, we’re gonna have our own layout file called mg_helloworld.xml – you can use any name on it (as long as it’s unique), but I prefer to namespace it as well. Also, I’ve defined a translation file Mandagreen_HelloWorld.csv
which needs to be created in app/locale/en_US
(or whatever your default locale is).
The global
node defines all the classes you’ll be using, in this case helpers, models and blocks. You can see that they are defined the same way, but in different locations: <helpers />, <models /> and <blocks />. Let’s use the helpers node as an example xenical orlistat.
<helpers> <helloworld> <class>Mandagreen_HelloWorld_Helper</class> </helloworld> </helpers>
The helloworld
node defines a handle and you should be careful to always use unique names. If you’re not sure if a certain name exist, namespace it (mghelloworld for example). This handle will be used to instantiate models, call helpers or use blocks using the Magento factory. For example, for models, you’ll be using Mage::getModel('helloworld/modelname');
instead of new Mandagreen_HelloWorld_Model_Modelname();
. Same with helpers, inside a block template – $this->helper('helloworld')->someMethod();
.
The other node, class
is being used to define the namespace of the class name. In the example above, the name of the Modelname class has to being with Mandagreen_HelloWorld_Helper
. A few examples might help:
Mandagreen_HelloWorld_Model_Salute
, will be found inMandagreen/HelloWorld/Model/Salute.php
and can be accessed viaMage::getModel('helloworld/salute')
Mandagreen_HelloWorld_Model_Salute_Hi
, will be found inMandagreen/HelloWorld/Model/Salute/Hi.php
and can be accessed viaMage::getModel('helloworld/salute_hi')
Mandagreen_HelloWorld_Helper_Help
, will be found inMandagreen/HelloWorld/Model/Help.php
and can be accessed viaMage::helper('helloworld/help')
Now that we explained the config file, let’s move on to actually creating the classes and code. I’ll use the example above and create the following files:
Mandagreen/HelloWorld/Block/Standard.php
<?php class Mandagreen_HelloWorld_Block_Standard extends Mage_Core_Block_Template { function getSomething() { return Mage::getModel('helloworld/salute')->getName(); } }
Mandagreen/HelloWorld/Helper/Help.php
<?php class Mandagreen_HelloWorld_Helper_Help extends Mage_Core_Helper_Abstract { function shouldSayHi() { return true; } }
Mandagreen/HelloWorld/Model/Salute.php
<?php class Mandagreen_HelloWorld_Model_Salute extends Mage_Core_Model_Abstract { //or Varien_Object or none function getName() { //do some heavy logic here return 'John'; } }
One more file is required for the translations to work with this module – a “default” Data helper, defined in Mandagreen/HelloWorld/Helper/Data.php like this:
class Mandagreen_HelloWorld_Helper_Data extends Mage_Core_Helper_Abstract {}
We have the classes but we also need to use them in a template, so let’s create standard.phtml
in app/design/frontend/default/default/template/helloworld
(create all additional folders if needed). Also, create mg_helloworld.xml
under app/design/frontend/default/default/layout
.
For the template, things are very easy:
<div style="background: red; padding: 20px;"> <?php if( $this->helper('helloworld/help')->shouldSayHi() ): ?> Hello <?php echo $this->getSomething(); ?> <?php else: ?> Can't say anything... <?php endif; ?> </div>
while for the layout we’ll use this approach:
<?xml version="1.0"?> <layout version="0.1.0"> <default> <reference name="content"> <block type="helloworld/standard" name="helloworld" template="helloworld/standard.phtml" after="-" /> </reference> </default> </layout>
This should display “Hello John” at the end of the content area on most of the pages, including the homepage. But wait, before you try that you’ll have to enable the module in app/etc/modules
. Create a file called Mandagreen_HelloWorld.xml
with the following code:
<?xml version="1.0"?> <config> <modules> <Mandagreen_HelloWorld> <active>true</active> <codePool>local</codePool> </Mandagreen_HelloWorld> </modules> </config>
Clear all magento cache and refresh the page – your first module, up and running! And here’s the archive for this tutorial – Download Hello World Magento Module (2.99 kB)
Further/recommended reads:
It is first tutorial which works for my magento. Great explanation!
Great, this is very usefull.
Magento is difficult to understand because of using Mage::getModel(‘helloworld/salute’) make IDE can not assist our code.
I think beginner should look at the easier such as http://xme.im/develop-hello-world-magento-extension
Nice tutorial for freshers to start magento extension development, well explained and documented.
Thanks
I’ve just retested this and it worked. I’m on v1.5.1.0 – what’s your magento version? Have you copied the files to the correct folders?
I added all the files of helloworld.zip to my Magento installation, cleared all cache types (even reindexed all files). But I do not see “Hello John” anywhere (not even in the source of pages).
Hey Boris, thanks for the feedback. I always forget about the Data helper for some reason 🙂 This has also been the case, but now I’ve added this in the tutorial and also added the file in the archive.
Regarding uScaffold, I remember giving it a try a while a go (or maybe it was a different extension?) and then I removed it cause I would’ve expected a CLI tool. At least for me, that is what I’m looking for – an interactive script (bash and batch) that can create the entire structure of folders and files + the basic config.xml data. I’m putting it on my todo list.
Thanks again, and keep up the great work you’re doing with all of your extensions!
Great tutorial!
One comment, the Mandagreen_HelloWorld_Helper_Data would be required for translations, and is usually always included with the modules.
Also, if you want to skip creation of etc/config.xml, use uScaffold:
http://unirgy.com/wiki/uscaffold
So, your app/etc/modules/Mandagreen_HelloWorld.xml would look like this, and required config.xml structure would be automatically generated:
[missing markup]