0

I need to move several elements of a layout without using layout.xml

I have followed the bellow code to create an observer and it correctly moves a single element. When I try adding the other elements to the update it still only moves one element.

namespace Company\Module\Observer;

class LayoutLoadBefore implements \Magento\Framework\Event\ObserverInterface
{
    /**
     * add custom layout updates
     *
     * @param \Magento\Framework\Event\Observer $observer
     * @return $this
     */
    public function execute(\Magento\Framework\Event\Observer $observer)
    {
        $move = false;

        // add your checks here

        if ($move) {
            /** @var \Magento\Framework\View\LayoutInterface $layout */
            $layout = $observer->getData('layout');
            $layout->getUpdate()->addUpdate('<move element="blah" destination="to" before="-" />');
        }

        return $this;
    }
}

I Have tried:

if (isset($move) && $move) {
            /** @var LayoutInterface $layout */
            $layout = $observer->getData('layout');
         
            $layout->getUpdate()->addUpdate('<move element="product.info.details" destination="product.info.media" after="-"/>');
            $layout->getUpdate()->addUpdate('<move element="catalog.product.related" destination="product.info.media" after="-"/>');
            $layout->getUpdate()->addUpdate('<move element="product.info.upsell" destination="product.info.media" after="product.info.details"/>');
        }
    return $this;

and this:

if (isset($move) && $move) {
            /** @var LayoutInterface $layout */
            $layout = $observer->getData('layout');
            $updateXml = '<move element="product.info.details" destination="product.info.media" after="-"/><move element="catalog.product.related" destination="product.info.media" after="-"/>';
            
            $layout->getUpdate()->addUpdate($updateXml);
        }

        return $this; 

But neither works. Do anyone know how to achieve this?

1 Answer 1

0

In Magento 2, moving multiple blocks without using XML can be achieved programmatically. Here's an example of how you can do it:

1.Create a custom module or navigate to an existing module where you want to implement the block movement logic.

2.Inside your module, create a class, let's call it BlockMovement, and define a method, for example, moveBlocks(), to perform the block movement. Here's an example implementation:

<?php

namespace Vendor\ModuleName;

use Magento\Framework\View\LayoutInterface;

class BlockMovement
{
    protected $layout;

    public function __construct(LayoutInterface $layout)
    {
        $this->layout = $layout;
    }

    public function moveBlocks()
    {
        $blockNames = ['block_name1', 'block_name2', 'block_name3'];
        $destination = 'destination_container_name';

        foreach ($blockNames as $blockName) {
            $block = $this->layout->getBlock($blockName);
            if ($block) {
                $this->layout->unsetElement($blockName);
                $this->layout->setBlock($destination, $block);
            }
        }
    }
}

4.In your module's di.xml file, configure a virtual type for the BlockMovement class and specify the layout argument:

<config>
    <preference for="Vendor\ModuleName\BlockMovement" type="Vendor\ModuleName\BlockMovement" />
    <virtualType name="Vendor\ModuleName\BlockMovement" type="Vendor\ModuleName\BlockMovement">
        <arguments>
            <argument name="layout" xsi:type="object">Magento\Framework\View\LayoutInterface</argument>
        </arguments>
    </virtualType>
</config>

5.Now, you can use dependency injection to instantiate the BlockMovement class in your desired controller, block, or any other class and call the moveBlocks() method to perform the block movement. For example:

<?php

namespace Vendor\ModuleName\Controller\Index;

use Magento\Framework\App\Action\Action;
use Vendor\ModuleName\BlockMovement;

class Index extends Action
{
    protected $blockMovement;

    public function __construct(
        Action\Context $context,
        BlockMovement $blockMovement
    ) {
        parent::__construct($context);
        $this->blockMovement = $blockMovement;
    }

    public function execute()
    {
        // Call the moveBlocks() method to move the blocks
        $this->blockMovement->moveBlocks();

        // ...
        // Rest of your controller logic
        // ...
    }
}
  • By following these steps, you can move multiple blocks programmatically without using XML in Magento 2. Remember to adjust the block names, destination container name, and module details according to your specific requirements.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.