2

I'm trying to create a list of child categories with links to those categories and their image.

I'm having an issue with getting the image, but all the other functions seem to be working properly. Here is my custom block inside a custom module. (By the way if theres already a better way to do this, do tell!)

# File ChildCategoryBlock.php
public function getChildCategories(){
    // $this->_catalogLayer is an instance of Magento\Catalog\Block\Navigation
    $children = $this->_catalogLayer->getCurrentCategory()->getChildrenCategories();
    foreach($children as $child){
        if( $imgsrc = $child->getImageUrl() ) {
            echo "<img src='" . $imgsrc . "' alt='' class='' />";
        }        // above does nothing

        var_dump( $child->getId() ); //-> (int) 9
        var_dump( $child->getName() ); //-> (str) Fitness
        var_dump( $child->getImage() ); //-> (bool) false
    }


}

I think I'm doing this correctly. In Magento I have a test image set for category ID 9 (Fitness):

Magento CMS - Category Fitness Image

4

edit

After looking at your answer, here are my comments.

Unfortunately Magento does not provide a getList method on the CategoryRepositoryInterface. This means we can't load a list of categories easily when using the repository, which leads to the only other method of loading categories via the repository which is looping & loading each separately.

While this will work, it's up to you to decide which code style you prefer for your particular use case. I've fixed up my code below which uses the collection pattern.

/edit

It looks like you need to add the image attribute to your category collection. A collection in Magento will not load all data for each entity, only the attributes that are explicitly specified.

The below code should do the trick:

$children = $this->_catalogLayer
    ->getCurrentCategory()
    ->getChildrenCategories()
    ->clear() // clears previously loaded collection data
    ->addAttributeToSelect('image')
;

You can also add multiple attributes to the collection if required:

$children = $this->_catalogLayer
    ->getCurrentCategory()
    ->getChildrenCategories()
    ->clear() // clears previously loaded collection data
    ->addAttributeToSelect([
        'image',
        'my_attribute',
        'my_other_attribute',
    ])
;
3
  • Thanks for the response. I was unable to get it to work this way, I'm not sure why (I also tried '*' as an argument). What I ended up doing seems completely incorrect but works. I'll post my solution, but if you care to try again and improve on mine I'll be happy to accept your answer. – jamil Feb 17 '17 at 0:18
  • Thanks it worked after your edits and seems more efficient than my way. While it makes sense to clear, I don't know how I would ever have known that :D – jamil Feb 17 '17 at 1:12
  • 1
    @jamil Basically, if you're not getting the attributes you expect, you can check if the collection has previously already been loaded by using the isLoaded() method. Once a collection has been loaded once (query made to DB) Magento will store the result in memory, and return the cached result. The clear() method just tells Magento to go back to the DB and query again. – Danny Nimmo Feb 17 '17 at 1:19
1

I needed to inject these classes

Magento\Framework\Registry // $_registry
Magento\Catalog\Api\CategoryRepositoryInterface // $_categoryRepository
Magento\Store\Model\StoreManagerInterface // $_storeManager

Then created these two functions to my block class.

public function getCategoryObject(){
    if ( !isset( $this->_category ) ){
        $this->_category = $this->_registry->registry('current_category');
    }
    return $this->_category;
}

public function getChildCategories(){
    $childrenTemp = $this->getCategoryObject()->getChildrenCategories();
    $storeId = $this->_storeManager->getStore()->getId();
    $children = [];
    foreach( $childrenTemp as $child ){
        $children[] = $this->_categoryRepository->get( $child->getId(), $storeId );
    }
    return $children;
}

Then in my block I can loop over children, and each object allows me to get the url using getImageUrl();

$children = $block->getChildCategories();
foreach( $children as $category ){
    echo $category->getUrl();
}

This seems crazy inefficient but I guess I don't know what I don't know and theres no documentation to prove me wrong /s

1
  • 1
    Just updated my answer, either method will work! – Danny Nimmo Feb 17 '17 at 1:00
1

You should add an event in 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="add_image_to_collection" instance="Namespace\Module\Observer\AddImage" />
    </event>
</config>

and the observer:

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

class AddImage implements ObserverInterface
{
    /**
     * @param Observer $observer
     * @return $this
     */
    public function execute(Observer $observer)
    {
        $select = $observer->getSelect();
        return $select->columns('image');
    }
}
1
  • Thanks for this, seems like a nice alternative to the other solutions – jamil Feb 9 '18 at 16:38

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.