El menú de Magento 2 desaparece

El menú principal de Magento 2 puede desaparecer por diferentes causas.

Block catalog.topnav y ESI de Varnish

El menú principal de Magento 2 está definido en el bloque catalog.topnav. Este bloque tiene un atributo ttl con el tiempo 3600 segundos equivalente a 1 hora. El ttl es Time To Live, el tiempo de vida de un proceso. En este caso el tiempo de vida del caché del bloque del menú.

        
            <block class="Magento\Theme\Block\Html\Topmenu" name="catalog.topnav" template="Magento_Theme::html/topmenu.phtml" ttl="3600" before="-"/>
        
    

Este atributo ttl opcional sirve para dar orden al sistema de caché de Magento invalidar el caché del menú cada hora. Por defecto el caché del contenido público se refresca cada 86400 segundos, equivalente a 1 día, pero los bloques pueden tener diferentes ttl.

Los bloques que tienen ttl, tendrán su propia petición esi de Varnish. En este caso el bloque catalog.topnav tendrá una petición como la siguiente:

        
            ReqURL  /tienda/page_cache/block/esi/blocks/%5B%22catalog.topnav%22%5D/handles/WyJkZWZhdWx0IiwiY21zX25vcm91dGVfaW5kZXgiLCJjbXNfcGFnZV92aWV3Il0%3D/
        
    

El segmento que va después de handles está codificado con base64. Si queremos saber la información, tendremos que descodificarlo.

Una de las maneras de descodificar es usando la función adob() de Javascript. Recordar descodificar antes la url con decodeURIComponent().

        
            atob(decodeURIComponent('WyJkZWZhdWx0IiwiY21zX25vcm91dGVfaW5kZXgiLCJjbXNfcGFnZV92aWV3Il0%3D'));
            # Output, un array de handles
            '["default","cms_noroute_index","cms_page_view"]
        
    

Es decir, esta petición trae caché del bloque catalog.topnav para los handles default, cms_noroute_index y cms_page_view.

Mala configuración del sistema de caché: Varnish vs Built In

Si hemos configurado el Full page caché con Varnish y no tenemos este servicio instalado y bien configurado, el menú no aparecerá porque Magento intentará traer los datos del caché de Varnish (ESI: Varnish Edge Side Includes) y no hay.

La ruta de la configuración es Stores > Settings > Configuration > Advanced > System > Full Page Cache.

app/code/Magento/PageCache/Observer/ProcessLayoutRenderElement.php
        
            /**
             * Replace the output of the block, containing ttl attribute, with ESI tag
             *
             * @param \Magento\Framework\View\Element\AbstractBlock $block
             * @param \Magento\Framework\View\Layout $layout
             * @return string
             */
            private function _wrapEsi(
                \Magento\Framework\View\Element\AbstractBlock $block,
                \Magento\Framework\View\Layout $layout
            ) {
                $handles = $layout->getUpdate()->getHandles();
                $pageSpecificHandles = $this->entitySpecificHandlesList->getHandles();
                $url = $block->getUrl(
                    'page_cache/block/esi',
                    [
                        'blocks' => $this->jsonSerializer->serialize([$block->getNameInLayout()]),
                        'handles' => $this->base64jsonSerializer->serialize(
                            array_values(array_diff($handles, $pageSpecificHandles))
                        )
                    ]
                );
                // Varnish does not support ESI over HTTPS must change to HTTP
                $url = ($url && substr($url, 0, 5) === 'https') ? 'http' . substr($url, 5) : $url;
                return sprintf('<esi:include src="%s" />', $url);
            }
        
    

Revisión del fichero VCL de configuraciones de Varnish

Si Varnish falla para la petición del fragmento del Top Menú, el menú tampoco se mostrará. En este caso verás algo como Varnish Service Unvailable en el código fuente de la página. Para ver logs de Varnish, ejecutamos el siguiente comando con el usuario root

    
       sudo varnishlog | grep -B 2 -A 2 -i 'VCL_Error'
       # ó
       sudo varnishlog -q 'RespStatus == 503' -g request
    
    

El output puede ser como el siguiente:

        
           VCL_call       HIT
           VCL_return     restart
           VCL_Error      Too many restarts
           RespProtocol   HTTP/1.1
           RespStatus     503
           RespReason     Service Unavailable
        
    

Entonces vamos a revisar el fichero de configuraciones en nuestro servidor /etc/varnish/default.vcl con el fichero vcl de Magento. Los comparamos. El error puede ser porque tenemos el vcl desactualizado.

Commando para generar el fichero vcl de Magento para Varnish

        
            bin/magento varnish:vcl:generate --export-version=6 --access-list localhost --backend-host localhost --backend-port 8080 --output-file var/default.vcl
        
    

Solución temporal

Si tenemos prisas y todo lo comentado anteriormente no da resultados, nos queda una solución rápida, que es eliminar el atributo opcional ttl del block catalog.topnav. Esta solución afectará el performance de la WEB, por lo tanto tiene que ser algo urgente y temporal. El menú está casi en todas las páginas. Una página lenta puede afectar negativamente las ventas.

Referencias