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:
1 2 3 4 5 6 | <?php \Magento\Framework\Component\ComponentRegistrar::register( \Magento\Framework\Component\ComponentRegistrar::MODULE, 'Magelearn_DynamicProduct' , __DIR__ ); |
Add composer.json file in it:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 | { "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" : { "type" : "git" , "reference" : "main" } } } ], "autoload" : { "files" : [ "registration.php" ], "psr-4" : { "Magelearn\\DynamicProduct\\" : "" } } } |
Add etc/module.xml file in it:
1 2 3 4 5 6 7 8 9 10 | <? 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.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | <? 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.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | <? 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.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 | <?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.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 | <?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.
1 2 3 4 5 6 7 8 | <? 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
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | <?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
1 2 3 4 5 6 | <? 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
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 | <?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
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | <?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
1 2 3 4 5 6 7 | 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
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 | 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"