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
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.
Posted on February 23, 2010
Posted by Erik Hansen
Add comment
Blog Categories
- Design (3)
- Development (9)
- Magento Development (26)
- PHP (1)
- Security (0)
- E-Commerce (5)
- General Business (5)
- Llama Culture (2)
- Magento (55)
- Management (4)
- Wiz (2)
- Online Marketing (1)
- Productivity (2)
- Uncategorized (4)
Comments
I've tried, but I am not
I've tried, but I am not getting my local.xml file to override anything. Its like It is being completely ignored. I created a new theme (genesis), and in there created 3 new folders (template, layout and genesis) and in the layout folder i have my local.xml file. The contents of the file is:
<?xml version="1.0" encoding="UTF-8"?>
css/local.css
page/1column.phtml
1
I simply want to update the default layout of the pages and this is not happening at all, neither is anything (for instance, breadcrumbs) being removed. Can anyone advise me as to what the solution is?
Some of the code was removed.
Some of the code was removed.
I am extremely impressed
I am extremely impressed thanks for sharing all information. It is a great post for the people to get the proper information.
Extremely awesome and helpful
Extremely awesome and helpful post for me... even about a year after you wrote it!! These layouts are tough to get the hang of, but your code example really helped me out.
You should write a book on templating Magento. Stuff like local.xml best practices and "stuff you need to know". I'd for sure buy it. ;)
@hartog actually in 1.5 the
@hartog actually in 1.5 the code has just been moved to a different method. Have a look in public function getFileLayoutUpdatesXml in the same file, line 418
Hello Great articles. How
Hello
Great articles.
How to unsetChil one block
Its possible ? or only emove is ok for this block ?
Thanks
hmm just a note here but
hmm just a note here but maybe it would be a good idea to dig into the source for this site and add "htmlspecialchars()"
to the php for the comment post. would make it a WHOLE lot easier on your commenters.
So I got past my initial
So I got past my initial issues and I am successfully designing a theme based on your method.
from: catalog_product_vie
from:
catalog_product_view>
reference name="content">
reference name="product.info">
action method="unsetChild">addto
remove name="addto"/>
/reference>
/reference>
from:
from:
addto
Why are you doing both
Why are you doing both unsetChild-addto AND remove addto ? Was the unsetChild not enough ?
from:
addto
Is there a tag type similar
Is there a tag type similar to that specifies if the shopping cart has anything in it? For example if I only wanted to display the My Cart toplink if the cart had something in it. I've seen a few ways it can be done by editing the php core directly, but I don't want to to that.
Cheers
Andrew
I love the way you explain
I love the way you explain it. Thank you!
http://www.webdosh.net/2011/12/magento-adding-and-removing.html
third try with xhtml
third try with xhtml tags:
Hi,
I love your article and I kept everything clean with this. I know you worte this ages ago, but maybe someone can give me a hand with one problem. I cannot add a new reference between content and footer without changing page.xml. Do you know a way to do this?
It works when I change page.xml and add into the default layout and:
<block type="core/text_list" name="middlespace" as="middlespace" translate="label">
<label>middlespace</label>
</block>
Then I can use:
<reference name="middlespace">
<block type="core/template" name="three-teasers-home" template="page/html/three-teasers-home.phtml" after="-" />
</reference>
But I don’t want to change page.xml, can you help me out? Or maybe someone else?
Hi, I love your article and
Hi,
I love your article and I kept everything clean with this. I know you worte this ages ago, but maybe someone can give me a hand with one problem. I cannot add a new reference between content and footer without changing page.xml. Do you know a way to do this?
It works when I change page.xml and add into the default layout and:
middlespace
Then I can use:
But I don’t want to change page.xml, can you help me out? Or maybe someone else?
Hi, I love your article and
Hi,
I love your article and I kept everything clean with this. I know you worte this ages ago, but maybe someone can give me a hand with one problem. I cannot add a new reference between content and footer without changing page.xml. Do you know a way to do this?
It works when I change page.xml and add into the default layout and:
middlespace
Then I can use:
But I don't want to change page.xml, can you help me out? Or maybe someone else?
if you want to create your
if you want to create your own magento blocks and insert it in a layout look at : http://www.about-magento.com/magento-create-block-44
I guess the code tag didn't
I guess the code tag didn't really work:
dark
Thanks for pointing out this
Thanks for pointing out this helpful technique. With the following code in local.xml, I was able to simply incorporate an alternate body style.
dark
How do you control number of
How do you control number of products in the category view in Magento?
Hi ehansen, Thanks for
Hi ehansen,
Thanks for great article lots of things are cleared to me by this article.
Thanks for your helpful tip.
Thanks for your helpful tip. I have a question. Are there any way to determine the block position from layout.xml file based on module configuration? EX: i have config from backend to show one block at: left, right or not. So the layout file of this module will reference to left, right or not. How do i approach this?
Sorry for my poor English. Hope you understand.
Thanks and hope to hear from you soon.
Great article, one issue that
Great article, one issue that I've come across is when you need to reorder the JavaScript includes in .
How do you normally approach this?
@Thomas- Sorry for being dump
@Thomas- Sorry for being dump here. Are you referring to create a custom module for "another block". Please explain what do you mean by "new reference" and "another block".
@ Zahid - you should not be
@ Zahid - you should not be using a "static" block to fetch database content. You should create a new reference or create another block to pull it in.
Magento 1.5.0.1 version Dear
Magento 1.5.0.1 version
Dear hansen,
we have gone through all the posts, excellent discussion but couldn't solve our simple problem i guess.
we are simply trying to display a news ticker on the right column of our home page.We are successful in creating a static block on the right column from the admin interface but data of news updates is required to be fetched from database.we have no clue how to fetch and display data on our static block. Design guide doesn't say any thing on the topic.
A quick help is appreciated.
@seif That is indeed
@seif That is indeed possible, if you copy the page refrence code to the xml you can change everything.
For example the category page is 'catalog_category_default'. You can find it if you look in your page source, it's attaced to you body class (don't forget to change the - with _ in the xml).
Hi . Thanks for this article
Hi .
Thanks for this article , well done .
Can i use local local.xml to force the template in every page to 3columns.phtml ?
Thanks !
Thanks for this article it is
Thanks for this article it is very helpfull, i was looking for this kind of tutorial.
Question tough: For example if i want to remove the ''My Cart" link out of the top.link, what is the best way to do this? Because in the checkout.xml this is inserted using a so i can't remove this using of because it isn't a block (am i right or am i totally thinking wrong)?
Also how can i change the quantity of the upsell blocks on the product detail page using the local.xml
Thanks!
Hi, this post has been quite
Hi, this post has been quite useful to me. Thank you.
I do have a question following from it, though. It seems like if you use a local.xml file that you would be updating the layout of every page with that theme.
If this is true, then every unique page would require a new theme. It seems like that would be bulky, time-consuming and difficult to update.
Is there a way to get the local.xml file to make different changes to the layout based upon the template which has been chosen for the particular page? Or have I misunderstood what Magento is doing?
Thanks
Custom Layout Update,it can
Custom Layout Update,it can work, thanks for your share.
skin_csscss/style.css
I am trying to move the
I am trying to move the breadcrumbs on the Product View Page, so that it appears just below the product name. Is there any way to achieve this. Thank you for your great tips.
@Jonathan_Hodges: Thanks,
@Jonathan_Hodges: Thanks, that worked like a charm. Didn't think of doing it that way. I found an article that in navigation.phtml loops through all cms pages and adds the cms-pages to the navigation. I think that fogged my "clear thinking". Happily, I posted my problem here and now I've got it working. Thanks again.
@Percy: You could add your
@Percy: You could add your static block in the default layout handle and echo it in the top of the footer template. Then unset child in the footer block in the layout handles for My Account and Checkout pages.
I am wondering if the
I am wondering if the following is possible:
I want to add a static block to the bottom of the content (between content and footer) for all pages, except for the checkout pages and the "My Account" pages. All other pages, being all CMS, Catalog, Products.
It seems to me that there should be a possibility to set this in the local.xml layout file. Can you help me with that?
@Conair:
@Conair: http://www.magentocommerce.com/design_guide
Hi I'm completely new to
Hi I'm completely new to magento. I just want to know where do i go to edit code. Is it through the Magento dashboard? Thanks i appreciate any help for this newbie.
I am so confused. Sorry! I
I am so confused. Sorry! I cannot figure this out. Why is it so difficult to edit the top menu bar with cart, login, etc? What file do I go to so I can just edit it, or put a stupid breadcrumbs add-in to manage the links myself? Sorry, I have searched at least 30 blogs and not gotten an answer and everything I try crashed the site, been working at it for at least 6 hours now, and it is late and the pub under my office is having karaoke night to top it off. hahahahah! Thanks for any help.
I think managing all custom
I think managing all custom updates via local.xml is a bad idea.
If your upgrading Magento you should still merge any changes to layout or template files. This method does not solve that issue, it only makes it more difficult to track down which files need to be merged. For instance, if an update include some new blocks in you really wouldn't be able to find out unless you went through all the diffs between magento and then your custom theme.
Your custom layout changes should be all in your custom_package/default (assuming version 1.4+ which falls back to base/default).
If you're running on a version of magento that falls back on base/default then it's possible to only update the necessary files in your custom package and theme directories. When you upgrade, you compare the changes between the old and new magento versions, check if any of those files exist in your custom theme and only merge those files.
I've stared a script to help speed up this process, https://github.com/rgranadino/Mage-Upgrade-Helper
As a bonus it can also scan app/code/local for php classes which extend core magento classes and inform you if they should be reviewed. Currently only runs on *nix systems due to the use of the diff command.
@hartog actually in 1.5 the
@hartog actually in 1.5 the code has just been moved to a different method. Have a look in public function getFileLayoutUpdatesXml in the same file, line 418
Thank you for this tutorial,
Thank you for this tutorial, it´s really good. I was wondering if it´s possible to add simple text via local.xml, like a phone number, or an adress into the top.links section, I just can´t figure it out. Cheers!
Ended up being a jQuery /
Ended up being a jQuery / Prototype conflict. I simply had to add jQuery.noConflict() at the end of my jquery.js file. I thought by replacing the $ with jQuery it would have fixed it originally.
I'm trying to add a new /
I'm trying to add a new / custom reference to my store. I've set it up so that I've got custom_content reference in my xml under the <catalog_product_view> and it set to getChildHtml('custom_content') in the view.phtml file. I've also added the custom page in my page.xml file, so it registers.
However, a LOT of basic stuff is yanked out immediately (like the Add to Cart button). When I add it back in local.xml I get a javascript error Cannot call method 'submit' of undefined.
If I copy the ENTIRE content reference from catalog.xml I still get the same error. What am I missing?!
Thanks!
@ hartog - the code is still
@ hartog - the code is still there, just moved a little - see line 418
By the way, in case you
By the way, in case you haven't seen it, check out Alan Storms "Layout Unremove" extension. Lets you "undo" remove tags using your local.xml file. You can just add:
http://alanstorm.com/magento_layout_unremove_in_local_xml
Allas... The code that
Allas...
The code that makes using local.xml possible has been commented out in 1.5.x :-(
@Mike plant I'm sure you
@Mike plant
I'm sure you have found the solution to your issue already, but can you not use the local.xml file for your theme to remove the specific block?
e.g.
<reference name="root">
<remove name="product_list_toolbar"/>
<reference>
@ehanson or whoever wrote this
This has been very useful to me! Thank you for this post and your contribution to the Magento community! The file really needs more documentation as well as a central repository for information like this. But then I suppose Magento as a whole could use better documentation.
Ok I figured it out. I
Ok I figured it out. I commented out the code for the logo in header.phtml.
Ok here we go! <reference
Ok here we go!
<reference name="header">
<action method="setTemplate"><template>page/html/homeheader.phtml</template></action>
<action method="unsetChild"><name>logo</name></action>
<remove name="logo"/>
</reference>
ok I am not posting the code
ok I am not posting the code correctly I put it in "code" tages. HMM. Maybe you can help anyway because you probably know the answer. Thank you.