Como sobrescribir una plantilla en Magento 2

Magento 2

Alberto Privado

  Magento 2

Sobrescribir una plantilla en Magento es algo que se realiza muy a menudo. Casi siempre se trata de una tarea trivial y sencilla, pero, en ocasiones, esta tarea se complica, hasta el punto de parecer casi imposible.

Por eso aquí vamos a explicar como sobrescribir las plantillas por defecto de Magento 2

Método 1: Ruta del archivo del tema

Este método se utiliza cuando queremos crear un tema. Para sobrescribir cualquier módulo o tema, basta con colocar nuestra plantilla en <directorio_del_tema>/<Proveedor_Modulo>/ruta/del/archivo

Por ejemplo, si queremos reemplazar el header en el módulo Magento_Theme de nuestro tema llamado Comerline, tendremos que colocar la plantilla en

Comerline/Magento_Theme/view/html/header.phtml

Método 2: Argumento de diseño de bloque

Este método se utiliza cuando queremos crear un módulo. Para sobrescribir con este método, lo único que tenemos que hacer es anular el argumento de plantilla del bloque. Tomando como ejemplo la plantilla Magento_Wishlist/view/frontend/templates/view.phtml, para reemplazar view.phtml, primero debemos crear en el módulo donde queramos remplazar dicha plantilla el sigiuente archivo XML:
<Proveedor>_<Módulo>/view/frontend/layout/wishlist_index_index.xml

Una vez hecho, podemos seguir uno de los dos métodos existentes para reemplazar la plantilla

Método nuevo

wishlist_index_index.xml

<?xml version="1.0"?>
<page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd">
    <body>
        <referenceBlock name="customer.wishlist">
            <arguments>
                <argument name="template" xsi:type="string">Proveedor_Modulo::view.phtml</argument>
            </arguments>
        </referenceBlock>
    </body>
</page>
Método antiguo (obsoleto, pero útil en algunos casos)

whislist_index_index.xml

<?xml version="1.0"?>
<page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd">
    <body>
        <referenceBlock name="customer.wishlist">
            <action method="setTemplate">
                <argument name="template" xsi:type="string">Proveedor_Modulo::view.phtml</argument>
            </action>
        </referenceBlock>
    </body>
</page>

El método nuevo es el apropiado para remplazar la plantilla, pero hay algunas situaciones en las que no funciona, por lo que es buena idea probar con el método antiguo para solucionar este problema.

Una vez hecho esto, debemos colocar nuestra plantilla personalizada en la ubicación que hemos especificado en el archivo XML, en este caso:
<Proveedor>_<Módulo>/view/frontend/templates/view.phtml

Por último, para hacer que el remplazo tenga efecto, hay que añadir unas líneas a nuestro archivo module.xml, el cual quedaría así para nuestro ejemplo:

etc/module.xml

<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Module/etc/module.xsd">
    <module name="Proveedor_Modulo" setup_version="100.0.0">
        <sequence>
            <module name="Magento_Wishlist"/>
        </sequence>
    </module>
</config>

Con esta modificación haremos que el módulo Magento_Wishlist se cargue, lo que nos garantiza el remplazo de la plantilla que queremos cambiar

Método 3: Preferencia de Clase

En algunos casos existen definiciones de bloque donde se incluye un atributo de plantilla, pero no un atributo de nombre. Estas definiciones de bloque no se pueden remplazar utilizando los métodos ya mencionados, pero eso no significa que no se pueda hacer. Utilizando el método de preferencia de clase podremos conseguir reemplazar la plantilla

En el siguiente ejemplo remplazaremos el bloque que contiene la plantilla cart/item/default.phtml en Magento/Checkout/view/frontend/layout/checkout_cart_item_renderers.xml

<block class="Magento\Checkout\Block\Cart\Item\Renderer" as="virtual" template="cart/item/default.phtml">

Como el alcance de la ruta de la plantilla lo establece el atributo de clase en el bloque, un prefijo Proveedor_Módulo parece innecesario si la plantilla y la clase del bloque están en el mismo módulo. Si queremos cambiar el alcance del módulo de la plantilla, solo tenemos que remplazar la clase del bloque con una preferencia de clase en el archivo di.xml

di.xml

<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
    <preference for="Magento\Checkout\Block\Cart\Item\Renderer" type="Proveedor\Modulo\Block\Checkout\Cart\Item\Renderer" />
</config>

Aunque no es necesario personalizar el bloque, hay que asegurarse de que dicho bloque existe. Para garantizar eso, lo único que hay que hacer es crear un bloque esqueleto

Renderer.php

<?php
/**
 * Este bloque sirve como una clase esqueleto para cambiar el alcance de la definición de bloque 
 * El atributo de plantilla en el bloque ahora será predeterminado para este módulo
 * en lugar del módulo central en la definición de bloque original
 */
namespace Proveedor\Modulo\Block\Checkout\Cart\Item;
class Renderer extends \Magento\Checkout\Block\Cart\Item\Renderer {}

Por último, para terminar de remplazar la plantilla, lo único que necesitamos hacer es añadir nuestra plantilla como cuando se hacer un remplazo normal desde el diseño. En este ejemplo la ruta sería Proveedor/Módulo/view/frontend/templates/cart/item/default.phtml

Esta solución, obviamente, solo es prudente hacerla en casos muy determinados

Método 4: Plugin

La preferencia de clase es una forma aceptable de anular la plantilla para todas las instancias de una clase y cuando el prefijo Vendor_Namespace falta en el atributo de plantilla. Sin embargo, en casos específicos, se debe ser más específico. Aquí es donde un plugin es útil

En este ejemplo usaremos un plugin para sobrescribir Magento_Catalog::category/products.phtml con nuestra plantilla

Así es como se ve la definición de bloque original para la plantilla de vista de categoría:

<block class="Magento\Catalog\Block\Category\View" name="category.products" template="Magento_Catalog::category/products.phtml">

Tendremos que conectar el plugin a la clase Magento\Catalog\Block\Category\View. La plantilla se cogerá y convertirá en HTML mediante el método toHtml(). Para remplazar esa plantilla, necesitamos cambiar la variable $_template en nuestra propia plantilla. Por suerte, ya existe un método en la clase Template. Teniendo esto en cuenta, podemos crear nuestro plugin y nuestro archivo di.xml

di.xml

<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
    <type name="Magento\Catalog\Block\Category\View">
        <plugin name="module_catalog_category_view_override_template" type="Proveedor\Modulo\Plugin\Catalog\Block\Category\View" />
    </type>
</config>

view.php

<?php
namespace Proveedor\Modulo\Plugin\Catalog\Block\Category;

class View
{
    public function beforeToHtml(\Magento\Catalog\Block\Category\View $subject)
    {
        if ($template === 'Magento_Catalog::category/products.phtml') {
            $subject->setTemplate('Proveedor_Modulo::catalog/category/products.phtml');
        }
    }
}

Para finalizar el proceso de remplazo de la plantilla, solo necesitamos colocar dicha plantilla en la ubicación adecuada, en este caso:
Proveedor/Modulo/view/frontend/templates/catalog/category/products.phtml

Solo se debe usar este método si el bloque no tiene ningún nombre y si tiene un prefijo Proveedor_Modulo y/o tiene una clase que puede manejar múltiples plantillas.

Estos son los principales métodos para sobrescribir una plantilla en Magento 2. Esperamos que os sea de ayuda este tutorial