The Better Way to Modify Magento Layouts

In this article, I’m going to be covering what I believe to be a very effective way of modifying the layout of any Magento theme.

For several of the first Magento themes I built, I copied the layout files from the default or blank theme into the custom theme layout folder. I would then modify the layout files directly, editing or commenting out content in files like: catalog.xml, page.xml, checkout.xml, etc… I never liked editing these files directly, as I knew that when it came time to upgrade to a newer version of Magento that had upgraded the layout files, I’d have to merge the changes into the new layout files.

One day, I was digging through the Magento code relating to layout files and discovered a bit of code that made me realize that it was possible to just place a local.xml file in my custom theme’s layout folder and have it loaded automatically by Magento. (this code is on line 283 in /app/code/core/Mage/Core/Model/Layout/Update.php in the fetchFileLayoutUpdates() method).

Due to Magento’s brilliant tags, it’s possible to do just about anything you want without having to edit any of the default layout files.

Before delving into the code, let’s look at the advantages/disadvantages of this method:

Advantages

  • Allows you to upgrade themes without having to merge in changes
  • All custom layout changes are centralized, allowing developers to more easily make changes to custom theme elements

Disadvantages

  • At first, it’s slower to use this method than hacking up the standard layout files directly
  • You will have one more place to look where the site might be pulling code (template phtmls, standard layout files, admin layout updates, AND local.xml)

Here is the slimmed down, commented local.xml from one of our recent projects:

<?xml version="1.0"?>
<layout version="0.1.0">
 
<default>
 
	<reference name="head">
		<!-- Magento looks in /skin/frontend/<INTERFACE>/<THEME>/js/buyprinting.js
		for this file -->
		<action method="addItem"><type>skin_js</type><name>js/buyprinting.js</name></action>
 
		<!-- This removes the item that was set in the page.xml file -->
		<action method="removeItem"><type>skin_js</type><name>js/iehover-fix.js</name></action>
 
		<!-- Magento looks in /js/prototype/element.storage.js for this file -->
		<action method="addJs"><name>prototype/element.storage.js</name></action>
 
		<action method="addCss">
<stylesheet>css/buyprinting.css</stylesheet></action>
	</reference>
 
	<reference name="header">
        <!-- This adds a CMS block that can be called from the template file
        associated with the header block. -->
		<block type="cms/block" name="cms_quick_help">
			<action method="setBlockId"><block_id>quick_help</block_id></action>
		</block>
 
        <!-- The remove tag removes the blocks with the specified name from the layout -->
		<remove name="top.menu"/>
		<remove name="store_language"/>
		<remove name="breadcrumbs"/>
	</reference>
 
	<reference name="top.nav">
		<remove name="catalog.topnav"/>
	</reference>
 
	<reference name="left">
		<remove name="left.newsletter"/>
		<remove name="left.permanent.callout"/>
		<remove name="catalogsearch.leftnav"/>
 
        <!-- When you use the remove tag, it removes any blocks with the specified name from
            the entire layout, regardless of the context. So, if I remove right.newsletter in
            the <default> context and that name is used in say the <catalog_product_view> context,
            then both blocks will be removed.  Because remove operates on the global context,
            you can only remove an element once.  Since <remove name="right.newsletter" /> is
            being called in catalogsearch.xml, we have to unset it, or else we'll get an error.
 
            The line below only unsets the block from the parent's context, not the global
            layout context -->
		<action method="unsetChild"><name>right.newsletter</name></action>
	</reference>
 
	<reference name="right">
        <!-- Some blocks have to be removed using remove, others via unsetChild.
            I've not spent the time digging into the code to figure out why -->
		<remove name="right.permanent.callout"/>
		<remove name="catalog.compare.sidebar"/>
		<remove name="left.reports.product.viewed"/>
		<action method="unsetChild"><name>sale.reorder.sidebar</name></action>
		<action method="unsetChild"><name>wishlist_sidebar</name></action>
		<action method="unsetChild"><name>right.reports.product.viewed</name></action>
		<remove name="cart_sidebar"/>
	</reference>
 
</default>
 
<!-- CATALOG PAGES -->
	<catalog_product_view><!-- 2columns-right -->
		<reference name="root">
			<action method="setTemplate"><template>page/2columns-left.phtml</template></action>
		</reference>
		<reference name="content">
			<reference name="product.info">
				<block type="cms/block" name="cms_product_info_tabs">
					<action method="setBlockId"><block_id>product_info_tabs</block_id></action>
				</block>
				<block type="catalog/product_view" name="product.clone_prices" as="prices" template="catalog/product/view/price_clone.phtml"/>
				<action method="unsetChild"><name>tierprices</name></action>
				<action method="unsetChild"><name>addto</name></action>
				<remove name="addto"/>
				<reference name="product.info.options.wrapper.bottom">
					<action method="unsetChild"><name>product.tierprices</name></action>
				</reference>
			</reference>
		</reference>
	</catalog_product_view>
 
</layout>

I hope with article has given you some direction as to how you can improve you Magento theming skills. If you have any additional tips/comments on coding layouts, please suggest them in the comments section.

55 Responses to “The Better Way to Modify Magento Layouts”

  1. Phillip Jackson

    March 5th, 2010 at 4:58 pm

    Great tutorial my friend –

    Is there any way you can add/override blocks by their named attributes by using admin layout updates? For instance, on a product page I would like to use a CMS static block in place of the product descriptions – or sometimes to insert a small static block (e.g. advertising, etc.) above the add to cart button on a simple product page.

    Any ideas?

  2. @Phillip Jackson – Yes, that is possible. Here’s the layout xml you’d add to replace a product description with a static content block:

    <reference name="product.info">
       <action method="unsetChild"><name>product.description</name></action>
          <block type="cms/block" name="product.description">
             <action method="setBlockId"><block_id>STATICCONTENTBLOCKID</block_id></action>
          </block>
       </action>
    </reference>
  3. Is it possible to add something to another column through this method? For example, if I wanted to remove the cart sidebar from the left column and add it to the right column how would I do that?

  4. @Jenn – Yes, that is possible. You can do that using the “append” method:

     
       <!-- Append the cart_sidebar block into the right block -->
       <reference name="right">
          <action method="append"><block>cart_sidebar</block></append>
       </reference>
     
       <!-- Remove the cart_sidebar block from the left sidebar -->
       <reference name="left">
          <action method="unsetChild"><block>cart_sidebar</block></action>
       </reference>
  5. @ehansen Can you direct a developer to any in-depth resources as to the structure, classes, etc of Magento? Documentation seems to be sparse which is making learning frustrating.

    Thanks for your advice!

  6. @Joel – I would recommend reading PHP Architect’s Guide to E-Commerce Programming with Magento. The first 5~ chapters provide a really good insight into the structure of Magento. After reading through the first 5~ chapters, you should start digging into Magento’s core modules. The app/code/core/Mage/Cms/ and app/code/core/Mage/Customer are two good modules to start with. Note: The book was written over a year ago, so a lot of the examples in the book are out-dated.

    In addition to reading that book, it’s important to have a solid understanding of Object-Oriented PHP.

  7. @ehansen – thanks, yeh I need to read SOME book, just didn’t know which one I could read that wasn’t too out-dated! Thanks for the recommendation on this book – I’ll give it a look over.

    I am familiar with OOP – and haven’t really poked around in the core modules yet, kind of wanted to read documentation before doing that.

    Thanks again.

  8. Your information is insightful and I strongly feel that you are the one to assist with the following two updates I am looking for.

    First I am looking to update a category through the Custom Layout Update and remove the prices from displaying. I would be looking to remove the price-box from that specific category. Something along the lines of:

    Also I have another snipet of code that I am using to which calls a specific file – template\feedreader\feedreader.phtml.

    In adding that file to the layout an update to the layout is added:

    Blog Posts
    http://www.url.com/feed/
    5

    However I am unable how to add this information to a specific place on the homepage. Can I create a CMS Static Block and use these functions that are necesasry to allow the feedreader.phtml to run? Or can I add a block to the homepage through the homepage Layout Update XML, and force the feed to display in a specific Static Block on the homepage?

  9. Here is the code:

    Blog Posts
    http://www.athletictapeinfo.com/feed/
    5

  10. Thanks for the tips. So if I wanted to change the default template layout to 2columns-left I would just added the following to the local.xml section?

    page/2columns-left.phtml

    Also, with just using local.xml (and not recreating a page.xml) I should be able to override templates like 2columns-left.phtml and header.html correct? It does not seem to work for me and I just wanted to verify that in theory it should. I just have .phtml copies from the default theme with a some simple html changes for testing. I have them located here:

    app\design\frontend\default\mytheme\templates\page\2columns-left.phtml
    app\design\frontend\default\mytheme\templates\page\html\header.phtml

    My css changes in skin\frontend\default\mytheme\css\ were picked up but from some reason none of the template changes worked.

    Any thoughts or any help in general would be great. I would love for your theming method to work for me.

    Thank in advance.

  11. @Josh & SEM Truth – Can you post your code examples inside of blocks like this so I can respond to your questions:

    <pre lang="xml" colla="+">
    …your code here…
    </pre>

  12. Yes, sorry about that. I used the code block instead. Here are the lines I added in the default section of local.xml:

    page/2columns-left.phtml

    Also, any thoughts on why the system is not using mytheme’s defined .phtml files?

  13. not sure why the pre tags are not working for me either. Here’s another go. Feel free to delete these comments.

    page/2columns-left.phtml

  14. So I got past my initial issues and I am successfully designing a theme based on your method.

    I was wondering if it is possible to override a remove call in a different layout xml? Basically, in the default customer.xml in the customer_account_login layout the left block is being removed. I want to override this in my local.xml so the left block will display for that layout. Is this possible without overwriting the customer.xml?

  15. Hi,
    this is a really helpful article.

    I found a lot of pre 1.4 tutorials, mainly copy layout and edit directly, but I prefere this new way of modifying themes.

    Does anybody know where to find all of those action methods`?
    Possible values etc

    Thanks in advance,
    Jo
    (greetings from germany)

  16. @Josh – Sorry for not getting back with you sooner. Glad you figured out your initial questions. Is this possible without overwriting the customer.xml? – Unfortunately it’s not possible to “unremove” a block that’s been removed. This is one of those instances where you’re going to have to edit one of the core layout files. If you have to edit one of the core layout files, I would recommend commenting the lines you edit. Also, if you’re using svn (or any other source control system) I’d recommend doing an “svn cp” of the core layout file to your custom layout directory and then making the edits. Doing so will ensure that the edits you make to the layout file show up as a changeset in svn.

    @Jo – Most of the “action methods” are contained in the Mage_Core_Block_Abstract class. In case you didn’t know this, the <block> syntax corresponds directly to Block classes that are found in the app/code/core/Mage folder. So a block tag with the type of “catalog/product_view” uses the Mage_Catalog_Block_Product_View class that can be found in the app/code/core/Mage/Catalog/Block/Product/View.php file. The “method” attribute value on <action> tags correspond directly to method names on the block.

  17. Thanks for the reply. I have another quick question, is it possible to remove links (do the opposite of method=”addLink”)? I am trying to remove some links from the my account sidebar block (customer_account_navigation) and I didn’t know if this was possible from local.xml.

  18. @Josh – There’s a removeLinkByUrl method – check out our posts about editing Magento’s top links and editing footer links for a more detailed documentation.

  19. Thanks for this gem – I’m now using it for all future themes.

    This post has been aped without credit at http://magentoexpert.blogspot.com/2010/05/better-way-to-modify-magento-layouts.html

  20. @David – Glad you found it useful. Thanks for the heads-up about the “magentoexpert” site. I’ll contact them requesting they remove the plagiarized post.

  21. Thank you for this post I found you via the Magento forum.

    really helpful….

  22. ehansen – thank you

    The layout update is as follows:

    blog_news
    http://www.url.com/feed/
    5

    This is great for adding something to a sidebar. But if I am trying to add this layout update and call it within a specific place within the homepage or a CMS block:

    {{block type=’feedreader/sidebar’ name=’left.feedreader’ template=’feedreader/sidebar.phtml’}}

    how would I be able to set actions or assign the layout update to a specific place within the layout of my design?

  23. blog_news
    http://www.athletictapeinfo.com/feed/
    5

  24. Hi

    Like Josh, I too am trying to remove ‘My Downloadable Products’ from the menu in the My Accounts section. OK, I can comment out the downloadable.xml in the base folder, but in the spirit of things, it’d be better to override this in local.xml.

    I’ve tried out the removeLinkByUrl method like, but it only throws an error. I’m a bit stumped (many things in magento stump me) – what is the helper method in the tag?

    cheers

    My current code is:

  25. FYI, in 1.4.1.0 you should name it local.xml, not layout.xml for Magento to read it properly. Here’s the documentation for that: Designing for Magento

  26. whew, been a long day…nevermind what I just said :D

  27. ehansen, is there a way that I can PM you the exact code I have been working with?

  28. You can email me at erik AT classyllama.com

  29. Hi,
    thanks for this tips (an other version of local.xml can be found in the last version of the magentoecommerce wiki).

    I’ve a little question (Magento 1.4.1) : I create a new theme and place this local.xml in /magento/app/design/frontend/default/mytheme/layout/local.xml
    But all the modification I’ve write in it doesn’t work… (I change the System>>Configuration>>Design : Themes >> default field to “mytheme”)
    If I put this local.xml file in an existing theme that not work too…
    (Same problem with the custom /app/design/frontend/mytheme/templates/page/html/xxx.phtml by the way)
    May I miss something.

    Thks for help.

  30. @Mickael: have you turned Magento’s caching off?

  31. Thanks a lot ! (and shame on me)

  32. I’ve been diggin’ everywhere on the web with no luck, you seem like a person that might know where I can edit the actual code that pulls up the tag that displays the page title in the CMS block? Not to be confused with the logo issue, I understand how that works. Is it a core file?

    Thank you kindly.

  33. Thank you for explaining the correct way to modify Magento layouts.

    I’m using magento 1.4.1 and learning how to modify my layout on a local server.

    I’m using the default theme and I defined this in System>Configuration>Design, defining the Template, Skin, Layout, & Defautl as default.

    I also turned off the cache.

    I then created a local.xml file in magento\app\design\frontend\default\default\layout and added the following lines:

    <reference name=”left”;&gt
    <remove name=”left.permanent.callout”/>
    </reference;&gt

    <reference name=”right”;&gt
    <remove name=”right.permanent.callout”/;&gt
    <remove name=”catalog.compare.sidebar”/;&gt
    <remove name=”right.poll”/>
    </reference;&gt

    However when I refresh the home page there are no changes to the layout.

    Any ideas on what I might be doing wrong?

    Cheers

  34. @bipedal_bill – Unfortunately I don’t know off the top of my head, so you’ll have to dig in and figure that out.

    @Steve – You need to wrap the XML in your local.xml file with the layout and default tags. See the example code block in the post for details.

  35. Thanks for the response.

    I had just omitted those lines from my post. Here’s the complete file.

    <?xml version=”1.0″?<
    <layout version=”0.1.0″<
    <default<

    <reference name=”right”<
    <remove name=”right.poll” /<
    <remove name=”right.permanent.callout” /<
    <remove name=”catalog.compare.sidebar” /<
    </reference<

    <reference name=”left”<
    <remove name=”left.permanenet.callout” /<
    </reference<

    <reference name=”head”<
    <action menthod=”addcss”<
    <link<local.css</link<
    </action&lt
    </reference<

    </default<
    </layout<

  36. Sorry, I screwed up my gt tags in the above post

    <?xml version=”1.0″?<
    <layout version=”0.1.0″<
    <default<

    <reference name=”right”<
    <remove name=”right.poll” />
    <remove name=”right.permanent.callout” />
    <remove name=”catalog.compare.sidebar” />
    </reference<

    <reference name=”left”>
    <remove name=”left.permanenet.callout” />
    </reference<

    <reference name=”head”>
    <action menthod=”addcss”>
    <link<local.css</link>
    </action>
    </reference>

    </default>
    </layout>

  37. @Steve – Unfortunately I’m not able to spot any errors with your XML, so you’re going to have to continue debugging on your own.

  38. I’ve put local.xml into my theme’s layout folder, but it doesn’t seem to load. Any thoughts? Here:s the code:

    Home/Home1

  39. @Matt – Can you convert your html to its html entity equivalent and then post it? You can use a tool like this to convert it: http://www.opinionatedgeek.com/dotnet/tools/htmlencode/encode.aspx

  40. Erik,

    Thank you for your time and I think I found the problem to my previous posts. I had copied & pasted your code into a file and I guess there were some extraneous characters that get inserted when using this procedure.

    So I recreated the file from scratch and for the most part everything seems to work with the exception of my left column.

    To be sure I’m not screwing anything else up I’m learning how to code the xml file using the default/default theme as supplied by magento in 1.4.1, and I have the cache turned off.

    <?xml version="1.0"?>
    <layout version="0.1.0">

    <default>
    <reference name="header">
    <remove name="store_language"/> <!– This works –>
    </reference>

    <reference name="left">
    <remove name="left.permanent.callout"/> <!– This does not –>
    <remove name="tags_popular"/> <!– This does not –>
    </reference>

    <reference name="content">
    </reference>

    <reference name="right">
    <!– This works –>
    <remove name="right.permanent.callout"/> <!– This works –>
    <remove name="right.poll"/> <!– This works –>
    <remove name="catalog.compare.sidebar"/> <!– This works –>
    <remove name="right.paypal"/> <!– This does not –>
    </reference>

    <reference name="footer">
    <remove name="footer_links"/> <!– This works –>
    </reference>
    </default>
    </layout>

    Can you see anything in my code that I might be missing.

    BTW. Thanks for the tip about encode.aspx

    Cheers.

  41. @Steve – Based on what I remember, the remove tag doesn’t always work. Some times, you have to use action method=”unsetChild”. See the initial example XML for how to use this.

  42. Excellent find – this has just saved me a load of work creating a new module just to add a few misc layout updates – now I can just stick them all in the local.xml file and viola! Cheers for sharing this!

  43. @Sam – If you’re creating your own module, you may actually want to create an xml file specifically for that module. In the config.xml file of your module, you can specify a new layout file using the layout tag. Search the app/code/core/Mage/Catalog/etc/config.xml file for layout to see an example of the exact syntax.

  44. Thanks – I have already made a load of modules, with their own layout files – but this is great for making small changes to the site structure, without having to either override another layout file, or add a new one via another module. I’m gonna use this for all those extra little changes that don’t warrant a full extension of their own!

  45. first thanks for the tip!

    after looking into this a bit more, i just wanted to suggest that you update your guide.

    there is a similar approach as described in the wiki which does not require hacking the core code:
    http://www.magentocommerce.com/wiki/4_-_Themes_and_Template_Customization/0_-_theming_in_magento/designing-for-magento

  46. the following will remove the paypal logo in 1.4:

  47. @jon – The method espoused in this post doesn’t hack any core code, so I’m not sure what you’re talking about. Can you be more specific as to what you think is being hacked? Thanks!

  48. How can you go about reactivating a left or right column after it’s been removed in the base xml file.

    E.g. checkout.xml’s onepage removes the left column, but I want a 2columns-left.phtml template. Even after calling the proper template, the remove prevents anything from displaying in the left column.

    page/2columns-left.phtml

    Left Column

    checkout-progress-wrapper

  49. <checkout_onepage_index translate=”label”>
    <reference name=”root”>
    <action method=”setTemplate”><template>page/2columns-left.phtml</template></action>
    <block type=”core/text_list” name=”left” as=”left” translate=”label”>
    <label>Left Column</label>
    </block>
    </reference>
    <reference name=”left”>
    <action method=”unsetChildren”></action>
    <block type=”page/html_wrapper” name=”checkout.progress.wrapper”>
    <action method=”setElementId”><value>checkout-progress-wrapper</value></action>
    <block type=”checkout/onepage_progress” name=”checkout.progress” before=”-” template=”checkout/onepage/progress.phtml”/>
    </block>
    </reference>
    </checkout_onepage_index>

  50. @Rick – This is unfortunately one of the few things that can’t be modified using the local.xml file. You can’t currently “unremove” a block that has been removed. You’re going to have to copy the checkout.xml file into your custom theme and comment out that remove line. We’ve considered overriding a Magento block to allow us to add an unremove a block, but we’ve not done that yet.

  51. As i new to magento i enciunterd some problem that is , when i install a new theme and start working on this .i want to replace position for my cart from right to left but i checkout.xml file is not there. please tell me the solution .

    please

  52. @Agam – I’d recommend posting that question to the Magento forums.

  53. That’s ok Mr.Erik Hansan i will follow your suggetion but i wanna ask u something that everything( template,layout) we found in our theme at path C:\xampp\htdocs\magento\app\design\frontend\blank\theme003 . but now i m confude that what base directory contain about our theme C:\xampp\htdocs\magento\app\design\frontend\base\default. instead my teme is in blank directory. please clear my confusion about this.

    if u have any structure or hirerchy to find all relevent .phtml , .xml file for my theme then please recommend me. that would me worthfull for me . thank you

Comment Form

For Code: Use the html code for < & >.  i.e. "&lt;YOUR_TAG&gt; ...your code... &lt;/YOUR_TAG&gt;"

XHTML: You can use these tags: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

Call us at 417-597-3397, email us at sales@classyllama.com, or use this form to contact us:

  1. (required)
  2. (required)
 

cforms contact form by delicious:days

Full builds (design and development) start at $70k