Removing and Moving
remove deletes an element and its children, display hides it, move reparents it; each fails in its own way.
<referenceBlock name="..." remove="true"/> | <move element="..." destination="..." after="..."/>Three directives change a page you did not write: the remove attribute, the display attribute and <move>. They are the reason you rarely need to edit a core file.
remove and display
<referenceBlock name="x" remove="true"/> takes the element and all its children out of the layout. The default is false, and a handle merged later can set remove="false" to cancel a removal. display="false" is different: the element stays in the layout and its object is still available to other code, but it renders nothing. When remove is true, display is ignored.
move
<move> reparents an element. element and destination are required; as, before and after are optional. Moves are processed before removals, so an element moved into a container that is being removed is removed with it.
What trips people up
Removing a core element can break a feature that looks unrelated. Magento_Theme puts the block formkey inside the content container. Remove that container and $block->getBlockHtml('formkey') in the product form template returns an empty string, so the hidden form key is missing and add-to-cart fails with an invalid form key message. Hide a thing with display="false" before reaching for remove, keep the target as narrow as possible, and run bin/magento cache:flush.
Example
<!-- app/code/Acme/Delivery/view/frontend/layout/catalog_product_view.xml -->
<page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd">
<body>
<!-- gone from the layout, with its children -->
<referenceBlock name="product.info.mailto" remove="true"/>
<!-- still in the layout, renders nothing -->
<referenceBlock name="view.addto.compare" display="false"/>
<!-- reparented, not duplicated -->
<move element="product.info.sku"
destination="product.info.price"
after="product.price.final"/>
</body>
</page>When to use it
- Hide the compare link on product pages for one theme.
- Move the coupon form above the totals on the cart page.
- Restore a block that a third-party module removed.
- Drop a core stylesheet your theme replaces.
More examples
Undoing someone else's removal
A module removed the Email to a Friend block and the merchant wants it back on one theme. remove="false" cancels the removal, and because theme files are merged after module files this wins without changing the module. Reach for it when a third-party extension removes something you need and you would rather not patch the extension.
<!-- app/design/frontend/Acme/storefront/Magento_Catalog/layout/catalog_product_view.xml -->
<page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd">
<body>
<referenceBlock name="product.info.mailto" remove="false"/>
</body>
</page>Moving a block between parents
before and after cannot cross parents, so this is the only way to lift a block out of one container and into another: move it, then position it inside the new parent with before="-" for first. Confirm both names exist in the merged layout first, because a move with an unknown element or destination simply does not happen.
<!-- app/code/Acme/Delivery/view/frontend/layout/checkout_cart_index.xml -->
<page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd">
<body>
<move element="checkout.cart.coupon" destination="checkout.cart.totals.container" before="-"/>
</body>
</page>Dropping a stylesheet instead of a block
This is the other <remove>, and the only one that works as an element. It takes src, not name, and it unlinks a stylesheet or script that another layout file added to the page head. Useful when a theme ships its own date picker styling and the core file would otherwise load twice. Run bin/magento cache:flush; in production mode also confirm the asset is no longer referenced in the rendered head.
<!-- app/design/frontend/Acme/storefront/Magento_Theme/layout/default_head_blocks.xml -->
<page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd">
<head>
<remove src="mage/calendar.css"/>
</head>
</page>
Discussion