Magento 2.3 - Topmenü-Registerkarten mit falscher (zwischengespeicherter) 'aktiver' Klasse

10

Ich habe ein kleines Menüproblem. Die aktiven Registerkarten stimmen nicht mit der aktiven Klasse überein. Wenn ich den static_blockCache deaktiviere , funktioniert er wieder, sodass das Menü tatsächlich zwischengespeichert ist und weiterhin den zwischengespeicherten Inhalt anzeigt, unabhängig von der ausgewählten Registerkarte.
Ich habe versucht, cacheable=falseden Block des betreffenden Topmenüs im default.xmlLayout zu aktivieren, aber dies hat nichts geändert.
wenn jemand dieses Problem bereits hatte oder einen Vorsprung hat ...

Bearbeiten:
Ich habe es schnell behoben, indem ich das Topmenü aus dem Cache entfernt habe (wenn ich verstanden habe, was ich richtig gemacht habe), aber wie Sie sehen, ist es nicht schrecklich, aber es funktioniert jetzt sehr gut

<?php

namespace MyNamespace\Indo\Block\Html;

use Magento\Framework\Data\Tree\NodeFactory;
use Magento\Framework\Data\TreeFactory;
use Magento\Framework\View\Element\Template;
use Magento\Framework\View\LayoutFactory;
use TemplateMonster\Megamenu\Helper\Data;

class Topmenu extends \Magento\Theme\Block\Html\Topmenu
{


    public $_helper;

    public $_layoutFactory;

    public function __construct(
        Template\Context $context,
        NodeFactory $nodeFactory,
        TreeFactory $treeFactory,
        Data $helper,
        LayoutFactory $layoutFactory,
        array $data = []
    )
    {
        parent::__construct($context, $nodeFactory, $treeFactory, $data);
        $this->_helper        = $helper;
        $this->_layoutFactory = $layoutFactory;
    }

    /**
     * Get block cache life time
     *
     * @return int
     * @since 100.1.0
     */
    protected function getCacheLifetime()
    {
        return 0;
    }
}
arno
quelle
1
+1 für gute Frage;)
Chirag Patel

Antworten:

4

Nach meinem Verständnis gibt es keine perfekte Lösung für dieses Problem. Unabhängig davon, für welches Update Sie sich entscheiden, hat es seine Nachteile.

Ich denke, es gibt möglicherweise auch zwei andere Techniken, die Sie verwenden können: ESI (Edge Side Includes) oder Locher. Obwohl ich keine Erfahrung oder Kenntnisse darüber habe, wenn dies gültige Techniken für diesen Zweck sind. Ich werde jemanden, der sie besser versteht, erklären lassen.

TLDR

Wenn Sie möchten, dass das Navigationssystem immer den richtigen aktiven Status anzeigt und es Ihnen nichts ausmacht, einen kleinen Leistungstreffer zu erzielen, deaktivieren Sie das Caching im Navigationsblock und versuchen Sie, ihn so nahe wie möglich am Stammblock zu halten.

Wenn Sie maximale Leistung wünschen, deaktivieren Sie das serverseitige Rendern und hoffen Sie, dass der Besucher JS aktiviert hat.


Überblick

In Magento gibt es sowohl serverseitige als auch clientseitige Logik, um den aktiven Status für Navigationselemente festzulegen. Standardmäßig ist aus irgendeinem Grund sowohl die server- als auch die clientseitige Logik aktiv.

Serverseitige Logik

Das Problem bei der Verwendung der serverseitigen Logik besteht darin, dass Sie den Block nicht zwischenspeichern können, da Sie auch diesen aktiven Status zwischenspeichern werden. Wenn Sie das Caching für das Navigationsmenü deaktivieren, ist das beste Szenario, dass Sie nur den Ganzseiten-Cache ungültig machen. Im schlimmsten Fall machen Sie einige andere Blöcke wie den Header usw. ungültig, je nachdem, wie Ihr Thema eingerichtet ist.

Die serverseitige Logik finden Magento\Theme\Block\Html\Topmenu::_getMenuItemClasses() Sie unter Sie verwendet die Eigenschaften is_activeund has_activefür das übergebene Baumknotenattribut, die in festgelegt sindMagento\Catalog\Plugin\Block\Topmenu::getCategoryAsArray

Clientseitige Logik

Der Nachteil dieser Methode ist, dass bis zum Laden des JS kein aktiver Status markiert ist. Und wenn der Client JS deaktiviert hat, hat er überhaupt keine aktive Anzeige.

Die Funktion, die die clientseitige Logik verarbeitet lib/web/mage/menu.js::_setActiveMenu() , funktioniert so, dass sie die href der Navigationselemente durchsucht und prüft, ob eine mit der aktuellen URL übereinstimmt.


Lösungen

Caching deaktivieren

Sie können das Caching im Navigationsblock deaktivieren. Dadurch wird auch das Caching in den übergeordneten Blöcken deaktiviert. Befindet sich Ihr Navigationsblock also innerhalb Ihres Headerblocks, wird Ihr Header auch nicht zwischengespeichert.

Sie können dies tun, indem Sie TTLden catalog.topnavWert auf dem XML-Knoten festlegen, 0der dem Überschreiben des Blocks und dem Überschreiben der Cache-Lebensdauer entspricht.

<reference name="catalog.topnav" ttl="0"/>

Verwenden Sie die clientseitige Logik

Die andere Methode besteht darin, den aktiven Status zu deaktivieren, der auf der Serverseite gerendert wird, und sich auf die clientseitige Logik zu verlassen.

Da die Magento\Theme\Block\Html\Topmenu::_getMenuItemClasses()Methode privat ist, können wir kein Plugin verwenden, um das Ergebnis zu ändern. Sie können die Klasse mit einer Voreinstellung und entweder überschreiben

  • Rufen Sie die übergeordnete Methode auf und entfernen Sie activeund has-activeaus dem endgültigen Array
  • Deklarieren Sie die Methode ohne die Logik neu, in der die aktive Klasse hinzugefügt wird.
Sam
quelle
Also, was machen wir dann? Wollen Sie damit sagen, dass jeder, der Magento verwendet, mit diesem Problem konfrontiert wird? Ich habe gerade ein Upgrade von 2.2.5 auf 2.2.9 durchgeführt und dieses Problem ist aufgetreten. Die aktive Klasse ändert sich nicht und zwei aktive Menüs werden zusammen im Frontend angezeigt.
Mohammed Joraid
2

Die @arno-Lösung in der ursprünglichen Frage funktioniert perfekt für mich, aber ich wollte die Implementierung des Codes etwas erweitern. Sowie die Vereinfachung des nicht benötigten Codes.

Erstellen Sie ein benutzerdefiniertes Modul für die Änderungen

app / code / VendorName / ModuleName / registration.php

<?php
\Magento\Framework\Component\ComponentRegistrar::register(
\Magento\Framework\Component\ComponentRegistrar::MODULE,
'VendorName_ModuleName',
__DIR__
);

app / code / VendorName / ModuleName / 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="VendorName_ModuleName" setup_version="1.0.0">
        <sequence>
            <module name="Magento_Theme"/>
        </sequence>
    </module>
</config>

app / code / VendorName / ModuleName / etc / 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\Theme\Block\Html\Topmenu" type="VendorName\ModuleName\Block\Html\Topmenu" />
</config>

app / code / VendorName / ModuleName / Block / Html / Topmenu.php

<?php

namespace VendorName\ModuleName\Block\Html;

class Topmenu extends \Magento\Theme\Block\Html\Topmenu
{
    /**
     * Get block cache life time
     *
     * @return int
     * @since 100.1.0
     */
    protected function getCacheLifetime()
    {
        return 0;
    }
}
RLTcode
quelle
+1 Ich bin neu in M2, also hat mir das geholfen
AdRock
1

Ihre Lösung sieht gut aus, aber meines Wissens CacheLifetimewird der Cache für diese Seite deaktiviert, wenn Sie auf Null gesetzt sindcacheable=false

Daher möchte ich empfehlen, den Cache programmgesteuert zu entfernen, anstatt CacheLifetimeNull zu setzen.

Sie können den Cache programmgesteuert auf folgende Weise löschen.

Konstruktor definieren - übergeben Magento\Framework\App\Cache\TypeListInterfaceund Magento\Framework\App\Cache\Frontend\Poolan den Konstruktor Ihrer Datei übergeben, wie unten definiert.

public function __construct(
    Context $context,
    \Magento\Framework\App\Cache\TypeListInterface $cacheTypeList,
    \Magento\Framework\App\Cache\Frontend\Pool $cacheFrontendPool
) {
    parent::__construct($context);
    $this->_cacheTypeList = $cacheTypeList;
    $this->_cacheFrontendPool = $cacheFrontendPool;
}

Fügen Sie nun den folgenden Code zu der Methode hinzu, in der Sie den clear/flushCache erstellen möchten

$types = array('config','layout','block_html','collections','reflection','db_ddl','eav','config_integration','config_integration_api','full_page','translate','config_webservice');
foreach ($types as $type) {
    $this->_cacheTypeList->cleanType($type);
}
foreach ($this->_cacheFrontendPool as $cacheFrontend) {
    $cacheFrontend->getBackend()->clean();
}

Auf diese Weise können Sie den Cache bereinigen und leeren.

Hinweis: Im obigen Code habe $types=ich alle Arten von Cache definiert. Sie können den Cache-Typ gemäß Ihren Anforderungen definieren.

Es gibt eine andere Methode zum Löschen des Cache, wenn Sie keinen Cache-Typ fest codieren möchten

public function __construct(
    \Magento\Framework\App\Cache\Manager $cacheManager
) {
    $this->cacheManager = $cacheManager;
}

private function whereYouNeedToCleanCache()
{
    $this->cacheManager->flush($this->cacheManager->getAvailableTypes());

    // or this
    $this->cacheManager->clean($this->cacheManager->getAvailableTypes());
}

Ich hoffe, es hilft!

Chirag Patel
quelle
1
Wenn Sie diesen Cache-Flush-Code auf einer der Frontend-Katalogseiten hinzufügen, ist dies ein großer Leistungsverlust. Gleichzeitiges Lesen und Schreiben des Cache belastet die Serverressourcen. Dies ist ein kleines Problem. Er sollte den Seiten-Cache nicht deaktivieren / bereinigen oder den Cache für einen kleinen visuellen Fehler blockieren.
obskure
@obscure Es könnte ein Leistungsabfall sein. Ich möchte nur vermeiden, mehr mit cache lifetime& zu spielen, cachable=falseda es sich um einen deaktivierten Cache für die gesamte Seite handelt und möglicherweise die Chance auf ein neues Problem besteht. Vielen Dank.
Chirag Patel
Wenn wir Cache Flush programmgesteuert verwenden, wird das Element nicht aus dem Cache gerendert. Ich war auch mit diesem Problem vor 1 Jahr mit Lack-Cache magento.stackexchange.com/questions/229527/…
Chirag Patel