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"