I have a magento installation where I need to place related products in the center column. This is the easy part. I moved
<block type="catalog/product_list_related" name="catalog.product.related" after="container1" template="catalog/product/list/related.phtml"/>
From the right reference block, to the bottom of the center reference block.
With this I achieved to place the related products in the center column, but all the way at the bottom.
I need the related products to be placed just above the price block in the div (class: product-shop)
I tried to position it with the After/before parameter in the XML but this doesnt seem to work.
If I place the block code higher up in the XML it doesn't show at all.
Moving blocks is quite easy to do correctly (i.e. using best practices). Best practices include not customizing any core layout file when possible as well as working with original block instances rather than reinstantiating them. All of this can be achieve using the custom layout file available to end-implementers.
Create a local.xml file in your custom theme's layout folder e.g. app/design/frontend/[package]/[theme]/layout/local.xml, and in there add the following:
<?xml version="1.0" encoding="UTF-8"?>
<layout>
<!--
In Magento v1 a move is accomplished by unsetting in one place
and inserting in another. This is possible using just layout xml
when the "new" parent block is a "Mage_Core_Block_Text_List"
instance. Otherwise a template needs editing.
In Magento v2 there will be actual "move" functionality.
-->
<catalog_product_view>
<reference name="right">
<!-- remove the block name from a parent -->
<action method="unsetChild">
<block>catalog.product.related</block>
</action>
</reference>
<reference name="content">
<!-- add the block name to a parent -->
<action method="insert">
<block>catalog.product.related</block>
</action>
<!--
Mage_Core_Block_Abstract::insert() accepts multiple arguments,
but by default it will insert the added block at the beginning
of the list of child blocks.
-->
</reference>
</catalog_product_view>
</layout>
You can revert the change to the original layout xml file at this point.
Related
I have a magento website, of which Ive customized the rightside bar static block fine.
It displays as it should on all pages except the product pages.
Is this something that needs editing in the layout xml files, within the magento control panel or within other design files?
Thanks!
update:
The problem is that the global right sidebar is displaying everything as it should, however the product page is still displaying the old version, without the amends.
You simply need to add the product view xml updates to your local.xml layout file (or create it). The file would be located at:
/app/design/frontend/your_package/your_theme/layout/local.xml
An abridged version of the xml you would need is:
<?xml version="1.0"?>
<layout version="0.1.0">
<!-- Layout Handle for Product View Page -->
<catalog_product_view>
<!-- Reference Pointing to Right Sidebar -->
<reference name="right">
<!-- Enter All Right Sidebar Layout Updates Here -->
</reference>
</catalog_product_view>
</layout>
If you renamed your right sidebar something else, change the reference name above to what you changed it to. Here's some quick references to show what you can do to arrange via local.xml:
Move or Remove Blocks
<reference name="right">
<!-- Removes Block By Name -->
<remove name="name_of_removed_block"/>
<!-- Insert Moved Block (Must Unset First, See Left Reference) -->
<action method="insert">
<blockName>name_of_unset_block</blockName>
<siblingName>name_of_adjacent_block</siblingName>
<after>1</after> <!-- 0 = Before / 1 = After Sibling Block -->
</action>
</reference>
<reference name="left">
<!-- Unset Block By Name, Can Be Inserted Elsewhere As Above -->
<action method="unsetChild">
<name>name_of_unset_block</name>
</action>
</reference>
Add A Block From a Template File
<!-- Blocks Left and Right Automatically Load All Child Html -->
<reference name="right">
<!-- Load New Block From Template File -->
<block type="core/template" name="new_block_name" template="page/html/newblock.phtml" after="adjacent_block_name" />
</reference>
<!-- Some Blocks (Like Header) Require Child Html to be Called After Set in XML -->
<reference name="header">
<!-- Adding a Block Below Won't Be Enough To Add Our Template File Here -->
<block type="core/template" name="new_header_block" template="page/html/headerblock.phtml" />
</reference>
Not all blocks added will show immediately, sometimes you need to go within the parent block's template file to add the child block where you would like. In the above example, I used the "header" block, for anything to actually be added I have to edit the .phtml file directly. (unless you have changed your header.phtml to only use $this->getChildHtml(''); as no block name indicates that Magento should load all child html blocks.)
In this case, we would have to make a change to header.phtml, and somewhere within that file (/app/design/frontend/your_package/your_theme/page/html/header.phtml) you would need to add:
<?php echo $this->getChildHtml('new_header_block'); ?>
Where you would like to see your block added to the header.
That should get you started in the right direction. Make sure that none of your pages/products/categories have any custom layout xml in their records on the backend that may be affecting what shows up on the front as well.
For example, I want to put my block on the product page before the description block. How would I find these reference names?
If I understand correctly, based on your question and subsequent comments, you are looking for a way to position blocks before other blocks in the layout?
If so, the layout system provides you with before and after block attributes, for this exact purpose.
The general use is to add a before or after attribute containing the block you would like to position - before or after.
Before Example
<block type="yourmodule/block_type" name="yourblock" before="the_block_name_to_position_before" />
After Example
<block type="yourmodule/block_type" name="yourblock" after="the_block_name_to_position_before" />
Positioned before product description
In your particular scenario, where you would like a block to be positioned before the product description block, you need a little extra xml due to how the product description block is being included into the layout:
<!-- file: app/design/frontend/your_package/your_theme/layout/local.xml -->
<catalog_product_view>
<reference name="product.info">
<block type="yourmodule/block_type" name="yourblock" template="yourmodule/template.phtml" before="product.description">
<action method="addToParentGroup"><group>detailed_info</group></action>
</block>
</reference>
</catalog_product_view>
The important thing to note here though, in terms of you original question, is the use of the before attribute for positioning.
In the Magento Control Panel set your Current Configuration Scope to a specific website. Then, under System -> Configuration -> Advanced -> Developer -> Debug` turn on Template Path Hints and Add Block Names to Hints.
After that, when you reload the page it will tell you what blocks to override to get the desired effect.
Having trouble setting a block template in Magento's layout xml. I'm attempting to set the template of a child block, not the entire page layout (almost all docs out there explain how to set template of the layout).
Background: I'm updating a layout handle in my custom action, using the <update /> tag in my module's layout xml.
Essentially, I want to reuse the layout and blocks of the built in product view action, but provide custom templates for a few blocks. (Not just overrides, these need to be brand new templates that are only triggered on my custom action and are themselves overrideable).
My layout html:
<?xml version="1.0"?>
<layout version="0.1.0">
<mymodule_product_index>
<update handle="catalog_product_view" />
<reference name="content">
<block type="catalog/product_view"
name="product.info" output="toHtml" template="mymodule/product.phtml" />
</reference>
<reference name="product.info.bundle">
<action method="setTemplate"><template>mymodule/customtemplate.phtml</template></action>
</reference>
</mymodule_product_index>
</layout>
The setTemplate on product.info.bundle never works; it doesn't seem to affect layout at all. I've tried wrapping the <reference> in other <reference> nodes from parent blocks with no effect. Is it possible to replace block templates in this way? I feel that my problem stems from the fact I'm using an <update />.
By the way, I know my layout xml is being loaded and there are no errors, the rest of the file is working fine, caching is disabled, have cleared cache anyway, etc.
Your approach is almost correct.
Two things:
1. Set a new template instead of instantiating a new block
Instead of just assigning a different template to the product.info block, you are creating a new instance with the same name, replacing the original instance, and then the new template is set on that. Instead use this:
<mymodule_product_index>
<update handle="catalog_product_view" />
<reference name="product.info">
<action method="setTemplate">
<template>mymodule/product.phtml</template>
</action>
</reference>
</mymodule_product_index>
That should take care of the product view template in a clean way.
2. Handle processing order
If you look at where the view block product.info.bundle for the bundled products is declared, you will see it happens in the bundle.xml file, in a layout update handle called <PRODUCT_TYPE_bundle>.
Your code is referencing the block from the <[route]_[controller]_[action]> layout handle, i.e. <mymodule_product_index>.
The thing to be aware of here is the processing order of layout handles.
Roughly it is:
<default>
<[route]_[controller]_[action]>
<custom_handles>
The <PRODUCT_TYPE_bundle> handle belongs to the third type of layout handles, which means it is processed after the <mymodule_product_index> handle.
In essence, you are referencing the block product.info.bundle before it has been declared.
To fix this you will need to use the <PRODUCT_TYPE_bundle> handle as well. Of course this will effect every bundled product display. Using layout XML only there is no clean way around that.
Here are a few suggestions how to solve that problem.
You could create a separate route in your module to show the bundled products, and then include the <PRODUCT_TYPE_bundle> handle using an update directive for that page, too.
In your custom action controller, you could add another layout update handle that is processed after <PRODUCT_TYPE_bundle>.
You could use an event observer to set the template on the product.info.bundle block if it is instantiated. One possibility would be the event controller_action_layout_generate_blocks_after.
You get the idea, there are many ways to work around this, but they require PHP.
Previously in Magento, the wishlist link was added using the following (in wishlist.xml):
<action method="addWishlistLink"></action>
And you could override that and remove it using the following (in your local.xml):
<remove name="wishlist_link"/>
However, in the newest Magento, 1.4.2, they've changed how the wishlist link is added to the following:
<action method="addLinkBlock"><blockName>wishlist_link</blockName></action>
Anyone know how to remove the wishlist link now they’ve changed how it’s added?
It appears there's no publicly available way to reliably remove the wishlist link block from the layout. (you can skip to the end for a workaround)
The addLinkBlock assumes the presence of the block that's been passed, so using remove in the way you describe results in a fatal error being thrown
Fatal error: Call to a member function getPosition() on a non-object in /Users/alanstorm/Sites/magento1point4.2.dev/app/code/core/Mage/Page/Block/Template/Links.php on line 112
Here's the core code that causes that error
app/code/core/Mage/Page/Block/Template/Links.php
public function addLinkBlock($blockName)
{
$block = $this->getLayout()->getBlock($blockName);
$this->_links[$this->_getNewPosition((int)$block->getPosition())] = $block;
return $this;
}
This method assumes its going to be able to pull out a block by whatever name gets passed, so we can't just remove the wishlist_link block as we could in previous versions.
The only mechanism for removing a link appears to be the following method on the same block class
app/code/core/Mage/Page/Block/Template/Links.php
public function removeLinkByUrl($url)
{
foreach ($this->_links as $k => $v) {
if ($v->getUrl() == $url) {
unset($this->_links[$k]);
}
}
return $this;
}
However, this is done using string comparison, and there's no reliable way (that I know of) to generate a URL Object from a layout file, cast it as a string, and pass it into the method (this would be required, as there are numerous configuration settings that can change what the final string URL will be). That makes this method not helpful for our needs.
So, what we can do it modify the existing wishlist_link block to use a blank or non-existant template. This way the block still renders, but it renders as an empty string. The end result is we avoid the fatal error mentioned above, but still manage to remove the link from our selected pages.
The following would remove the link from all the pages using the default handle.
<!-- file: local.xml -->
<layout>
<default>
<reference name="wishlist_link">
<action method="setTemplate"><template>blank-link.phtml</template></action>
</reference>
</default>
</layout>
In your local.xml file,
<?xml version="1.0"?>
<layout version="0.1.0">
<default>
<reference name="root">
<reference name="top.links">
<!-- Remove wishlist link in magento 1.4.x and newer -->
<remove name="wishlist_link"/>
</reference>
</reference>
</default>
</layout>
You can remove the wishlist link from the admin panel System > Configuration > Wishlist > Enabled = "No"
Add the following to your local.xml file.
<reference name="top.links">
<remove name="wishlist_link"/>
</reference>
This works! I have removed Wishlink from Toplinks and wanted to add it back into another block but that doesn't seem possible when you remove it in this way. Sadly.
I know I'm years late here, but for all of those people who are still looking for answers to this.
I have a way to work around this issue that is only a bit of extra work but it's not hacky and it gives you FULL control of your top.links block.
Simply unset the top.links block and re-create it, it will be empty (no more wishlist_link block) and all you have to do is add whichever links you want inside of it! (Do all of this in your theme/layout/local.xml file of course).
<layout version="0.1.0">
<default>
<!-- HEADER -->
<reference name="header">
<!-- Unsetting the already existing top links block -->
<action method="unsetChild">
<name>topLinks</name>
</action>
<!-- Re-creating a new top links block -->
<block type="page/template_links" name="top.links" as="topLinks">
<!-- EXAMPLE: Account Dashboard Link -->
<action method="addLink" translate="label title" module="catalog">
<label>Account Dashboard</label>
<url helper="customer/getAccountUrl"/>
<title>Account Dashboard</title>
</action>
<!-- You can add any other links that you want -->
</block>
</reference>
</default>
</layout>
Also remember that for some links like Sign In and Log Out you will need to reference your top.links block inside the appropriate <customer_logged_out> and <customer_logged_in> handles instead of inside of <default> as a guide for this you can look at Magento's customer.xml file.
IMPORTANT: If there are any modules included in your project that add links to the top.links block, those links won't show up because local.xml is processed last, so just keep that in mind when using this method :)
I am a Certified Magento Front End Developer with over 3 years of experience and I have overcome LOTS of layout XML headaches to the point where we became best friends.
In Magento how do I specify how many products I would like displayed horizontally in the grid. By default it is 3 and I can't see where to change this (I would like to set it to 2).
Thanks,
Alan.
Difficult to find comprehensive instruction for Magento 1.4 with theming changes and local.xml, however there's possibly a bug with the columns in grid view as noted here:
http://www.lotusseedsdesign.com/blog/change-grid-view-column-4-product-listing
I got by with this in local.xml for a one column page/4 column grid:
<?xml version="1.0" encoding="UTF-8"?>
<layout>
<!-- Other template tweaks here -->
<catalog_category_default>
<reference name="content">
<reference name="category.products">
<reference name="product_list">
<action method="addColumnCountLayoutDepend"><layout>empty</layout><count>4</count></action>
<action method="addColumnCountLayoutDepend"><layout>one_column</layout><count>4</count></action>
</reference>
</reference>
</reference>
</catalog_category_default>
in the catalog.xml layout file you can add an 'action' tag inside the product-list block that will set the number of columns... the template (list.phtml) will call it as get[Something], so you want to have the method="set[Something]" in the layout file be the same. The class the methods are being called on is in app/code/core/Mage/Catalog/Block/Product/List.php ... I think. catalog.xml has in it some commented out examples of using 'action' for doing paging, so you should be able to copy those. Bit vague...but no code handy to look at.