1

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.

9

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"}}
  • 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 – Raphael at Digital Pianism Apr 8 '16 at 8:19
  • 4
    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 Apr 8 '16 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 Apr 21 '16 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 Apr 21 '16 at 15:56
  • Reference from within CMS block / page like so: {{block class="Vendor\ModuleName\Block\CategoryCollect" template="Vendor_ModuleName::categorycollect.phtml"}} – Joshua34 Apr 21 '16 at 15:57
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();
  • 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 Apr 7 '16 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 – Raphael at Digital Pianism Apr 8 '16 at 8:18
  • How can I modify the collection? – Jimmery Apr 21 '16 at 15:38
2

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_url');
    }
}
2

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;?>
  • be aware this will not work with "flat" categories enabled – roman204 May 15 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 17 hours ago
  • 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. – Adel Abula - MageBinary 34 mins ago

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.