Magento, Magento 2

Add Category Filter to Product Grid in Magento 2 Admin

Add Category Filter to Product Grid in Magento 2 Admin

In this tutorial, Today I will explain to how to add category filter to product grid in Magento 2 admin. In Magento 2 Product Grid, There are no category column by default display in Grid. But, Sometimes we need to filter products by category in Magento 2 admin.

In addition, Magento 2 UI component provides many functionalities in UI Grid. So, If we want to add custom column and filter functionality in grid for example, if you want to add category column and filter in product UI Grid. Then, you can follow this article. In addition, There are multi select dropdown added in this filter functionality. So, If you want to apply multiple category filter Then, you can apply multiple category filter in product grid.

Meanwhile, Magento 2 provides features that product can apply in multiple categories. So, We can assign single product in Multiple Categories.

However, Magento 2 UI Grid provides by default columns management system. So, if you want to hide category columns then, you can de-select checkbox in columns management.

I created one module filter products by category in Magento 2 admin. So, Let’s follow the steps for that.

You may also like this :

Steps of Add Category Filter to Product Grid in Magento 2 Admin :

1) First of all, Let’s assume that you have created simple module for that. Create product_listing.xml file to add category column in Product Grid. You can create file at app/code/RH/CategoryFilter/view/adminhtml/ui_component/ and paste the below code :

<?xml version="1.0" encoding="UTF-8"?>
<!--
/**
 * Copyright © Magento, Inc. All rights reserved.
 * See COPYING.txt for license details.
 */
/**
 * Created By : Rohan Hapani
 */
-->
<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="RH\CategoryFilter\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>

2) After that, We need to create Category.php at app/code/RH/CategoryFilter/Ui/Component/Listing/Column/ and paste the below code for add category column data as per product vise before prepare data source :

<?php
/**
 * Copyright © Magento, Inc. All rights reserved.
 * See COPYING.txt for license details.
 */

/**
 * Created By : Rohan Hapani
 */
namespace RH\CategoryFilter\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\ProductCategoryList
     */
    private $productCategory;

    /**
     * @var \Magento\Catalog\Api\CategoryRepositoryInterface
     */
    private $categoryRepository;

    /**
     * @param ContextInterface                                 $context
     * @param UiComponentFactory                               $uiComponentFactory
     * @param array                                            $components
     * @param array                                            $data
     * @param \Magento\Catalog\Model\ProductCategoryList       $productCategory
     * @param \Magento\Catalog\Api\CategoryRepositoryInterface $categoryRepository
     */
    public function __construct(
        ContextInterface $context,
        UiComponentFactory $uiComponentFactory,
        array $components = [],
        array $data = [],
        \Magento\Catalog\Model\ProductCategoryList $productCategory,
        \Magento\Catalog\Api\CategoryRepositoryInterface $categoryRepository
    ) {
        parent::__construct($context, $uiComponentFactory, $components, $data);
        $this->productCategory = $productCategory;
        $this->categoryRepository = $categoryRepository;
    }

    /**
     * Prepare date for category column
     * @param  array  $dataSource
     * @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'];
                $categoryIds = $this->getCategoryIds($productId);
                $categories = [];
                if (count($categoryIds)) {
                    foreach ($categoryIds as $categoryId) {
                        $categoryData = $this->categoryRepository->get($categoryId);
                        $categories[] = $categoryData->getName();
                    }
                }
                $item[$fieldName] = implode(',', $categories);
            }
        }
        return $dataSource;
    }


    /**
     * get all the category id
     *
     * @param int $productId
     * @return array
     */
    private function getCategoryIds(int $productId)
    {
        $categoryIds = $this->productCategory->getCategoryIds($productId);
        $category = [];
        if ($categoryIds) {
            $category = array_unique($categoryIds);
        }
        return $category;
    }
}

3) Then, Create di.xml file at app/code/RH/CategoryFilter/etc/adminhtml/ for override file Magento\Catalog\Ui\DataProvider\Product\ProductDataProvider file :

<?xml version="1.0"?>
<!--
/**
 * Copyright © Magento, Inc. All rights reserved.
 * See COPYING.txt for license details.
 */

/**
 * Created By : Rohan Hapani
 */
-->
<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="RH\CategoryFilter\Ui\DataProvider\Product\ProductDataProvider" />
</config>

4) After that, Create ProductDataProvider.php file at app/code/RH/CategoryFilter/Ui/DataProvider/Product/ to add filterable collection for UI Grid :

<?php
/**
 * Copyright © Magento, Inc. All rights reserved.
 * See COPYING.txt for license details.
 */

/**
 * Created By : Rohan Hapani
 */
namespace RH\CategoryFilter\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);
        }
    }
}

5) In Last, You need to create CategoryList.php file at app/code/RH/CategoryFilter/Model/Category/ and paste the below code to add filter list in dropdown filter of UI Grid:

<?php
/**
 * Copyright © Magento, Inc. All rights reserved.
 * See COPYING.txt for license details.
 */

/**
 * Created By : Rohan Hapani
 */
namespace RH\CategoryFilter\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;

    /**
     * @param \Magento\Catalog\Model\ResourceModel\Category\CollectionFactory $collectionFactory
     */
    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'];
    }
}

That’s it !!!

In conclusion, You can add multiple category list name in product UI Grid and display multiple category name with comma separated value.

Output :

Product Category Filter Magento 2

Now, you just need to clean cache and check it to filter products by category in Magento 2 admin :

php bin/magento c:c

I hope this blog is easy to understand about how to add category filter to product grid in Magento 2 admin. In case, I missed anything or need to add some information, always feel free to leave a comment in this blog, I’ll get back with proper solution.

Keep liking and sharing !!

Tagged ,