Mehrschichtige Navigation für die benutzerdefinierte Sammlung auf einer benutzerdefinierten Seite - magento2

12

Ich arbeite daran, eine geschichtete Navigation in magento2 für eine benutzerdefinierte Produktkollektion abzurufen. Ich erhalte eine benutzerdefinierte Sammlung, die bereits auf der benutzerdefinierten Seite angezeigt werden muss, damit die geschichtete Navigation angezeigt wird. Versuchte, diese magento1-Lösung anzupassen, kam aber nicht weit.

Irgendeine Idee, wie ich es in magento2 erreichen könnte. Was ich bisher getan habe, ist wie folgt:

Erweitert den Katalog ListProduct Block für benutzerdefinierte Produktliste auf meiner benutzerdefinierten Seite.

class View extends \Magento\Catalog\Block\Product\ListProduct
{


    public function __construct(
    \Magento\Catalog\Block\Product\Context $context,
    \Magento\Framework\Data\Helper\PostHelper $postDataHelper,
    \Magento\Catalog\Model\Layer\Resolver $layerResolver,
    CategoryRepositoryInterface $categoryRepository,
    \Magento\Framework\Url\Helper\Data $urlHelper,
    array $data = [],
    \Custom\LayerNavigation\Model\Layer $testlayerobj
    ) {
        parent::__construct($context,$postDataHelper,$layerResolver,
        $categoryRepository,$urlHelper,$data);
        $this->_coreRegistry = $context->getRegistry();
        $this->_testlayer = $testlayerobj;
    }

    protected function _getProductCollection()
    {
        if ($this->_productCollection === null) {
          $this->_productCollection = $this->getLayer()->getProductCollection();
        }
        return $this->_productCollection;
     }

    public function getLayer()
    {

       $layer = $this->_coreRegistry->registry('current_layer');
       if ($layer) {
          return $layer;
        }
        return $this->_testlayer;
     }

}

Verwendet den zentralen Suchblock für die mehrschichtige Navigation in der Layoutdatei

<referenceContainer name="sidebar.main">
        <block class="Magento\LayeredNavigation\Block\Navigation\Search" name="catalogsearch.leftnav" before="-" template="layer/view.phtml">
            <block class="Magento\LayeredNavigation\Block\Navigation\State" name="catalogsearch.navigation.state" as="state" />
            <block class="Magento\LayeredNavigation\Block\Navigation\FilterRenderer" name="catalogsearch.navigation.renderer" as="renderer" template="layer/filter.phtml"/>
        </block>
</referenceContainer>

Erweitertes Core-Layer-Modell zum Ändern der Sammlung.

class Layer extends \Magento\Catalog\Model\Layer
{
    public function __construct(
      optionStoreFactory  $optionstoreFactory,
      Attrhelper $attrhelper,
      productCollectionFactory $productCollectionFactory,
      AttributevalueFactory $attributevalueFactory,
      CategoryRepositoryInterface $categoryRepository,
      \Magento\Store\Model\StoreManagerInterface $storeManager,
      \Magento\Framework\App\Request\Http $request,
      \Magento\Framework\Registry $registry,
      \Magento\Catalog\Model\Layer\Search\CollectionFilter $filter,
      array $data = []
    ) {
       $this->optionstoreFactory       = $optionstoreFactory;
       $this->attributevalueFactory    = $attributevalueFactory;
       $this->_attrhelper              = $attrhelper;
       $this->request                  = $request;
       $this->productCollectionFactory = $productCollectionFactory;
       $this->categoryRepository = $categoryRepository;
       $this->_storeManager = $storeManager;
       $this->filter = $filter;
       $this->registry = $registry;
    }

    public function getProductCollection()
    {
        $attributevalue = $this->getAttributeValue(); //eg: Manufacturer Attribute details
        $attr_code = $attributevalue->getAttributeCode();
        $attr_option_value = $attributevalue->getOptionId();
        $collection = $this->productCollectionFactory->create();
        $store_id = $this->request->getParam('store_id');
        $collection->addAttributeToSelect('*')
               ->addAttributeToFilter($attr_code , ['finset'=>$attr_option_value ])
               ->addAttributeToFilter('visibility','4')
               ->setStore($store_id)
               ->addFieldToFilter('status', array('eq' => 1))
               ->setOrder('id', 'DESC');
        $this->prepareProductCollection($collection);
        return $collection;
    }

    public function prepareProductCollection($collection)
    {
        $this->filter->filter($collection, $this->getCurrentCategory());
       return $this;
    }

    public function getCurrentCategory()
    {
       $category = $this->registry->registry('current_category');
       if ($category) {
           $this->setData('current_category', $category);
       } else {
           $category = $this->categoryRepository->get($this->getCurrentStore()->getRootCategoryId());
       $this->setData('current_category', $category);
       }
      return $category;
    }

    public function getCurrentStore()
    {
        return $this->_storeManager->getStore();
    }

}

Ab sofort wird die Ebenennavigation angezeigt, die jedoch nicht für meine benutzerdefinierte Sammlung spezifisch ist. Gemäß meinem Debugging wird die Sammlung vollständig aus der Stammkategorie herausgefiltert (die den gesamten Produktkatalog enthält) und dementsprechend werden die Ebenen abgerufen.

mp196
quelle
Jeder Vorschlag wäre sehr dankbar ..!
mp196
Haben Sie eine Lösung dafür gefunden? Wenn ja, teilen Sie bitte Ihre Antwort
Nalin Savaliya
Leute, hat jemand von euch einen Hinweis darauf?
aton1004
Es ist mir gelungen, die geschichtete Navigation auf einer benutzerdefinierten Seite für meine benutzerdefinierte Sammlung zu erstellen. Es wird einige Zeit dauern, bis die Lösung hier veröffentlicht wird, da sie sehr lang ist. (In ein oder zwei Tagen werde ich wahrscheinlich die Lösung veröffentlichen.)
dauern,

Antworten:

3

Ich konnte die Navigation mit den folgenden Änderungen erreichen. Mit dieser Lösung bin ich möglicherweise nicht ganz korrekt. Kommentare und Vorschläge sind daher sehr willkommen.

1) Bereiten Sie di.xml wie folgt für den Frontend-Abschnitt vor:

<!-- Magento only includes 2 type of layer resolvers i.e Category and search whereas our custom page is neither a category page nor a search page so we need to add a new layer resolver on our custom page-->
<type name="Magento\Catalog\Model\Layer\Resolver">
    <arguments>
        <argument name="layersPool" xsi:type="array">
            <item name="category" xsi:type="string">Magento\Catalog\Model\Layer\Category</item>
            <item name="search" xsi:type="string">Magento\Catalog\Model\Layer\Search</item>
            <item name="customlayer" xsi:type="string">Custom\Navigation\Model\Layer</item>
        </argument>
    </arguments>
</type>

<!-- To prepare the filterlist for our custom collection which would be passed to the left navigation we need below virtual types for our custom page navigation -->
<virtualType name="customFilterList" type="Custom\Navigation\Model\Layer\FilterList">
    <arguments>
        <argument name="filterableAttributes" xsi:type="object">Custom\Navigation\Model\Layer\FilterableAttributeList</argument>
        <argument name="filters" xsi:type="array">
            <item name="attribute" xsi:type="string">Custom\Navigation\Model\Layer\Filter\Attribute</item>
            <item name="category" xsi:type="string">Custom\Navigation\Model\Layer\Filter\Category</item>
        </argument>
    </arguments>
</virtualType>

<!-- once the filter list virtual type is ready we can pass the same to our navigation , I have prepared the virtual type of the core navigation for my custom module and have passed the custom filter list to it -->
<virtualType name="Custom\Navigation\Block\Navigation\Custnavigation" type="Magento\LayeredNavigation\Block\Navigation">
    <arguments>
        <argument name="filterList" xsi:type="object">customFilterList</argument>
    </arguments>
</virtualType>

<!-- As we will be modifying the layer model collection we will need to extend the core model layer, Below virtual type will be required to extend the Catalog model layer else it will throw error for the context in construct method-->
<virtualType name="Custom\Navigation\Model\Layer\Context" type="Magento\Catalog\Model\Layer\Context">
    <arguments>
        <argument name="collectionProvider" xsi:type="object">Custom\Navigation\Model\Layer\ItemCollectionProvider</argument>
        <argument name="stateKey" xsi:type="object">Custom\Navigation\Model\Layer\StateKey</argument>
        <argument name="collectionFilter" xsi:type="object">Custom\Navigation\Model\Layer\CollectionFilter</argument>
    </arguments>
</virtualType>
<type name="Custom\Navigation\Model\Layer">
    <arguments>
        <argument name="context" xsi:type="object">Custom\Navigation\Model\Layer\Context</argument>
    </arguments>
</type>

2) Modell-Layer-Datei: Erweitern Sie die Modell-Layer-Datei mit Ihrem benutzerdefinierten Modell und ändern Sie die Sammlung.

namespace Custom\Navigation\Model;
class Layer extends \Magento\Catalog\Model\Layer
{

//Apart from the default construct argument you need to add your model from which your product collection is fetched.

    public function __construct(
        \Magento\Catalog\Model\Layer\ContextInterface $context,
        \Magento\Catalog\Model\Layer\StateFactory $layerStateFactory,
        AttributeCollectionFactory $attributeCollectionFactory,
        \Magento\Catalog\Model\ResourceModel\Product $catalogProduct,
        \Magento\Store\Model\StoreManagerInterface $storeManager,
        \Magento\Framework\Registry $registry,
        CategoryRepositoryInterface $categoryRepository,
        array $data = []
    ) {
    parent::__construct(
            $context,
            $layerStateFactory,
            $attributeCollectionFactory,
            $catalogProduct,
            $storeManager,
            $registry,
            $categoryRepository,
            $data
        );
    }

    public function getProductCollection()
    {

        /*Unique id is needed so that when product is loaded /filtered in the custom listing page it will be set in the
         $this->_productCollections array with unique key else you will not get the updated or proper collection.
        */

        if (isset($this->_productCollections['some_uinique_id'])) {
            $collection = $this->_productCollections['some_uinique_id'];
        } else {
            //$collection = Your logic to get your custom collection.
            $this->prepareProductCollection($collection);
            $this->_productCollections['some_unique_id'] = $collection;
        }

        return $collection;
    }

3) Ich habe die folgenden Dateien erweitert, wie sie in der Datei di.xml verwendet werden (Ich habe die Datei durch einfaches Erweitern beibehalten und die Konstruktionsmethode nicht instanziiert, da ich bei Bedarf keine Änderungen in dieser Datei erforderlich habe. Sie können die spezifische Funktion in der erweiterten Datei ändern Dementsprechend konnte die von mir angewendete Lösung das Problem mit dem Kategoriefilter derzeit nicht lösen. Sie enthält weiterhin die Stammkategoriefilter. Daher musste eine Problemumgehung durchgeführt werden, um die Facettendaten einzuschließen (Problemumgehung siehe 4. Punkt).

- Custom\Navigation\Model\Layer\FilterList extends
           \Magento\Catalog\Model\Layer\FilterList



 - Custom\Navigation\Model\Layer\FilterableAttributeList extends
   \Magento\Catalog\Model\Layer\Category\FilterableAttributeList



 - Custom\Navigation\Model\Layer\Filter\Attribute extends
   \Magento\Catalog\Model\Layer\Filter\Attribute



 - Custom\Navigation\Model\Layer\Filter\Category extends
   \Magento\CatalogSearch\Model\Layer\Filter\Category (Why catalog
           search is used i have mentioned the same in 4th point)



 - Custom\Navigation\Model\Layer\ItemCollectionProvider extends
   \Magento\Catalog\Model\Layer\Category\ItemCollectionProvider



 - Custom\Navigation\Model\Layer\StateKey extends
   \Magento\Catalog\Model\Layer\Category\StateKey



 - Custom\Navigation\Model\Layer\CollectionFilter extends
   \Magento\Catalog\Model\Layer\Category\CollectionFilter

4) Es musste eine Problemumgehung für den Kategoriefilter in der geschichteten Navigation durchgeführt werden, da die Option in Bezug auf die gefilterte Sammlung nicht angezeigt wurde. Wenn jemand die Lösung findet, aktualisieren Sie sie bitte. Nachstehend ist der Code aufgeführt, mit dem ich den Fehler mit den Facettendaten behoben habe, der beim Einfügen der Kategorie in meine benutzerdefinierte Filterliste aufgetreten ist. Aufgrund der Anwendung dieses Patches wurde die Kategorieoption in meiner Navigation nicht angezeigt. Die übrigen Filter entsprachen meiner Sammlung.

namespace Custom\Navigation\Model\Layer\Filter;

/**
 * Layer category filter
 */
class Category extends \Magento\CatalogSearch\Model\Layer\Filter\Category
{
     /**
      * @var \Magento\Framework\Escaper
      */
    private $escaper;

    /**
     * @var CategoryDataProvider
     */
    private $dataProvider;

    /**
     * @param \Magento\Catalog\Model\Layer\Filter\ItemFactory $filterItemFactory
     * @param \Magento\Store\Model\StoreManagerInterface $storeManager
     * @param \Magento\Catalog\Model\Layer $layer
     * @param \Magento\Catalog\Model\Layer\Filter\Item\DataBuilder $itemDataBuilder
     * @param \Magento\Catalog\Model\CategoryFactory $categoryFactory
     * @param \Magento\Framework\Escaper $escaper
     * @param CategoryManagerFactory $categoryManager
     * @param array $data
     */
    public function __construct(
        \Magento\Catalog\Model\Layer\Filter\ItemFactory $filterItemFactory,
        \Magento\Store\Model\StoreManagerInterface $storeManager,
        \Magento\Catalog\Model\Layer $layer,
        \Magento\Catalog\Model\Layer\Filter\Item\DataBuilder $itemDataBuilder,
        \Magento\Framework\Escaper $escaper,
        \Magento\Catalog\Model\Layer\Filter\DataProvider\CategoryFactory $categoryDataProviderFactory,
        array $data = []
    ) {
        parent::__construct(
            $filterItemFactory,
            $storeManager,
            $layer,
            $itemDataBuilder,
            $escaper,
            $categoryDataProviderFactory,
            $data
        );
        $this->_escaper = $escaper;
        $this->_requestVar = 'cat';
        $this->dataProvider = $categoryDataProviderFactory->create(['layer' => $this->getLayer()]);
    }

    /**
     * Get data array for building category filter items
     *
     * @return array
     */
    protected function _getItemsData()
    {
        /** @var \Magento\CatalogSearch\Model\ResourceModel\Fulltext\Collection $productCollection */
        $productCollection = $this->getLayer()->getProductCollection();

        $optionsFacetedData = '' ;// $productCollection->getFacetedData('category'); (Here i have set $optionsFacetedData as blank so that category option will not be included in layered navigation)
        $category = $this->dataProvider->getCategory();
        $categories = $category->getChildrenCategories();

        $collectionSize = $productCollection->getSize();

        if ($category->getIsActive()) {
            foreach ($categories as $category) {
                if ($category->getIsActive()
                    && isset($optionsFacetedData[$category->getId()])
                    && $this->isOptionReducesResults($optionsFacetedData[$category->getId()]['count'], $collectionSize)
                ) {
                    $this->itemDataBuilder->addItemData(
                        $this->escaper->escapeHtml($category->getName()),
                        $category->getId(),
                        $optionsFacetedData[$category->getId()]['count']
                    );
                }
            }
        }
        return $this->itemDataBuilder->build();
    }
}

5) Wenn Ihre benutzerdefinierte Seite in die Ausführungsmethode Ihres Controllers geladen wird, müssen Sie die benutzerdefinierte Ebene festlegen, die wir in der Datei di.xml zusammen mit der Kategorie und der Suchebene hinzugefügt haben.

 - include the below argument in your controller construct method.

     "\Magento\Catalog\Model\Layer\Resolver $layerResolver",

 - inside execute method set your custom layer resolver for your module.

    $this->layerResolver->create('customlayer');

6) Fügen Sie in Ihrer Layout-XML-Datei für die benutzerdefinierte Seite den folgenden Code im Hauptteil hinzu.

<attribute name="class" value="page-with-filter"/>

<referenceContainer name="sidebar.main">
<!-- below is the virtual type of the core navigation we created -->
    <block class="Custom\Navigation\Block\Navigation\Custnavigation" name="custom.leftnav" before="-" template="Magento_LayeredNavigation::layer/view.phtml">
        <block class="Magento\LayeredNavigation\Block\Navigation\State" name="catalog.navigation.state" as="state" />
        <block class="Magento\LayeredNavigation\Block\Navigation\FilterRenderer" name="catalog.navigation.renderer" as="renderer" template="Magento_LayeredNavigation::layer/filter.phtml"/>
    </block>
</referenceContainer>
mp196
quelle
Ich verwende Ihren Code mit einer benutzerdefinierten Sammlung in Magento 2.1.7. aber ich bekomme eine leere Seite. Ich denke, dass Custom \ Navigation \ Block \ Navigation \ Custnavigation in den obigen Codes fehlt. Können Sie mir bitte den vollständigen Code geben?
Magiercode
Nein, es gibt keinen solchen Block. Stattdessen habe ich einen virtuellen Typ dafür erstellt. Sie können den di.xml-Code überprüfen und der hier veröffentlichte Code ist der vollständige Code.
mp196
Ok, kannst du mir bitte die Postleitzahl des gesamten Codes schicken?
Magiercode
Leider kann die Postleitzahl nicht gesendet werden, da der oben beantwortete Code nur ein kleiner Teil der von uns entwickelten kostenpflichtigen Erweiterung war.
mp196
1
Überprüfen Sie, ob Sie $ this-> layerResolver = $ layerResolver hinzugefügt haben. in Ihrem Konstrukt für die im Dateikonstruktor hinzugefügte Klasse. \ Magento \ Catalog \ Model \ Layer \ Resolver $ layerResolver
mp196
2

Ich habe meine benutzerdefinierte Produktsammlung erfolgreich auf die mehrschichtige Navigation und Symbolleiste der Kategorieseite angewendet.

Ich hole zum Beispiel die Sammlung der Produkte ab, deren Preis unter 100 liegt.

Schritt 1: Fügen Sie das folgende Code-Snippet hinzu

app / code / Vendor / Module / 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">

    <type name="Magento\Catalog\Model\Layer">
        <plugin name="custom_product_model_layer" type="Vendor\Module\Plugin\Layer" />
    </type>

    <type name="Magento\Catalog\Block\Product\ProductList\Toolbar">
        <plugin name="custom_product_toolbar" type="Vendor\Module\Plugin\Toolbar" />
    </type>

    <virtualType name="categoryFilterList" type="Magento\Catalog\Model\Layer\FilterList">
        <arguments>
            <argument name="filters" xsi:type="array">
                <item name="attribute" xsi:type="string">Magento\Catalog\Model\Layer\Filter\Attribute</item>
                <item name="price" xsi:type="string">Magento\Catalog\Model\Layer\Filter\Price</item>
                <item name="decimal" xsi:type="string">Magento\Catalog\Model\Layer\Filter\Decimal</item>
                <item name="category" xsi:type="string">Magento\Catalog\Model\Layer\Filter\Category</item>
            </argument>
        </arguments>
    </virtualType>

</config>

Schritt 2: Plugin für die Produktabholung erstellen

app / code / Vendor / Module / Plugin / Layer.php

<?php
namespace Vendor\Module\Plugin;
class Layer
{
  public function aroundGetProductCollection(
    \Magento\Catalog\Model\Layer $subject,
    \Closure $proceed
  ) {

    $result = $proceed();
    $result->addAttributeToFilter('price', array('lt' => 100));
    return $result;
  }
}

Schritt 3: Plugin für Symbolleiste erstellen

app / code / Vendor / Module / Plugin / Toolbar.php

<?php
namespace Vendor\Module\Plugin;
class Toolbar
{

  protected $_objectManager;
  protected $request;

  public function __construct(
    \Magento\Framework\ObjectManagerInterface $objectmanager,
    \Magento\Framework\App\Request\Http $request
  ) {
    $this->_objectManager = $objectmanager;
    $this->request = $request;
  }

  public function aroundSetCollection(
    \Magento\Catalog\Block\Product\ProductList\Toolbar $subject,
    \Closure $proceed,
    $request
  ) {
    $result = $proceed($request);

    $this->_collection = $request;
    $category = $this->_objectManager->get('Magento\Framework\Registry')->registry('current_category');
    if($category)
    {
      $page = $this->request->getParam('p');
      if($page == '')
      {
        $page = 1;
      }
      $this->_collection->getCurPage();
      $this->_collection->setCurPage($page);  
    }
    //else
    //{
    //  $this->_collection->setCurPage($this->getCurrentPage());
    //}

    return $result;
  }

}
Dinesh Yadav
quelle
Hallo, ich habe Ihren Code verwendet. Er aktualisiert die Produktkollektion korrekt. Er aktualisiert jedoch nicht die Filterliste wie Kategorie, Preis, Attribute und auch die Anzahl ihrer Produkte. Können Sie mir dabei helfen, es ist dringend für mich? @ DineshYadav
Sujeet Pandit
Ihre Lösung hat perfekt funktioniert. Ich habe einige zusätzliche Schnickschnack hinzugefügt, um auf bestimmte Kategorien zu achten und deren Sammlung dann komplett neu zu schreiben.
Pixiemedia
@pixiemedia Du kannst meine Antwort positiv bewerten, wenn es für dich funktioniert hat ☺️
Dinesh Yadav
ich habe übrigens schon;) ein kleines problem gefunden - im plugin code bricht der letzte teil nach dem letzten sonst die suchergebnisse. kommentiere das bisschen aus
pixiemedia
funktioniert nicht mehr auf M2.2 - SQL-Fehler SQLSTATE [42S22]: Spalte nicht gefunden: 1054 Unbekannte Spalte 'e.min_price' in 'Feldliste' - Ausarbeitung der Lösung
Pixiemedia
0

Ich war in der Lage, eine geschichtete Navigation zu erhalten, die hauptsächlich für eine benutzerdefinierte Produktkollektion auf einer benutzerdefinierten Seite funktioniert. Ich habe den Quellcode für mein Modul hier hochgeladen . Die einzigen Probleme sind, dass der Preisfilter nicht die richtigen Produktzählungen anzeigt. Aus diesem Grund habe ich die Ebenen-Navigationsansicht geändert, um den Preisfilter auszublenden. Da ich jedoch eine benutzerdefinierte Ansichtsdatei verwendet habe, können die Filter in der Seitenleiste aus irgendeinem Grund nicht mehr ausgeblendet werden.

Wenn jemand das Problem beheben kann, können Sie eine Pull-Anfrage stellen. Ich versuche auch herauszufinden, wie dies für eine CMS-Seite implementiert werden kann, die über das Magento 2-Backend erstellt wurde, anstatt für eine Seite, die manuell über XML erstellt wurde.

R. Townley
quelle