Question

I need to show category tree, just like in admin section, in my custom page. I viewed this solution in magento.stackexchange.com. It was good but limited to 2 levels of category. I need all the categories. How can it be done?

Was it helpful?

Solution

I searched over internet for solution to this but got nothing useful. Then I diverted my research towards Magento core where I found \Magento\Catalog\Block\Adminhtml\Category\Tree class where I found a function getTree(). Then I tried to observed it's return value in my custom template file. The effort became fruitful as I got the desired result.

I created a block file where I have injected the above class as:

<?php
namespace Vendor\Module\Block;

class CategoriesColle extends \Magento\Framework\View\Element\Template
{

    ...
    protected $adminCategoryTree;

    /**
     * @param \Magento\Framework\View\Element\Template\Context $context
     * @param \Magento\Catalog\Helper\Category $categoryHelper
     * @param array $data
     */
    public function __construct(

       ...
        \Magento\Catalog\Block\Adminhtml\Category\Tree $adminCategoryTree

    )
    {
        ...
        $this->adminCategoryTree = $adminCategoryTree;

    }
    public function getTree()
    {
        return $this->adminCategoryTree->getTree(); 
    }
...

}

The return value of the getTree() is the desired array of the category tree which can be verified by dumping the value in template file.

OTHER TIPS

You can create your own tree with custom collection as follows: Firstly add a field in your ui-form:

<field name="custom" component="Namespce_Modulename/js/select-category" sortOrder="20" formElement="select">
<argument name="data" xsi:type="array">
    <item name="config" xsi:type="array">
        <item name="filterOptions" xsi:type="boolean">true</item>//to add filter in select-ui
        <item name="multiple" xsi:type="boolean">false</item>//select multiple or not
        <item name="showCheckbox" xsi:type="boolean">true</item>//to show checkboxes
        <item name="disableLabel" xsi:type="boolean">true</item>
    </item>
</argument>
<settings>
    <required>true</required>
    <validation>
        <rule name="required-entry" xsi:type="boolean">true</rule>
    </validation>
    <elementTmpl>ui/grid/filters/elements/ui-select</elementTmpl>
    <label translate="true">Select Category</label>//label to Field
    <dataScope>data.custom</dataScope>//To map
    <componentType>field</componentType>
    <listens>
        <link name="${ $.namespace }.${ $.namespace }:responseData">setParsed</link>
    </listens>
</settings>
<formElements>
    <select>
        <settings>
            <options class="Namespace\ModuleName\Ui\Component\Form\Category\Options"/>
        </settings>
    </select>
</formElements>

Now create Js file to map the field's value:

Namespace_Modulename/view/adminhtml/web/js/select-category.js

define([
'Magento_Ui/js/form/element/ui-select'
], function (Select) {
'use strict';
return Select.extend({
    /**
     * Parse data and set it to options.
     *
     * @param {Object} data - Response data object.
     * @returns {Object}
     */
    setParsed: function (data) {
        var option = this.parseData(data);
        if (data.error) {
            return this;
        }
        this.options([]);
        this.setOption(option);
        this.set('newOption', option);
    },
    /**
     * Normalize option object.
     *
     * @param {Object} data - Option object.
     * @returns {Object}
     */
    parseData: function (data) {
        return {
            value: data.category.entity_id,
            label: data.category.name
        };
    }
});
});

Create a file to get options to display:

Namespace\ModuleName\Ui\Component\Form\Category\Options.php

<?php
namespace Namespace\ModuleName\Ui\Component\Form\Category;

use Magento\Framework\Data\OptionSourceInterface;
use Magento\Category\Model\ResourceModel\Category\CollectionFactory as      CategoryCollectionFactory;
use Magento\Framework\App\RequestInterface;

/**
* Options tree for "Categories" field
*/
class Options implements OptionSourceInterface
{

protected $categoryCollectionFactory;

/**
 * @var RequestInterface
 */
protected $request;

/**
 * @var array
 */
protected $categoryTree;

/**
 * @param CategoryCollectionFactory $categoryCollectionFactory
 * @param RequestInterface $request
 */
public function __construct(
    CategoryCollectionFactory $categoryCollectionFactory,
    RequestInterface $request
) {
    $this->categoryCollectionFactory = $categoryCollectionFactory;
    $this->request = $request;
}

/**
 * {@inheritdoc}
 */
public function toOptionArray()
{
    return $this->getCategoryTree();
}

/**
 * Retrieve categories tree
 *
 * @return array
 */
protected function getCategoryTree()
{
    if ($this->categoryTree === null) {
        $collection = $this->categoryCollectionFactory->create();

        $collection->addNameToSelect();

        foreach ($collection as $category) {
            $categoryId = $category->getEntityId();
            if (!isset($categoryById[$categoryId])) {
                $categoryById[$categoryId] = [
                    'value' => $categoryId
                ];
            }
            $categoryById[$categoryId]['label'] = $category->getName();
        }
        $this->categoryTree = $categoryById;
    }
    return $this->categoryTree;
}

}

Hope it helps!

// Get all the children categories of given category collection factory
foreach ($collection as $key => $value) {
            $temp = $value->getData();
            $categoryObj = $this->_repository->get($temp['entity_id']);
            $subcategories = $categoryObj->getChildrenCategories();
            foreach($subcategories as $key2 => $subcategorie) {
                if($subcategorie->hasChildren()) {
                    $childCategoryObj = $this->_repository->get($subcategorie->getId());
                    $childSubcategories = $childCategoryObj->getChildrenCategories();
                    foreach($childSubcategories as $childSubcategorie) {
                        $temp2 = $childSubcategorie->getData();
                        $temp1['children'][] = $temp2;
                    }
                    $temp['children'][] = $temp1;
                }
            }
            $item[$key][] = $temp;
        }
// Here you can get all the children upto 2 level in "item" variable
echo "<pre>";
print_r($item);
$objectManager = \Magento\Framework\App\ObjectManager::getInstance();
                //$category = $objectManager->create('Magento\Catalog\Model\Category')
                //Magento\Customer\Model\ResourceModel\Customer\CollectionFactory
                $category = $objectManager->create('Magento\Catalog\Model\ResourceModel\Category\CollectionFactory')->create()
                    ->addAttributeToSelect('entity_id')
                    ->addAttributeToSelect('name')
                    ->addAttributeToSelect('parent_id')
                    ->addAttributeToSelect('url_path')
                    ->addAttributeToSelect('request_path')
                    ->addAttributeToSelect('include_in_menu')
                    //->addAttributeToSelect('*')
                    ->addAttributeToFilter('level',array('nin' => array(1)))
                    ->addAttributeToFilter('path',array('like' => '%'.$rootCategoryId.'%'))
                    ->addAttributeToSort('parent_id', 'ASC')
                    ->addAttributeToSort('position', 'ASC')
                    ->addAttributeToSort('path', 'ASC');
            
                // print_r($category->getData());
                $catArray = [];
                foreach ($category as $cat){
                    $catArray[$cat->getID()]['id']= $cat->getID();
                    $catArray[$cat->getID()]['name'] = $cat->getName();
                    $catArray[$cat->getID()]['parent_id'] = $cat->getParentId();
                    $catArray[$cat->getID()]['position'] = $cat->getPosition();
                    $catArray[$cat->getID()]['path'] = $cat->getPath();
                }
                print_r($catArray);
Licensed under: CC-BY-SA with attribution
Not affiliated with magento.stackexchange
scroll top