Friday, December 30, 2011

Magento: template tags


Magento uses its own replacement tags to render dynamic content in CMS pages, e-mail
templates, and static blocks. You might have noticed that in CMS pages and static blocks
there are some {{ double curly brace wrapped }} items with some attributes. These are
known as template tags. In this recipe, we used the store tag only while there were five other
tags. Some of the template tags are as follows:
ff Block: This creates a static block with specified ID. For example: {{block
type='core/template' template='cms/your_page.phtml'}}
ff Layout: This renders an HTML layout output for the specified layout. The
handle attribute expects the name of a layout handle. For example: {{layout
handle="default"}}
ff Media: This retrieves path of files from root/media folder. For example: {{media
url="images/logo.png"}}
ff Skin: This gets files from active theme in skin/frontend folder. For example: <img
src="{{skin url='images/media/about_us.png'}}"/>
ff Store: This creates routes and custom URLs for Magento store. For example:
{{store url="contact"}} would render the full URL for that path.
ff htmlescape: This escapes html characters as its name suggests. For example:
{{htmlescape var=""}}
ff var: This renders a variable. For example: {{var my_variable}}
ff protocol: This renders the proper protocol (HTTP or HTTPS) depending on current
context. For example: {{protocol url="www.domain.com/"}}
If you want to see the methods that handle this stuff you can have a look on app/code/
core/Mage/Core/Model/Email/Template/Filter.php.

Monday, December 19, 2011

SEO: Generic Metadata

    Title - Authors should use the title element to identify the contents of a document. Since users often consult documents out of context, authors should provide context rich page titles.

    <title></title>
    Author - Provide metadata to add semantic information to pages and sites. For example, use RDF to indicate the document's author.

    <meta name="author" content="">
    Description - Some search engines will index the META Description Tag found in the <head></head> section of your web pages. These indexing search engines may present the content of your meta description tag as the result of a search query.

    <meta name="description" content="">
    Contact Information - The ADDRESS element may be used by authors to supply contact information for a document and often appears at the beginning or end of a document.

    <address></address>
    Language Code - Language information is useful for accessibility, authoring tools, translation tools, font selection, page rendering, search, and scripting. There are four places where language information can be declared. One of those is in a meta element in the document head with the content attribute set tocontent-language.

    <meta http-equiv="content-language" content="en, fr, sp" />
    Explicit Language Annotations - In a language attribute on an element within the document.

    <p>The Spanish word for <em>thank you</em> is <em lang="es">gracias</em>.
    HTML Profile - The profile attribute of the HEAD specifies the location of a metadata profile. The value of the profile attribute is a URI.

    <head profile="http://www.example.com/profiles/html">

Saturday, December 17, 2011

Magento: Admin Controller Override


Magento: Block Controller Model Helper Override


This article will show how you can override Magento Block, Controller, Model and Helper files. We will be dealing with the config XML files and the class files to override.
We override Magento core classes to update/modify the core functionalities according to our need. We can directly makes changes in the core Magento classes but doing so will hamper us when we upgrade the Magento version. All our changes will go away then. Because, when we upgrade Magento, the new core files will replace the old core files which we had changed.
But when we override the Magento core class files, all changes will be done in our local files and the core files remain intact. So, this will not do affect our changes when we upgrade Magento.
Block Override

Scenario: I want to display 3 products per page in product listing.
For this we need to use setPageSize function.
Mage_Catalog_Block_Product_List class is responsible for getting product items in product listing page.
I will override this Block class with my module’s class MyNamespace_MyModule_Block_Product_List. So, the path of class MyNamespace_MyModule_Block_Product_List is MyNamespace/MyModule/Block/Product/List.php
Here is the xml code which is to be written in etc/config.xml for my custom module.
<global>
    <blocks>
        <catalog>
            <rewrite>
                <product_list>MyNamespace_MyModule_Block_Product_List</product_list>
            </rewrite>
        </catalog>
    </blocks>
<global>

MyNamespace_MyModule_Block_Product_List class.
I have used setPageSize(3). This means that, 3 products are displayed per page.
<?php
class MyNamespace_MyModule_Block_Product_List extends Mage_Catalog_Block_Product_List
{
     /**
     * Retrieve loaded category collection
     *
     * @return Mage_Eav_Model_Entity_Collection_Abstract
     */
    protected function _getProductCollection()
    {
        if (is_null($this->_productCollection)) {
            $layer = Mage::getSingleton('catalog/layer');
            /* @var $layer Mage_Catalog_Model_Layer */
            if ($this->getShowRootCategory()) {
                $this->setCategoryId(Mage::app()->getStore()->getRootCategoryId());
            }

            // if this is a product view page
            if (Mage::registry('product')) {
                // get collection of categories this product is associated with
                $categories = Mage::registry('product')->getCategoryCollection()
                    ->setPage(1, 1)
                    ->load();
                // if the product is associated with any category
                if ($categories->count()) {
                    // show products from this category
                    $this->setCategoryId(current($categories->getIterator()));
                }
            }

            $origCategory = null;
            if ($this->getCategoryId()) {
                $category = Mage::getModel('catalog/category')->load($this->getCategoryId());
                if ($category->getId()) {
                    $origCategory = $layer->getCurrentCategory();
                    $layer->setCurrentCategory($category);
                }
            }
            $this->_productCollection = $layer->getProductCollection();

            $this->prepareSortableFieldsByCategory($layer->getCurrentCategory());

            if ($origCategory) {
                $layer->setCurrentCategory($origCategory);
            }
        }
        return $this->_productCollection->setPageSize(3);
    }
}

Controller Override

Scenario: I want to display products of ‘Living Room’ category to logged in customer only. When guest users try to view the ‘Living Room’ category, they should be redirected to login page.
For this I need to override the Mage_Catalog_CategoryController class.
config.xml
There are 2 ways to write the xml code for controller override. You can use any one of the following:-
The First way
<global>
    <routers>
        <catalog>
            <rewrite>
                <category>
                    <to>MyNamespace_MyModule/catalog_category</to>
                    <override_actions>true</override_actions>
                    <actions>
                       <view><to>MyNamespace_MyModule/catalog_category</to></view>
                    </actions>
                </category>
            </rewrite>
        </catalog>
    </routers>
<global>

The Second way
<global>
    <rewrite>
        <mynamespace_mymodule_catalog_category>
            <from><![CDATA[#^/catalog/category/#]]></from>
            <to>/mymodule/catalog_category/</to>
        </mynamespace_mymodule_catalog_category>
    </rewrite>
<global>

Now, you need to create a controller class MyNamespace_MyModule_Catalog_CategoryController
The path for the controller file will be MyNamespace/MyModule/Catalog/CategoryController.php
<?php
require_once('Mage/Catalog/controllers/CategoryController.php');
class MyNamespace_MyModule_Catalog_CategoryController extends Mage_Catalog_CategoryController
{
    /**
     * Initialize requested category object
     *
     * @return Mage_Catalog_Model_Category
     */
    protected function _initCatagory()
    {
        Mage::dispatchEvent('catalog_controller_category_init_before', array('controller_action'=>$this));
        $categoryId = (int) $this->getRequest()->getParam('id', false);
        if (!$categoryId) {
            return false;
        }

        $category = Mage::getModel('catalog/category')
            ->setStoreId(Mage::app()->getStore()->getId())
            ->load($categoryId);

        if (!Mage::helper('catalog/category')->canShow($category)) {
            return false;
        }
        Mage::getSingleton('catalog/session')->setLastVisitedCategoryId($category->getId());
        Mage::register('current_category', $category);
        try {
            Mage::dispatchEvent('catalog_controller_category_init_after', array('category'=>$category, 'controller_action'=>$this));
        } catch (Mage_Core_Exception $e) {
            Mage::logException($e);
            return false;
        }

        /**
         * My Code
         * Checking category name and customer logged in
         * if category name is 'Living Room' and customer is not logged
         * then redirect to customer login page
         */

        if($category->getName() == 'Living Room' && Mage::helper('customer')->isLoggedIn() == false) {
            $this->_redirectUrl(Mage::getUrl('customer/account/login'));
        }

        return $category;
    }
}

Model Override

Scenario: I want to add some text e.g. ‘Product:’ in front of every product name. And, I want fixed price for every product e.g. 100.
For this you need to override Mage_Catalog_Model_Product class.
config.xml
<global>
    <models>
        <catalog>
            <rewrite>
                <product>MyNamespace_MyModule_Model_Catalog_Product</product>
            </rewrite>
        </catalog>
    </models>
<global>

Now, you need to create a model class MyNamespace_MyModule_Model_Catalog_Product
The path for the model file will be MyNamespace/MyModule/Model/Catalog/Product.php
<?php
class MyNamespace_MyModule_Model_Catalog_Product extends Mage_Catalog_Model_Product
{
     /**
     * Get product name
     * Adding a text 'Product:' before product name
     *
     * @return string
     */
    public function getName()
    {
        return "Product: ".$this->_getData('name');
        //return $this->_getData('name');
    }

    /**
     * Returning a fixed price '100' for every product
     *
     * @return unknown
     */
    public function getPrice()
    {
        return 100;
        //return $this->getPriceModel()->getPrice($this);
    }
}

Helper Override

Scenario: When any logged in customer reviews any product, his/her review (after admin approval) can be viewed from My Account –> My Product Reviews. In this page, you will see list of reviews done by the customer. The review detail is truncated to 50 characters. I want to display more. I want to truncate to 100 characters and display it.
For this you need to override Mage_Review_Helper_Data class.
config.xml
<global>
    <helpers>
        <review>
            <rewrite>
                <data>MyNamespace_MyModule_Helper_Review_Data</data>
            </rewrite>
        </review>
    </helpers>
<global>

Now, you need to create a helper class MyNamespace_MyModule_Helper_Review_Data
The path for the helper file will be MyNamespace/MyModule/Helper/Review/Data.php
<?php
class MyNamespace_MyModule_Helper_Review_Data extends Mage_Review_Helper_Data
{
    /**
     * Truncating to 100 characters
     * In core file, there is truncation to 50 characters
     *
     * @param string $origDetail
     * @return string
     */
    public function getDetail($origDetail){
        return nl2br(Mage::helper('core/string')->truncate($origDetail, 100));
    }
}

Magento: Block Controller Model Helper Override





Saturday, December 3, 2011

Magento: Multi-Site, Multi-Domain Setup


One of Magento’s greatest strengths is its capabilities for scaling to support multi-store and multi-language retailing all from the same backend. In this tutorial, we will be showing you how to take advantage of Magento’s scalability by creating multiple websites with unique domain names sharing the same product catalog. (***NOTE: Each store can also be configured to offer a unique product catalog as well.)

For this example, we’ll be attempting to set up domain1.com, domain2.com and domain3.com.

Generally, Magento is installed into the folder /var/www/http, as per the Magento Installation Guide, and you can find more information related to the initial setup and configuration of any Magento installation there.  We aren’t going to through an full blown installation right now though, and for our purposes, we are going to presume that the Magento instance has already been installed in the server.

We’ll be dividing the process into steps based on the areas of configuration we will need to deal with–namely, Categories, Store Configuration in Magento Admin, Store Configuration in the Server.

1: Categories

First, will need to create our Categories.  Since all three websites will be sharing the same catalog, we will be using the default root Category in Catalog -> Categories -> Manage Categories and will be creating our categories under that root category (i.e. Clothing, Electronics, etc.).


These categories (Clothing, Electronics) should be set as both “Is Active” from the General Information tab and “Is Anchor” from the Display Settings tab for them to appear on the frontend of your Magento shop.  (***NOTE: If the websites will not be sharing the same catalog, a Root Category must be created for each website.  Thus, if there are 3 websites, there will be 3 Root Categories with subcategories under them.)

2: Store Configuration in the Magento Admin

1. Now that we have created our Categories, it’s time to create our websites by going to System -> Manage Stores and clicking the “Create Website” button.

    * Name – domain name of our new website
    * Code – a parameter that will be used in configuring the Apache web server to point to that particular domain name


2. Once the website has been created, we’ll create the store corresponding to this website by clicking on the “Create Store” button in System -> Manage Stores.

    * Website – website to which this store will be associated
    * Name – the same as the website name
    * Root Category – the root category that will be used for this store. (Refer to Step 1 for Details)


3. Then, we create the store view which is the interface that the customer will be able to access on the frontend.  Click the “Create Store View” button in System -> Manage Stores.

    * Store – store to which this view will be associated
    * Name – name of this store view (i.e. English Version, German Version, etc.)
    * Code – code for this store view
    * Status – if enabled, this store view will be accessible from our frontend, otherwise, it will not be accessible

      4. After the Store has been created, we need to configure the Unsecure Base URL and Secure Base URL under System -> Configuration -> General -> Web.  Before we set their respective base URLs, we first need to ensure that the configuration scope is set to the domain1.com website to define which site we are working on.

      Then, we modify the base URLs for both Unsecure:

      and Secure:

      with the corresponding domain name by unchecking the ”Use default [STORE VIEW]” checkbox and then save the configuration.

      5. Now we just repeat Steps 2-4 for the other two websites, domain2.com and domain3.com by replacing the fields with their respective information.

      3: Store Configuration in the Server

      1. Now we re-configure the Apache configuration file, httpd.conf, for all domains to set the DocumentRoot to our Magento directory.  In this case, the directory is /var/www/http

      <VirtualHost *:80>
          ServerAdmin webmaster@domain1.com
          DocumentRoot /var/www/http
          ServerName domain0.com
      </VirtualHost>

      <VirtualHost *:80>
          ServerAdmin webmaster@domain2.com
          DocumentRoot /var/www/http
          ServerName domain1.com
      </VirtualHost>

      <VirtualHost *:80>
          ServerAdmin webmaster@domain3.com
          DocumentRoot /var/www/http
          ServerName domai2.com
      </VirtualHost>


      2. Edit the .htaccess file at /var/www/http/.htaccess and add the following lines below:


      SetEnvIf Host www\.domain1\.com MAGE_RUN_CODE=domain1_com
      SetEnvIf Host www\.domain1\.com MAGE_RUN_TYPE=website
      SetEnvIf Host ^domain1\.com MAGE_RUN_CODE=domain1_com
      SetEnvIf Host ^domain1\.com MAGE_RUN_TYPE=website

      SetEnvIf Host www\.domain2\.com MAGE_RUN_CODE=domain2_com
      SetEnvIf Host www\.domain2\.com MAGE_RUN_TYPE=website
      SetEnvIf Host ^domain2\.com MAGE_RUN_CODE=domain2_com
      SetEnvIf Host ^domain2\.com MAGE_RUN_TYPE=website

      SetEnvIf Host www\.domain3\.com MAGE_RUN_CODE=domain3_com
      SetEnvIf Host www\.domain3\.com MAGE_RUN_TYPE=website
      SetEnvIf Host ^domain3\.com MAGE_RUN_CODE=domain3_com
      SetEnvIf Host ^domain3\.com MAGE_RUN_TYPE=website


      3. Restart Apache Server

      If you are on a Red Hat based distribution, you’ll be able to type service apache restart.  For other distributions, you’ll want to type apachectl restart.  (***NOTE: The second option here is different than “apachectl graceful” which will run a graceful restart and reload configuration files, without terminating current connections.  We don’t have any visitors to our site yet, so it’s okay to do a “apachectl restart”.)

Thursday, December 1, 2011

Create a simple custom module

 Part of customizing Magento is, of course, creating custom Modules. These allow you to inject functionality anywhere, whether in a “static” block fashion that’s more than static, or a shipping/payment module, or large module to do something as large as integrating a 3rd party system (or multiple systems).

There are many things custom Modules can do, from editing your Database, to handling module upgrades to overriding classes (Blocks, Controllers, Models) … and more!

This blog post is a very basic start on creating your own custom module and hooking it up to a phtml file in your own theme.

I will be creating a Flexsin Example module. ‘Flexsin’ is the namespace (vs Mage), ‘Example’ is the module (vs Catalog, Page, Core, Shipping etc).

Step One

Inform Magento that you have a custom module.
app/etc/modules/Flexsin_All.xml Notice the _All in the xml file name. I can declare all of my modules here. (Say I have more than Example, I can also declare my Example2 module in this file).

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

I have informed Magento that I have an active module (you can turn it off from here by setting ‘active’ to false. I have also informed Magento that it is located in the ‘local’ code pool.

Step Two

Configure your new module. Note the file locations (need to create directories as necessary).
app/code/local/Flexsin/Example/etc/config.xml

<?xml version="1.0"?>
<config>
<modules>
<Flexsin_Example>
<version>0.1.0</version>
</flexsin_Example>
</modules>
<global>
<blocks>
<flexsin_example>
<class>Flexsin_Example_Block</class>
</Flexsin_example>
</blocks>
</global>
</config>

I have informed Magento of my module version (it’s an arbitrary version). Version matters when you set up your module to be update-able. (A newer version will inform Magento to run the update files if you have them).

I have also informed Magento that my module contains  block files which are found in flexsin/example/block. My class name will have “Flexsin_Example_Block”. If you want to see the many possibilities of stuff that goes in here, check out Mage config files (such as Catalog/etc/config.xml). You’ll also see other xml files in there. Those explanations are for another post.
Step Three

Here is my block code. It doesn’t really do anything, but shows some functionality.
app\code\local\Flexsin\Example\Block\View.php

<?php
/**
* Example View block
*
* @codepool   Local
* @category   Flexsin
* @package    Flexsin_Example
* @module     Example
*/
class Flexsin_Example_Block_View extends Mage_Core_Block_Template
{
private $message;
private $att;

protected function createMessage($msg) {
$this->message = $msg;
}

public function receiveMessage() {
if($this->message != '') {
return $this->message;
} else {
$this->createMessage('Hello World');
return $this->message;
}
}

protected function _toHtml() {
$html = parent::_toHtml();

if($this->att = $this->getMyCustom() && $this->getMyCustom() != '') {
$html .= '<br />'.$this->att;
} else {
$html .= '<br />No Custom Attribute Found';
}

return $html;
}
}

The function receiveMessage() just returns “Hello World”
The function _toHtml() is responsible for outputting the template associated with the block. Make sure you run paret::_toHtml and return it as part of any other items returned in that function!
Step Four

Here we create our template (phtml) file.
app\design\frontend\default\flexsin\template\example\view.phtml

<?php

/**
* Flexsin view template
*
* @see Flexsin_Example_Block_View
*
*/
?>
<div>
<span><strong>This is the output of the Flexsin example:</strong></span><br />
<span style="color:#FF9933;">
<?php
echo $this->receiveMessage();
?>
</span>
</div>
This just outputs some HTML and also runs the receiveMessage() function from our block (view.php).

Two caveats here. By placing our view.phtml file in it’s location, we have created our own theme. You must make sure that
a) Magento knows about your theme (Admin->System->Design)
and
b) If you use the this block in a CMS page, you set the CMS page to use your theme (Admin->CMS->Manage Pages->’Your Page’->Custom Design->Custom Theme drop down)

You’re custom module is now ready for use.

In a cms page, add this to your content:
{{block type="flexsin_example/view" my_custom="Test" template="example/view.phtml" }}

Or something like this in the Layout Update XML area (Custom Design area in a CMS page)
<reference name="right">
<block type="flexsin_example/view" my_custom="Test" template="example/view.phtml" />
</reference>
//this will add your block in the right column

Now you should successfully have your block and the Hello World message being displayed (on your CMS page).

Wednesday, November 30, 2011

Magento: Exception printing is disabled by default for security reasons

When I go to any product detail page, I get the following error:-
    There has been an error processing your request
    Exception printing is disabled by default for security reasons.

I don’t get the detailed information about the error as I used to get in previous versions of Magento.
Solution:
In your magento root, there is a folder called errors.
Go inside the errors folder.
There is a file named local.xml.sample.
Rename it to local.xml
Hence, the problem is solved. Now, I am able to see detailed error information.

Thursday, November 24, 2011

Custom Module


List of created files:
app/etc/modules/Flexsin_Helloworld.xml
app/code/local/Flexsin/Helloworld/Block/Helloworld.php
app/code/local/Flexsin/Helloworld/controllers/IndexController.php
app/code/local/Flexsin/Helloworld/etc/config.xml
app/code/local/Flexsin/Helloworld/Model/Helloworld.php
app/code/local/Flexsin/Helloworld/Model/Mysql4/Helloworld.php
app/code/local/Flexsin/Helloworld/Model/Mysql4/Helloworld/Collection.php
app/code/local/Flexsin/Helloworld/Model/Status.php
app/code/local/Flexsin/Helloworld/sql/helloworld_setup/mysql4-install-0.1.0.php
app/design/frontend/flexsin/default/layout/helloworld.xml
app/design/frontend/flexsin/default/template/helloworld/helloworld.phtml
app/code/local/Flexsin/Helloworld/Block/Adminhtml/Helloworld.php
app/code/local/Flexsin/Helloworld/Block/Adminhtml/Helloworld/Edit.php
app/code/local/Flexsin/Helloworld/Block/Adminhtml/Helloworld/Grid.php
app/code/local/Flexsin/Helloworld/Block/Adminhtml/Helloworld/Edit/Form.php
app/code/local/Flexsin/Helloworld/Block/Adminhtml/Helloworld/Edit/Tabs.php
app/code/local/Flexsin/Helloworld/Block/Adminhtml/Helloworld/Edit/Tab/Form.php
app/code/local/Flexsin/Helloworld/controllers/Adminhtml/HelloworldController.php
app/code/local/Flexsin/Helloworld/Helper/Data.php
app/design/adminhtml/flexsin/default/layout/helloworld.xml

Wednesday, November 23, 2011

Magento Files and Folders Structure


The files and folders included in the main directory are as follows:
.htaccess - contains mod_rewrite rules, which are essential for the Search Engine Friendly URLs. There you can also find standard web server and php directives that can improve your web site performance.

.htaccess.sample - this is a backup of the .htaccess file. If you modify .htaccess it can be used in order to get the default settings.

404 (directory) - The folder stores the default 404 template and skin for Magento.

app (directory) - This folder contains the modules, themes, configuration and translation files. Also there are the template files for the default administration
theme and the installation.

cron.php - a Cron Job should be set for this file. Executing of the file on a defined time period will ensure that the complicated Magento caching system will not affect the web site performance.

downloader (directory) - This is the storage of the web downloader files. They are used for the installation and upgrade of Magento through your browser.

favicon.ico - the default favicon for Magento. A small icon that is shown in the browser's tool bar once your web site is loaded.

index.php - the main index file for Magento.

index.php.sample - A backup of the default index file. It can be used to revert the changes in a case of a index.php modification.

js (directory) - Contains the pre-compiled libraries of the JavaScript code included in Magento.

lib (directory) - The Magento core code is located in this folder. It contains the software's PHP libraries.

LICENSE_AFL.txt - The Academic Free License under which the Magento software is distributed.

LICENSE.txt - The Open Software License under which the Magento software is distributed.

media (directory) - This is the storage of the Magento media files - images out of the box, generated thumbnails, uploaded products images. It is also used as a container for importing images through the mass import/export tools.

pear - The file controls the automatic update through the downloader script and SSH. It handles the update of each individual Magento module.

php.ini.sample - This file contains sample php directives that can be used in order to modify your PHP setup. If you want to alter the default setup edit the file and then rename it to php.ini.

pkginfo (directory) - Contains files with information regarding the modules upgrades' changes.

report (directory) - This folder contains the skin of the Magento errors reports.

skin (directory) - There are located the themes files - images, JavaScript files, CSS files, Flash files. Also there can be found the skin files for the installation of skins and administration templates.

var (directory) - Cache, sessions, database backups, data exports and cached error reports can be found in this directory.

If you want to modify an existing template or set a new one you should know that the template files are separated in 3 folders:
/app/design/frontend/default/YOUR_TEMPLATE_NAME/layout/ - Contains the .xml files that define which modules should be called by the template files and loaded in defined areas on the site.
/app/design/frontend/default/YOUR_TEMPLATE_NAME/template/ - Contains files and subfolders that structure the final output for the users using the functions located in the layout/ folder.
/skin/frontend/default/YOUR_TEMPLATE_NAME/ - Contains the CSS, images, JavaScript and Flash files related to the template.

Adding and removing javascript / css when and where you need it


Adding and removing javascript and css is handled separately within Magento. CSS is added in the usual fashion, where you have a <link rel=”stylesheet”… />. However, any included javascript (unless linked to “by hand” from a theme’s skin) is pulled via a php files which reads through the “js” folder in the root directory (root/js/index.php is responsible for this).
That is all well and good for Magento. The real question is how we, as developers, add these items when we need them. How you as a developer add css or javascript is, luckily, handled the same.
In this post, we will show how to add and remove javascript and css to a CMS page (and anywhere else) that you may need.
Method 1: Layout xml.
a) For files you want to include on every page
For css or js files you want to add to every page, you edit the page. xml files located in your layout folder (app/design/frontend/default/your_theme/layout/page.xml). Within this file, at the top you will find the <default> area with the <block name=”root” … >. This block has a child named “head” which contains the included css and js elements.


<block type="page/html_head" name="head" as="head">
<action method="addJs"><script>prototype/prototype.js</script></action>
<action method="addJs" ifconfig="dev/js/deprecation"><script>prototype/deprecation.js</script></action>
<action method="addJs"><script>prototype/validation.js</script></action>
<action method="addJs"><script>scriptaculous/builder.js</script></action>

...

</block>
Here you can add your javascript and css. Note that any Js files you add are relative to the “js” folder in your root directory. The css files are included from the skin files of the current and default templates (skin/frontend/default/your_template(& default)/css).
b) Specific areas
If you want to include css or js on only certain areas (such as the checkout process or catalog pages), you can do that also. For instance, if you want it in a single product view (product view vs product list), you can open up catalog.xml, find <catalog_product_view> area (near line 168 in vs 1.2.1).  Add your code in there – notice that we are using the <reference> tag rather than <block> tags. We use the “reference” tag to reference other blocks that are in other areas of the template.


<reference name="head">
<action method="addJs"><script>varien/product.js</script></action>

<action method="addItem"><type>js_css</type><name>calendar/calendar-win2k-1.css</name><params/><!--<if/><condition>can_load_calendar_js</condition>--></action>
<action method="addItem"><type>js</type><name>calendar/calendar.js</name><!--<params/><if/><condition>can_load_calendar_js</condition>--></action>
<action method="addItem"><type>js</type><name>calendar/lang/calendar-en.js</name><!--<params/><if/><condition>can_load_calendar_js</condition>--></action>
<action method="addItem"><type>js</type><name>calendar/calendar-setup.js</name><!--<params/><if/><condition>can_load_calendar_js</condition>--></action>
</reference>

The use of can also be used in your layout XML areas in the admin backend (CMS pages, category and product designs). This can accomplish the same thing, as well as adding or removing other blocks.
Method 2: Block Code
We can accomplish all of this in code as well. These functions are defined within Mage_Page_Block_Html_Head. So, we can use this code with in a block class (not a .phtml file!):

$headBlock = $this->getLayout()->getBlock('head');
$headBlock->addJs('somefolder/yay.js');

I suggest looking over the page. xml file as long as finding the removeItem syntax ($type, $name for the method, for the xml), which will be very handy for you for adding or removing assets as and when you need them!
<action method="removeItem"><type>js</type><name>calendar/calendar.js</name</action>

$this->getLayout->getBlock('head')->removeItem('js', 'calendar/calendar.js');


Adding and removing javascript / css when and where you need it


Adding and removing javascript and css is handled separately within Magento. CSS is added in the usual fashion, where you have a <link rel=”stylesheet”… />. However, any included javascript (unless linked to “by hand” from a theme’s skin) is pulled via a php files which reads through the “js” folder in the root directory (root/js/index.php is responsible for this).
That is all well and good for Magento. The real question is how we, as developers, add these items when we need them. How you as a developer add css or javascript is, luckily, handled the same.
In this post, we will show how to add and remove javascript and css to a CMS page (and anywhere else) that you may need.
Method 1: Layout xml.
a) For files you want to include on every page
For css or js files you want to add to every page, you edit the page.xml files located in your layout folder (app/design/frontend/default/your_theme/layout/page.xml). Within this file, at the top you will find the <default> area with the <block name=”root” … >. This block has a child named “head” which contains the included css and js elements.

Saturday, November 19, 2011

web services using php as JSON format


Create a php file with following code:

$hostname="localhost";
$username="bhoopendra";
$password="";
$database="my_db";
$table='comment';
$con=mysql_connect($hostname, $username, $password) or die(mysql_error());
mysql_select_db($database, $con) or die(mysql_error());
$result=mysql_query("SELECT * FROM ".$table) or die(mysql_error());

while($row = mysql_fetch_assoc($result)) {
$data[]=$row;
 
}

$file=fopen("web.xml", "w");
if(fwrite($file,json_encode($data))){
//header('location: web.xml');
}

web services using php as xml format


Create a php file with following code:
$hostname="localhost";
$username="bhoopendra";
$password="";
$database="my_db";
$table='comment';
$con=mysql_connect($hostname, $username, $password) or die(mysql_error());
mysql_select_db($database, $con) or die(mysql_error());
$result=mysql_query("SELECT * FROM ".$table) or die(mysql_error());
$doc = new DomDocument('1.0');
$root = $doc->createElement('root');
$root = $doc->appendChild($root);

while($row = mysql_fetch_assoc($result)) {
$occ = $doc->createElement($table);
  $occ = $root->appendChild($occ);
  foreach ($row as $fieldname => $fieldvalue) {
$child = $doc->createElement($fieldname);
$child = $occ->appendChild($child);
$value = $doc->createTextNode($fieldvalue);
$value = $child->appendChild($value);
 }
}
$xml_string = $doc->saveXML();
//echo $xml_string;
$file=fopen("web.xml", "w");
if(fwrite($file,$xml_string)){
header('location: web.xml');
}

Friday, November 18, 2011

Magento: Get parent id of simple product associated to configurable product


A simple product is associated with a configurable product. You have the id of the simple product. Now, you need the id of the configurable product with which the simple product is associated.
Get parent product id, i.e. get id of configurable product from a simple product.

$_product = Mage::getModel('catalog/product')->load(YOUR_SIMPLE_PRODUCT_ID);
$parentIdArray = $_product->loadParentProductIds()->getData('parent_product_ids');
print_r($parentIdArray);

Magento: Get order option of configurable and bundle product in cart


We are not allowed to order configurable and bundle products directly. We have to select product options from product detail page of configurable or bundle product. Only then we can add the product to cart.
The following code fetches the order option selected for configurable and bundle products:

// For configurable product
Mage::getModel('catalog/product_type_configurable')->getOrderOptions($this->getProduct());
 
// For bundle product
Mage::getModel('bundle/product_type')->getOrderOptions($this->getProduct());

Magento: Displaying / Adding Gift Message in Order


Gift Message facility is present in Magento by default. You can add gift message in order as a whole or in individule order items.
By default, the gift message is not enabled in Magento.

Here is how you display gift message adding form in order/checkout:-
1) First of all, go to System -> Configuration -> Advanced -> Disable modules output and check if Mage_GiftMessage is Enabled. This should be Enabled.
2) Now, go to System -> Configuration -> SALES -> Sales -> Gift Messages.
3) Here, you will find two selection lists:-
Allow Gift Messages on Order Level: By default it is ‘No’. When you change it to ‘Yes’ then you will be able to add a single gift message to the whole order. The gift message form is displayed in ‘Shipping Method’ section of Checkout page.
Allow Gift Messages for Order Items: By default it is ‘No’. When you change it to ‘Yes’ then you will be able to add gift message separately to individual item of your shopping cart. The gift message form is displayed in ‘Shipping Method’ section of Checkout page.
4) You can also enable or disable gift messages in individual product from ‘Manage Products’. When you edit any product, you will see a selection list of Allow Gift Message. By default, it is set to Use config, i.e. it will use the value set in configuration (see #3 ‘Allow Gift Messages for Order Items’). Here, you can set ‘Yes’ or ‘No’ to display gift message adding facilty to the particular product or not.

Magento: How to enable backorders?


Difference between backorder and pre-order
A backorder is for an item that was in stock previously but is temporarily out of stock.
A pre-order is for an item that has not been released yet.
Scenario for backorder:
For example, a customer orders 3 items. One item is not in stock. Shouldn’t I be able to Invoice only the 2 items I am shipping now, and then go back in next week and Invoice for the third item when it is back in stock? How do I set this up? – Source: magentocommerce forum
Backorders simply means that the item you are going to order is out of stock and you will receive the item OR the item will be delivered to you when the item will be in stock.
By default, backorder is not enabled in magento. Hence, you cannot add items to cart when the item is out of stock. But, if you enable backorders then you can add item to cart even if it is out of stock.
To enable backorders, go to:
Admin Panel -> System -> Configuration -> Catalog Tab -> Inventory -> Product Stock Options -> Backorders = Allow Qty Below 0 and Notify Customer
Edit Product to Qty = 0 and Stock Availability = In Stock
And backorders are enabled!
When you add the particular product to cart, the product is added to cart and you will see the following message:
* This product is not available in the requested quantity. 1 of the items will be backordered.
You can order the product even if it is out of stock. The product will be delivered to you when it is in stock.

Tuesday, November 15, 2011

Magento : Adding a home link to the menu bar


There are following step:
1. Now look for the top.phtml file in app/design/frontend/YOUR_PACKAGE/
YOUR_THEME/template/catalog/navigation/ directory. In my case, the
absolute path of top.phtml file for active default theme is: /var/www/magento.
local.com/public/app/design/frontend/base/default/template/
catalog/navigation/.
2. The code should look like this:
<?php $_menu = $this->renderCategoriesMenuHtml(0,'level-top') ?>
<?php if($_menu): ?>
<div class="nav-container">
<ul id="nav">
<?php echo $_menu ?>
</ul>
</div>
<?php endif ?>
3. Next, let's add the new alternative home link now. Add the following code snippet
before the foreach loop:
<!-- NEW HOME LINK -->
<li class="home"><a href="<?php echo $this->getUrl('')?>"><?php
echo $this->__('Home') ?></a></li>
<!-- NEW HOME LINK -->
4. After the changes, now the top.phtml file should look like this:
<?php $_menu = $this->renderCategoriesMenuHtml(0,'level-top') ?>
<?php if($_menu): ?>
Chapter 2
25
<div class="nav-container">
<ul id="nav">
<!-- NEW HOME LINK -->
<li class="home"><a href="<?php echo $this-
>getUrl('')?>"><?php echo $this->__('Home') ?></a></li>
<!-- NEW HOME LINK -->
<?php echo $_menu ?>
</ul>
</div>
<?php endif ?>
5. Next, we will add some CSS style for the active state of our home link like other
menus in the top navigation bar. Find the styles.css file from the skin/
frontend/YOUR_PACKAGE/YOUR_THEME/css/ directory and open it. In my case,
the location of styles.css file is: /var/www/magento.local.com/public/
skin/frontend/default/default/css.
6. Now append the following line at the end of styles.css file:
body.cms-home #nav li.home a { color:#d96708; }
7. Reload the home page and see the changes. A new home menu will appear:

Sunday, November 13, 2011

Adding a step to the Onepage Checkout

The default Magento onepage checkout includes six steps for the customer to complete. However, sometimes you may have a requirement to create an extra checkout step. An example of this might be an option for your customer to choose a free gift as part of their order, or an extra step to collect special delivery instructions. Using delivery instructions as an example, we'll demonstrate how this can be achieved.

The first file we need to modify is app/code/core/Mage/Checkout/Block/Onepage.php. Obviously we don't want to modify the code in the core context, so copy the file to app/code/local/Mage/Checkout/Block/Onepage.php. Magento will use this file automatically.

In the getSteps() method of this class there is an array of the step codes, in order of viewing. We need to add our own step code in this array, in the relevant place. For this example, the code will be deliveryinstructions so we will change the line to be this:

$stepCodes = array('billing', 'shipping', 'shipping_method', 'deliveryinstructions', 'payment', 'review');

Next, we need to create a new file - app/code/local/Mage/Checkout/Block/Onepage/Deliveryinstructions.php. As you can see from the name, this is the block file that runs our new step. You can use this class to do any special setup work for your block, but more than likely all you'll need is this:

<?php
class Mage_Checkout_Block_Onepage_Deliveryinstructions extends Mage_Checkout_Block_Onepage_Abstract
{
    protected function _construct()
    {
        $this->getCheckout()->setStepData('deliveryinstructions', array(
            'label'     => Mage::helper('checkout')->__('Delivery Instructions'),
            'is_show'   => $this->isShow()
        ));
        parent::_construct();
    }
}

Now we need to make the actual template. The file we need is: <THEME DIRECTORY>/template/checkout/onepage/deliveryinstructions.phtml. Often the best way to create this file is to copy one of the other files, perhaps billing.phtml or shipping.phtml. Then, just modify the file to suit your needs.

With the template created, we need to tell Magento about it by editing the <THEME DIRECTORY>/layout/checkout.xml file. This will tell Magento when to load our new template file. Below the multishipping sections in this file the <checkout_onepage_index> context begins. Look through it until you find the references to the login, billing, shipping, shipping method, payment and review templates. These are all inside the content reference area. At the position between all these files that you want your step to show, you need to add a reference to your new template. It should look something like this:

<block type="checkout/onepage_deliveryinstructions" name="checkout.onepage.deliveryinstructions" as="deliveryinstructions" template="checkout/onepage/deliveryinstructions.phtml"/>

Following on from that, we need to override the onepage controller to put in our extra step. How to actually override a controller is beyond the scope of this post, however the Magento wiki article on overriding controllers should tell you everything you need to know.

There are two parts we need to work with in our overridden controller, and the first one is the save<STEP>Action method for the step before ours. In this example, I'm putting my new step between the Shipping Method step and the Payment Method step, so I'm going to override the saveShippingMethodAction method. We need to change the goto_section in the method to be our new step, so it should look like this:

$result['goto_section'] = 'deliveryinstructions';

We also need to remove the following code, as we don't need to update our delivery instructions section. We will need the code again for the next part, so keep it handy:

$result['update_section'] = array(
        'name' => 'payment-method',
        'html' => $this->_getPaymentMethodsHtml()
);

The next change to this controller should be to add a new method, called saveDeliveryinstructionsAction. This method must perform two functions; it should call the method on the Onepage Model, and also pass any data back to the browser. The following code is an example of what we need, copied and modified from the saveShippingMethodAction method:

public function saveDeliveryinstructionsAction()
{
 $this->_expireAjax();
 if ($this->getRequest()->isPost()) {
  $data = $this->getRequest()->getPost('deliveryinstructions', '');
  $result = $this->getOnepage()->saveDeliveryinstructions($data);
  /*
  $result will have error data if shipping method is empty
  */
  if(!$result) {
   Mage::dispatchEvent('checkout_controller_onepage_save_deliveryinstructions', array('request'=>$this->getRequest(), 'quote'=>$this->getOnepage()->getQuote()));
   $this->getResponse()->setBody(Zend_Json::encode($result));

   $result['goto_section'] = 'payment';
   $result['update_section'] = array(
       'name' => 'payment-method',
       'html' => $this->_getPaymentMethodsHtml()
   );

  }
  $this->getResponse()->setBody(Zend_Json::encode($result));
 }
}

In the last step we called a method that we haven't defined yet, so we'll do that now. This method is in the app/code/core/Mage/Checkout/Model/Type/Onepage.php file. Like the past few files, we are going to modify the saveShippingMethod method and also copy it to a new method. The saveShippingMethod code should be modified to look like this:

public function saveShippingMethod($shippingMethod)
{
    if (empty($shippingMethod)) {
        $res = array(
            'error' => -1,
            'message' => Mage::helper('checkout')->__('Invalid shipping method.')
        );
        return $res;
    }
    $rate = $this->getQuote()->getShippingAddress()->getShippingRateByCode($shippingMethod);
    if (!$rate) {
        $res = array(
            'error' => -1,
            'message' => Mage::helper('checkout')->__('Invalid shipping method.')
        );
        return $res;
    }
    $this->getQuote()->getShippingAddress()->setShippingMethod($shippingMethod);
    $this->getQuote()->collectTotals()->save();

    $this->getCheckout()
        ->setStepData('shipping_method', 'complete', true)
        ->setStepData('deliveryinstructions', 'allow', true);

    return array();
}

Unfortunately, there is no simple way to save the data that we collect. For example, information about a customer will be saved completely differently to shipping information like our delivery instructions; the delivery instructions will be saved differently again to how we would add a free gift to the order.

Because of this I won't show you any code for actually saving the data you've captured, though we may address this in a follow up post at a later date. The following code is the new method that does not save anything:

public function saveDeliveryinstructions($deliveryinstructions)
{
    // Save the data here

    $this->getCheckout()
        ->setStepData('deliveryinstructions', 'complete', true)
        ->setStepData('payment', 'allow', true);

    return array();
}

Next, we need to make a couple of JavaScript changes. These changes will be made in the <SKIN DIRECTORY>/js/opcheckout.js> file. In the Checkout class, we need to change the setShippingMethod method to go to the delivery information block, similar to the way we have in the files above. Then we need to make a setDeliveryinstructions method which will be exactly the same as the setShippingMethod method before we modified it.

There is a class further down in the file called ShippingMethod, inside of which is a method called nextStep. We need to change it as per the above method so that the step goes to the delivery instructions step rather than the payment step. Then, again like before, we need to copy the whole class and modify it so that it's now a DeliveryInstructions class, making sure to set the next step to be the payment step.

There is now one final requirement, which is to add in our step in the progress meter on the right side of the checkout. To do this we need to edit <THEME DIRECTORY>/template/checkout/onepage/progress.phtml. If you look at the file, you'll have a pretty good idea of how the template should be laid out and below is an example of what to add in for our example delivery instructions:

<?php if ($this->getCheckout()->getStepData('deliveryinstructions', 'is_show')): ?>
 <?php if ($this->getCheckout()->getStepData('deliveryinstructions', 'complete')): ?>
  <li>
   <h4 class="complete"><?php echo $this->__('Delivery Instructions') ?> <span class="separator">|</span> <a href="#deliveryinstructions" onclick="checkout.accordion.openSection('opc-deliveryinstructions');return false;"><?php echo $this->__('Change') ?></a></h4>
   <div class="content">
    <!-- Here write code to display the data the customer enters -->
   </div>
  </li>
 <?php else: ?>
  <li>
   <h4><?php echo $this->__('Delivery Instructions') ?></h4>
  </li>
 <?php endif; ?>
<?php endif; ?>

We have now added a new step to our checkout and made it accessible in the same way as the rest of the checkout steps. Using this as a base, you can develop the concept further to provide additional information or options to the customer during checkout. Of course, too many steps will likely turn people away, so it's a matter of balancing the need to collect extra information with the need to make the checkout as quick and easy to complete as possible.

Creating a Custom Magento Shipping Method


Explaining The Shipping Architecture

Before making our own module, we’ll look at how Magento’s existing shipping rate functionality operates. If you are already familiar with this, then you should skip to the next section.
For this walkthrough we’ll use the “Flatrate” shipping method which is available by default with Magento. This method requires two files (excluding inherited classes and so on), these are:
  • app/code/core/Mage/Shipping/Model/Carrier/Flatrate.php
  • app/code/core/Mage/Shipping/etc/config.xml

Open Flatrate.php and take a look - there are four elements of the class which are essential to the operation of this rate.
app/code/core/Mage/Shipping/Model/Carrier/Flatrate.php
protected $_code = 'flatrate';
protected $_isFixed = true;
 
public function collectRates() {}
public function getAllowedMethods() {}

The first important element is the $_code property. This is a code which must be unique to your shipping method. It’s important to note this code is specified in other places, so you need to be consistent with its naming (more on this later). The next property, $_isFixed, is telling Magento that this shipping method is a fixed, one time fee - rather than a recurring payment, which is the alternative option here.
The second file is config.xml; this file is for all Magento shipping methods and as such, it is quite large. However, we are only interested in one part of it:
app/code/core/Mage/Shipping/etc/config.xml
<carriers>
    <flatrate>
        <active>1</active>
        <sallowspecific>0</sallowspecific>
        <model>shipping/carrier_flatrate</model>
        <name>Fixed</name>
        <price>5.00</price>
        <title>Flat Rate</title>
        <type>I</type>
        <specificerrmsg>This shipping method is currently unavailable...(etc)</specificerrmsg>
        <handling_type>F</handling_type>
    </flatrate>
</carriers>

Notice how the node is called <flatrate> to match the $_code property in the Flatrate.php class we saw earlier. Most of the nodes above are easy to understand, but some will benefit from a little more explanation:
sallowspecific set to 1 to limit the countries the rate is applicable to
title the courier name
name the rate name
type an option specific to flatrate, whether the charge is per item or order
specifierrmsg a message to show if the method does not apply to this country
handling_type whether the handling charge is fixed, per item or a percentage

The <model> node in config.xml, as shown above, tells Magento which shipping class to use; in our example, that is shipping/carrier_flatrate. Magento converts shipping/carrier_flatrate to Mage_Shipping_Model_Carrier_Flatrate (found in app/code/core/Mage/Shipping/Model/Carrier/Flatrate.php). The class within Magento responsible for loading the correct rate is Mage_Shipping_Model_Shipping. It is a good idea to take a look at this class and familiarise yourself with how Magento handles this.
We can also take a deeper look at the flatrate classfile. This class extends Mage_Shipping_Model_Carrier_Abstract and implements Mage_Shipping_Model_Carrier_Interface. In fact since all shipping methods must do the same, we can work out which methods require implementation, and which are already there. In general we will be interested in implementing two methods:
  • collectRates()
  • getAllowedMethods()

All other implementation is provided in Mage_Shipping_Model_Carrier_Abstract, so these two methods are all we need to create our own shipping model.

Creating Your Own Rate

This example shows how to create a simple shipping rate, which can provide the basis of a more complicated rate should you need to adapt this for your own purposes. The first step is to make our module skeleton by creating a directory structure along these lines:
app/code/local/Foobar/
app/code/local/Foobar/Shipping/
app/code/local/Foobar/Shipping/etc/
app/code/local/Foobar/Shipping/Model/

Then we need to add a module activation file to app/etc/modules/Foobar_Shipping.xml with the following contents:
app/etc/modules/Foobar_Shipping.xml
<?xml version="1.0"?>
<config>
    <modules>
        <Foobar_Shipping>
            <active>true</active>
            <codePool>local</codePool>
            <depends>
                <Mage_Shipping/>
            </depends>
        </Foobar_Shipping>
    </modules>
</config>

Next we make the config file; here’s the one I used when creating this example:
app/code/local/Foobar/Shipping/etc/config.xml
<?xml version="1.0" ?>
<config>
    <modules>
        <Foobar_Shipping>
            <version>0.1.0</version>
        </Foobar_Shipping>
    </modules>
    <global>
        <models>
            <foobar_shipping>
                <class>Foobar_Shipping_Model</class>
            </foobar_shipping>
        </models>
    </global>
    <default>
        <carriers>
            <foobar_customrate>
                <active>1</active>
                <model>foobar_shipping/carrier_customrate</model>
                <title>Foobar Shipping</title>
                <name>Default Rate</name>
            </foobar_customrate>
        </carriers>
    </default>
</config>

Finally we add our custom shipping class.
app/code/local/Foobar/Shipping/Model/Carrier/Customrate.php
<?php
 
class Foobar_Shipping_Model_Carrier_Customrate
    extends Mage_Shipping_Model_Carrier_Abstract
    implements Mage_Shipping_Model_Carrier_Interface
{
    protected $_code = 'foobar_customrate';
    protected $_isFixed = true;
 
    public function collectRates(Mage_Shipping_Model_Rate_Request $request)
    {
 
        if (!$this->getConfigFlag('active')) {
            return false;
        }
 
        $result = Mage::getModel('shipping/rate_result');
 
        $method = Mage::getModel('shipping/rate_result_method');
        $method->setCarrier('foobar_customrate');
        $method->setCarrierTitle($this->getConfigData('title'));
        $method->setMethod('foobar_customrate');
        $method->setMethodTitle($this->getConfigData('name'));
        $method->setPrice(5);
        $method->setCost(2);
 
        $result->append($method);
 
        return $result;
    }
 
    public function getAllowedMethods()
    {
        return array('foobar_customrate' => $this->getConfigData('name'));
    }
}

After clearing your cache, go and ahead and add a product to your cart and go to checkout. You should see our shipping method sitting there with a charge (of 5 units of whatever currency your Magento is set up to use). Congratulations - you have a basic shipping module available for use!

Behind the Scenes

When we hit the checkout, Magento uses the collectRates() method in our class; via this method you can offer shipping rates (or not) by storing an object in $result, which is Mage_Shipping_Model_Rate_Result. Basically, you add instances of Mage_Shipping_Model_Rate_Result_Method ($method in our example) to this object via the append() method. The rate result object holds all the values such as carrier and method name, as well as the all-important price and cost. In this way it becomes easy to offer multiple rates via the collectRates() method, simply by creating more rate results and calling append() for each one, in this way:
<?php
 
$result = Mage::getModel('shipping/rate_result');
 
$method = Mage::getModel('shipping/rate_result_method');
$method->setCarrier('foobar_customrate');
$method->setCarrierTitle($this->getConfigData('title'));
$method->setMethod('foobar_customrate_one');
$method->setMethodTitle('Rate 1');
$method->setPrice(5);
$method->setCost(2);
 
$result->append($method);
 
$method = Mage::getModel('shipping/rate_result_method');
$method->setCarrier('foobar_customrate');
$method->setCarrierTitle($this->getConfigData('title'));
$method->setMethod('foobar_customrate_two');
$method->setMethodTitle('Rate 2');
$method->setPrice(5);
$method->setCost(2);
 
$result->append($method);
After using the code above, you will see two shipping methods available for use. Methods are grouped by carrier, and the Carrier Title and Method Title are displayed on the frontend. If your shipping method uses multiple rates then it makes little sense to use the config to specify the names attribute, which is why they are hardcoded here. In this case you are free to remove the <name> node from your config.xml, as it is not used anywhere else.