The ‘View’ of Magento’s MVC pattern implementation is divided in two parts: Layout and Template. The template represents a HTML block while layout defines the location of the block on a web page. Magento provides ultimate flexibility and re-usability of design by layouts defined in XML.
Layout XML files can be found in
app/design/frontend/[package]/[theme]/layout. Each Magento module may define its own layout XML file in the
<frontend> <layout> <updates> <mymodule> <file>mymodule.xml</file> </mymodule> </updates> </layout> </frontend>
Each layout XML file represents its own design update. For example, catalog navigation is part of the
Mage_Catalog module and
Mage_Catalog module defines a layout update file:
catalog.xml. So the block for the catalog navigation and its location on the page is defined in
Before the page is rendered, Magento loads all configured layout update files and its design updates to determine which block is to be rendered at which location.
Here is an example layout XML file
contacts.xml for the
Mage_Contacts module. The
root element of any layout XML file is
<layout version="0.1.0"> <default> <reference name="footer_links"> <action method="addLink" translate="label title" module="contacts" ifconfig="contacts/contacts/enabled"><label>Contact Us</label><url>contacts</url><title>Contact Us</title><prepare>true</prepare></action> </reference> </default> <contacts_index_index translate="label"> <label>Contact Us Form</label> <reference name="root"> <action method="setTemplate"><template>page/2columns-right.phtml</template></action> <action method="setHeaderTitle" translate="title" module="contacts"><title>Contact Us</title></action> </reference> <reference name="content"> <block type="core/template" name="contactForm" template="contacts/form.phtml"/> </reference> </contacts_index_index> </layout>
First level child elements of the
<layout> node are called layout handles. Each layout handle represents an update to the page layout. It may define new blocks to be included in a page at a specific location or remove a specific block from the page. It may also define the modifications in existing blocks already included in the page by other layout XML files.
After Magento loads all layout XML files, it determines which layout handles need to be processed. Normally, the layout handle is selected based on the controller action being executed. In most cases, Magento loads the layout handle with name:
For example, when the contact us page is requested, then
index action of
index controller of
Mage_Contacts is executed. Module front name of
contacts. So the layout handle to be processed for the contact us page is
For any page, Magento always processes the default layout handle. So the updates defined in default handle are processed for every page regardless of which part of the site we are browsing. As the example above illustrates, the
Mage_Contacts module requires a link to the “Contact Us” page in the footer on every page so the specific elements for it is defined in the default handle. These elements are discussed further in the next section.
A layout handle may contain the following elements:
label: This element is introduced since Magento 1.4. It defines the label of the handle which is shown as a descriptive reference in some areas of the admin panel.
reference: This element is used to link an already defined block in any layout XML. To add any child block to an existing block, to modify attributes of an existing block or to perform any action on an existing block, the
referenceelement is used to link to the existing block. The
referenceelement must have a
nameattribute which refers to the existing block’s name.
block: This element is used to define a new block. This element is usually defined inside a
referenceelement when we want to create a new block. The
blockelement must have a
nameattribute, which is a unique identifier of the block in the layout and a
typeattribute, which defines the block class name. If the block is of type or subtype of
core/template, it can also have the
templateattribute which defines the actual phtml template file to be used for rendering the block
remove: This element is used to remove an existing block from the layout. The block to be removed is specified with the
action: This element defines an action to be performed on the referenced or newly defined block. An action is simply a method of the block instance on which it is to be executed. The
methodattribute defines the method name in the block instance and all child elements of the action element are treated as parameters to the method. This element can be placed inside
update: This element loads an existing layout handle into the current layout handle. It provides a kind of inheritance of layout handles. It must have the
handleattribute, which defines the handle of the block to be included.
For example, all customer account pages have a similar layout and apply some common layout updates. So instead of defining all updates for the individual pages, a common layout handle:
customer_accountis defined in
<customer_account translate="label"> <label>Customer My Account (All Pages)</label> <!-- Mage_Customer --> <reference name="root"> <action method="setTemplate"><template>page/2columns-left.phtml</template></action> </reference> <reference name="content"> <block type="page/html_wrapper" name="my.account.wrapper"> <action method="setElementClass"><value>my-account</value></action> </block> </reference> <reference name="left"> <block type="customer/account_navigation" name="customer_account_navigation" before="-" template="customer/account/navigation.phtml"> <action method="addLink" translate="label" module="customer"><name>account</name><path>customer/account/</path><label>Account Dashboard</label></action> <action method="addLink" translate="label" module="customer"><name>account_edit</name><path>customer/account/edit/</path><label>Account Information</label></action> <action method="addLink" translate="label" module="customer"><name>address_book</name><path>customer/address/</path><label>Address Book</label></action> </block> <block type="catalog/product_compare_sidebar" name="catalog.compare.sidebar" template="catalog/product/compare/sidebar.phtml"/> <block type="sales/reorder_sidebar" name="sale.reorder.sidebar" as="reorder" template="sales/reorder/sidebar.phtml"/> <remove name="tags_popular"/> </reference> </customer_account>
This handle is then loaded on all account page handles. Here is an example of the customer address page handle in the same
<customer_address_index translate="label"> <label>Customer My Account Address Book</label> <!-- Mage_Customer --> <update handle="customer_account"/> <reference name="my.account.wrapper"> <block type="customer/address_book" name="address_book" before="-" template="customer/address/book.phtml"/> </reference> </customer_address_index>
So when, the customer address page is rendered, the layout blocks defined in
customer_accountare also applied to the page.
Before rendering the page, all
block elements defined in the layout are instantiated. Nested
block elements define child blocks. If any block element defines an
output attribute, then it is considered as an output block. Only the output blocks are rendered and added to the response. All other child blocks are rendered only if they are called by the parent block. Let’s see how this works.
In Magento’s default theme, the block
root is defined as an output block. This block is defined in the
page.xml file. With the particular value of the
template attribute, this block defines the page template to be used when rendering it, i.e. 1 column, 2 columns with left sidebar, 2 columns with right sidebar, 3 columns etc. By default, the 3 columns template is assigned to the page. There are also other child blocks defined under
footer etc. These child blocks are rendered in the
root template file (
3columns.phtml) by calling something like this:
In any template, the child blocks can be rendered by calling the
getChildHtml() method as above and passing the child block name as the first argument. If the method is called without arguments, it will render all child blocks of the current block that are defined in the layout XML for that block.
Hence, Magento processes layout using a recursive rendering process. First the
root block then its child blocks and then the child’s child blocks and so on.
Putting it all together
Let’s look at the example of
contacts.xml file. The goal of this layout update file is to add a footer link to the contact us page if contact us is enabled in the system configuration and define the page structure of the “Contact Us” page.
There is already a block
footer_links defined in page.xml file to display links in page footer. The
footer_links block has an
addLink method to add new links within the block. So here, the existing
footer_links block can be referenced and the
addLink action can be called on it with certain parameters to add a “Contact Us” page link to it. As the “Contact Us” page link needs to be added in the footer for every page this should be defined in the
<default> <reference name="footer_links"> <action method="addLink" translate="label title" module="contacts" ifconfig="contacts/contacts/enabled"><label>Contact Us</label><url>contacts</url><title>Contact Us</title><prepare>true</prepare></action> </reference> </default>
Here, default handle contains a reference to the footer_links block and performs an action
addLink on it by passing the parameters
title, etc. Also, in this case, the attribute
translate is used to define which parameters need to be translated before passing them to the method. In the above example,
title are translated using the current locale. The translation will be searched with the module scope defined in the attribute module. The attribute
ifconfig defines the system configuration key to be checked before performing the method action. The system configuration key used as value of
ifconfig, are normally defined as Yes/No type configuration values and return a Boolean value. If configuration returns false, the action will not be performed. In our case, if value of
contacts/contacts/enabled is false, i.e. Contact Us is disabled from system configuration, the action to add the link will not be performed and the Contact Us link will not appear in the footer.
ifconfig can only be used within an
action element and only when the action needs to be performed if a particular configuration value is set to ‘Yes’.
<contacts_index_index translate="label"> <label>Contact Us Form</label> <reference name="root"> <action method="setTemplate"><template>page/2columns-right.phtml</template></action> <action method="setHeaderTitle" translate="title" module="contacts"><title>Contact Us</title></action> </reference> <reference name="content"> <block type="core/template" name="contactForm" template="contacts/form.phtml"/> </reference> </contacts_index_index>
As mentioned before, Magento automatically determines the handle to be loaded on the basis of a current action being executed. In case of the contact us page, it would call the
indexAction. The front name of
contacts. So the layout handle would be
contacts_index_index. The label is given as
Contact Us Form to identify the page in some areas of admin panel, for example the widget instance creation form:
Next, the Contact Us page should have two columns with right sidebar. As explained in the previous section, the page template is defined by the
root node and by default uses the 3 column template. So, to modify this for the Contact Us page, the
root node is referenced here using the
reference element. To assign a different template to the page, the
setTemplate method should be called. So, an
action element is defined to call the
setTemplate method with the desired template path as a parameter:
<reference name="root"> <action method="setTemplate"><template>page/2columns-right.phtml</template></action> </reference>
Finally, in the main content area, a contact form should be displayed. To add the contact form block, the
content block is referenced and a new
block element is defined to include the contact form:
<reference name="content"> <block type="core/template" name="contactForm" template="contacts/form.phtml"/> </reference>
Magento defines some built-in block types which are widely used in layout.
core/template: This block renders a template defined by its
templateattribute. The majority of blocks defined in the layout are of type or subtype of
page/html: This is a subtype of
core/templateand defines the root block. All other blocks are child blocks of this block.
page/html_header: Defines the header part of the page which contains the site logo, top links, etc.
page/template_links: This block is used to create a list of links. Links visible in the footer and header area use this block type.
core/text_list: Some blocks like
rightetc. are of type
core/text_list. When these blocks are rendered, all their child blocks are rendered automatically without the need to call the
page/html_wrapper: This block is used to create a wrapper block which renders its child blocks inside an HTML tag set by the action
setHtmlTagName. The default tag is
<div>if no element is set.
page/html_breadcrumbs: This block defines breadcrumbs on the page.
page/html_footer: Defines footer area of page which contains footer links, copyright message etc.
core/messages: This block renders error/success/notice messages.
page/switch: This block can be used for the language or store switcher.
This is a list of only commonly used block types. There are many other block types which are used in advanced theme implementations.
Layout XMLs make the theme design modular by using layout handles. These are just the basics of layout XML in Magento. More advanced implementation can be done by utilizing layout handles and actions. We will cover some more advanced usage of layout XML in next article of this series.
Originally published on magebase.com. Copyright © 2010 Magebase - All Rights Reserved.