The Dynamic Product module enables you to select specific products directly from the product grid within the system configuration tab. These selections are then saved in the core_config_data table, allowing you to access and display them wherever needed.
You can find the complete module on GitHub at Magelearn_DynamicProduct
Or Check the below images for a better understanding of the functionality of this module.
Let's start it by creating a custom extension.
Create a folder inside app/code/Magelearn/DynamicProduct
Add registration.php file in it:
<?php
\Magento\Framework\Component\ComponentRegistrar::register(
\Magento\Framework\Component\ComponentRegistrar::MODULE,
'Magelearn_DynamicProduct',
__DIR__
);Add composer.json file in it:
{
"name": "magelearn/magento2-module-dynamic-product",
"description": "The Dynamic Product module enables you to select specific products directly from the product grid within the system configuration tab. These selections are then saved in the `core_config_data` table, allowing you to access and display them wherever needed.",
"type": "magento2-module",
"license": "Apache-2.0",
"authors": [
{
"name": "Vijay Rami",
"email": "vijaymrami@gmail.com"
}
],
"minimum-stability": "dev",
"prefer-stable": true,
"version":"1.0",
"require": {
"php": ">=8.0.0"
},
"repositories": [
{
"type": "package",
"package": {
"name": "magelearn/magento2-module-dynamic-product",
"version": "1.0",
"source": {
"url": "https://github.com/vijayrami/Magelearn_DynamicProduct.git",
"type": "git",
"reference": "main"
}
}
}
],
"autoload": {
"files": [
"registration.php"
],
"psr-4": {
"Magelearn\\DynamicProduct\\": ""
}
}
}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_DynamicProduct" setup_version="1.0.0">
<sequence>
<module name="Magento_Backend"/>
<module name="Magento_Config"/>
<module name="Magento_Cms"/>
</sequence>
</module>
</config>Add etc/acl.xml file.
<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Acl/etc/acl.xsd">
<acl>
<resources>
<resource id="Magento_Backend::admin">
<resource id="Magento_Backend::stores">
<resource id="Magento_Backend::stores_settings">
<resource id="Magento_Config::config">
<resource id="Magelearn_DynamicProduct::config" title="Magelearn DynamicProduct Grid Section" sortOrder="50" />
</resource>
</resource>
</resource>
</resource>
</resources>
</acl>
</config>Now to give the CMS Page list options at System configuration at admin,
we will add etc/adminhtml/system.xml file.
<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Config:etc/system_file.xsd">
<system>
<tab id="magelearn" translate="label" sortOrder="10">
<label>Magelearn Modules</label>
</tab>
<section id="dynamic_list" translate="label" sortOrder="10" showInDefault="1" showInWebsite="1" showInStore="1">
<class>separator-top</class>
<label>Select Products From Grid</label>
<tab>magelearn</tab>
<resource>Magelearn_DynamicProduct::config</resource>
<group id="selection" translate="label" type="text" sortOrder="10" showInDefault="1" showInWebsite="1" showInStore="1">
<label>General Configuration</label>
<field id="select_product" translate="label" type="text" sortOrder="10" showInDefault="1" showInWebsite="1" showInStore="1">
<label>Select Product</label>
<frontend_model>Magelearn\DynamicProduct\Block\Adminhtml\System\Config\Product</frontend_model>
</field>
</group>
</section>
</system>
</config>Now as per highlighted code above, we will add
Block/Adminhtml/System/Config/Product.php file.
<?php
declare(strict_types=1);
namespace Magelearn\DynamicProduct\Block\Adminhtml\System\Config;
use Magento\Backend\Block\Template\Context;
use Magento\Framework\Data\Form\Element\AbstractElement;
use Magento\Config\Block\System\Config\Form\Field;
use Magento\Backend\Block\Widget\Grid\Extended;
class Product extends Field
{
protected $_template = 'Magelearn_DynamicProduct::system/config/product.phtml';
public function __construct(
Context $context,
array $data = []
) {
parent::__construct($context, $data);
}
protected function _getElementHtml(AbstractElement $element)
{
$this->setElement($element);
return $this->_toHtml();
}
public function getProductGridUrl()
{
return $this->getUrl('dynamicproduct/product/grid', [
'element_id' => $this->getElement()->getHtmlId()
]);
}
public function getFormKey()
{
return $this->formKey->getFormKey();
}
}Now as per highlighted code above, we will add our template file and route file.
Add view/adminhtml/templates/system/config/product.phtml file.
<?php
/** @var \Magelearn\DynamicProduct\Block\Adminhtml\System\Config\Product $block */
$element = $block->getElement();
$fieldId = $element->getHtmlId();
?>
<div class="admin__field">
<div class="admin__field-control">
<input type="text"
id="<?= $block->escapeHtmlAttr($fieldId) ?>"
name="<?= $block->escapeHtmlAttr($element->getName()) ?>"
value="<?= $block->escapeHtmlAttr($element->getValue()) ?>"
class="input-text admin__control-text"
readonly="readonly" />
<button type="button"
class="action-default scalable"
id="<?= $block->escapeHtmlAttr($fieldId) ?>_button">
<span><?= $block->escapeHtml(__('Select Product')) ?></span>
</button>
<div id="<?= $block->escapeHtmlAttr($fieldId) ?>_modal" class="product-chooser-modal" style="display:none;"></div>
</div>
</div>
<script>
require([
'jquery',
'Magento_Ui/js/modal/modal',
'mage/url',
'productChooser'
], function($, modal, urlBuilder, productChooser) {
'use strict';
productChooser({
fieldId: '<?= $block->escapeJs($fieldId) ?>',
gridUrl: '<?= $block->escapeJs($block->getProductGridUrl()) ?>',
formKey: '<?= $block->escapeJs($block->getFormKey()) ?>'
});
});
</script>Also add etc/adminhtml/routes.xml file.
<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:App/etc/routes.xsd">
<router id="admin">
<route id="dynamicproduct" frontName="dynamicproduct">
<module name="Magelearn_DynamicProduct" />
</route>
</router>
</config>Now add Controller file at Controller/Adminhtml/Product/Grid.php
<?php
declare(strict_types=1);
namespace Magelearn\DynamicProduct\Controller\Adminhtml\Product;
use Magento\Backend\App\Action;
use Magento\Backend\App\Action\Context;
use Magento\Framework\View\Result\LayoutFactory;
class Grid extends Action
{
protected $resultLayoutFactory;
public function __construct(
Context $context,
LayoutFactory $resultLayoutFactory
) {
parent::__construct($context);
$this->resultLayoutFactory = $resultLayoutFactory;
}
public function execute()
{
$resultLayout = $this->resultLayoutFactory->create();
$resultLayout->getLayout()->getBlock('product.grid');
return $resultLayout;
}
}Also add layout file at
app/code/Magelearn/DynamicProduct/view/adminhtml/layout/dynamicproduct_product_grid.xml
<?xml version="1.0"?>
<layout xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/layout_generic.xsd">
<container name="root" label="Root">
<block class="Magelearn\DynamicProduct\Block\Adminhtml\Product\Grid" name="product.grid"/>
</container>
</layout>Now as per highlighted code above, add our block class at
app/code/Magelearn/DynamicProduct/Block/Adminhtml/Product/Grid.php
<?php
declare(strict_types=1);
namespace Magelearn\DynamicProduct\Block\Adminhtml\Product;
use Magento\Backend\Block\Widget\Grid\Extended;
use Magento\Backend\Block\Template\Context;
use Magento\Backend\Helper\Data;
use Magento\Catalog\Model\ResourceModel\Product\CollectionFactory;
use Magento\Catalog\Model\Product\Visibility;
use Magento\Catalog\Model\Product\Attribute\Source\Status;
class Grid extends Extended
{
protected $productCollectionFactory;
protected $visibility;
protected $status;
public function __construct(
Context $context,
Data $backendHelper,
CollectionFactory $productCollectionFactory,
Visibility $visibility,
Status $status,
array $data = []
) {
$this->productCollectionFactory = $productCollectionFactory;
$this->visibility = $visibility;
$this->status = $status;
parent::__construct($context, $backendHelper, $data);
}
protected function _construct()
{
parent::_construct();
$this->setId('productGrid');
$this->setDefaultSort('entity_id');
$this->setDefaultDir('DESC');
$this->setUseAjax(true);
$this->setSaveParametersInSession(false);
// Set this to false to show radio buttons instead of checkboxes
$this->setMassactionBlockName('Magento\Backend\Block\Widget\Grid\Massaction');
}
protected function _prepareCollection()
{
$collection = $this->productCollectionFactory->create();
$collection->addAttributeToSelect(['name', 'sku', 'price', 'status'])
->addAttributeToFilter('status', ['in' => $this->status->getVisibleStatusIds()])
->addAttributeToFilter('visibility', ['in' => $this->visibility->getVisibleInSiteIds()]);
$this->setCollection($collection);
return parent::_prepareCollection();
}
protected function _prepareColumns()
{
// Add checkbox column before other columns
$this->addColumn('in_products', [
'header_css_class' => 'a-center',
'type' => 'checkbox', // Use 'radio' for single selection, 'checkbox' for multiple
'name' => 'in_products',
'values' => $this->_getSelectedProducts(),
'align' => 'center',
'index' => 'entity_id',
'header' => false,
'renderer' => 'Magelearn\DynamicProduct\Block\Adminhtml\Grid\Renderer\Checkbox'
//'html_name' => 'product_id' // For Radio Button only
]);
$this->addColumn('entity_id', [
'header' => __('ID'),
'type' => 'number',
'index' => 'entity_id',
'header_css_class' => 'col-id',
'column_css_class' => 'col-id'
]);
$this->addColumn('name', [
'header' => __('Name'),
'index' => 'name'
]);
$this->addColumn('sku', [
'header' => __('SKU'),
'index' => 'sku'
]);
$this->addColumn('price', [
'header' => __('Price'),
'type' => 'currency',
'currency_code' => (string)$this->_scopeConfig->getValue(
\Magento\Directory\Model\Currency::XML_PATH_CURRENCY_BASE,
\Magento\Store\Model\ScopeInterface::SCOPE_STORE
),
'index' => 'price'
]);
return parent::_prepareColumns();
}
protected function _getSelectedProducts()
{
$selected = $this->getRequest()->getParam('selected', []);
return is_array($selected) ? $selected : [];
}
public function getGridUrl()
{
return $this->getUrl('dynamicproduct/product/grid', ['_current' => true]);
}
// This function is important for row click handling
public function getRowUrl($row)
{
return '#';
}
}Now as per the highlighted code above, to render the checkboxes add our renderer class at
app/code/Magelearn/DynamicProduct/Block/Adminhtml/Grid/Renderer/Checkbox.php
<?php
declare(strict_types=1);
namespace Magelearn\DynamicProduct\Block\Adminhtml\Grid\Renderer;
use Magento\Framework\DataObject;
class Checkbox extends \Magento\Backend\Block\Widget\Grid\Column\Renderer\Checkbox
{
public function render(DataObject $row)
{
$entityId = $row->getData($this->getColumn()->getIndex());
$htmlName = 'product_id'; // Define the custom HTML name here
return '<input type="checkbox" name="' . $htmlName . '[]" value="' . $entityId . '" class="checkbox" />';
}
}Now as per the highlighted code in templates view/adminhtml/templates/system/config/product.phtml file,
We will add our JS file.
For that add file at view/adminhtml/requirejs-config.js
var config = {
map: {
'*': {
productChooser: 'Magelearn_DynamicProduct/js/product-chooser'
}
}
};Now as per the highlighted code above add the file at view/adminhtml/web/js/product-chooser.js
define([
'jquery',
'Magento_Ui/js/modal/modal',
'mage/translate'
], function($, modal, $t) {
'use strict';
return function(config) {
var fieldId = config.fieldId;
var buttonId = fieldId + '_button';
var modalId = fieldId + '_modal';
// Initialize modal
var modalElement = $('#' + modalId);
var modalOptions = {
type: 'slide',
responsive: true,
innerScroll: true,
modalClass: 'product-chooser-modal-container',
title: $t('Choose Product'),
buttons: [{
text: $t('Select'),
class: 'action-primary',
click: function() {
var selected = modalElement.find('input[name="product_id[]"]:checked');
if (selected.length) {
var productIds = selected.map(function() {
return $(this).val();
}).get();
var productName = selected.closest('tr').find('td:nth-child(3)').text().trim();
console.log('Selected product name:', productName);
$('#' + fieldId).val(productIds.join(','));
modalElement.modal('closeModal');
} else {
alert($t('Please select a product.'));
}
}
}, {
text: $t('Cancel'),
class: 'action-secondary',
click: function() {
modalElement.modal('closeModal');
}
}]
};
modalElement.modal(modalOptions);
// Handle button click
$('#' + buttonId).on('click', function(e) {
e.preventDefault();
$.ajax({
url: config.gridUrl,
type: 'POST',
dataType: 'html',
data: {
form_key: config.formKey
},
showLoader: true,
success: function(data) {
modalElement.html(data).trigger('contentUpdated');
modalElement.modal('openModal');
// Add click handler for rows
modalElement.on('click', 'tr.data-row', function(e) {
// Don't trigger if clicking on the checkbox button itself
if (!$(e.target).is('input[type="checkbox"]')) {
var checkbox = $(this).find('input[type="checkbox"]');
checkbox.prop('checked', !checkbox.prop('checked'));
}
});
},
error: function(xhr, status, error) {
console.error('Error loading product grid:', error);
}
});
});
};
});Now to display product chooser modal window properly, we will add our CSS file at
view/adminhtml/web/css/source/_module.less





0 Comments On "Enabling Product Selection and Displaying Product Grid in Magento 2 System Configuration"