Magento2: How to add new grid in Category Listing Page

Here is a tutorial on how to add new Grid in Category Listing Page. For this example we will assume we want to add a grid same as Product Category Positions for Category Brands. It should look something like below:


Assume that you have a custom module called Namespace_Module. You will create following files in your module:

Namespace_Module\view\adminhtml\ui_component\category_form.xml
<?xml version="1.0" encoding="UTF-8"?>
<!--
/**
* @author Reena Parekh <reena1.parekh@gmail.com>
*/
-->
<form xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Ui:etc/ui_configuration.xsd">
<fieldset name="my_custom_grid_positions" sortOrder="40">
<settings>
<collapsible>true</collapsible>
<label translate="true">My Custom Grid</label>
</settings>
<container name="assign_positions_container" sortOrder="160">
<htmlContent name="html_content">
<block name="my_custom_grid"
class="Namespace\Module\Block\Adminhtml\Category\MyCustomGrid"/>
</htmlContent>
</container>
</fieldset>
</form>


Namespace_Module\Block\Adminhtml\Category\MyCustomGrid.php
<?php
/**
* @author Reena Parekh <reena1.parekh@gmail.com>
*/
namespace Namespace\Module\Block\Adminhtml\Category;
/**
* Class MyCustomGrid
* @package Namespace\Module\Block\Adminhtml\Category
*/
class MyCustomGrid extends \Magento\Backend\Block\Template
{
/**
* Block template
*
* @var string
*/
protected $_template = 'Namespace_Module::catalog/category/edit/grid.phtml';
/**
* @var \Namespace\Module\Block\Adminhtml\Category\Tab\MyCustomGrid
*/
protected $blockGrid;
/**
* @var \Magento\Framework\Registry
*/
protected $registry;
/**
* @var \Magento\Framework\Json\EncoderInterface
*/
protected $jsonEncoder;
/**
* @var \Namespace\Module\Helper\Data
*/
protected $dataHelper;
/**
* MyCustomGrid constructor.
*
* @param \Magento\Backend\Block\Template\Context $context
* @param \Magento\Framework\Registry $registry
* @param \Magento\Framework\Json\EncoderInterface $jsonEncoder
* @param \Namespace\Module\Helper\Data $dataHelper
* @param array $data
*/
public function __construct(
\Magento\Backend\Block\Template\Context $context,
\Magento\Framework\Registry $registry,
\Magento\Framework\Json\EncoderInterface $jsonEncoder,
\Namespace\Module\Helper\Data $dataHelper,
array $data = []
) {
$this->dataHelper = $dataHelper;
$this->registry = $registry;
$this->jsonEncoder = $jsonEncoder;
parent::__construct($context, $data);
}
/**
* Retrieve instance of grid block
*
* @return \Magento\Framework\View\Element\BlockInterface
* @throws \Magento\Framework\Exception\LocalizedException
*/
public function getBlockGrid()
{
if (null === $this->blockGrid) {
$this->blockGrid = $this->getLayout()->createBlock(
\Namespace\Module\Block\Adminhtml\Category\Tab\MyCustomGrid::class,
'category.mycustom.grid'
);
}
return $this->blockGrid;
}
/**
* Return HTML of grid block
*
* @return string
*/
public function getGridHtml()
{
return $this->getBlockGrid()->toHtml();
}
/**
* @return string
*/
public function getGridJson()
{
$category = $this->getCategory();
$categoryId = $category->getId();
$positionArr = $this->dataHelper->getPositions($categoryId);
if (!empty($positionArr)) {
return $this->jsonEncoder->encode($positionArr);
}
return '{}';
}
/**
* Retrieve current category instance
*
* @return array|null
*/
public function getCategory()
{
return $this->registry->registry('category');
}
}


Namespace_Module\view\adminhtml\templates\catalog\category\edit\assign.phtml
<?php
/**
* @author Reena Parekh <reena1.parekh@gmail.com>
*/
/** @var \Namespace\Module\Block\Adminhtml\Category\MyCustomGrid $block */
/** @var \Namespace\Module\Block\Adminhtml\Category\Tab\MyCustomGrid $blockGrid */
//PLEASE USE PROPER NAMING CONVENTION. EVERYTHING BELOW IS JUST FOR EXAMPLE PURPOSES.
$blockGrid = $block->getBlockGrid();
$gridJsObjectName = $blockGrid->getJsObjectName();
?>
<?= $block->getGridHtml() ?>
<input type="hidden" name="my_custom_grid_data" id="in_grid_data" data-form-part="category_form" value="" />
<script type="text/x-magento-init">
{
"*": {
"Namespace_Module/catalog/category/assign": {
"selectedRows": <?= /* @noEscape */ $block->getGridJson() ?>,
"gridJsObjectName": <?= /* @noEscape */ '"' . $gridJsObjectName . '"' ?: '{}' ?>
}
}
}
</script>
<!-- @todo remove when "UI components" will support such initialization -->
<script>
require('mage/apply/main').apply();
</script>
view raw assign.phtml hosted with ❤ by GitHub


Namespace_Module\view\adminhtml\web\catalog\category\edit\assign.js
/**
* @author Reena Parekh <reena1.parekh@gmail.com>
*/
/* global $, $H */
define([
'mage/adminhtml/grid'
], function () {
'use strict';
return function (config) {
var selectedRows = config.selectedRows,
categoryRows = $H(selectedRows),
gridJsObject = window[config.gridJsObjectName];
$('in_grid_data').value = Object.toJSON(categoryRows);
/**
* Change product position
*
* @param {String} event
*/
function positionChange(event) {
var element = Event.element(event);
if (element && element.entityElement) {
categoryRows.set(element.entityElement.innerText, element.value);
$('in_grid_data').value = Object.toJSON(categoryRows);
}
}
/**
* Initialize category product row
*
* @param {Object} grid
* @param {String} row
*/
function categoryProductRowInit(grid, row) {
var entityId = $(row).getElementsByClassName('col-entity_id')[0],
position = $(row).getElementsByClassName('input-text')[0];
if (entityId && position) {
entityId.positionElement = position;
position.entityElement = entityId;
Event.observe(position, 'keyup', positionChange);
}
}
gridJsObject.initRowCallback = categoryProductRowInit;
if (gridJsObject.rows) {
gridJsObject.rows.each(function (row) {
categoryProductRowInit(gridJsObject, row);
});
}
};
});
view raw assign.js hosted with ❤ by GitHub


Namespace_Module\Controller\Adminhtml\Category\Assign.php
<?php
/**
* @author Reena Parekh <reena1.parekh@gmail.com>
*/
namespace Namespace\Module\Controller\Adminhtml\Category;
class Assign extends \Magento\Catalog\Controller\Adminhtml\Category
{
/**
* @var \Magento\Framework\Controller\Result\RawFactory
*/
protected $resultRawFactory;
/**
* @var \Magento\Framework\View\LayoutFactory
*/
protected $layoutFactory;
/**
* @param \Magento\Backend\App\Action\Context $context
* @param \Magento\Framework\Controller\Result\RawFactory $resultRawFactory
* @param \Magento\Framework\View\LayoutFactory $layoutFactory
*/
public function __construct(
\Magento\Backend\App\Action\Context $context,
\Magento\Framework\Controller\Result\RawFactory $resultRawFactory,
\Magento\Framework\View\LayoutFactory $layoutFactory
) {
parent::__construct($context);
$this->resultRawFactory = $resultRawFactory;
$this->layoutFactory = $layoutFactory;
}
/**
* Grid Action
* Display list of products related to current category
*
* @return \Magento\Framework\Controller\Result\Raw
*/
public function execute()
{
$category = $this->_initCategory(true);
if (!$category) {
/** @var \Magento\Backend\Model\View\Result\Redirect $resultRedirect */
$resultRedirect = $this->resultRedirectFactory->create();
return $resultRedirect->setPath('catalog/*/', ['_current' => true, 'id' => null]);
}
/** @var \Magento\Framework\Controller\Result\Raw $resultRaw */
$resultRaw = $this->resultRawFactory->create();
return $resultRaw->setContents(
$this->layoutFactory->create()->createBlock(
\Namespace\Module\Block\Adminhtml\Category\Tab\MyCustomGrid::class,
'category.mycustom.grid'
)->toHtml()
);
}
}
view raw Assign.php hosted with ❤ by GitHub


Namespace_Module\Block\Adminhtml\Category\Tab\MyCustomGrid.php
<?php
/**
* @author Reena Parekh <reena1.parekh@gmail.com>
*/
namespace Namespace\Module\Block\Adminhtml\Category\Tab;
/**
* Class MyCustomGrid
*/
class MyCustomGrid extends \Magento\Backend\Block\Widget\Grid\Extended
{
/**
* Core registry
*
* @var \Magento\Framework\Registry
*/
protected $_coreRegistry = null;
/**
* @var \Namespace\Module\Model\MyModelFactory
*/
protected $myModelFactory;
/**
* MyCustomGrid constructor.
*
* @param \Magento\Backend\Block\Template\Context $context
* @param \Magento\Backend\Helper\Data $backendHelper
* @param \Namespace\Module\Model\MyModelFactory $myModelFactory
* @param \Magento\Framework\Registry $coreRegistry
* @param array $data
*/
public function __construct(
\Magento\Backend\Block\Template\Context $context,
\Magento\Backend\Helper\Data $backendHelper,
\Namespace\Module\Model\MyModelFactory $myModelFactory,
\Magento\Framework\Registry $coreRegistry,
array $data = []
) {
parent::__construct($context, $backendHelper, $data);
$this->myModelFactory = $myModelFactory;
$this->_coreRegistry = $coreRegistry;
}
/**
* @return void
*/
protected function _construct()
{
parent::_construct();
$this->setId('my_custom_grid');
$this->setDefaultSort('position');
$this->setUseAjax(true);
}
/**
* @return array|null
*/
public function getCategory()
{
return $this->_coreRegistry->registry('category');
}
/**
* @return MyCustomGrid
*/
protected function _prepareCollection()
{
if ($this->getCategory()->getId()) {
$this->setDefaultFilter(['in_category' => 1]);
}
$collection = $this->myModelFactory->create()->getCollection();
$this->setCollection($collection);
return parent::_prepareCollection();
}
/**
* @return MyCustomGrid
* @throws \Exception
*/
protected function _prepareColumns()
{
$this->addColumn(
'entity_id',
[
'header' => __('ID'),
'sortable' => true,
'index' => 'entity_id',
'header_css_class' => 'col-id',
'column_css_class' => 'col-id'
]
);
$this->addColumn('value', ['header' => __('My Name Column'), 'index' => 'value']);
$this->addColumn(
'position',
[
'header' => __('Position'),
'type' => 'number',
'index' => 'position',
'editable' => true
]
);
return parent::_prepareColumns();
}
/**
* @return string
*/
public function getGridUrl()
{
return $this->getUrl('moduleFrontName/*/assign', ['_current' => true]);
}
}



For saving, updating and deleting the positions you need to create plugin on category save which takes the posted json, compares with original json and performs the required operation.

Comments

Popular posts from this blog

SEO for your Press Releases [Updated 2025 list]

XDebug - PHPStorm - Mac: How to configure Xdebug with PHPStorm on Mac OS and PHP 7.3