Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Magento - move block from right to left

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


Yet another update

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!

like image 795
Bosworth99 Avatar asked Mar 15 '12 19:03

Bosworth99


People also ask

How do I change the position of a block in Magento 2?

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.

How do I move elements in Magento 2?

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.

How do you add a block to the sidebar in Magento 2?

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.

What is container magento2?

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.


2 Answers

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.

like image 176
Bosworth99 Avatar answered Oct 04 '22 23:10

Bosworth99


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! -->
like image 39
ColinM Avatar answered Oct 04 '22 23:10

ColinM