4

I am trying to get at Category Images from within Magento_Catalog\template\navigation\left.phtml. This file shows a list of sub-categories.

This is that file:

<?php if (!$block->getCategory()) {
    return;
} ?>
<?php $_categories = $block->getCurrentChildCategories(); ?>
<?php $_count = is_array($_categories) ? count($_categories) : $_categories->count(); ?>
<?php if ($_count): ?>
    <div class="block filter">
        <div class="title">
            <strong><?php /* @escapeNotVerified */ echo __('Shop By') ?></strong>
        </div>
        <div class="content">
            <strong class="subtitle"><?php /* @escapeNotVerified */ echo __('Shopping Options') ?></strong>
            <dl class="options" id="narrow-by-list2">
                <dt><?php /* @escapeNotVerified */ echo __('Category') ?></dt>
                <dd>
                    <ol class="items">
                        <?php foreach ($_categories as $_category): ?>
                            <?php if ($_category->getIsActive()): ?>
                                <li class="item">
                                    <a href="<?php /* @escapeNotVerified */ echo $block->getCategoryUrl($_category) ?>"<?php if ($block->isCategoryActive($_category)): ?> class="current"<?php endif; ?>>
                                        <img src="<?php echo $block->getCategory($_category)->getImageUrl(); ?>">
                                        <p><?php echo $block->escapeHtml($_category->getName()) ?></p>
                                    </a>
                                    <span class="count"><?php /* @escapeNotVerified */ echo $_category->getProductCount() ?></span>
                                </li>
                            <?php endif; ?>
                        <?php endforeach ?>
                    </ol>
                </dd>
            </dl>
        </div>
    </div>
<?php endif; ?>

The line I was hoping would work is:

$block->getCategory($_category)->getImageUrl();

However this is returning the image for the current category, not the sub-categories.

4 Answers 4

11

Three hours later...

This will render from a category page. You may have to modify to work with your exact requirements.

Add this block to your Module: Block/CategoryCollect.php

<?php
namespace Joshua34\UpdateHead\Block;
class CategoryCollect extends \Magento\Framework\View\Element\Template
{
    protected $_categoryHelper;
    protected $categoryFlatConfig;
    protected $topMenu;

    /**
     * @param \Magento\Framework\View\Element\Template\Context $context
     * @param \Magento\Catalog\Helper\Category $categoryHelper
     * @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\Theme\Block\Html\Topmenu $topMenu
    )
    {
        $this->_categoryHelper = $categoryHelper;
        $this->categoryFlatConfig = $categoryFlatState;
        $this->topMenu = $topMenu;
        parent::__construct($context);
    }

    /**
     * Return categories helper
     */
    public function getCategoryHelper()
    {
        return $this->_categoryHelper;
    }

    /**
     * Return categories helper
     * getHtml($outermostClass = '', $childrenWrapClass = '', $limit = 0)
     * example getHtml('level-top', 'submenu', 0)
     */
    public function getHtml()
    {
        return $this->topMenu->getHtml();
    }

    /**
     * Retrieve current store categories
     *
     * @param bool|string $sorted
     * @param bool $asCollection
     * @param bool $toLoad
     * @return \Magento\Framework\Data\Tree\Node\Collection|\Magento\Catalog\Model\Resource\Category\Collection|array
     */
    public function getStoreCategories($sorted = false, $asCollection = false, $toLoad = true)
    {
        return $this->_categoryHelper->getStoreCategories($sorted, $asCollection, $toLoad);
    }

    /**
     * Retrieve child store categories
     *
     */
    public function getChildCategories($category)
    {
        if ($this->categoryFlatConfig->isFlatEnabled() && $category->getUseFlatResource()) {
            $subcategories = (array)$category->getChildrenNodes();
        } else {
            $subcategories = $category->getChildren();
        }
        return $subcategories;
    }
}

Add this template file to your Module: view/frontend/templates/categorycollect.phtml

<?php
$objectManager = \Magento\Framework\App\ObjectManager::getInstance();
$category = $objectManager->get('Magento\Framework\Registry')->registry('current_category');//get current category
$subcats = $category->getChildrenCategories();
$_helper = $this->helper('Magento\Catalog\Helper\Output');
?>
<ul>
    <?php
    foreach ($subcats as $subcat) {
        if ($subcat->getIsActive()) {
            $_category = $objectManager->create('Magento\Catalog\Model\Category')->load($subcat->getId());
            $_outputhelper = $this->helper('Magento\Catalog\Helper\Output');
            $subcaturl = $subcat->getUrl();

            $_imgHtml = '';
            if ($_imgUrl = $_category->getImageUrl()) {

                $_imgHtml = '<img src="' . $_imgUrl . '" />';
                $_imgHtml = $_outputhelper->categoryAttribute($_category, $_imgHtml, 'image');

                /* @escapeNotVerified */
                echo '<li><a href="' . $subcaturl . '" class="block-promo" title="' . $subcat->getName() . '">' . $_imgHtml . '<span style="background-color: rgba(255,255,255,0.9)" class="content bg-white"><strong>Place custom code here</strong><br><br><span class="action more button">Learn More</span></span></a></li>';
            }
        }
    } ?>
</ul>

Reference from within CMS block / page

 {{block class="Vendor\ModuleName\Block\CategoryCollect" template="Vendor_ModuleName::categorycollect.phtml"}}
8
  • Even though I assume that would work, loading the entire category is not very efficient in terms of performance and the use of collection with addAttributeToSelect('image') should be preferred Commented Apr 8, 2016 at 8:19
  • 6
    Between me and M2, efficiency is constantly being sacrificed just to accomplish basic tasks. Not enough time, docs or support to discover the "best way" while still accomplishing "a way", in a timely manner.
    – Joshua34
    Commented Apr 8, 2016 at 13:34
  • @Joshua34com thanks for this! just want to check - is view/frontend/templatescategorycollect.phtml correct? I have no files there - most of my phtml files are in Magento_Theme/templates - if that place is correct, how do I reference it so it appears on a page of my choice?
    – Jimmery
    Commented Apr 21, 2016 at 15:37
  • Sorry, corrected answer spelling. File should be created within your module here: app/code/Vendor/ModuleName/view/frontend/templates/categorycollect.phtml
    – Joshua34
    Commented Apr 21, 2016 at 15:56
  • Reference from within CMS block / page like so: {{block class="Vendor\ModuleName\Block\CategoryCollect" template="Vendor_ModuleName::categorycollect.phtml"}}
    – Joshua34
    Commented Apr 21, 2016 at 15:57
5

You can add attributes to child category collections with a plugin, here's an example module (code not tested):

./composer.json

{
    "name": "stackoverflow/module-child-category-image",
    "require": {
        "magento/framework": "101.*",
        "magento/magento-composer-installer": "*"
    },
    "type": "magento2-module",
    "autoload": {
        "files": [
            "registration.php"
        ],
        "psr-4": {
            "StackOverflow\\ChildCategoryImage\\": ""
        }
    }
}

./registration.php

<?php
\Magento\Framework\Component\ComponentRegistrar::register(
    \Magento\Framework\Component\ComponentRegistrar::MODULE,
    'StackOverflow_ChildCategoryImage',
    __DIR__
);

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

./etc/di.xml

<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
    <type name="Magento\Catalog\Model\ResourceModel\Category">
        <plugin name="category" type="\StackOverflow\ChildCategoryImage\Plugin\Category" />
    </type>
</config>

./etc/frontend/events.xml

<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Event/etc/events.xsd">
    <event name="catalog_category_flat_loadnodes_before">
        <observer name="category_flat_add_image" instance="StackOverflow\ChildCategoryImage\Observer\FlatCategory" />
    </event>
</config>

./Plugin/Category.php

<?php
namespace StackOverflow\ChildCategoryImage\Plugin;

use Magento\Catalog\Model\ResourceModel\Category as Subject;

class Category
{
    /**
     * Add Image to Child Category Collection
     *
     * @param Subject $subject
     * @param Magento\Catalog\Model\Category $category
     * @return Magento\Catalog\Model\ResourceModel\Category\Collection
     */
    public function afterGetChildrenCategories(
        Subject $subject,
        $collection
    ) {
        $collection->addAttributeToSelect('image_url');
        return $collection;
    }
}

./Observer/FlatCategory.php

<?php
namespace StackOverflow\ChildCategoryImage\Observer;

use Magento\Framework\Event\ObserverInterface;
use Magento\Framework\Event\Observer;

class FlatCategory implements ObserverInterface
{
    public function execute(
        Observer $observer
    ) {
        $select = $observer->getData('select');
        $select->columns('image');
    }
}
1
  • 1
    Best solution, however for Magento 2.3.3 I had to change 'image_url' to 'image' in the observer
    – Dan Norris
    Commented Jan 15, 2020 at 15:14
3

Lots of solutions above would cause serious performance issues. Try this.

$_category  = $block->getCurrentCategory();
$_subCategories = $_category->getChildrenCategories()->addAttributeToSelect('image');
<?php foreach ($_subCategories as $_sub):?>
    <?php echo($_sub->getImageUrl());?>
<?php endforeach;?>
3
  • 1
    be aware this will not work with "flat" categories enabled
    – roman204
    Commented May 15, 2019 at 7:42
  • In the interest of self improvement, where do you see a performance issue in my solution? It's just modifying the original collection with a plugin and modifying the column selection for flat?
    – Chedaroo
    Commented Jun 25, 2019 at 13:02
  • Nothing wrong with your solution. I was referring to the very first solution. " $_category = $objectManager->create('Magento\Catalog\Model\Category')->load($subcat->getId());" loading in the template is slow as. Commented Jun 26, 2019 at 5:48
2

To me:

$block->getCategory($_category)->getImageUrl();

Means that you are retrieving the main category of the block so yeah to fix that, I reckon you should modify your code to this:

$_category->getImageUrl();
3
  • I agree with your first point, however $_category->getImageUrl(); only returns false. When I do a var_dump(get_class_methods($_category)); there doesnt seem to be anything there that relates to images.
    – Jimmery
    Commented Apr 7, 2016 at 16:16
  • yeah problem is the image is not part of the child categories attribute that's why you get nothing I reckon you'll have to modify the collection to select the image Commented Apr 8, 2016 at 8:18
  • How can I modify the collection?
    – Jimmery
    Commented Apr 21, 2016 at 15:38

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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