Categories
Magento 2

Category Image Paths in Magento 2

There appears to be either a bug or an oddity in the way Magento 2 stores images against categories. Confusingly, there are three types of image paths which may be returned from a category.

1. Just the Image Name

This does not include path information and typically will be from attributes added in third party modules. The full base path and image path needs to be prepended to get the full path of the image.

2. The image path from ‘/media’

This includes the relative path from the media folder and does not include ‘pub’

3. The image path from ‘/pub’

This includes the full relative path from the root directory.

Magento’s core code checks for whether its path starts with a slash to determine what path modifications need to be made to get the full image path. NICE.

$isRelative = substr($imageName, 0, 1) === '/';

Helper to account for Magento 2’s behaviour

use Magento\Framework\App\Filesystem\DirectoryList;

class CategoryImageHelper extends \Magento\Framework\App\Helper\AbstractHelper {
    // Magento seemingly don't store this as a const anywhere so everyone usually just throws this
    // string around willy-nilly. I'm sure that's not creating problems down the road!
    const CATEGORY_DIR = 'catalog/category/';
    
    protected $_filesystem;
    protected $_storeManager;

    public function __construct(
        \Magento\Framework\App\Helper\Context $context,
        \Magento\Store\Model\StoreManagerInterface $storeManager,
        \Magento\Framework\Filesystem $filesystem
    ) {
        parent::__construct($context);
        $this->_filesystem = $filesystem;
        $this->_storeManager = $storeManager;
    }


    /**
     * 
     * @param string $imageName
     * @return string|bool
     */
     protected function getImagePath($imageName) 
     {
        $realPath = '';
        // Yeah. this is how Magento do it in Catalog/Model/Category.
        $isRelative = substr($imageName, 0, 1) === '/';
        
        if($isRelative) {
            // Magento might include pub in its image name. YEAH. *MIGHT*.
            $hasPub = strpos($imageName, '/' . DirectoryList::PUB . '/') === 0;
            $realPath = $this->_filesystem->getDirectoryRead($hasPub ? DirectoryList::ROOT : DirectoryList::PUB)->getAbsolutePath($imageName);
        } else {
            $realPath = $this->_filesystem->getDirectoryRead(DirectoryList::MEDIA)->getAbsolutePath(self::CATEGORY_DIR . $imageName);
        }
            
        if (!$this->_filesystem->isFile($realPath) || !$this->_filesystem->isExist($realPath)) {
            return false;
        }

        return $realPath;
    }
}