Add category column and filter in an efficient way to the product grid in the Magento 2 admin

By vijayramiUpdated 3 March 2021
Magento2Magento2 Extensions
objectManager

Let's start it by creating custom module.

You can find complete module on Github

Create folder inside app/code/Magelearn/GridColumn

Add registration.php file in it:
<?php
/**
 * Copyright ©  All rights reserved.
 * See COPYING.txt for license details.
 */
use Magento\Framework\Component\ComponentRegistrar;

ComponentRegistrar::register(ComponentRegistrar::MODULE, 'Magelearn_GridColumn', __DIR__);
Add composer.json file in it:
{
    "name": "magelearn/module-gridcolumn",
    "description": "Add Extra column Product's category to the products grid in Magento2 Backend.",
    "type": "magento2-module",
    "license": "OSL-3.0",
    "authors": [
        {
            "email": "info@mage2gen.com",
            "name": "Mage2Gen"
        },
        {
            "email": "vijaymrami@gmail.com",
            "name": "vijay rami"
        }
    ],
    "minimum-stability": "dev",
    "require": {},
    "autoload": {
        "files": [
            "registration.php"
        ],
        "psr-4": {
            "Magelearn\\GridColumn\\": ""
        }
    }
}
Add etc/module.xml file in it:
<?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="Magelearn_GridColumn" setup_version="1.0.0"/>
</config>
To display new column in product listing grid we will override view/adminhtml/ui_component/product_listing.xml.

Create file product_listing.xml inside view/adminhtml/ui_component folder.
<?xml version="1.0"?>
<listing xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Ui:etc/ui_configuration.xsd">
    <columns name="product_columns" class="Magento\Catalog\Ui\Component\Listing\Columns">
        <column name="category_id" class="Magelearn\GridColumn\Ui\Component\Listing\Column\Category">
            <argument name="data" xsi:type="array">
            	<item name="options" xsi:type="object">Magelearn\GridColumn\Model\Category\Categorylist</item>
                <item name="config" xsi:type="array">
                	<item name="filter" xsi:type="string">select</item>
                    <item name="add_field" xsi:type="boolean">true</item>
                    <item name="label" xsi:type="string" translate="true">Categories</item>
                    <item name="sortOrder" xsi:type="number">75</item>
                    <item name="dataType" xsi:type="string">select</item>
                </item>
            </argument>
        </column>

    </columns>
</listing>

To Display category name on Product listing grid, we will create our column renderer class.

Create Category.php file inside app/code/Magelearn/GridColumn/Ui/Component/Listing/Column folder.

<?php

namespace Magelearn\GridColumn\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
{
	protected $_productRepository;
	protected $_categoryFactory;
	
	public function __construct(
        ContextInterface $context,
        UiComponentFactory $uiComponentFactory,
        \Magento\Catalog\Model\ProductRepository $productRepository,
        \Magento\Catalog\Model\CategoryFactory $categoryFactory,
        array $components = [],
        array $data = []
    ) {
        parent::__construct($context, $uiComponentFactory, $components, $data);
    	$this->_productRepository = $productRepository;
		$this->_categoryFactory = $categoryFactory;
    }
	
    public function prepareDataSource(array $dataSource)
    {
        if (isset($dataSource['data']['items'])) {
        	$fieldName = $this->getData('name');
            foreach ($dataSource['data']['items'] as & $item) {
                $productId = $item['entity_id'];
				$categories = [];
				
                $product = $this->_productRepository->getById($productId);
                $cats = $product->getCategoryIds();
				
                if (count($cats)) {
                    foreach ($cats as $cat) {
						$category = $this->_categoryFactory->create()->load($cat);
                        $categories[] = $category->getName();
                    }
                }
                $item[$fieldName] = implode(',', $categories);
            }
        }
        return $dataSource;
    }
}

If you want to just add new column on the admin product listing grid then add these code files.

Just remove highlighted code from view/adminhtml/ui_component/product_listing.xml file.

Now, let we check to give category filter option.

Create Categorylist.php file inside app/code/Magelearn/GridColumn/Model/Category folder.

<?php

namespace Magelearn\GridColumn\Model\Category;

class CategoryList implements \Magento\Framework\Option\ArrayInterface
{
    public function __construct(
        \Magento\Catalog\Model\ResourceModel\Category\CollectionFactory $collectionFactory
    ) {
        $this->_categoryCollectionFactory = $collectionFactory;

    }
    public function toOptionArray($addEmpty = true)
    {

        $collection = $this->_categoryCollectionFactory->create()
        			->addAttributeToSelect('name')//->addRootLevelFilter()->load();
        			->addAttributeToFilter('level', ['gt' => 1]) //remove root category 
                	->addAttributeToFilter('is_active', ['gt' => 0]); //for active categories
        $options = [];
        if ($addEmpty) {
            $options[] = ['label' => __('-- Please Select a Category --'), 'value' => ''];
        }
        foreach ($collection as $category) {
            $options[] = ['label' => $category->getName(), 'value' => $category->getId()];
        }
        return $options;
    }
}

Now, to display result properly after filter, need to modify default DataProvider for ProductDataProvider.

For that first create di.xml file inside app/code/Magelearn/GridColumn/etc folder.

<?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="Magelearn\GridColumn\Ui\DataProvider\Product\ProductDataProvider" />
</config>

Now create ProductDataProvider.php file inside app/code/Magelearn/GridColumn/Ui/DataProvider/Product/ folder.

<?php

namespace Magelearn\GridColumn\Ui\DataProvider\Product;

class ProductDataProvider extends \Magento\Catalog\Ui\DataProvider\Product\ProductDataProvider
{
    public function addFilter(\Magento\Framework\Api\Filter $filter)
    {
        if ($filter->getField() == 'category_id') {
            $this->getCollection()->addCategoriesFilter(array('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);
        }
    }
}

After adding above files, just run Magento commands:

php bin/magento set:upg

php bin/magento set:d:c

php bin/magento set:s:d -f en_US

php bin/magento c:c

php bin/magento c:f

Now, you can see New column "Categories" will be added in product listing grid and also filter with active categories list be added.

Add category column and filter in an efficient way to the product grid in the Magento 2 admin | Vijay M. Rami