4

I would like to add an extra column based on a product attribute <my_attribute_code> in the product grid that appears when editing a category in the section "Products In Category" ideally before the SKU Column

enter image description here

Is it possible?

2 Answers 2

6

Try following way to add a column. I have added a product creation time column as an example:

app/code/SR/MagentoCommunity/etc/adminhtml/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">
    <preference for="Magento\Catalog\Block\Adminhtml\Category\Tab\Product" type="SR\MagentoCommunity\Block\Adminhtml\Category\Tab\Product"/>
</config>

app/code/SR/MagentoCommunity/Block/Adminhtml/Category/Tab/Product.php

<?php
namespace SR\MagentoCommunity\Block\Adminhtml\Category\Tab;

class Product extends \Magento\Catalog\Block\Adminhtml\Category\Tab\Product
{
    /**
     * Set collection object
     *
     * @param \Magento\Framework\Data\Collection $collection
     * @return void
     */
    public function setCollection($collection)
    {
        $collection->addAttributeToSelect('created_at');
        parent::setCollection($collection);
    }

    /**
     * @return $this
     */
    protected function _prepareColumns()
    {
        parent::_prepareColumns();
        $this->addColumnAfter('created_at', array(
            'header' => __('Created At'),
            'index' => 'created_at',
        ), 'sku');

        $this->sortColumnsByOrder();
        return $this;
    }
}
3
  • Thanks I'll try that and test :)
    – gabtzi
    May 22, 2019 at 12:24
  • It worked great. I was able to add my attribute like this :) Thank you very much
    – gabtzi
    May 22, 2019 at 12:46
  • Great! Thanks :) Apr 30, 2021 at 7:23
0

I've got an alternate way of going about this. Its requires more complicated code, but doesn't require replacing a whole class through dependency injection, so swings and roundabouts. I hope that a different perspective may help people in other situations, but the approach from Sohel Rana seems pretty good.

First, the extra column can be targeted through a system event backend_block_widget_grid_prepare_grid_before. This event is fired at the start of the method \Magento\Backend\Block\Widget\Grid::_prepareGrid. In your modules /etc/events.xml add:

    <event name="backend_block_widget_grid_prepare_grid_before">
        <observer name="my_observer_name" instance="<My Namespace>\<My Module name>\Observer\AddStockColumnToCategoryGridObserver" />
    </event>

Then actually create the observer Observer\AddStockColumnToCategoryGridObserver.php with the content:

namespace <My Namespace>\<My Module name>/Observer;

class AddStockColumnToCategoryGridObserver implements ObserverInterface
{
    public function execute(Observer $observer)
    {
        /** @var \Magento\Catalog\Block\Adminhtml\Category\Tab\Product */
        $grid = $observer->getGrid();

        if($grid && $grid instanceof \Magento\Catalog\Block\Adminhtml\Category\Tab\Product) {
            $grid->addColumnAfter(
                'stock',
                [
                    'header' => __('Created Ad'),
                    'index' => 'created_at',
                    'type' => 'date'],
                'sku'
            );
            $grid->sortColumnsByOrder();
        }
    }
}

The event is fired for all grids, not just the product tab in the category catalogue, which is why we need to test for the correct grid subclass.

If you look at the order in which the relevant subclasses call their parents, you can see that the standard columns have already been added to the grid before the event is dispatched, this is why we need to call $grid->sortColumnsByOrder(), to ensure the columns are reordered before being rendered.

The above will render the new column, but there is not yet any data in the collection to be displayed. The collection object needs to be manipulated so it will get the required data from the database.

Unfortunately, the collection has not been prepared before the backend_block_widget_grid_prepare_grid_before event is dispatched, or we could just use that. Its even more annoying that this event is specifically dispatched including a parameter set with $this->getCollection(), but in this point in the cycle the result is null.

The only point I could find to tie into was the same as Sohel Rana's answer, setCollection. As setCollection is a public method, its possible to use a plugin to modify the collection. Begin by defining the plugin in etc/adminhtml/di.xml`:

<type name="Magento\Catalog\Block\Adminhtml\Category\Tab\Product">
    <plugin name="my_plugin_name" type="<My namespace>\<My Module Name>\Plugin\Block\Adminhtml\Category\Tab\Product" disabled="false" />
</type>

Then write the actual plugin itself in <My namespace>/<My Module Name>/Plugin/Block/Adminhtml/Category/Tab/Product.php:

namespace <My namespace>\<My Module Name>\Plugin\Block\Adminhtml\Category\Tab;

use Magento\Framework\Data\Collection;

class Product extends \Magento\Catalog\Block\Adminhtml\Category\Tab\Product
{
    public function beforeSetCollection(\Magento\Catalog\Block\Adminhtml\Category\Tab\Product $subject, Collection $collection)
    {
        $collection->addAttributeToSelect('created_at');
    }
}

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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