Custom forms in Magento

39,079

Solution 1

If any one is interested, I solved this by building my own module which was heavily based on the Magento_Contacts module.

Here are some links that helped me figure things out.

http://www.magentocommerce.com/wiki/custom_module_with_custom_database_table

http://inchoo.net/ecommerce/magento/magento-custom-emails/

Solution 2

To make $this->getFormAction() return the URL to your custom controller, you have two options:

  1. call setFormAction() somewhere else on the block.
  2. use a custom block type that implements getFormAction().

(1) is what happens in Mage_Contacts_IndexController::indexAction(), but (2) is the cleaner approach and I'm going to explain it in detail:

Create a custom module

app/etc/modules/Stack_Form.xml:

<?xml version="1.0"?>
<config>
    <modules>
        <Stack_Form>
            <active>true</active>
            <codePool>local</codePool>
        </Stack_Form>
    </modules>
</config>

app/code/local/Stack/Form/etc/config.xml:

<?xml version="1.0"?>
<config>
    <modules>
        <Stack_Form>
            <version>0.1.0</version>
        </Stack_Form>
    </modules>
    <frontend>
        <routers>
            <stack_form>
                <use>standard</use>
                <args>
                    <module>Stack_Form</module>
                    <frontName>feedback</frontName>
                </args>
            </stack_form>
        </routers>
    </frontend>
    <global>
        <blocks>
            <stack_form>
                <class>Stack_Form_Block</class>
            </stack_form>
        </blocks>
    </global>
</config>

This configuration registers the stack_form block alias for own blocks and the feedback front name for own controllers.

Create custom block

app/code/local/Stack/Form/Block/Form.php

class Stack_Form_Block_Form extends Mage_Core_Block_Template
{
    public function getFormAction()
    {
        return $this->getUrl('stack_form/index/post`);
    }
}

Here we implemented getFormAction() to generate the URL for our custom controller (the result will be BASE_URL/feedback/index/post).

Create custom controller

app/code/local/Stack/Form/controllers/IndexController.php

class Stack_Form_IndexController extends Mage_Contacts_IndexController
{
    public function postAction()
    {
        // your custom post action
    }
}

If the form should behave exactly like the contact form, just with a different email template and additional form fields, there are two solutions that I have outlined at https://magento.stackexchange.com/q/79602/243 where only one of them actually requires a custom controller action to send the form:

If you look at the contacts controller used in the form action, you will find that

  1. the transactional template is taken directly from the configuration
  2. all POST data is passed to the template (as template variable data), so that you can add any additional fields to the form template and use them in the email template. But validation is hard coded for "name", "comment", "email" and "hideit".

So, if you need a completely different email template or additional/changed input validation, your best bet is to create a custom controller with a modified copy of the postAction of Mage_Contacts_IndexController.

But there is another solution that is a bit limited but without any custom code involved:

  • create a hidden input that determines the type of the form. It could be just <input type="hidden" name="custom" value="1" />.
  • in the contact transactional email template, use the if directive to show different content based on the form type:

    {{if data.custom}}
        ... custom contact form email ...
    {{else}}
        ... standard contact form email ...
    {{/if}}
    

How to use this custom block

You can add the form anywhere in the CMS using this code (CMS directive):

{{block type="stack_form/form" template="path/to/your/form.phtml"}}

If you do this, you need to add "stack_form/form" to the block whitelist under System > Permissions > Blocks!

Or in the layout using this code (layout XML):

<block type="stack_form/form" name="any_unique_name" template="path/to/your/form.phtml" />

Solution without custom module

If you use the solution without custom controller and a single email template mentioned above, you can set the form action using layout XML as well.

To achieve this, we use the feature to call helpers as parameters for block actions. Unfortunately, the core helper does not have a public method to get a URL but the helper from Mage_XmlConnect has, so you can use that one:

<block type="core/template" name="any_unique_name" template="path/to/your/form.phtml">
    <action method="setFormAction">
        <param helper="xmlconnect/getUrl">
            <route>contacts/index/post</route>
        </param>
    </action
</block>

In the CMS directive you cannot use helpers, so there you would need to put the actual URL:

{{block type="stack_form/form" template="path/to/your/form.phtml" form_action="/feedback/index/post"}}

Since you probably have different CMS pages/blocks in different store views, this should not be a big problem.

Share:
39,079
Dan
Author by

Dan

Updated on July 09, 2022

Comments

  • Dan
    Dan almost 2 years

    Can anyone provide a dummy guide \ code snippets on how to create a front end form in Magento that posts data to a controller action.

    Im trying to write a variant of the contact us from. (I know its easy to modify the contact us form, as outlined here). I'm trying to also create a feedback form with additional fields.

    Given this basic form:

    <form action="<?php echo $this->getFormAction(); ?>" id="feedbackForm" method="post">   
                    <div class="input-box">
                        <label for="name"><?php echo Mage::helper('contacts')->__('Name') ?> <span class="required">*</span></label><br />
                        <input name="name" id="name" title="<?php echo Mage::helper('contacts')->__('Name') ?>" value="<?php echo $this->htmlEscape($this->helper('contacts')->getUserName()) ?>" class="required-entry input-text" type="text" />
                    </div>
    
        <div class="button-set">
            <p class="required"><?php echo Mage::helper('contacts')->__('* Required Fields') ?></p>
            <button class="form-button" type="submit"><span><?php echo Mage::helper('contacts')->__('Submit') ?></span></button>
        </div>
    </form>
    

    What are the basic step I need to take to get inputted name to a controller action for processing?

  • Alex Bogias
    Alex Bogias almost 8 years
    I tried your tutorial mate but i just see an empty page! Do i have to include anything inside public function postAction()? I created a copy of stack_form.phtml of app\design\frontend\base\default\template\contacts\form.phml and tried the {{block... way in a new cms page
  • Fabian Schmengler
    Fabian Schmengler almost 8 years
    yes, the postAction method must contain your custom code to create an email from the form input and show a success message to the user. As stated above, that can be a modified copy of the postAction of Mage_Contacts_IndexController
  • Alex Bogias
    Alex Bogias almost 8 years
    I added it but with the same results... What about function getFormAction? Can this be empty?
  • Alex Bogias
    Alex Bogias almost 8 years
    I now get Fatal error: Call to a member function setFormAction() on boolean in app/code/core/Mage/Contacts/controllers/IndexController.php on line 55
  • Alex Bogias
    Alex Bogias almost 8 years
    OK i had to whitelist the block stack_form/form
  • Alex Bogias
    Alex Bogias almost 8 years
    But i know get the about error on submit. I copied pasted everything inside public function postAction() to my postAction()
  • Fabian Schmengler
    Fabian Schmengler almost 8 years
    I added the whitelist bit to the answer, this is a new requirement since one of the recent patches.
  • Gem
    Gem over 5 years
    My feedback form : dropbox.com/sh/32zqgejubfllz0h/AACkB_iIh-KJQxtEUikZ8i9Na?dl=‌​0 How can i display in all pages including home page @Dan
  • treyBake
    treyBake over 4 years
    the first link is a redirect to their main documentation page now :/