Inserting an Additional Step Into Checkout

There are several things that need to be considered in implementing an additional step. Here the basics that may be useful to now. As always this will be stepped through by implementing a new module.

config.xml:

<?xml version="1.0"?>
<config>

    <modules>
        <Howto_Customcheckout>
            <version>0.1.0</version>
        </Howto_Customcheckout>
    </modules>

    <admin>
        <routers>
            <customcheckout>
                <use>admin</use>
                <args>
                    <module>Howto_Customcheckout</module>
                    <frontName>customcheckout</frontName>
                </args>
            </customcheckout>
        </routers>
    </admin>

    <frontend>
        <layout>
            <updates>
                <customcheckout module="customcheckout">
                    <file>howto_customcheckout.xml</file>
                </customcheckout>
            </updates>
        </layout>
    </frontend>

    <global>
        <rewrite>
            <customcheckout_controller_rewrite> <!--This can be any unique id -->
                <from><![CDATA[#^/checkout/onepage/#]]></from>
                <!-- the URL which to override-->
                <to>/customcheckout/onepage/</to>
                <!-- destination url -->
            </customcheckout_controller_rewrite>
        </rewrite>

        <blocks>
            <customcheckout>
                <class>Howto_Customcheckout_Block</class>
            </customcheckout>
            <checkout>
                <rewrite>
                    <onepage>Howto_Customcheckout_Block_Checkout_Onepage</onepage>
                    <onepage_progress>Howto_Customcheckout_Block_Checkout_Onepage_Progress</onepage_progress>
                </rewrite>
            </checkout>
        </blocks>

        <helpers>
            <customcheckout>
                <class>Howto_Customcheckout_Helper</class>
            </customcheckout>
        </helpers>

        <models>
            <checkout>
                <rewrite>
                    <type_onepage>Howto_Customcheckout_Model_Checkout_Type_Onepage</type_onepage>
                </rewrite>
            </checkout>

            <customcheckout>
                <class>Howto_Customcheckout_Model</class>
            </customcheckout>

        </models>

    <global>

</config>

FILL IN OTHER DETAILS HERE….

An important part of the process in relation to the display of the new step goes to the layout aspect.

/app/design/frontend/default//layout/howto_customcheckout.xml

<?xml version="1.0" encoding="ISO-8859-1"?>
<layout version="0.1.0">
    <checkout_onepage_index> <!-- Adding our new step to onepage block  -->
        <reference name='checkout.onepage'>
            <action method='setTemplate'><template>checkout/onepage.phtml</template></action>

            <block type="customcheckout/checkout_onepage_customcheckout" name="checkout.onepage.customcheckout" as="customcheckout" template="checkout/onepage/customcheckout.phtml">
                <block type="customcheckout/checkout_onepage_customcheckout" name="checkout.onepage.customcheckout.child" as="customcheckout_child" template="checkout/onepage/customcheckout/customcheckout_child.phtml" />
            </block>

        </reference>
        
        <reference name='checkout.progress'> <!-- Change the template of progress block -->
            <action method='setTemplate'><template>checkout/onepage/progress.phtml</template></action>
        </reference> <!-- Here we change the template of the progress block to our custom template created -->
    </checkout_onepage_index>

    <checkout_onepage_customcheckout>
        <!-- Mage_Checkout -->
        <remove name="right"/>
        <remove name="left"/>

        <block type="customcheckout/checkout_onepage_customcheckout" name="root" output="toHtml" template="checkout/onepage/customcheckout/customcheckout_child.phtml"/>
    </checkout_onepage_customcheckout>

    <checkout_onepage_progress>  <!-- Change the template of progress block -->
        <reference name='root'>
            <action method='setTemplate'><template>checkout/onepage/progress.phtml</template></action>
        </reference>
    </checkout_onepage_progress>
</layout>

/app/code/local/Howto/Customcheckout/Block/Checkout/Onepage.php

<?php

class Webholism_DeliveryTimes_Block_Checkout_Onepage extends Mage_Checkout_Block_Onepage
{
	/**
	 * Get checkout steps codes
	 *
	 * @return array
	 */
	protected function _getStepCodes()
	{
		return array('billing', 'shipping', 'additionaltest', 'deliverytimes', 'payment', 'review');
	}

    public function getSteps()
    {
        $steps = array();

        if (!$this->isCustomerLoggedIn()) {
            $steps['login'] = $this->getCheckout()->getStepData('login');
        }

        // Adding new deliverytimes step, and remove shipping_method as this is to be automatically specified
        $stepCodes = array('billing', 'shipping', 'customcheckout', 'shipping-method', 'payment', 'review');

        foreach ($stepCodes as $step) {
            $steps[$step] = $this->getCheckout()->getStepData($step);
        }
        return $steps;
    }

/app/design/frontend/default//template/checkout/onepage/customcheckout.phtml

<?php ?>
<form  action="" id="co-customcheckout-form">
    <fieldset>
        <ul class="form-list">
            <li id="checkout-customcheckout-load">
                <?php echo ($this->getChildHtml('customcheckout_child')); ?>
            </li>
        </ul>

        <div class="buttons-set" id="customcheckout-buttons-container">
            <p class="back-link"><a href="#" onclick="checkout.back(); return false;"><small>&laquo; </small><?php echo $this->__('Back') ?></a></p>
            <button type="button" title="<?php echo $this->__('Continue') ?>" class="button" onclick="customcheckout.save()"><span><span><?php echo $this->__('Continue') ?></span></span></button>
            <span class="please-wait" id="customcheckout-please-wait" style="display:none;">
                <img src="<?php echo $this->getSkinUrl('images/opc-ajax-loader.gif') ?>" alt="<?php echo $this->__('Loading next step...') ?>" title="<?php echo $this->__('Loading next step...') ?>" class="v-middle" /> <?php echo $this->__('Loading next step...') ?>
            </span>
        </div>
    </fieldset>
</form>
<script type="text/javascript">
    //<![CDATA[
    var customcheckout = new CustomcheckoutMethod('co-customcheckout-form','<?php echo $this->getUrl('customcheckout/onepage/saveCustomcheckout') ?>');
    var customcheckoutForm = new VarienForm('co-customcheckout-form');
    //]]>
</script>

Transactional Email – Adding Custom Function Output

Having the basics of Transactional Emails under one’s belt it is then safe to start taking things to the next level.

Consider the case of wanting to implement a new function that is currently not part of the basic order Transactional Email list.

In this case it is possible to rewrite the order model and implement your own functionality.

The creation of the necessary skeleton files are as follows:

/etc/module/{Namespace}_{Module}.xml

<?xml version="1.0" encoding="ISO-8859-1"?>
<config>
    <modules>
        <{Namespace}_{Module}>
            <active>true</active>
            <codePool>local</codePool>
        </{Namespace}_{Module}>
    </modules>
</config>

/app/code/local/{Namespace}/{Module}/etc/config.xml

<?xml version="1.0" encoding="UTF-8"?>
<config>
    <modules>
        <{Namespace}_{Module}>
            <version>0.1.0</version>
        </{Namespace}_{Module}>
    </modules>

    <global>
        <models>
           <core>
                <rewrite>
                    <email_template>{Namespace}_{Module}_Model_Email_Template</email_template>
                </rewrite>
            </core>
            <sales>
                <rewrite>
                    <order>{Namespace}_{Module}_Model_Email_Order</order>
                </rewrite>
            </sales>

            <emails>
                <class>{Namespace}_{Module}_Model</class>
            </emails>
        </models>

        <!-- Adds an entry into Transactional Email -->
        <template>
            <email>
                <!-- This value should reflect the path defined in the system.xml file: customer - order_confirmation_email - confirmation_template -->
                <customer_order_confirmation_email_confirmation_template translate="label" module="customer">
                    <label>Custom Order Confirmation</label>
                    <!-- Create file in the language locations at /app/locale/<language code>/email/order/confirmation.hmtl -->
                    <file>order/confirmation.html</file>
                    <type>html</type>
                </customer_order_confirmation_email_confirmation_template>
            </email>
        </template>
    </global>
</config>

/app/code/local/{Namespace}/{Module}/Model/Email/Order.php

<?php
class {Namespace}_{Module}_Model_Email_Order extends Mage_Sales_Model_Order {

	public function customFunction() {
		return 'This is a custom function return string';
	}
}

/app/code/local/{Namespace}/{Module}/Model/Email/Template.php

<?php
class {Namespace}_{Module}_Email_Template extends Mage_Core_Model_Email_Template {

	public function sendTransactional($templateId, $sender, $email, $name, $vars=array(), $storeId=null)
	{
		$this->setSentSuccess(false);
		if (($storeId === null) && $this->getDesignConfig()->getStore()) {
			$storeId = $this->getDesignConfig()->getStore();
		}

		if (is_numeric($templateId)) {
			$this->load($templateId);
		} else {
			$localeCode = Mage::getStoreConfig('general/locale/code', $storeId);
			$this->loadDefault($templateId, $localeCode);
		}

		if (!$this->getId()) {
			throw Mage::exception('Mage_Core', Mage::helper('core')->__('Invalid transactional email code: ' . $templateId));
		}

		if (!is_array($sender)) {
			$this->setSenderName(Mage::getStoreConfig('trans_email/ident_' . $sender . '/name', $storeId));
			$this->setSenderEmail(Mage::getStoreConfig('trans_email/ident_' . $sender . '/email', $storeId));
		} else {
			$this->setSenderName($sender['name']);
			$this->setSenderEmail($sender['email']);
		}

		if (!isset($vars['store'])) {
			$vars['store'] = Mage::app()->getStore($storeId);
		}

		// Added code for custom var example.
		$vars['custom_var'] = 'This is a custom var';
		}

		$this->setSentSuccess($this->send($email, $name, $vars));
		return $this;
	}
}

Template definition (note that this was specified in the config.xml file above)
/app/locale/{language_code}/template/email/order/confirmation.html

<!--@subject {{var store.getFrontendName()}}: New Order # {{var order.increment_id}} @-->
<!--@vars
{"store url=\"\"":"Store Url",
"var logo_url":"Email Logo Image Url",
"var logo_alt":"Email Logo Image Alt",
"htmlescape var=$order.getCustomerName()":"Customer Name",
"var store.getFrontendName()":"Store Name",
"store url=\"customer/account/\"":"Customer Account Url",
"var order.increment_id":"Order Id",
"var order.getCreatedAtFormated('long')":"Order Created At (datetime)",
"var order.getBillingAddress().format('html')":"Billing Address",
"var payment_html":"Payment Details",
"var order.getShippingAddress().format('html')":"Shipping Address",
"var order.getShippingDescription()":"Shipping Description",
"layout handle=\"sales_email_order_items\" order=$order":"Order Items Grid",
"var order.getEmailCustomerNote()":"Email Order Note"}
@-->
<!--@styles
body,td { color:#2f2f2f; font:11px/1.35em Verdana, Arial, Helvetica, sans-serif; }
@-->

<body style="background:#F6F6F6; font-family:Verdana, Arial, Helvetica, sans-serif; font-size:12px; margin:0; padding:0;">
<div style="background:#F6F6F6; font-family:Verdana, Arial, Helvetica, sans-serif; font-size:12px; margin:0; padding:0;">

    {{var order.customFunction()}} <!-- as defined in /app/code/local/{Namespace}/{Module}/Model/Email/Order.php -->
    {{var custom_var}} <!-- as defined in /app/code/local/{Namespace}/{Module}/Model/Email/Template.php -->

    <table cellspacing="0" cellpadding="0" border="0" width="100%">
        <tr>
            <td align="center" valign="top" style="padding:20px 0 20px 0">
                <table bgcolor="#FFFFFF" cellspacing="0" cellpadding="10" border="0" width="650" style="border:1px solid #E0E0E0;">
                    <!-- [ header starts here] -->
                    <tr>
                        <td valign="top"><a href="{{store url=""}}"><img src="{{var logo_url}}" alt="{{var logo_alt}}" style="margin-bottom:10px;" border="0"/></a></td>
                    </tr>
                    <!-- [ middle starts here] -->
                    <tr>
                        <td valign="top">
                            <h1 style="font-size:22px; font-weight:normal; line-height:22px; margin:0 0 11px 0;"">Hello, {{htmlescape var=$order.getCustomerName()}}</h1>
                            <p style="font-size:12px; line-height:16px; margin:0;">
                                Thank you for your order from {{var store.getFrontendName()}}.
                                Once your package ships we will send an email with a link to track your order.
                                You can check the status of your order by <a href="{{store url="customer/account/"}}" style="color:#1E7EC8;">logging into your account</a>.
                                If you have any questions about your order please contact us at <a href="mailto:{{config path='trans_email/ident_support/email'}}" style="color:#1E7EC8;">{{config path='trans_email/ident_support/email'}}</a> or call us at <span class="nobr">{{config path='general/store_information/phone'}}</span> Monday - Friday, 8am - 5pm PST.
                            </p>
                            <p style="font-size:12px; line-height:16px; margin:0;">Your order confirmation is below. Thank you again for your business.</p>
                    </tr>
                    <tr>
                        <td>
                            <h2 style="font-size:18px; font-weight:normal; margin:0;">Your Order #{{var order.increment_id}} <small>(placed on {{var order.getCreatedAtFormated('long')}})</small></h2>
                        </td>
                    </tr>
                    <tr>
                        <td>
                            <table cellspacing="0" cellpadding="0" border="0" width="650">
                                <thead>
                                <tr>
                                    <th align="left" width="325" bgcolor="#EAEAEA" style="font-size:13px; padding:5px 9px 6px 9px; line-height:1em;">Billing Information:</th>
                                    <th width="10"></th>
                                    <th align="left" width="325" bgcolor="#EAEAEA" style="font-size:13px; padding:5px 9px 6px 9px; line-height:1em;">Payment Method:</th>
                                </tr>
                                </thead>
                                <tbody>
                                <tr>
                                    <td valign="top" style="font-size:12px; padding:7px 9px 9px 9px; border-left:1px solid #EAEAEA; border-bottom:1px solid #EAEAEA; border-right:1px solid #EAEAEA;">
                                        {{var order.getBillingAddress().format('html')}}
                                    </td>
                                    <td>&nbsp;</td>
                                    <td valign="top" style="font-size:12px; padding:7px 9px 9px 9px; border-left:1px solid #EAEAEA; border-bottom:1px solid #EAEAEA; border-right:1px solid #EAEAEA;">
                                        {{var payment_html}}
                                    </td>
                                </tr>
                                </tbody>
                            </table>
                            <br/>
                            {{depend order.getIsNotVirtual()}}
                            <table cellspacing="0" cellpadding="0" border="0" width="650">
                                <thead>
                                <tr>
                                    <th align="left" width="325" bgcolor="#EAEAEA" style="font-size:13px; padding:5px 9px 6px 9px; line-height:1em;">Shipping Information:</th>
                                    <th width="10"></th>
                                    <th align="left" width="325" bgcolor="#EAEAEA" style="font-size:13px; padding:5px 9px 6px 9px; line-height:1em;">Shipping Method:</th>
                                </tr>
                                </thead>
                                <tbody>
                                <tr>
                                    <td valign="top" style="font-size:12px; padding:7px 9px 9px 9px; border-left:1px solid #EAEAEA; border-bottom:1px solid #EAEAEA; border-right:1px solid #EAEAEA;">
                                        {{var order.getShippingAddress().format('html')}}
                                        &nbsp;
                                    </td>
                                    <td>&nbsp;</td>
                                    <td valign="top" style="font-size:12px; padding:7px 9px 9px 9px; border-left:1px solid #EAEAEA; border-bottom:1px solid #EAEAEA; border-right:1px solid #EAEAEA;">
                                        {{var order.getShippingDescription()}}
                                        &nbsp;
                                    </td>
                                </tr>
                                </tbody>
                            </table>
                            <br/>
                            {{/depend}}
                            {{layout handle="sales_email_order_items" order=$order}}
                            <p style="font-size:12px; margin:0 0 10px 0">{{var order.getEmailCustomerNote()}}</p>
                        </td>
                    </tr>
                    <tr>
                        <td bgcolor="#EAEAEA" align="center" style="background:#EAEAEA; text-align:center;"><center><p style="font-size:12px; margin:0;">Thank you, <strong>{{var store.getFrontendName()}}</strong></p></center></td>
                    </tr>
                </table>
            </td>
        </tr>
    </table>
</div>
</body>

Having created the module it is then time to create the Transactional Email in the administrator of Magento.
Magento Admin Panel -> System -> Transactional Emails -> Add New Template
The Template select should now allow you to select the template that you have created, it will be visible from the name defined in the config.xml file ().

Once this Template has been added, it can then be set as the default order template.

To achieve this then select magento Admin Panel -> System -> Configuration -> Sales (Sales Emails)
Then expand the Order panel. In the New Order Confirmation select, choose the name that was defined in the previous step when the new template was defined.

That will now give you the opportunity to use custom variables and custom functions in your order transactional emails.

Transactional Emails Basics

In the process of wanting to add a new dynamic value, based on a customer account, into the invoice email that is sent out when a customer buys something from the store, it became evident that understanding of transactional emails would be needed.

To view Transactional Emails it is possible to to into the Magento backend System -> Transactional Emails. Within this section it is possible to create a new template based on the templates defined in the file structure.

Having defined a template in the previous section, it is then possible to associate that template to an action. This is done in the Magento backend System -> Configuration -> Sales (Sales Emails).

Admin Controllers

In the config.xml file of the module extension, define the following:

   <admin>
        <routers>
            <adminhtml>
                <args>
                    <modules>
                        <{Namespace}_{Module} before="Mage_Adminhtml">{Namespace}_{Module}</{Namespace}_{Module}>
                    </modules>
                </args>
            </adminhtml>
        </routers>
    </admin>

In the controller file, example indexController.php, define the following:
class {Namespace}_{Module}_Adminhtml_IndexController extends Mage_Adminhtml_Controller_Action {
public function indexAction() {
/* Debug code */
//Zend_Debug::dump($this->getLayout()->getUpdate()->getHandles()); die ();

$this->loadLayout();
$this->renderLayout();
}
}

Note: This will not allow the testing of the page in the back end as this requires the use of a nonce key that is added by Magento when yo link to a URL defined in the core or in an extension. So do not assume that {base_url}{admin}{frontname}{controller}{action} will not grant access to a page. It is possible however to obtain a url with the command: Mage::helper(“adminhtml”)->getUrl(‘{frontname}/{action}’)

Email Templates

When dealing with the default emails that are sent out by the system, such as int he case of new registration, order confirmation and the like the code for these are placed in the /app/locale//template/.. folders.

One thing to consider in the deciphering of these template files is that it will be possible to see entries such as: {{layout handle=”sales_email_order_items” order=$order}} in the file, and it is possible to wonder what on earth such notation relates to.

The sales_email_order_items part of this refers to the file /app/design/frontend/base/default/layout/sales.xml. Here there is the following section:



defaultsales/order_email_items_order_default
groupedsales/order_email_items_order_grouped

colspan=”3″ align=”right” style=”padding:3px 9px”
align=”right” style=”padding:3px 9px”

1





The above excerpt shows defaultsales/order_email_items_order_default, and this is referencing /app/design/frontend//default/template/email/order/items/order/default.phtml

It is then possible to place an override file in your frontend template to alter the values in this file.

XAMPP – MySQL Corruption

Having used XAMPP for a time on a Mac, I have encountered a few situations in which my databases have become corrupted. I cannot say why, and if I knew I would definitely attempt to avoid this, as it often sets me back a reasonable amount of time.

Whilst this is not an instructional guide on recovering your data, this is a way to simply try and get your environment working again once such a situation has occurred as I have been left unable to start the MySQL server on my local machine and resorted to all sorts of re-installations of software in an attempt to get my XAMPP environment operational again.

So if faced with an inability to start the MySQL Database service, consider implementing the following:

1. Look to /Applications/XAMPP/xamppfiles/var/mysql/ directory and there should b a file that ends with .local.err. Open this file and this will provide some possible insight into what may be going on. Often in my situations I would see something like:

The exact text will differ, but this may provide with some assistance.

2. Then try using: innodb_force_recovery = 1 after the [mysqld] line in the /Applications/XAMPP/xamppfiles/etc/my.cnf file. This may require use of sudo when modifying this file; for example: sudo vi /Applications/XAMPP/xamppfiles/etc/my.cnf and then enter the password. Save the file; if using vi this is achieved with :w command (more information here: http://www.howtogeek.com/102468/a-beginners-guide-to-editing-text-files-with-vi/).

3. Retry starting the XAMPP MySQL Database server. Check the output of the .local.err file to see what information has been introduced to the end of this file.

4. Database repair is possible with the use of the command: sudo /Applications/XAMPP/xamppfiles/bin/mysqlcheck -c –all-databases. This will go through all the DB instances and attempt to repair them.

5. Sometimes this will not work however, and you just need to cut and run. If that is the situation, then it is possible to ensure that the MySQL Database service is disabled and then manually delete the database directories. When you then restart the MySQL Database service these will not longer be visible in the list.

6. Restore the database from a backup, and make any modifications that may be necessary if it is a remote backup, to ensure that the local parameters are set.

Hopefully that will be enough to get the system functional once again.

Customising Transactional Emails

If it is necessary to change the any of the transactional emails, it is possible to do this from within the administrator interface. First let’s clarify the term transactional email, by this consider the following forms that are generated with the standard operating processes:
Contact Form
Credit Memo Update
Credit Memo Update for Guest
Currency Update Warning
Forget Admin Password
Forgot Password
Invoice Update
Invoice Update for Guest
Log cleanup Warning
Moneybookers activate Email
New Credit Memo
New Credit Memo for Guest
New Invoice
New Invoice for Guest
New Order
New Order for Guest
New Shipment
New Shipment for Guest
New account
New account for Guest
Newsletter subscription confirmation
Newsletter subscription success
Newsletter unsubscription success
Order Update
Order Update for Guest
Payment Failed
Product alerts Cron error
Product price alert
Product stock alert
Remind Password
Send product to a friend
Share Wishlist
Shipment Update
Shipment Update for Guest
Sitemap generate Warnings
Token Status Change

To update any of these forms it is possible to enter the Administrator Backend. Then go to the following menu option System -> Transactional Emails.

Then Add New Template. From the new form that opens:

Backend -> System -> Transactional Emails -> Add New Template -> Load default template

This will allow selection of the forms listed above when selecting the Template* dropdown.

Then select the locale dropdown to define the language option that the new template will be applied to.

When the Load Template button is selected this will populate the bottom half of the form and it will be possible to customise this directly and save it. This template will then be used for the conditions applied.

Adding A Custom Column To The Adminhtml Grid Widget

Recently it was necessary to add a new custom column to the Adminhtml Grid widget, as a new delivery date value had been created but was not appearing in the orders view associated to the customer.

So the form to be modified has been centralised and can be found at: /app/design/adminhtml/default/{theme}/template/widget/grid.phtml

at the top of this form the following was added, based on the requirement of the custom delivery date field that had already been created.

$this->addColumn('delivery_datetime', array(
    'header' => $this->__('Delivery Datetime'),
    'index' => 'delivery_datetime',
    'type' => 'date',
    'width' => '100px',
));

This was superb and added the column to the end of the grid. However, it was far more useful to apply the column after the store information, so the order of the grid was changed with the following code snippet:

$this->addColumnsOrder('delivery_datetime', 'store_id')
    ->sortColumnsByOrder();

The store_id value was extracted when the following debug code was added into the form, which while a little unsightly, both from a coding and a layout perspective, identified the values involved in the grid:

‘);
var_dump ($innerInnerColumn);
}
}
}
?>
[\php]

This code was placed after

<?php foreach ($this->getColumns() as $_column): ?>

Resources:
magento-grid-column-position

Checkout – Making Required Fields Un-Required or Vice Versa

There are times that you simply do not need people to submit information, and while Magento has its own idea on that, the mavericks among you simply need to go your own way.

This is a 2 step process:
1. Open up the relevant .phtml files, and removed the offending text that defines these fields as required. Primarily, the two files to consider are /app/design/frontend/defaul/{theme}/template/checkout/onepage/billing.phtml and /app/design/frontend/defaul/{theme}/template/checkout/onepage/shipping.phtml

In these files you are likely to see the following, or similar syntax:

<label for="shipping:telephone" class="required"><em>*</em><?php echo $this->__('Telephone') ?></label>

The removal of the text class=”required” and * will firstly be required. Apply those changes to the file for all of the fields that are required and that are no longer required to have such status.

This is great, but submitting the form will still produce an alert and not allow you to continue. A somewhat frustrating turn of events. The next thing is to turn to the database.

2. Find the eav_attribute table and find the field for the value that you are looking to modify. You will find a column labelled ‘is_required’. Change the value for the field of interest from 1 to 0. If it is not set to 1, then the field will probably not have generated the alert and error mentioned previously.

That is it. You should now have a working form. Yippee.

Note, that to make a field required you would want to follow the steps above but do the opposite:
1. Convert the html from

<label for="shipping:telephone"><?php echo $this->__('Telephone') ?></label>

to

<label for="shipping:telephone" class="required"><em>*</em><?php echo $this->__('Telephone') ?></label>

2. Change the database entry for the is_required column from 0 to 1 for the row related to the value in question.

Adding Checkboxes To An Admin Form

If the requirement is to offer an administrator an assortment of form options from an array it is possible to use a checkbox field.

The following will simply output the data from the array as defined in the

class {Namespace}_{Module}_Block_Adminhtml_{Controller}_Edit_Tab_{Formname} extends Mage_Adminhtml_Block_Widget_Form
{
    protected function _prepareForm()
    {
        $form = new Varien_Data_Form();
        $this->setForm($form);

        $fieldset = $form->addFieldset('{formname}_form',
            array('legend' => 'Legend'));

        $possibleOptionsArray = Mage::getModel('{namespace}/{module}')->getArrayFunction('array', 'name');

        $fieldset->addField('{id}', 'checkboxes', array(
            'label'     => $this->__('Label'),
            'name'      => '{row_name}[]',
            'value'     => $currentValueArray,
            'values'    => $possibleOptionsArray,
            'disabled'  => false
        ));

Important note: ‘name’ => ‘{row_name}[]’,
The name definition should be an array that ends with [].

controller saveAction to contain the following:

foreach ($data as $key => $value)
{
    if (is_array($value))
    {
        $data[$key] = implode(',',$this->getRequest()->getParam($key));
    }
}