سؤال

In admin, I want to add column of category and also add category filter in product grid.

How to do this?

Please help me.

Thanks.

هل كانت مفيدة؟

المحلول

To add category column in product grid, add this below code in your

  • Use default Magento class for complete category tree: Magento\Catalog\Ui\Component\Product\Form\Categories\Options

  • For any custom category list use the custom class as below: Vendor\Module\Model\Category\CategoryList

Reference : Add Category Filter to Product Grid in Magento 2 Admin

product_listing.xml file :

<?xml version="1.0" encoding="UTF-8"?>
<listing xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Ui:etc/ui_configuration.xsd">
    <listingToolbar name="listing_top">
        <filters name="listing_filters">
            <filterSelect name="category_id" provider="${ $.parentName }" component="Magento_Ui/js/form/element/ui-select" template="ui/grid/filters/elements/ui-select">
                <argument name="data" xsi:type="array">
                    <item name="config" xsi:type="array">
                        <item name="filterOptions" xsi:type="boolean">true</item>
                        <item name="levelsVisibility" xsi:type="number">1</item>
                    </item>
                </argument>
                <settings>
                    <options class="Magento\Catalog\Ui\Component\Product\Form\Categories\Options"/>
                    <caption translate="true">– Please Select a Category –</caption>
                    <label translate="true">Categories</label>
                    <dataScope>category_id</dataScope>
                    <imports>
                        <link name="visible">componentType = column, index = ${ $.index }:visible</link>
                    </imports>
                </settings>
            </filterSelect>
        </filters>
    </listingToolbar>
    <columns name="product_columns" class="Magento\Catalog\Ui\Component\Listing\Columns">
        <column name="category_id" class="Vendor\Module\Ui\Component\Listing\Column\Category">
            <argument name="data" xsi:type="array">
                <item name="config" xsi:type="array">
                    <item name="label" xsi:type="string" translate="true">Categories</item>
                    <item name="sortOrder" xsi:type="number">35</item>
                </item>
            </argument>
        </column>
    </columns>
</listing>

Now, we need to override prepareDataSource() method. To get category values in the prepareDataSource() method like below code :

Vendor\Module\Ui\Component\Listing\Column\Category.php

<?php

namespace Vendor\Module\Ui\Component\Listing\Column;

use Magento\Framework\View\Element\UiComponentFactory;
use Magento\Framework\View\Element\UiComponent\ContextInterface;

class Category extends \Magento\Ui\Component\Listing\Columns\Column
{

    /**
     * @var \Magento\Catalog\Model\ProductFactory
     */
    private $productFactory;

    /**
     * @var \Magento\Catalog\Model\CategoryFactory
     */
    private $categoryFactory;

    /**
     * [__construct description]
     * @param ContextInterface                       $context            [description]
     * @param UiComponentFactory                     $uiComponentFactory [description]
     * @param array                                  $components         [description]
     * @param array                                  $data               [description]
     * @param \Magento\Catalog\Model\ProductFactory  $productFactory     [description]
     * @param \Magento\Catalog\Model\CategoryFactory $categoryFactory    [description]
     */
    public function __construct(
        ContextInterface $context,
        UiComponentFactory $uiComponentFactory,
        array $components = [],
        array $data = [],
        \Magento\Catalog\Model\ProductFactory $productFactory,
        \Magento\Catalog\Model\CategoryFactory $categoryFactory
    ) {
        parent::__construct($context, $uiComponentFactory, $components, $data);
        $this->productFactory = $productFactory;
        $this->categoryFactory = $categoryFactory;
    }

    /**
     * Prepare date for category column
     * @param  array  $dataSource [description]
     * @return array
     */
    public function prepareDataSource(array $dataSource)
    {
        $fieldName = $this->getData('name');
        if (isset($dataSource['data']['items'])) {
            foreach ($dataSource['data']['items'] as &$item) {
                $productId = $item['entity_id'];
                $product = $this->productFactory->create()->load($productId);
                $categoryIds = $product->getCategoryIds();
                $categories = [];
                if (count($categoryIds)) {
                    foreach ($categoryIds as $categoryId) {
                        $categoryData = $this->categoryFactory->create()->load($categoryId);
                        $categories[] = $categoryData->getName();
                    }
                }
                $item[$fieldName] = implode(',', $categories);
            }
        }
        return $dataSource;
    }
}

create di.xml file for override class :

<?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\Catalog\Ui\DataProvider\Product\ProductDataProvider" type="Vendor\Module\Ui\DataProvider\Product\ProductDataProvider" />
</config>

Now, add method addFilter() to Vendor\Module\Ui\DataProvider\Product\ProductDataProvider.php

<?php

namespace Vendor\Module\Ui\DataProvider\Product;

class ProductDataProvider extends \Magento\Catalog\Ui\DataProvider\Product\ProductDataProvider
{
    /**
     * For filter grid according to category
     * @param \Magento\Framework\Api\Filter $filter
     */
    public function addFilter(\Magento\Framework\Api\Filter $filter)
    {
        if ($filter->getField() == 'category_id') {
            $this->getCollection()->addCategoriesFilter(['in' => $filter->getValue()]);
        } elseif (isset($this->addFilterStrategies[$filter->getField()])) {
            $this->addFilterStrategies[$filter->getField()]
                ->addFilter(
                    $this->getCollection(),
                    $filter->getField(),
                    [$filter->getConditionType() => $filter->getValue()]
                );
        } else {
            parent::addFilter($filter);
        }
    }
}

And last to add Options to the category filter dropdown :

Vendor\Module\Model\Category\CategoryList.php

<?php

namespace Vendor\Module\Model\Category;

use Magento\Catalog\Model\Category as CategoryModel;

class CategoryList implements \Magento\Framework\Option\ArrayInterface
{

    /**
     * @var \Magento\Catalog\Model\ResourceModel\Category\CollectionFactory
     */
    private $categoryCollectionFactory;
    /**
     * [__construct description]
     * @param \Magento\Catalog\Model\ResourceModel\Category\CollectionFactory $collectionFactory [description]
     */
    public function __construct(
        \Magento\Catalog\Model\ResourceModel\Category\CollectionFactory $collectionFactory
    ) {
        $this->categoryCollectionFactory = $collectionFactory;
    }

    /**
     * Get list of categories
     * @return array
     */
    public function toOptionArray()
    {
        $collection = $this->categoryCollectionFactory->create();
        $collection->addAttributeToSelect(['name', 'is_active', 'parent_id']);
        $categoryById = [
            CategoryModel::TREE_ROOT_ID => [
                'value' => CategoryModel::TREE_ROOT_ID,
                'optgroup' => null,
            ],
        ];
        foreach ($collection as $category) {
            foreach ([$category->getId(), $category->getParentId()] as $categoryId) {
                if (!isset($categoryById[$categoryId])) {
                    $categoryById[$categoryId] = ['value' => $categoryId];
                }
            }

            $categoryById[$category->getId()]['is_active'] = $category->getIsActive();
            $categoryById[$category->getId()]['label'] = $category->getName();
            $categoryById[$category->getParentId()]['optgroup'][] = &$categoryById[$category->getId()];
        }

        return $categoryById[CategoryModel::TREE_ROOT_ID]['optgroup'];
    }
}

Hope, It will helpful for you.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى magento.stackexchange
scroll top