January 2, 2010

Magento – Custom email contact form with notification system

In this article, hopefully, you will learn how to create a module that uses its own controller, programatically creates a block based on core template and assigned via file, handles form submission and utilizes Magento notification system to output the notifications to user.
Although the module it self might look relatively simple in the end, keep in mind that these are powerful concepts that you can latter reuse for much more complex requirements.
file 1:
/app/etc/modules/ActiveCodeline_SimpleContact.xml
content of file 1:
<?xml version="1.0"?>
 
<config>
    <modules>
        <ActiveCodeline_SimpleContact>
            <active>true</active>
            <codePool>local</codePool>
        </ActiveCodeline_SimpleContact>
    </modules>    
</config>
file 2: app/code/local/ActiveCodeline/SimpleContact/etc/config.xml
content of file 2:
<?xml version="1.0"?>
 
<config>
    <modules>
        <ActiveCodeline_SimpleContact>
            <version>0.1.0</version>
        </ActiveCodeline_SimpleContact>
    </modules>   
 
    <frontend>
        <routers>
            <JustSomeFreeRouterNameHereNo1>
                <use>standard</use>
                <args>
                    <module>ActiveCodeline_SimpleContact</module>
                    <frontName>activecodeline-simplecontact</frontName>
                </args>
            </JustSomeFreeRouterNameHereNo1>
        </routers>
    </frontend>    
</config>
As we dissect our module, the first thing that pops up is the “frontend” element. We can see it has lot of sub-elements of which “routers” is first. In order for something in Magento to be accessible on certain url, that something needs to have controller, like all Zend powered applications. Unlike pure Zend apps, Magento has its own way of mapping controllers, trough xml definitions.
I intentionally used “JustSomeFreeRouterNameHereNo1″ for element name making it self explanatory. You can freely assign name to a router wheres “use” and “args” are two parameters each router should have. Parametar “module” if the full name of your module and “frontName” is the actual url path trough which you acccess your controller. In example above I would access my controller indexAction() method trough url like http://shop.local/index.php/activecodeline-simplecontact/index/ or http://shop.local/index.php/activecodeline-simplecontact/. In case we have url rewrite set up we can even access it by omitting the “index.php” part from url.
Now we will look into the content of IndexController.php.
file 3: app/code/local/ActiveCodeline/SimpleContact/controllers/IndexController.php
content of file 3:
<?php
 
class ActiveCodeline_SimpleContact_IndexController extends Mage_Core_Controller_Front_Action
{
    public function indexAction()
    {
        //Get current layout state
        $this->loadLayout();   
 
        $block = $this->getLayout()->createBlock(
            'Mage_Core_Block_Template',
            'activecodeline.simple_contact',
            array(
                'template' => 'activecodeline/simple_contact.phtml'
            )
        );
 
        $this->getLayout()->getBlock('content')->append($block);
        //$this->getLayout()->getBlock('right')->insert($block, 'catalog.compare.sidebar', true);
 
        $this->_initLayoutMessages('core/session');
 
        $this->renderLayout();
    }
 
    public function sendemailAction()
    {
        //Fetch submited params
        $params = $this->getRequest()->getParams();
 
        $mail = new Zend_Mail();
        $mail->setBodyText($params['comment']);
        $mail->setFrom($params['email'], $params['name']);
        $mail->addTo('somebody_else@example.com', 'Some Recipient');
        $mail->setSubject('Test ActiveCodeline_SimpleContact Module for Magento');
        try {
            $mail->send();
        }        
        catch(Exception $ex) {
            Mage::getSingleton('core/session')->addError('Unable to send email. Sample of a custom notification error from ActiveCodeline_SimpleContact.');
 
        }
 
        //Redirect back to index action of (this) activecodeline-simplecontact controller
        $this->_redirect('activecodeline-simplecontact/');
    }
}
 
?>
Above file, although simple, demonstrates two powerful concepts. First we have an example of creating a block “on the fly”. There are several ways one can add an output block to be shown in Magento, this is the “hardest” way. Most of the materials you will find on the web will show you how to do it from xml files. However, I want you to know how to do it from code.
There is one important reason why you should now how to do this from code: Simplicity! If you were to output the block from layout files then you are adding at leas one more file to your module. The more files you have in your module, bigger the chance for bugs. This is really something you should consider and keep in mind for modules who actually require controllers and are not very user centric.
When I say “not very user centric” I think in terms where designer needs to have full control of layout and the way it is arranged. However in cases where not much layout modifications will be required on custom made controller output I believe that “saving yourself” from writing another layout file is the right way to go.
Note that inside the method call createBlock i use ‘Mage_Core_Block_Template’ as one of the parameters. This is the block class. In this example core block template is used. However, you can freely use one of your own declared blocks (will be shown in latter modules). Created block is appended (inserted actualy) in existing block named “content”. Block “content” is one that is almost always present in the output.
Inside the sendemailAction method we have another important concept, the notification system example. Catch exception block triggers the “adding in the notification message” to the session storage. There are few different storage mechanism inside the Magento. Most of them simply extend core/session without any noticeable diference, therefore unles you wish to extend the existing and write your own, you can use the Mage::getSingleton(‘core/session’). You can use 4 diferent types of notification messages: error, warning, notice, success. Which you can call respectively like trough methods addError(’Custom error here’), addWarning(’Custom warning here’), addNotice(’Custom notice here’), addSuccess(’Custom success here’) as shown above.
Any notifications added to ‘core/session’ storage are outputted to frontend trough view files. For instance one such example is app/design/frontend/default/default/template/page/3columns.phtml file. Inside the file there is the getChildHtml(‘global_messages’) ?> line of code that outputs all global notifications. Note that the “global_messages” referes to block name from within the page.xml layout file, which in turn referes to Magento “core/messages” (Mage_Core_Block_Messages) class type.
Final file for our module is the view file itself. As you might notice from the IndexController, we are using the ‘activecodeline/simple_contact.phtml’ as one of the parameters passed to createBlock method. What this means is that our module is going to look for app/design/frontend/default/default/template/activecodeline/simple_contact.phtml file. Note that if we were to assign diferent template then “default” to be used for our site then ‘activecodeline/simple_contact.phtml’ would refer to folder and file from within that template. If that file is not find in this “other” template then the system would look for one in default template.
file 4: app/design/frontend/default/default/template/activecodeline/simple_contact.phtml
content of file 4:
<div class="box simple_contact">
 
<form id="simple_contact_form" name="simple_contact_form" action="<?php echo $this->getUrl('activecodeline-simplecontact/') ?>index/sendemail" method="post">
 
    <fieldset class="group-select">
        <h4 class="legend">ActiveCodeline_SimpleContact module sample</h4>
        <ul>
        <li>
                <div class="input-box">
                    <label for="name">Gimme your name <span class="required">*</span></label><br />
 
                    <input name="name" id="name" title="Name" value="" class="required-entry input-text" type="text" />
                </div>
 
                <div class="input-box">
                    <label for="email">And your email <span class="required">*</span></label><br />
                    <input name="email" id="email" title="Email" value="" class="required-entry input-text validate-email" type="text" />
                </div>
 
                <div class="clear"></div>
 
                <div class="input-box">
           &nbsp;        <label for="comment">Some comment?</label><br />
 
                    <textarea name="comment" id="comment" title="Comment" class="required-entry input-text" style="height:100px;" cols="50" rows="3"></textarea>
                </div>
                </li>
                </ul>
    </fieldset>
    <div class="button-set">
        <p class="required">* Required Fields</p>
        <button class="form-button" type="submit"><span>Submit</span></button>
 
    </div>
</form>
 
</div>
Content of above file is mostly HTML related so there is not much to talk about it.
That’s it, the end.

15 comments:

  1. Hello there. I am dying to know how to send more text or more description from other fields within the comments parameter - please help! Thanks so much!!

    ReplyDelete
  2. This was extremely helpful to me. Thank you so much!!

    ReplyDelete
  3. You need to set helper info in modules config.xml, if you want to use for example "Mage::helper" e.g. for translation in your form:

    <global>
    <helpers>
    <activecodeline-simplecontact>
    <class>ActiveCodeline_SimpleContact_Helper</class>
    </activecodeline-simplecontact>
    </helpers>
    </global>

    ReplyDelete
  4. I need to know that I have to modify some of the HTML templates. Will I lose the old modifications?
    Magento Design Templates

    ReplyDelete
  5. very useful article about magento ecommerce. now a days magento ecommerce site reaching well in the market. Thanks for the post about magento ecommerce.Magento Developers

    ReplyDelete
  6. I have been visiting various blogs for my term papers writing research. I have found your blog to be quite useful. Keep updating your blog with valuable information... Regards

    ReplyDelete
  7. How we get admin email address to send email . I want to send email to admin but don't want to hard code email

    ReplyDelete
  8. Great post thanks for sharing such informative post.

    ReplyDelete
  9. Amazing coding.As a new Magento Developer this coding will definitely help me.Thanks for sharing.

    ReplyDelete
  10. Cool code, created all the files, placed them right as you said in the right folders en copied the html code in to the offline maintanance page of magento. Which modifications do i have to do more to get it work properly?

    ReplyDelete
  11. I can't get this to work at all, it shows in admin as a module but when i try and visit the url in the front end of the website it merely goes to the default 404 page....

    ReplyDelete
  12. I like your post very much! It is so unique and creative!
    very nice coding realy
    thanks

    ReplyDelete
  13. this content very useful, I have added some more fields and they are working just fine. Thanks again

    ReplyDelete
  14. Magento has its own way of mapping controllers, trough xml definitions.Thanks for sharing it.

    magento customisation

    ReplyDelete
  15. He is the copy cat! Copied from http://inchoo.net/ecommerce/magento/magento-email/magento-custom-email-contact-form-with-notification-system/

    ReplyDelete