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).