-1

I am using Magento 2.2.4 for online Bookstore. I have books under categories and sub-categories.

I need to list all these categories and sub-categories on Homepage left side like in the Screenshot below.

enter image description here

When clicking on the ctaegory, it should be navigated to the books under relevant category. Since I am fresher to Magento and PHP, I am trying customization using CMS rather code modifications. I tried this with widgets and blocks, but I could not find an effective way. Is there a way to do this?

1

I have to do something similar and I have used following code to achieve the requirement.

app/code/Anshu/CategoryFilter/registration.php

<?php

\Magento\Framework\Component\ComponentRegistrar::register(
    \Magento\Framework\Component\ComponentRegistrar::MODULE,
    'Anshu_CategoryFilter',
    __DIR__
);

app/code/Anshu/CategoryFilter/etc/module.xml

<?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="Anshu_CategoryFilter" setup_version="1.0.0">
        <sequence>
            <module name="Magento_Catalog"/>
        </sequence>
    </module>
</config>

app/code/Anshu/CategoryFilter/Block/CategoryFilter.php

<?php

namespace Anshu\CategoryFilter\Block;

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

    /**
     * @var \Magento\Catalog\Helper\Category
     */
    protected $_categoryHelper;

    /**
     * @var \Magento\Catalog\Model\Indexer\Category\Flat\State
     */
    protected $categoryFlatConfig;

    /**
     * @var \Magento\Catalog\Model\CategoryFactory
     */
    protected $_categoryFactory;

    /**
     * @param Template\Context                                        $context
     * @param \Magento\Catalog\Helper\Category                        $categoryHelper
     * @param \Magento\Catalog\Model\Indexer\Category\Flat\State      $categoryFlatState
     * @param \Magento\Catalog\Model\CategoryFactory                  $categoryFactory
     * @param array                                                   $data
     */
    public function __construct(
        \Magento\Framework\View\Element\Template\Context $context,
        \Magento\Catalog\Helper\Category $categoryHelper,
        \Magento\Catalog\Model\Indexer\Category\Flat\State $categoryFlatState,
        \Magento\Catalog\Model\CategoryFactory $categoryFactory,
        $data = []
    )
    {
        $this->_categoryHelper           = $categoryHelper;
        $this->categoryFlatConfig        = $categoryFlatState;
        $this->_categoryFactory          = $categoryFactory;
        parent::__construct($context, $data);
    }

    /**
     * Get all categories
     *
     * @param bool $sorted
     * @param bool $asCollection
     * @param bool $toLoad
     *
     * @return array|\Magento\Catalog\Model\ResourceModel\Category\Collection|\Magento\Framework\Data\Tree\Node\Collection
     */
    public function getCategories($sorted = false, $asCollection = false, $toLoad = true)
    {
        $cacheKey = sprintf('%d-%d-%d-%d', $this->getSelectedRootCategory(), $sorted, $asCollection, $toLoad);
        if ( isset($this->_storeCategories[ $cacheKey ]) )
        {
            return $this->_storeCategories[ $cacheKey ];
        }
        /**
         * Check if parent node of the store still exists
         */
        $category = $this->_categoryFactory->create();

        $storeCategories = $category->getCategories($this->getSelectedRootCategory(), $recursionLevel = 0, $sorted, $asCollection, $toLoad);
        $this->_storeCategories[ $cacheKey ] = $storeCategories;
        return $storeCategories;
    }

    /**
     * Get current store root category id
     *
     * @return int|mixed
     */
    public function getSelectedRootCategory()
    {
        return $this->_storeManager->getStore()->getRootCategoryId();
    }

    /**
     * @param        $category
     * @param string $html
     * @param int    $level
     *
     * @return string
     */
    public function getChildCategoryView($category, $html = '', $level = 1)
    {   
        // Check if category has children
        if ( $category->hasChildren() )
        {  
            $childCategories = $this->getSubcategories($category);
            $childCount = (int)$category->getChildrenCount();
            if ( $childCount > 0 )
            {   
                $html .= '<ul class="o-list o-list--unstyled" style="display:none">';
                // Loop through children categories
                foreach ( $childCategories as $childCategory )
                {
                    $html .= '<li class="level' . $level . '">';
                    $html .= '<a href="' . $this->getCategoryUrl($childCategory) . '" title="' . $childCategory->getName() . '">' . $childCategory->getName() . '</a>';
                    if ($childCategory->hasChildren())
                    {
                        $html .= '<span class="expand"><i class="fa fa-plus">+/-</i></span>';
                        $html .= $this->getChildCategoryView($childCategory, '', ($level + 1));
                    }

                    $html .= '</li>';
                }
                $html .= '</ul>';
            }
        }
        return $html;
    }

    /**
     * Retrieve subcategories
     * 
     * @param $category
     *
     * @return array
     */ 
    public function getSubcategories($category)
    {
        if ($this->categoryFlatConfig->isFlatEnabled() && $category->getUseFlatResource()) {
            $subcategories = (array)$category->getChildrenNodes();
        } else {
            $subcategories = $category->getChildren();
        }
        return $subcategories;
    }

    /**
     * Return Category URL
     *
     * @param $category
     *
     * @return string
     */
    public function getCategoryUrl($category)
    {
        return $this->_categoryHelper->getCategoryUrl($category);
    }
}

app/code/Anshu/CategoryFilter/view/frontend/requirejs-config.js

var config = {
    map: {
        '*': {
            categoryfilter: 'Anshu_CategoryFilter/js/categoryfilter'
        }
    }
};

app/code/Anshu/CategoryFilter/view/frontend/web/js/categoryfilter.js

require(['jquery'], function ($) {
    $(function () {
        $('.category-heading').on('click', function () {
            $('.category-filter').toggle();
        });
        $('.category-filter').on('click', '.o-list .expand, .o-list .expanded', function () {
            var element = $(this).parent('li');
            if (element.hasClass('active')) {
                element.find('ul:first').slideUp();
                element.removeClass('active');
            } else {
                element.addClass('active');
                element.children('ul').slideDown();
                element.parent('ul').find('i').addClass('fa-plus');
                element.find('> span i').addClass('fa-minus');
            }
        });
    });
});

app/code/Anshu/CategoryFilter/view/frontend/templates/categoryfilter.phtml

<?php
$categories = $block->getCategories();
?>
<div class="category-filter-area">
    <div class="filter-heading">
        <h3><?php echo __('CATEGORY'); ?></h3>
    </div>
    <div class="category-filter">
        <ul class="o-list">
            <?php
            // Loop through categories
            foreach ( $categories as $category ) {
                ?>
                <li class="level0">
                    <a href="<?php echo $block->getCategoryUrl($category); ?>" title="<?php echo $category->getName(); ?>">
                        <?php echo $category->getName(); ?>
                    </a>
                    <?php if ( $category->hasChildren() ) { ?>
                        <span class="expand"><i class="fa fa-plus">+/-</i></span>
                    <?php } ?>

                    <?php echo $block->getChildCategoryView($category, $html = '', $level = $category->getLevel() + 1); ?>
                </li>
            <?php } ?>
        </ul>
    </div>
</div>    
<script type="text/javascript">
    require(['jquery','categoryfilter'], function () {});
</script>

You can modify this code according to your requirement. I hope this will be helpful.

I have to show this block on cms page, so I have called it in CMS page in admin. You can call this or show this block at any place you want.

  • Thanks for the clarification. but I am not much familiar with code editing. also, my directory structure is a bit different than yours. Is there any easy way to do it using Blocks and Widgets.. like navigate bars? – SMash May 16 '18 at 8:30
  • 1
    Writes an entire module for OP - OP: "Thanks but I don't write code" – domdambrogia Jul 9 '18 at 23:12

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.