I'm Trying To Create Category Chooser in etc/system.xml
Is That Possible to Create Category Chooser in system.xml
?
Choose Like This
Magento Stack Exchange is a question and answer site for users of the Magento e-Commerce platform. It only takes a minute to sign up.
Sign up to join this communityI'm Trying To Create Category Chooser in etc/system.xml
Is That Possible to Create Category Chooser in system.xml
?
Choose Like This
You can follow this below steps to add multi select dropdown using chosen library :
Add this below code inside your system.xml :
app/code/Vendor/Module/etc/adminhtml/system.xml
<!--
/**
* Created By : Rohan Hapani
*/
-->
<field id="category_multiselect" translate="label" type="multiselect" showInDefault="1" showInWebsite="1" showInStore="1" sortOrder="10">
<label>Category Multi Select Dropdown</label>
<source_model>Vendor\Module\Model\Source\Category</source_model>
<frontend_model>Vendor\Module\Block\Adminhtml\MultiSelect</frontend_model>
<can_be_empty>1</can_be_empty>
</field>
Then, create frontend model file MultiSelect.php to display multi select dropdown :
app/code/Vendor/Module/Block/Adminhtml/MultiSelect.php
<?php
/**
* Created By : Rohan Hapani
*/
namespace Vendor\Module\Block\Adminhtml;
class MultiSelect extends \Magento\Config\Block\System\Config\Form\Field
{
/**
* Retrieve Element HTML fragment
*
* @param AbstractElement $element
* @return string
*/
protected function _getElementHtml(\Magento\Framework\Data\Form\Element\AbstractElement $element)
{
$script = " <script>
require([
'jquery',
'chosen'
], function ($, chosen) {
$('#" . $element->getId() . "').chosen({
width: '100%',
placeholder_text: '" . __('Select Options') . "'
});
$('#" . $element->getId() . "_inherit').change(function() {
$('#" . $element->getId() . "').prop('disabled', $(this).is(':checked'));
$('#" . $element->getId() . "').trigger('chosen:updated');
});
})
</script>";
return parent::_getElementHtml($element) . $script;
}
}
Create Category.php source model file
app/code/Vendor/Module/Model/Source/
<?php
/**
* Created By : Rohan Hapani
*/
namespace Vendor\Module\Model\Source;
use Magento\Framework\Option\ArrayInterface;
class Category implements ArrayInterface
{
protected $collectionFactory;
/**
* @param EavConfig $eavConfig
*/
public function __construct(
\Magento\Catalog\Model\ResourceModel\Category\CollectionFactory $collectionFactory
) {
$this->collectionFactory = $collectionFactory;
}
public function toOptionArray()
{
$optionArray = [];
$arr = $this->collectionFactory->create()->addAttributeToSelect('*');
foreach ($arr as $key => $value) {
$optionArray[] = [
'value' => $value->getId(),
'label' => $value->getName(),
];
}
return $optionArray;
}
}
Create adminhtml_system_config_edit.xml to add CSS
app/code/Vendor/Module/view/adminhtml/layout/adminhtml_system_config_edit.xml
<?xml version="1.0" encoding="UTF-8"?>
<!--
/**
* Created By : Rohan Hapani
*/
-->
<page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd">
<head>
<css src="Vendor_Module::css/chosen/chosen.css"/>
</head>
</page>
Create app/code/Vendor/Module/view/adminhtml/requirejs-config.js file for add js
var config = {
map: {
'*': {
chosen: 'Vendor_Module/js/chosen/chosen.jquery'
}
}
};
To Download chosen zip : Click here
Deploy and clean cache.
Output :
Github : Click Here
You need to update system.xml file with below category filed
<field id="categories" translate="label" type="multiselect" sortOrder="12" showInDefault="1" showInWebsite="1" showInStore="1">
<label>Category</label>
<source_model>Namespace\Yourmodule\Model\Config\Source\Category</source_model>
</field>
And now create this file Category.php
Path: app/code/Namespace/Yourmodule/Model/Config/Source/
And add this code
<?php
namespace Namespace\Yourmodule\Model\Config\Source;
use Magento\Framework\Option\ArrayInterface;
class Category implements ArrayInterface
{
protected $_categoryFactory;
protected $_categoryCollectionFactory;
public function __construct(
\Magento\Catalog\Model\CategoryFactory $categoryFactory,
\Magento\Catalog\Model\ResourceModel\Category\CollectionFactory $categoryCollectionFactory
)
{
$this->_categoryFactory = $categoryFactory;
$this->_categoryCollectionFactory = $categoryCollectionFactory;
}
public function getCategoryCollection($isActive = true, $level = false, $sortBy = false, $pageSize = false)
{
$collection = $this->_categoryCollectionFactory->create();
$collection->addAttributeToSelect('*');
// select only active categories
if ($isActive) {
$collection->addIsActiveFilter();
}
// select categories of certain level
if ($level) {
$collection->addLevelFilter($level);
}
// sort categories by some value
if ($sortBy) {
$collection->addOrderField($sortBy);
}
// select certain number of categories
if ($pageSize) {
$collection->setPageSize($pageSize);
}
return $collection;
}
public function toOptionArray()
{
$arr = $this->_toArray();
$ret = [];
foreach ($arr as $key => $value)
{
$ret[] = [
'value' => $key,
'label' => $value
];
}
return $ret;
}
private function _toArray()
{
$categories = $this->getCategoryCollection(true, false, false, false);
$catagoryList = array();
foreach ($categories as $category)
{
$catagoryList[$category->getEntityId()] = __($this->_getParentName($category->getPath()) . $category->getName());
}
return $catagoryList;
}
private function _getParentName($path = '')
{
$parentName = '';
$rootCats = array(1,2);
$catTree = explode("/", $path);
// Deleting category itself
array_pop($catTree);
if($catTree && (count($catTree) > count($rootCats)))
{
foreach ($catTree as $catId)
{
if(!in_array($catId, $rootCats))
{
$category = $this->_categoryFactory->create()->load($catId);
$categoryName = $category->getName();
$parentName .= $categoryName . ' -> ';
}
}
}
return $parentName;
}
}
Result:
Hope this will help you!
You can try this way ..
First you update below field in system.xml
<field id="categories" translate="label" type="multiselect" sortOrder="60" showInDefault="1" showInWebsite="1" showInStore="1" >
<label>Categories</label>
<source_model>Vendor\Module\Model\Source\Categories</source_model>
</field>
After create file Categories.php
app/code/Vendor/Module/Model/Source/Categories.php
<?php
namespace Vendor\Module\Model\Source;
use Magento\Framework\Option\ArrayInterface;
use Magento\Catalog\Model\ResourceModel\Category\CollectionFactory;
class Categories implements ArrayInterface
{
const ALL_CATEGORIES = 0;
const SYSTEM_CATEGORY_ID = 1;
const ROOT_LEVEL = 1;
/**
* @var CollectionFactory
*/
private $collectionFactory;
public function __construct(
CollectionFactory $collectionFactory
) {
$this->collectionFactory = $collectionFactory;
}
/**
* Options getter
*
* @return array
*/
public function toOptionArray()
{
$optionArray = [];
$arr = $this->toArray();
foreach ($arr as $value => $label) {
$optionArray[] = [
'value' => $value,
'label' => $label
];
}
return $optionArray;
}
/**
* Get options in "key-value" format
*
* @return array
*/
public function toArray()
{
return $this->getChildren(self::SYSTEM_CATEGORY_ID, self::ROOT_LEVEL);
}
/**
* @param $parentCategoryId
* @param $level
* @return array
*/
private function getChildren($parentCategoryId, $level)
{
$options[self::ALL_CATEGORIES] = __('All Categories');
$collection = $this->collectionFactory->create();
$collection->addAttributeToSelect('name');
$collection->addAttributeToFilter('level', $level);
$collection->addAttributeToFilter('parent_id', $parentCategoryId);
$collection->addAttributeToFilter('is_active', 1);
$collection->setOrder('position', 'asc');
foreach ($collection as $category) {
if ($category->getLevel() > self::ROOT_LEVEL) {
$options[$category->getId()] =
str_repeat(". ", max(0, ($category->getLevel() - 1) * 3)) . $category->getName();
}
if ($category->hasChildren()) {
$options = array_replace($options, $this->getChildren($category->getId(), $category->getLevel() + 1));
}
}
return $options;
}
}
Check this doc.
https://devdocs.magento.com/guides/v2.4/ui_comp_guide/components/ui-secondary-uiselect.html
May be help for you.