Sobreescribir un bloque y un template en Magento2 (di.xml)

di.xml en Magento2

Otra de las novedades (o de las nuevas formas de hacer las cosas) en Magento2 es la inyección de dependencias. Para quienes no estén familiarizados con el patrón, algo de lectura introductoria, explicación de cómo opera en Magento y documentación oficial.

Ahora bien, vayamos a un ejemplo de la vida real, uno de esos con los cuales en más de una oportunidad nos vamos a chocar en el día a día: Sobreescribir un bloque.

Nuevamente voy a hacer uso del módulo Barbanet_SampleModule, y sólo a fines didácticos voy a modificar el footer de Magento2.

Entonces, dado que ayer creé mi theme Barbanet/SampleTheme, mi home hoy se ve así.

Homepage Magento2

Y el footer, en particular:

Footer en Magento2

Voy a aplicar dos modificaciones al mismo tiempo, pero una mediante el bloque que devuelve el string de copyright y la otra mediante el reemplazo del archivo phtml.

Lo primero, crear mi propio bloque Footer, que se ubicará en /Block/Html/Footer.php, para reempalzar a \Magento\Theme\Block\Html\Footer.

<?php
 
namespace Barbanet\SampleModule\Block\Html;
 
/**
 * Html page footer block
 */
class Footer extends \Magento\Theme\Block\Html\Footer
{
 
    /**
     * Retrieve copyright information + a sample modification
     *
     * @return string
     */
    public function getCopyright()
    {
        if (!$this->_copyright) {
            $this->_copyright = $this->_scopeConfig->getValue(
                'design/footer/copyright',
                \Magento\Store\Model\ScopeInterface::SCOPE_STORE
            );
            $this->_copyright .= " No hagan esto en casa sin la supervisión de un adulto.";
        }
        return $this->_copyright;
    }
}

De más está aclarar que la modificación que le hice es demasiado tonta y sólo tiene como utilidad su costado didáctico.

Una vez que el bloque exista, vamos a generar dentro del directorio /etc de nuestro módulo, el archivo di.xml, y vamos a agregarle este contenido.

<?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\Theme\Block\Html\Footer" type="Barbanet\SampleModule\Block\Html\Footer" />
</config>

Básicamente, le estamos diciendo a Magento que cuando se invoque el objeto Magento\Theme\Block\Html\Footer, en lugar de ejecutar ese, invoque Barbanet\SampleModule\Block\Html\Footer.

Como la clase Barbanet\SampleModule\Block\Html\Footer extiende del original, todos sus métodos estarán disponibles.

Ahora veamos la segunda parte, que será reemplazar el phtml que usa dicho bloque (esto no es necesario para probar la inyección de dependencia, sino que intencionalmente estoy modificando tanto el bloque con el template).

Voy a crear, siempre dentro de mi módulo, el template /view/frontend/templates/html/copyright.phtml.

<small class="copyright">
    <span><?php /* @escapeNotVerified */ echo $block->getCopyright() ?></span>
    <p>Block and template override</p>
</small>

No es más que una copia del original con una línea extra. Nuevamente, la intención es probar como alterar el comportamiento de los bloques y las plantillas.

Y ahora, vía layout, hacemos el reemplazo.

<?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">
    <head>
        <title>Barbanet Sample Module Default title</title>
    </head>
    <referenceBlock name="copyright">
        <action method="setTemplate">
            <argument name="template" xsi:type="string">Barbanet_SampleModule::html/copyright.phtml</argument>
        </action>
    </referenceBlock>
</page>

Un detalle a tener en cuenta con esto, es la secuencia de los módulos. Dentro de /etc/module.xml, teníamos esta definición:

<?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="Barbanet_SampleModule" setup_version="2.3.0">
        <sequence>
            <module name="Magento_Store"/>
        </sequence>
    </module>
</config>

Le agregamos el módulo Magento_Theme, para garantizar que se lea primero ese y luego el nuestro, dejando el código final así:

<?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="Barbanet_SampleModule" setup_version="2.3.0">
        <sequence>
            <module name="Magento_Store"/>
            <module name="Magento_Theme"/>
        </sequence>
    </module>
</config>

Hecho todo, activé los template path hints (que están donde siempre, con el agregado que hay un parámetro de configuración adicional para el adminhtml), y al recargar, puedo ver que:

Override del bloque footer en Magento2
Override del bloque footer en Magento2

Por un lado, en lugar de usar el bloque original del footer se está usando el que definí. A nivel template, ya no se lee el original del theme (que es una herencia de mi theme definido), sino que se aplicó mi phtml.

El resultado final:

Footer sobreescrito en Magento2

Y la home funciona como al comienzo, salvo el footer.

Los cambios al módulo Barbanet_SampleModule que se mostraron aquí fueron agregados en el tag 2.3.0.