I want to share the experience of programming modules for Magento. Many thanks to
jeje for the invitation.
The article describes in detail the creation of a module that implements the additional functions of customer registration. Objectives - to give an idea about the development of Magento on a specific example from beginning to end, to show the main approaches, the organization of the code, point out some features. The article focuses more on beginners, but those familiar with Magento can take something useful for themselves. Of course, it’s impossible to describe everything in one article, but if the topic turns out to be relevant, this could be the beginning of a series of articles.
The following points are affected:
- module creation
- work with blocks, templates and layout (layout)
- controller override
- module installation scripts
As a result, we will get registration with CAPTCHA verification, group selection field and saving invitation code.

')
What is conceived
There is a registration page / magento / customer / account / create. We want to add a CAPTCHA check, and also ask the customers for the group and invitation code. The obtained data is stored in the database. By default, Magento defines three groups of General, Wholesale and Retailer clients. Of these, we offer to choose a future client. Magento does not know anything about the invitation code - we will create a new attribute.
I want to note that this is
not a ready-made solution , but just an example, compiled for convenience of presentation.
Search
We are looking for where the template files are located, where and how the registration data is saved.
- Customer Registration Form Templates
/magento/app/design/frontend/default/default/template/customer/form/register.phtml
- registration form
- Attributes add in the installer module, example:
/magento/app/code/core/Mage/Customer/sql/customer_setup/mysql4-upgrade-0.8.7-0.8.8.php
the details will be lower when we write the installer for our module. - We find the description of variable fields (attributes) in the module configuration:
/magento/app/code/core/Mage/Customer/etc/config.xml
inside <fieldsets>
tags
- The registration form will post the data to the address:
http: // localhost / magento / customer / account / createpost /
Accordingly, the request is processed by the Mage_ Customer _ Account Controller method createPost Action method (line # 234)
Implementation
The variant with the change of found files is not considered. Create your own theme and module.
The theme is simple:
- create a new folder in / magento / app / design / frontend / default / mytheme
default - interface name
mytheme is the name of our theme
- we copy files with preservation of directory structure in a new theme
- edit / create templates at your discretion
The templates of our theme with the same name will block the templates of the standard theme. Thus, we do not make changes to the native Magento files.
With the module a little more interesting:
Create a new module -
CustomerMod . The folder structure of all modules is the same:
magento / app / code / local /
Examples
CustomerMod
- Block
- etc
- Helper
- Model
- sql
Do not forget to add a file with the description of our modules:
magento / app / etc / modules / Examples_All.xml <config>
<modules>
<Examples_CustomerMod>
<active> true </ active>
<codePool> local </ codePool>
</ Examples_CustomerMod>
</ modules>
</ config>
Fields on the registration page
Let's start by adding a group selection field to the registration page (“General”, “Wholesale”, “Retailer”). To display information, Magento operates with blocks and templates. A block can be called a template renderer. Each page consists of blocks, a template is indicated for each block.
We will add our block with our template inside the block of the registration form. In other words, our block will be a child of a form block.
1. Actually new template
Group selection template in a separate file:
/magento/app/design/frontend/default/example_theme/template/customer/form/register/groupselect.phtmlwith simple content:
<? php $ customer_groups = Mage :: helper ('customer') -> getGroups () -> toOptionArray (); ?>
<fieldset class = "group-select">
<h4 class = "legend"> <? php echo $ this -> __ ('Customer Group')?> </ h4>
<ul>
<? php foreach ($ customer_groups as $ cg) {?>
<li class = "f-left" style = "margin: 2px 4px;" >
<input type = "radio" name = "group_id" id = "group_id"
value = "<? php echo $ cg ['value'];?>"
<? php if ($ cg ['value'] == 1) echo 'checked = 1'?> />
<label> <? php echo $ cg ['label']; ?> </ label>
</ li>
<? php} // end foreach?>
</ ul>
</ fieldset>
Please note that the name of the field “group_id” must match the name of the attribute.
2. Adjustment layout
The mutual arrangement of blocks and snapping to templates are described in layout. These are xml files that are located in the
magento/app/design/_/_/layout
folder
magento/app/design/_/_/layout
.
In our case will be:
/magento/app/design/frontend/default/example_theme/layout/customermod.xml <layout version = "0.1.0">
<customer_account_create>
<reference name = "customer_form_register">
<block type = "core / template" name = "customergroups-select" template = "customer / form / register / groupselect.phtml" />
<block type = "captcha / recaptcha" name = "captcha" />
</ reference>
</ customer_account_create>
</ layout>
We refer to the
customer_form_register
block. We describe our child block inside it:
type is a block class that ultimately renders a pattern. In this case, “core / template”, which means
Mage_Core_Block_Template
.
name - the name can be any. It is necessary to refer to the block, for example in reference.
template - block template
Do not forget to specify the layout updates in the module configurations so that Magento takes into account the changes specified in
customermod.xml
:
/magento/app/code/local/Examples/CustomerMod/etc/config.xml <frontend>
<layout>
<updates>
<customermod>
<file> customermod.xml </ file>
</ customermod>
</ updates>
</ layout>
</ frontend>
3. Block output by parent block.
Our block is not yet visible, because we have to "call" the child block in the parent using the getChildHtml (BLOCK_NAME) method.
Copy
register.phtml
to our theme from the
default theme and add the necessary call in front of the
Login Information section:
/magento/app/design/frontend/default/example_theme/template/customer/form/register.phtml ...
<? php echo $ this-> getChildHtml ('customergroups-select')?>
<fieldset class = "group-select wide">
<h4 class = "legend"> <? php echo $ this -> __ ('Login Information')?> </ h4>
...
4. Saving data
The group selection should now appear in the registration form.
“But wait, the customer registers with“ Retailer ”- and in the admin panel it is still in the General group!” - yes, the
group_id
field is not saved.
To save the entered fields, you need to specify them in the fieldsets in the configuration:
/magento/app/code/local/Examples/CustomerMod/etc/config.xml <fieldsets>
<customer_account>
<group_id> <create> 1 </ create> <update> 1 </ update> </ group_id>
</ customer_account>
</ fieldsets>
Why - ask the developers of Magento, - but this is how the Customer controller works. Who is interested - see
/magento/app/code/core/Mage/Customer/controllers/AccountController.php
method
createPostAction.
New attribute
Attributes are described in the
eav_attributes table, respectively, working with attributes is reduced to editing the entries of the
eav_attributes table.
There are also
static attributes whose values ​​are stored in separate columns (for example,
sales_order
).
1. Installation scripts
All actions for modifying the model are performed in installation scripts stored in the sql folder inside each module.
/magento/app/code/core/Mage/Customer/sql/customer_setup
Scripts are of two types -
setup and
upgrade . Magento runs the corresponding script once when installing or updating the module. After installation, an entry appears in the
core_resource table, for example:
'customermod_setup', '0.1.0'
In other words, the scripts are run for two reasons:
- no module entry in the core_resource table
- the module version specified in core_resource is lower than in the module config.xml
It is worth noting that the
uninstall mechanism is
not provided . The created attributes will have to be deleted by hand in case of anything.
Scripts are executed by the installer. By default, the installer class is
Mage_Core_Model_Resource_Setup
, but it does not contain methods for working with the
EAV model (and we are going to create the attributes), so in our case we need
Mage_Eav_Model_Entity_Setup
.

2. Attribute Creation Script
Examples of installation scripts can be found in standard modules. Sometimes there is just a run of SQL commands. But it is desirable to use the methods of the classes of installers to the maximum, and to resort to SQL commands last.
$ installer = $ this;
/ * @var $ installer Mage_Customer_Model_Entity_Setup * /
$ installer-> startSetup ();
$ installer-> addAttribute ('customer', 'invitation_code', array (
'type' => 'varchar',
'input' => 'text',
'label' => 'Invitation Code',
'global' => 1,
'visible' => 1,
'required' => 1,
'user_defined' => 1,
'default' => null,
'visible_on_front' => 1
))
$ installer-> endSetup ();
I think after so many prefaces comments to the script itself are not required.
3. We update the template
Add a new field to the registration form template:
/magento/app/design/frontend/default/example_theme/template/customer/form/register.phtml <div class = "input-box">
<label for = "invitation_code"> <? php echo $ this -> __ ('Invitation Code')?> <span class = "required"> * </ span> </ label> <br/>
<input type = "text" name = "invitation_code" id = "invitation_code" title = "<? php echo $ this -> __ ('Invitation Code')?>" class = "required-entry input-text" />
</ div>
4. Update the configuration
Add a description of the installation script:
/magento/app/code/local/Examples/CustomerMod/etc/config.xml <global>
<resources>
<customermod_setup>
<setup>
<module> Examples_CustomerMod </ module>
<class> Mage_Eav_Model_Entity_Setup </ class>
</ setup>
<connection> <use> core_setup </ use> </ connection>
</ customermod_setup>
<customermod_write> <connection> <use> core_write </ use> </ connection> </ customermod_write>
<customermod_read> <connection> <use> core_read </ use> </ connection> </ customermod_read>
</ resources>
And do not forget to specify a new field in
fieldsets
<fieldsets>
<customer_account>
<group_id> <create> 1 </ create> <update> 1 </ update> </ group_id>
<invitation_code> <create> 1 </ create> <update> 1 </ update> </ invitation_code>
</ customer_account>
</ fieldsets>
Now in the registration form there is an
Invitation Code field, the value of which is stored in the
invitation_code
attribute for each client. Also, a new field appeared in the admin panel on the client account page in the
Account Information tab.

Captcha
To implement the "captcha" take
reCAPTCHA . Further, there may be many ways: include the captcha functionality into an existing module, make it separate, you can push everything into a template and edit the standard controller.
In my opinion it is better to issue in a separate module. The steps to create a new module, a separate template, modifications to the layout (layout) are the same as described above. Let us dwell on what has not yet been affected: the controller and helper.
The values ​​from the registration form are transferred to the controller
Mage_Customer_AccountController
Magento has a mechanism for redefining the controllers (
since version 1.3, the mechanism has changed somewhat ). Instead of changes in the standard controller, we will create a new one inherited from the standard one.
So in order.
Download the
recaptcha-php library and copy it to the / magento / lib folder.
1. Controller
In the configuration of the CustomerMod module we describe the controller:
<config>
...
<frontend>
...
<routers>
<customer>
<args>
<modules>
<Examples_CustomerMod before = "Mage_Customer"> Examples_CustomerMod </ Examples_CustomerMod>
</ modules>
</ args>
</ customer>
</ routers>
...
Actually the controller itself.
/magento/app/code/local/Examples/CustomerMod/controllers/AccountController.php require_once ("Mage / Customer / controllers / AccountController.php");
require_once ('recaptcha / recaptchalib.php');
class Examples_CustomerMod_AccountController extends Mage_Customer_AccountController {
public function createPostAction () {
$ request = $ this-> getRequest ();
$ captchaIsValid = Mage :: helper ('captcha') -> captchaIsValid ($ request);
if ($ captchaIsValid) {
parent :: createPostAction ();
} else {
$ this -> _ getSession () -> setCustomerFormData ($ this-> getRequest () -> getPost ());
$ this -> _ getSession () -> addError ($ this -> __ ('Verification code was not correct. Please try again.'));
$ this -> _ redirectError (Mage :: getUrl ('* / * / create', array ('_ secure' => true)));
}
}
}
Unlike all other classes defined in Magento, for controllers it is necessary to explicitly point to the file containing the parent class and third-party libraries, so two require_once are needed. The code is minimal, we use the standard function from recaptchalib. But the verification of the introduced captcha itself is in a separate helper class. If you need to add the same check to other controllers, then everything will be reduced to checking the result of
Mage::helper('captcha')->captchaIsValid($request).
Here you can add, for example, the authenticity of the invitation code.
2. Helper
The helper in Magento is a singleton class that usually contains a set of helper methods. The helper is accessed using the
Mage::helper()
method with the module name as a parameter. In our case,
Examples_Captcha_Helper_Data
will contain captcha check functions.
/magento/app/code/local/Examples/Captcha/Helper/Data.php require_once ('recaptcha / recaptchalib.php');
class Examples_Captcha_Helper_Data extends Mage_Core_Helper_Abstract
{
const CAPTCHA_PUBLIC_KEY = "public-key-for-the-website";
const CAPTCHA_PRIVATE_KEY = "private-key-for-the-website";
public function captchaIsValid (Mage_Core_Controller_Request_Http $ request) {
if ($ request) {
$ resp = recaptcha_check_answer (self :: CAPTCHA_PRIVATE_KEY,
$ _SERVER ["REMOTE_ADDR"],
$ request-> getParam ("recaptcha_challenge_field"),
$ request-> getParam ("recaptcha_response_field"));
return $ resp-> is_valid;
}
return false;
}
public function captchaGetError (Mage_Core_Controller_Request_Http $ request) {
if ($ request) {
$ resp = recaptcha_check_answer (self :: CAPTCHA_PRIVATE_KEY,
$ _SERVER ["REMOTE_ADDR"],
$ request-> getParam ("recaptcha_challenge_field"),
$ request-> getParam ("recaptcha_response_field"));
return $ resp-> error;
}
return false;
}
public function getPublicKey () {return Examples_Captcha_Helper_Data :: CAPTCHA_PUBLIC_KEY; }
}
3. CAPTCHA block
It would not be bad to display a picture of the captcha itself on the page. There is a function for this recaptcha_get_html (). Despite the fact that the function can be called from a template (phtml), we will follow the ideas and architecture of Magento - we will create a new type of block, at the same time we will know how a block can be without a template. To do this, we describe the class
Examples_Captcha_Block_Recaptcha
. The call to the
recaptcha_get_html()
function is
recaptcha_get_html()
into the
_toHtml
method. This method is called when drawing a block in HTML. (see
/magento/app/code/core/Mage/Core/Block/Abstract.php
line
# 643 )
/magento/app/code/local/Examples/Captcha/Block/Recaptcha.php require_once ('recaptcha / recaptchalib.php');
class Examples_Captcha_Block_Recaptcha extends Mage_Core_Block_Abstract {
public function _toHtml () {
$ html = recaptcha_get_html (Mage :: helper ('captcha') -> getPublicKey ());
return $ html;
}
}
Add a new block to the layout. The template for this block is not needed; it already displays the finished captcha.
/magento/app/design/frontend/default/example_theme/layout/customermod.xml <? xml version = "1.0"?>
<layout version = "0.1.0">
<customer_account_create>
<reference name = "customer_form_register">
<block type = "core / template" name = "customergroups-select" template = "customer / form / register / groupselect.phtml" />
<block type = "captcha / recaptcha" name = "captcha" />
</ reference>
</ customer_account_create>
</ layout>
4. Configuration
It remains only to indicate in the configuration of the Captcha module that it contains a block and a helper
/magento/app/code/local/Examples/Captcha/etc/config.xml <? xml version = "1.0" encoding = "UTF-8"?>
<config>
<modules>
<Examples_Captcha>
<version> 0.1.0 </ version>
</ Examples_Captcha>
</ modules>
<global>
<blocks>
<captcha> <class> Examples_Captcha_Block </ class> </ captcha>
</ blocks>
<helpers>
<captcha>
<class> Examples_Captcha_Helper </ class>
</ captcha>
</ helpers>
</ global>
</ config>
And the captcha is ready.

Conclusion
Thanks to read to the end! I hope you find it interesting or at least helpful :). You can
download the finished sample . Magento version 1.3.2.4 was used for writing the article.
If the topic is interesting in Habré, then I will gladly listen to the wishes of the new article.
There are ideas and some materials for articles on the topic:
- Magento Review Gingerbread and Rake
- Events and listeners in Magento on the example of adding an email-notification.
- Debugging in Magento (about the test page, about Firebug, about Mage :: log)
- Models in Magento. Add your entities and attributes
- How I Added Blocks to Magento Email Templates
- PDF to Magento. Bitter truth
- Work with collections in Magento on the example of creating a report
- IDE selection / configuration for Magento development