How to add a custom image field to Catalog Category in Magento 2

31 octobre 2018 0 Par admin

This article explains the steps needed to add a custom image field to categories in Magento 2. The code is tested on Magento version 2.1.2.

First, in the InstallData script of your custom module, insert a category image attribute to Catalog Category model. In this example the attribute name is ‘thumbnail’.
File: app/code/Vendor/Module/Setup/InstallData.php

    ...
    public function install(ModuleDataSetupInterface $setup, ModuleContextInterface $context)
    {                
        /** @var \Magento\Catalog\Setup\CategorySetup $categorySetup */
        $categorySetup = $this->categorySetupFactory->create(['setup' => $setup]);
 
        $categorySetup->addAttribute(
            \Magento\Catalog\Model\Category::ENTITY,
            'thumbnail',
            [
                'type' => 'varchar',
                'label' => 'Thumbnail',
                'input' => 'image',
                'backend' => 'Magento\Catalog\Model\Category\Attribute\Backend\Image',
                'required' => false,
                'sort_order' => 5,
                'global' => ScopedAttributeInterface::SCOPE_STORE,
                'group' => 'Content',
                'is_used_in_grid' => false,
                'is_visible_in_grid' => false,
                'is_filterable_in_grid' => false
            ]
        );
    }    
    ...

$categorySetup->addAttribute(
\Magento\Catalog\Model\Category::ENTITY,
‘thumbnail’,
[
‘type’ => ‘varchar’,
‘label’ => ‘Thumbnail’,
‘input’ => ‘image’,
‘backend’ => ‘Magento\Catalog\Model\Category\Attribute\Backend\Image’,
‘required’ => false,
‘sort_order’ => 5,
‘global’ => ScopedAttributeInterface::SCOPE_STORE,
‘group’ => ‘Content’,
‘is_used_in_grid’ => false,
‘is_visible_in_grid’ => false,
‘is_filterable_in_grid’ => false
]
);
}

Then add the image field to Category form using category_form.xml. In this example, our thumbnail image field will appear after the default ‘Category Image’ field.
File: app/code/Vendor/Module/view/adminhtml/ui_component/category_form.xml

<form xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Ui:etc/ui_configuration.xsd">    
    <fieldset name="content">
        <argument name="data" xsi:type="array">
            <item name="config" xsi:type="array">
                <item name="label" xsi:type="string" translate="true">Content</item>
                <item name="collapsible" xsi:type="boolean">true</item>
                <item name="sortOrder" xsi:type="number">10</item>
            </item>
        </argument>        
        <field name="thumbnail">
            <argument name="data" xsi:type="array">
                <item name="config" xsi:type="array">
                    <item name="dataType" xsi:type="string">string</item>
                    <item name="source" xsi:type="string">category</item>
                    <item name="label" xsi:type="string" translate="true">Thumbnail Image</item>
                    <item name="visible" xsi:type="boolean">true</item>
                    <item name="formElement" xsi:type="string">fileUploader</item>
                    <item name="elementTmpl" xsi:type="string">ui/form/element/uploader/uploader</item>
                    <item name="previewTmpl" xsi:type="string">Magento_Catalog/image-preview</item>
                    <item name="required" xsi:type="boolean">false</item>
                    <item name="sortOrder" xsi:type="number">41</item>
                    <item name="uploaderConfig" xsi:type="array">
                        <item name="url" xsi:type="url" path="your_module_admin_frontname/category_thumbnail/upload"/>
                    </item>
                </item>
            </argument>
        </field>        
    </fieldset>    
</form>

Then we create a backend controller action, which is specified in ‘uploaderConfig’ section in the above ‘category_form.xml’, to handle image upload.
File: app/code/Vendor/Module/Controller/Adminhtml/Category/Thumbnail/Upload.php

namespace Vendor\Module\Controller\Adminhtml\Category\Thumbnail;
 
use Magento\Framework\Controller\ResultFactory;
 
/**
 * Class Upload
 */
class Upload extends \Magento\Backend\App\Action
{
    /**
     * Image uploader
     *
     * @var \Magento\Catalog\Model\ImageUploader
     */
    protected $imageUploader;
 
    /**
     * Upload constructor.
     *
     * @param \Magento\Backend\App\Action\Context $context
     * @param \Magento\Catalog\Model\ImageUploader $imageUploader
     */
    public function __construct(
        \Magento\Backend\App\Action\Context $context,
        \Magento\Catalog\Model\ImageUploader $imageUploader
    ) {
        parent::__construct($context);
        $this->imageUploader = $imageUploader;
    }
 
    /**
     * Check admin permissions for this controller
     *
     * @return boolean
     */
    protected function _isAllowed()
    {
        return $this->_authorization->isAllowed('Magento_Catalog::categories');
    }
 
    /**
     * Upload file controller action
     *
     * @return \Magento\Framework\Controller\ResultInterface
     */
    public function execute()
    {
        try {           
            $result = $this->imageUploader->saveFileToTmpDir('thumbnail');
 
            $result['cookie'] = [
                'name' => $this->_getSession()->getName(),
                'value' => $this->_getSession()->getSessionId(),
                'lifetime' => $this->_getSession()->getCookieLifetime(),
                'path' => $this->_getSession()->getCookiePath(),
                'domain' => $this->_getSession()->getCookieDomain(),
            ];
        } catch (\Exception $e) {
            $this->_objectManager->get('Psr\Log\LoggerInterface')->critical($e);
            $result = ['error' => $e->getMessage(), 'errorcode' => $e->getCode()];
        }
        return $this->resultFactory->create(ResultFactory::TYPE_JSON)->setData($result);
    }
}

use Magento\Framework\Controller\ResultFactory;

/**
* Class Upload
*/
class Upload extends \Magento\Backend\App\Action
{
/**
* Image uploader
*
* @var \Magento\Catalog\Model\ImageUploader
*/
protected $imageUploader;

/**
* Upload constructor.
*
* @param \Magento\Backend\App\Action\Context $context
* @param \Magento\Catalog\Model\ImageUploader $imageUploader
*/
public function __construct(
\Magento\Backend\App\Action\Context $context,
\Magento\Catalog\Model\ImageUploader $imageUploader
) {
parent::__construct($context);
$this->imageUploader = $imageUploader;
}

/**
* Check admin permissions for this controller
*
* @return boolean
*/
protected function _isAllowed()
{
return $this->_authorization->isAllowed(‘Magento_Catalog::categories’);
}

/**
* Upload file controller action
*
* @return \Magento\Framework\Controller\ResultInterface
*/
public function execute()
{
try {
$result = $this->imageUploader->saveFileToTmpDir(‘thumbnail’);

$result[‘cookie’] = [
‘name’ => $this->_getSession()->getName(),
‘value’ => $this->_getSession()->getSessionId(),
‘lifetime’ => $this->_getSession()->getCookieLifetime(),
‘path’ => $this->_getSession()->getCookiePath(),
‘domain’ => $this->_getSession()->getCookieDomain(),
];
} catch (\Exception $e) {
$this->_objectManager->get(‘Psr\Log\LoggerInterface’)->critical($e);
$result = [‘error’ => $e->getMessage(), ‘errorcode’ => $e->getCode()];
}
return $this->resultFactory->create(ResultFactory::TYPE_JSON)->setData($result);
}
}

To save the image details to database, a Plugin for Magento\Catalog\Controller\Adminhtml\Category\Save is created to append the image field details during category save action.
File: app/code/Vendor/Module/Controller/Adminhtml/Category/Save/Plugin.php

namespace Vendor\Module\Controller\Adminhtml\Category\Save;
 
class Plugin
{           
    //add thumnail field to $data for saving
    public function afterImagePreprocessing(\Magento\Catalog\Controller\Adminhtml\Category\Save $subject, $data)
    {
        if (isset($data['thumbnail']) && is_array($data['thumbnail'])) {
            if (!empty($data['thumbnail']['delete'])) {
                $data['thumbnail'] = null;
            } else {
                if (isset($data['thumbnail'][0]['name']) && isset($data['thumbnail'][0]['tmp_name'])) {
                    $data['thumbnail'] = $data['thumbnail'][0]['name'];
                } else {
                    unset($data['thumbnail']);
                }
            }
        }else{
            $data['thumbnail'] = null;
        }
 
        return $data;
    }
 
}

class Plugin
{
//add thumnail field to $data for saving
public function afterImagePreprocessing(\Magento\Catalog\Controller\Adminhtml\Category\Save $subject, $data)
{
if (isset($data[‘thumbnail’]) && is_array($data[‘thumbnail’])) {
if (!empty($data[‘thumbnail’][‘delete’])) {
$data[‘thumbnail’] = null;
} else {
if (isset($data[‘thumbnail’][0][‘name’]) && isset($data[‘thumbnail’][0][‘tmp_name’])) {
$data[‘thumbnail’] = $data[‘thumbnail’][0][‘name’];
} else {
unset($data[‘thumbnail’]);
}
}
}else{
$data[‘thumbnail’] = null;
}

return $data;
}

}

Finally, to retrieve and display the saved image in a category form we create another Plugin for Magento\Catalog\Model\Category\DataProvider
File: app/code/Vendor/Module/Model/Category/DataProvider/Plugin.php

namespace Vendor\Module\Model\Category\DataProvider;
 
class Plugin
{       
    protected $_storeManager;
 
    public function __construct(        
        \Magento\Store\Model\StoreManagerInterface $storeManager
    ) {       
        $this->_storeManager = $storeManager;    
    }
 
    //retrieve thumnail data for output
    public function afterGetData(\Magento\Catalog\Model\Category\DataProvider $subject, $result)
    {
        $category = $subject->getCurrentCategory();
        $categoryData = $result[$category->getId()];
 
        if (isset($categoryData['thumbnail'])) {
            unset($categoryData['thumbnail']);
            $categoryData['thumbnail'][0]['name'] = $category->getData('thumbnail');
            $categoryData['thumbnail'][0]['url'] = $this->getThumbnailUrl($category->getData('thumbnail'));
        }
 
        $result[$category->getId()] = $categoryData;
 
        return $result;
    }
 
    protected function getThumbnailUrl($imageName){
        $url = $this->_storeManager->getStore()->getBaseUrl(
                \Magento\Framework\UrlInterface::URL_TYPE_MEDIA
            ) . 'catalog/category/' . $imageName;
        return $url;
    }
}

class Plugin
{
protected $_storeManager;

public function __construct(
\Magento\Store\Model\StoreManagerInterface $storeManager
) {
$this->_storeManager = $storeManager;
}

//retrieve thumnail data for output
public function afterGetData(\Magento\Catalog\Model\Category\DataProvider $subject, $result)
{
$category = $subject->getCurrentCategory();
$categoryData = $result[$category->getId()];

if (isset($categoryData[‘thumbnail’])) {
unset($categoryData[‘thumbnail’]);
$categoryData[‘thumbnail’][0][‘name’] = $category->getData(‘thumbnail’);
$categoryData[‘thumbnail’][0][‘url’] = $this->getThumbnailUrl($category->getData(‘thumbnail’));
}

$result[$category->getId()] = $categoryData;

return $result;
}

protected function getThumbnailUrl($imageName){
$url = $this->_storeManager->getStore()->getBaseUrl(
\Magento\Framework\UrlInterface::URL_TYPE_MEDIA
) . ‘catalog/category/’ . $imageName;
return $url;
}
}

The complete working module for Magento 2.1.x can be downloaded here.

Please follow and like us: