1

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.

2

1 Answer 1

5

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.

1
  • 1
    Thanks man ..!!! It's working :)
    – Niket
    Apr 24, 2019 at 2:55

Not the answer you're looking for? Browse other questions tagged or ask your own question.