How to get category tree in Magento 2?

The 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?

The Solutions:

Below are the methods you can try. The first solution is probably the best. Try others if the first one doesn’t work. Senior developers aren’t just copying/pasting – they read the methods carefully & apply them wisely to each case.

Method 1

I searched over internet for solution to this but got nothing useful. Then I diverted my research towards Magento core where I found MagentoCatalogBlockAdminhtmlCategoryTree 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 VendorModuleBlock;

class CategoriesColle extends MagentoFrameworkViewElementTemplate
{

    ...
    protected $adminCategoryTree;

    /**
     * @param MagentoFrameworkViewElementTemplateContext $context
     * @param MagentoCatalogHelperCategory $categoryHelper
     * @param array $data
     */
    public function __construct(

       ...
        MagentoCatalogBlockAdminhtmlCategoryTree $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.

Method 2

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="NamespaceModuleNameUiComponentFormCategoryOptions"/>
        </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:

NamespaceModuleNameUiComponentFormCategoryOptions.php

<?php
namespace NamespaceModuleNameUiComponentFormCategory;

use MagentoFrameworkDataOptionSourceInterface;
use MagentoCategoryModelResourceModelCategoryCollectionFactory as      CategoryCollectionFactory;
use MagentoFrameworkAppRequestInterface;

/**
* 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!

Method 3

$objectManager = MagentoFrameworkAppObjectManager::getInstance();
                //$category = $objectManager->create('MagentoCatalogModelCategory')
                //MagentoCustomerModelResourceModelCustomerCollectionFactory
                $category = $objectManager->create('MagentoCatalogModelResourceModelCategoryCollectionFactory')->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);

Method 4

// 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 => $subcategory) {
                if($subcategory->hasChildren()) {
                    $childCategoryObj = $this->_repository->get($subcategory->getId());
                    $childSubcategories = $childCategoryObj->getChildrenCategories();
                    foreach($childSubcategories as $childSubcategory) {
                        $temp2 = $childSubcategory->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);


All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0

Leave a Comment