Not sure why this is so difficult. If I understand THIS correctly, I should be able to swiftly accomplish my goals... But no joy.
So - I'm building my first theme, and still getting my head around layout...
I'm working specifically on the Catalog Product View
page, and am converting this page from a right column layout to a left column layout. I simply want to move the blocks from the right into the left.
In the default catalog.xml, product_list_related
is defined:
</catalog_product_view>
//...
<reference name="right">
<block type="catalog/product_list_related" name="catalog.product.related" before="-" template="catalog/product/list/related.phtml"/>
</reference>
</catalog_product_view>
In my local.xml, I'm simply trying to move this block:
<layout>
// bunch other page directives
<catalog_product_view>
<reference name="root">
<action method="setTemplate"><template>page/2columns-left.phtml</template></action>
</reference>
<reference name="right">
<action method="unsetChild"><name>catalog.product.related</name></action>
</reference>
<reference name="left">
<action method="insert"><blockName>catalog.product.related</blockName></action>
// note that that "catalog.leftnav" gets inserted as expected
<block type="catalog/layer_view" name="catalog.leftnav" after="-" template="catalog/layer/view.phtml"/>
</reference>
</catalog_product_view>
</layout>
As noted - inserting catalog.leftnav
works as expected, so I'm assuming everything else is set up correctly. The target block renders as expected if I leave the template and other directives unchanged, which tells me that the block should render once its been properly unset and inserted...
This is driving me nuts... but what else is new with Magento.
Cheers -
b[]x
UPDATE
Because I simply can not get a local.xml
override to work, I'm just falling back on a modified catalog.xml
. I'm a reasonably smart guy... it worries me that I can't get this to work (and that magento just silently fails, whatever the case ) - but I can't waste anymore time dicking around with this stupid issue.
Moving on.
UPDATE, again.
Spent some time, now, working in magento and getting more familiar with its complexities. I came back to this issue today as I need to get my local.xml working right.
I really don't know what I had wrong, but this set of directives finally worked.
<reference name="right">
<action method="unsetChild">
<alias>catalog.product.related</alias>
</action>
</reference>
<reference name="left">
<action method="insert">
<block>catalog.product.related</block>
</action>
</reference>
A key point I'll make note of for others dealing with this:
Layout xml directives call available methods within magento classes. In this case, Page.xmls "Left" block is of type Mage_Core_Block_Text
, which inherits from Mage_Core_Block_Abstract
which contains the methods unsetChild
and insert
.
from Mage_Core_Block_Abstract
:
/**
* Unset child block
*
* @param string $alias
* @return Mage_Core_Block_Abstract
*/
public function unsetChild($alias)
{
if (isset($this->_children[$alias])) {
unset($this->_children[$alias]);
}
if (!empty($this->_sortedChildren)) {
$key = array_search($alias, $this->_sortedChildren);
if ($key !== false) {
unset($this->_sortedChildren[$key]);
}
}
return $this;
}
and
/**
* Insert child block
*
* @param Mage_Core_Block_Abstract|string $block
* @param string $siblingName
* @param boolean $after
* @param string $alias
* @return object $this
*/
public function insert($block, $siblingName = '', $after = false, $alias = '')
{
if (is_string($block)) {
$block = $this->getLayout()->getBlock($block);
}
if (!$block) {
/*
* if we don't have block - don't throw exception because
* block can simply removed using layout method remove
*/
//Mage::throwException(Mage::helper('core')->__('Invalid block name to set child %s: %s', $alias, $block));
return $this;
}
if ($block->getIsAnonymous()) {
$this->setChild('', $block);
$name = $block->getNameInLayout();
} elseif ('' != $alias) {
$this->setChild($alias, $block);
$name = $block->getNameInLayout();
} else {
$name = $block->getNameInLayout();
$this->setChild($name, $block);
}
if ($siblingName === '') {
if ($after) {
array_push($this->_sortedChildren, $name);
} else {
array_unshift($this->_sortedChildren, $name);
}
} else {
$key = array_search($siblingName, $this->_sortedChildren);
if (false !== $key) {
if ($after) {
$key++;
}
array_splice($this->_sortedChildren, $key, 0, $name);
} else {
if ($after) {
array_push($this->_sortedChildren, $name);
} else {
array_unshift($this->_sortedChildren, $name);
}
}
$this->_sortInstructions[$name] = array($siblingName, (bool)$after, false !== $key);
}
return $this;
}
Local xml parameters are important, then, not in name (specifically), but in order ie:
<reference name="left">
<action method="insert">
<block>catalog.product.related</block>
<siblingName>catalog.leftnav</siblingName>
<after>1</after>
<alias>catalog_product_related</alias>
</action>
</reference>
Ultimately, this makes local.xml a really powerful method of manipulating the system, but if you are unfamiliar with it and the magento system, get ready for weeks or months of work to really get your head around it.
Cheers
I've run into the problem several times now, where a block I want to move has been removed. This is a problem, as any block that has been removed from layout is nuked forever.
However, with Alan Storm's very handy Unremove Plugin you can undo whats been done:
<checkout_onepage_index>
<x-unremove name="left" />
<reference name="right">
<action method="unsetChild">
<alias>checkout.progress.wrapper</alias>
</action>
</reference>
<reference name="left">
<action method="insert">
<block>checkout.progress.wrapper</block>
</action>
</reference>
</checkout_onepage_index>
It manages this feat by watching the layout object, and building a list of removed blocks, which can be later referenced.
Nice!
For moving a block to another destination, we need to use the <move> tag with a specific element name and destination place. <move> Tag will set the declared block or container element as a child of another element in the specified order.
Use following code snippet in layout file to move blocks and containers. Here is an example. We will move price block to media block on product page. Now we will move the price block.
On the Admin Panel, Content > Elements > Pages . Choose the page where you want to place the block, then open the edit mode. On the left panel, select the Design tab, in the Layout Update XML box, insert the code for the right or left sidebar.
Containers are what page framework is built from. They are the basic elements of Magento page structure. Header, footer, left sidebar, main column are the main containers of a Magento webpage.
This is a dusty thread now, but for the record, this is the final answer I went with.
<reference name="right">
<action method="unsetChild">
<alias>checkout.progress.wrapper</alias>
</action>
</reference>
<reference name="left">
<action method="insert">
<block>checkout.progress.wrapper</block>
</action>
</reference>
Magento recommends including this in your local.xml
, and it has proved an effective technique.
An alternative approach is to rename the "right" block to "left" rather than move blocks from right to left. However, this will not work if the "right" block is being removed in the first place as I suggested might be the case in my other answer.
<remove name="left" />
<reference name="right">
<action method="setNameInLayout"><name>left</name></action>
</reference>
<reference name="root">
<action method="setChild"><alias>left</alias><name>left</name></action>
<action method="unsetChild"><alias>right</alias></action>
</reference>
<!-- make sure nothing referencing "right" comes after this! -->
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With