0

I want to discribe How I have created image upload field in an admin form.

My module's name is Paracrab\Banners

  1. Firstly You should add field in Paracrab/Banners/view/adminhtml/ui_component/name_name_form.xml

<field name="image" sortOrder="30" formElement="imageUploader"> <argument name="data" xsi:type="array"> <item name="config" xsi:type="array"> <item name="source" xsi:type="string">banner</item> </item> </argument> <settings> <elementTmpl>ui/form/element/uploader/image</elementTmpl> <dataType>string</dataType> <label translate="true">Banner Image</label> <visible>true</visible> <required>false</required> </settings> <formElements> <imageUploader> <settings> <required>false</required> <uploaderConfig> <param xsi:type="url" name="url" path="banner/banner/upload"/> </uploaderConfig> <openDialogTitle>Media Gallery</openDialogTitle> <initialMediaGalleryOpenSubpath>paracrab/image</initialMediaGalleryOpenSubpath> <allowedExtensions>jpg jpeg gif png</allowedExtensions> <maxFileSize>4194304</maxFileSize> </settings> </imageUploader> </formElements> </field>

name="image"it is name field in database.

  1. Will create admin Controller and Action
<?php
namespace Paracrab\Banners\Controller\Adminhtml\Banner;

use Magento\Framework\App\Action\HttpPostActionInterface;
use Magento\Framework\Controller\ResultFactory;

class Upload extends \Magento\Backend\App\Action implements HttpPostActionInterface
{

    /**
     * @var \Paracrab\Banners\Model\ImageUploader
     */
    protected $imageUploader;


    public function __construct(
        \Magento\Backend\App\Action\Context $context,
        \Paracrab\Banners\Model\ImageUploader $imageUploader
    ) {
        parent::__construct($context);
        $this->imageUploader = $imageUploader;
    }

    /**
     * @return \Magento\Framework\App\ResponseInterface|\Magento\Framework\Controller\ResultInterface
     */
    public function execute()
    {
        $imageId = $this->_request->getParam('param_name', 'image');

        try {
            $result = $this->imageUploader->saveFileToTmpDir($imageId);
        } catch (\Exception $e) {
            $result = ['error' => $e->getMessage(), 'errorcode' => $e->getCode()];
        }
        return $this->resultFactory->create(ResultFactory::TYPE_JSON)->setData($result);
    }
}

Did you notice \Paracrab\Banners\Model\ImageUploader in __construct ? You need create this class.

  1. Create Paracrab\Banners\Model\ImageUploader class
<?php
namespace Paracrab\Banners\Model;


class ImageUploader
{

    /**
     * @var \Magento\MediaStorage\Helper\File\Storage\Database
     */
    protected $coreFileStorageDatabase;

    /**
     * @var \Magento\Framework\Filesystem\Directory\WriteInterface
     */
    protected $mediaDirectory;

    /**
     * @var \Magento\MediaStorage\Model\File\UploaderFactory
     */
    private $uploaderFactory;

    /**
     * @var \Magento\Store\Model\StoreManagerInterface
     */
    protected $storeManager;

    /**
     * @var \Psr\Log\LoggerInterface
     */
    protected $logger;

    /**
     * @var
     */
    protected $baseTmpPath;

    /**
     * @var
     */
    protected $basePath;

    /**
     * @var
     */
    protected $allowedExtensions;

    /**
     * @var array
     */
    private $allowedMimeTypes;

    /**
     * ImageUploader constructor.
     * @param \Magento\MediaStorage\Helper\File\Storage\Database $coreFileStorageDatabase
     * @param \Magento\Framework\Filesystem $filesystem
     * @param \Magento\MediaStorage\Model\File\UploaderFactory $uploaderFactory
     * @param \Magento\Store\Model\StoreManagerInterface $storeManager
     * @param \Psr\Log\LoggerInterface $logger
     * @param $baseTmpPath
     * @param $basePath
     * @param $allowedExtensions
     * @param array $allowedMimeTypes
     * @throws \Magento\Framework\Exception\FileSystemException
     */
    public function __construct(
        \Magento\MediaStorage\Helper\File\Storage\Database $coreFileStorageDatabase,
        \Magento\Framework\Filesystem $filesystem,
        \Magento\MediaStorage\Model\File\UploaderFactory $uploaderFactory,
        \Magento\Store\Model\StoreManagerInterface $storeManager,
        \Psr\Log\LoggerInterface $logger,
        $baseTmpPath,
        $basePath,
        $allowedExtensions,
        $allowedMimeTypes = []
    ) {
        $this->coreFileStorageDatabase = $coreFileStorageDatabase;
        $this->mediaDirectory = $filesystem->getDirectoryWrite(\Magento\Framework\App\Filesystem\DirectoryList::MEDIA);
        $this->uploaderFactory = $uploaderFactory;
        $this->storeManager = $storeManager;
        $this->logger = $logger;
        $this->baseTmpPath = $baseTmpPath;
        $this->basePath = $basePath;
        $this->allowedExtensions = $allowedExtensions;
        $this->allowedMimeTypes = $allowedMimeTypes;
    }


    /**
     * @param $baseTmpPath
     */
    public function setBaseTmpPath($baseTmpPath)
    {
        $this->baseTmpPath = $baseTmpPath;
    }


    /**
     * @param $basePath
     */
    public function setBasePath($basePath)
    {
        $this->basePath = $basePath;
    }

    /**
     * @param $allowedExtensions
     */
    public function setAllowedExtensions($allowedExtensions)
    {
        $this->allowedExtensions = $allowedExtensions;
    }

    /**
     * @return mixed
     */
    public function getBaseTmpPath()
    {
        return $this->baseTmpPath;
    }

    /**
     * @return mixed
     */
    public function getBasePath()
    {
        return $this->basePath;
    }

    /**
     * @return mixed
     */
    public function getAllowedExtensions()
    {
        return $this->allowedExtensions;
    }

    /**
     * @param $path
     * @param $imageName
     * @return string
     */
    public function getFilePath($path, $imageName)
    {
        return rtrim($path, '/') . '/' . ltrim($imageName, '/');
    }

    /**
     * @param $imageName
     * @return mixed
     * @throws \Magento\Framework\Exception\LocalizedException
     */
    public function moveFileFromTmp($imageName)
    {
        $baseTmpPath = $this->getBaseTmpPath();
        $basePath = $this->getBasePath();

        $baseImagePath = $this->getFilePath($basePath, $imageName);
        $baseTmpImagePath = $this->getFilePath($baseTmpPath, $imageName);

        try {
            $this->coreFileStorageDatabase->copyFile(
                $baseTmpImagePath,
                $baseImagePath
            );
            $this->mediaDirectory->renameFile(
                $baseTmpImagePath,
                $baseImagePath
            );
        } catch (\Exception $e) {
            throw new \Magento\Framework\Exception\LocalizedException(
                __('Something went wrong while saving the file(s).')
            );
        }

        return $imageName;
    }

    /**
     * @param $fileId
     * @return array
     * @throws \Magento\Framework\Exception\LocalizedException
     * @throws \Magento\Framework\Exception\NoSuchEntityException
     */
    public function saveFileToTmpDir($fileId)
    {
        $baseTmpPath = $this->getBaseTmpPath();

        /** @var \Magento\MediaStorage\Model\File\Uploader $uploader */
        $uploader = $this->uploaderFactory->create(['fileId' => $fileId]);
        $uploader->setAllowedExtensions($this->getAllowedExtensions());
        $uploader->setAllowRenameFiles(true);
        if (!$uploader->checkMimeType($this->allowedMimeTypes)) {
            throw new \Magento\Framework\Exception\LocalizedException(__('File validation failed.'));
        }
        $result = $uploader->save($this->mediaDirectory->getAbsolutePath($baseTmpPath));

        unset($result['path']);

        if (!$result) {
            throw new \Magento\Framework\Exception\LocalizedException(
                __('File can not be saved to the destination folder.')
            );
        }

        /**
         * Workaround for prototype 1.7 methods "isJSON", "evalJSON" on Windows OS
         */
        $result['tmp_name'] = str_replace('\\', '/', $result['tmp_name']);
        $result['url'] = $this->storeManager
                ->getStore()
                ->getBaseUrl(
                    \Magento\Framework\UrlInterface::URL_TYPE_MEDIA
                ) . $this->getFilePath($baseTmpPath, $result['file']);
        $result['name'] = $result['file'];

        if (isset($result['file'])) {
            try {
                $relativePath = rtrim($baseTmpPath, '/') . '/' . ltrim($result['file'], '/');
                $this->coreFileStorageDatabase->saveFile($relativePath);
            } catch (\Exception $e) {
                $this->logger->critical($e);
                throw new \Magento\Framework\Exception\LocalizedException(
                    __('Something went wrong while saving the file(s).')
                );
            }
        }

        return $result;
    }
}

This class was copied from

vendor/magento/module-catalog/Model/ImageUploader.php
  1. You need create virtualType for this class in etc/di.xml with parameters
 <virtualType name="Paracrab\Banners\ImageUploader" type="Paracrab\Banners\Model\ImageUploader">
        <arguments>
            <argument name="baseTmpPath" xsi:type="string">paracrab/tmp/image</argument>
            <argument name="basePath" xsi:type="string">paracrab/image</argument>
            <argument name="allowedExtensions" xsi:type="array">
                <item name="jpg" xsi:type="string">jpg</item>
                <item name="jpeg" xsi:type="string">jpeg</item>
                <item name="gif" xsi:type="string">gif</item>
                <item name="png" xsi:type="string">png</item>
            </argument>
            <argument name="allowedMimeTypes" xsi:type="array">
                <item name="jpg" xsi:type="string">image/jpg</item>
                <item name="jpeg" xsi:type="string">image/jpeg</item>
                <item name="gif" xsi:type="string">image/gif</item>
                <item name="png" xsi:type="string">image/png</item>
            </argument>
        </arguments>
    </virtualType>
    <type name="Paracrab\Banners\Controller\Adminhtml\Banner\Upload">
        <arguments>
            <argument name="imageUploader" xsi:type="object">Paracrab\Banners\ImageUploader</argument>
        </arguments>
    </type>
    <type name="Paracrab\Banners\Controller\Adminhtml\Banners\Save">
        <arguments>
            <argument name="imageUploader" xsi:type="object">Paracrab\Banners\ImageUploader</argument>
        </arguments>
    </type>
  1. Also You should create class Paracrab/Banners/Model/Banner/FileInfo.php
<?php
namespace Paracrab\Banners\Model\Banner;

use Magento\Framework\App\Filesystem\DirectoryList;
use Magento\Framework\File\Mime;
use Magento\Framework\Filesystem;
use Magento\Framework\Filesystem\Directory\WriteInterface;
use Magento\Framework\Filesystem\Directory\ReadInterface;

/**
 * Class FileInfo
 *
 * Provides information about requested file
 */
class FileInfo
{
    /**
     * Path in /pub/media directory
     */
    const ENTITY_MEDIA_PATH = 'paracrab/image';

    /**
     * @var Filesystem
     */
    private $filesystem;

    /**
     * @var Mime
     */
    private $mime;

    /**
     * @var WriteInterface
     */
    private $mediaDirectory;

    /**
     * @var ReadInterface
     */
    private $baseDirectory;


    /**
     * @var \Magento\Store\Model\StoreManagerInterface
     */
    protected $_storeManager;

    /**
     * @param Filesystem $filesystem
     * @param Mime $mime
     */
    public function __construct(
        Filesystem $filesystem,
        Mime $mime,
        \Magento\Store\Model\StoreManagerInterface $storeManager
    ) {
        $this->filesystem = $filesystem;
        $this->mime = $mime;
        $this->_storeManager = $storeManager;
    }

    /**
     * Get WriteInterface instance
     *
     * @return WriteInterface
     */
    public function getMediaDirectory()
    {
        if ($this->mediaDirectory === null) {
            $this->mediaDirectory = $this->filesystem->getDirectoryWrite(DirectoryList::MEDIA);
        }
        return $this->mediaDirectory;
    }

    /**
     * Get Base Directory read instance
     *
     * @return ReadInterface
     */
    private function getBaseDirectory()
    {
        if (!isset($this->baseDirectory)) {
            $this->baseDirectory = $this->filesystem->getDirectoryRead(DirectoryList::ROOT);
        }

        return $this->baseDirectory;
    }

    /**
     * Retrieve MIME type of requested file
     *
     * @param string $fileName
     * @return string
     */
    public function getMimeType($fileName)
    {
        $filePath = $this->getFilePath($fileName);
        $absoluteFilePath = $this->getMediaDirectory()->getAbsolutePath($filePath);

        $result = $this->mime->getMimeType($absoluteFilePath);
        return $result;
    }

    /**
     * @param $fileName
     * @return string
     * @throws \Magento\Framework\Exception\NoSuchEntityException
     */
    public function getAbsolutePatch($fileName)
    {

        $absoluteFilePath = $this->_storeManager->getStore()->getBaseUrl(\Magento\Framework\UrlInterface::URL_TYPE_MEDIA);
        $absoluteFilePath .= $this->getFilePath($fileName);
        return $absoluteFilePath;
    }

    /**
     * Get file statistics data
     *
     * @param string $fileName
     * @return array
     */
    public function getStat($fileName)
    {
        $filePath = $this->getFilePath($fileName);

        $result = $this->getMediaDirectory()->stat($filePath);
        return $result;
    }

    /**
     * Check if the file exists
     *
     * @param string $fileName
     * @return bool
     */
    public function isExist($fileName)
    {
        $filePath = $this->getFilePath($fileName);

        $result = $this->getMediaDirectory()->isExist($filePath);
        return $result;
    }

    /**
     * Construct and return file subpath based on filename relative to media directory
     *
     * @param string $fileName
     * @return string
     */
    private function getFilePath($fileName)
    {
        $filePath = ltrim($fileName, '/');

        $mediaDirectoryRelativeSubpath = $this->getMediaDirectoryPathRelativeToBaseDirectoryPath();
        $isFileNameBeginsWithMediaDirectoryPath = $this->isBeginsWithMediaDirectoryPath($fileName);

        // if the file is not using a relative path, it resides in the paracrab/image media directory
        $fileIsInModuleMediaDir = !$isFileNameBeginsWithMediaDirectoryPath;

        if ($fileIsInModuleMediaDir) {
            $filePath = self::ENTITY_MEDIA_PATH . '/' . $filePath;
        } else {
            $filePath = substr($filePath, strlen($mediaDirectoryRelativeSubpath));
        }

        return $filePath;
    }

    /**
     * Checks for whether $fileName string begins with media directory path
     *
     * @param string $fileName
     * @return bool
     */
    public function isBeginsWithMediaDirectoryPath($fileName)
    {
        $filePath = ltrim($fileName, '/');

        $mediaDirectoryRelativeSubpath = $this->getMediaDirectoryPathRelativeToBaseDirectoryPath();
        $isFileNameBeginsWithMediaDirectoryPath = strpos($filePath, $mediaDirectoryRelativeSubpath) === 0;

        return $isFileNameBeginsWithMediaDirectoryPath;
    }

    /**
     * Get media directory subpath relative to base directory path
     *
     * @return string
     */
    private function getMediaDirectoryPathRelativeToBaseDirectoryPath()
    {
        $baseDirectoryPath = $this->getBaseDirectory()->getAbsolutePath();
        $mediaDirectoryPath = $this->getMediaDirectory()->getAbsolutePath();

        $mediaDirectoryRelativeSubpath = substr($mediaDirectoryPath, strlen($baseDirectoryPath));

        return $mediaDirectoryRelativeSubpath;
    }
}

This class similar this vendor/magento/module-catalog/Model/Category/FileInfo.php

  1. You have DataProvider for displaing form in whole. This is code my DataProvider class
<?php
namespace Paracrab\Banners\Model\Banner;

use Paracrab\Banners\Model\ResourceModel\Banner\CollectionFactory as BannerCollectionFactory;
use Magento\Framework\App\Request\DataPersistorInterface;
use Magento\Ui\DataProvider\Modifier\PoolInterface;
use Paracrab\Banners\Api\BannerRepositoryInterface;
use Paracrab\Banners\Model\Banner\FileInfo;

class DataProvider extends \Magento\Ui\DataProvider\ModifierPoolDataProvider
{
    /**
     * @var \Paracrab\Banners\Model\ResourceModel\Banner\Collection
     */
    protected $collection;

    /**
     * @var DataPersistorInterface
     */
    protected $dataPersistor;

    /**
     * @var
     */
    protected $loadedData;

    /**
     * @var \Magento\Framework\App\Request\Http
     */
    protected $request;

    /**
     * @var BannerRepositoryInterface
     */
    protected $bannerRepository;

    /**
     * @var \Paracrab\Banners\Model\Banner\FileInfo
     */
    protected $fileInfo;

    /**
     * DataProvider constructor.
     * @param $name
     * @param $primaryFieldName
     * @param $requestFieldName
     * @param BannerCollectionFactory $pageCollectionFactory
     * @param DataPersistorInterface $dataPersistor
     * @param \Magento\Framework\App\Request\Http $request
     * @param BannerRepositoryInterface $bannerRepository
     * @param \Paracrab\Banners\Model\Banner\FileInfo $fileInfo
     * @param array $meta
     * @param array $data
     * @param PoolInterface|null $pool
     */
    public function __construct(
        $name,
        $primaryFieldName,
        $requestFieldName,
        BannerCollectionFactory $pageCollectionFactory,
        DataPersistorInterface $dataPersistor,
        \Magento\Framework\App\Request\Http $request,
        BannerRepositoryInterface $bannerRepository,
        FileInfo $fileInfo,
        array $meta = [],
        array $data = [],
        PoolInterface $pool = null
    ) {
        $this->collection = $pageCollectionFactory->create();
        $this->dataPersistor = $dataPersistor;
        $this->request = $request;
        $this->bannerRepository = $bannerRepository;
        $this->fileInfo = $fileInfo;
        parent::__construct($name, $primaryFieldName, $requestFieldName, $meta, $data, $pool);
    }

    /**
     * @return array
     * @throws \Magento\Framework\Exception\LocalizedException
     */
    public function getData()
    {
        if (isset($this->loadedData)) {
            return $this->loadedData;
        }

        $bannerId = $this->request->getParam('banner_id');

        if($bannerId) {
            $item = $this->bannerRepository->getById($bannerId);
            $fileName = $item->getData('image');

            if($this->fileInfo->isExist($fileName) && $fileName !== '') {
                $stat = $this->fileInfo->getStat($fileName);
                $image = [
                    0 => [
                      'name' =>  basename($fileName),
                      'url' => $this->fileInfo->getAbsolutePatch($fileName),
                      'size' => isset($stat) ? $stat['size'] : 0,
                      'type' => $this->fileInfo->getMimeType($fileName)
                    ]
                ];

                $item->setData('image', $image);

            }

            $this->loadedData[$item->getId()] = $item->getData();
        }

        $data = $this->dataPersistor->get('paracrab_banner');

        if (!empty($data)) {
            $page = $this->collection->getNewEmptyItem();
            $page->setData($data);
            $this->loadedData[$page->getId()] = $page->getData();
            $this->dataPersistor->clear('paracrab_banner');
        }

        return $this->loadedData;
    }
}

7. You have Action for saving data from form. This is how my Action look like

<?php
namespace Paracrab\Banners\Controller\Adminhtml\Banners;

use Magento\Framework\App\Action\HttpPostActionInterface;
use Magento\Backend\App\Action\Context;
use Magento\Framework\App\Request\DataPersistorInterface;
use Magento\Framework\Exception\LocalizedException;
use Paracrab\Banners\Model\Banner;
use Paracrab\Banners\Model\BannerFactory;
use Paracrab\Banners\Api\BannerRepositoryInterface;
use Paracrab\Banners\Model\ImageUploader;

class Save extends \Magento\Backend\App\Action implements HttpPostActionInterface
{
    /**
     * @var DataPersistorInterface
     */
    protected $dataPersistor;

    /**
     * @var BannerFactory
     */
    private $bannerFactory;

    /**
     * @var BannerRepositoryInterface
     */
    private $bannerRepository;

    /**
     * @var ImageUploader
     */
    private $imageUploader;


    /**
     * Save constructor.
     * @param Context $context
     * @param DataPersistorInterface $dataPersistor
     * @param BannerFactory $bannerFactory
     * @param BannerRepositoryInterface $bannerRepository
     * @param ImageUploader $imageUploader
     */
    public function __construct
    (
        Context $context,
        DataPersistorInterface $dataPersistor,
        BannerFactory $bannerFactory,
        BannerRepositoryInterface $bannerRepository,
        ImageUploader $imageUploader
    )
    {
        $this->dataPersistor = $dataPersistor;
        $this->bannerFactory = $bannerFactory;
        $this->bannerRepository = $bannerRepository;
        $this->imageUploader = $imageUploader;
         parent::__construct($context);
    }

    /**
     * @return \Magento\Framework\App\ResponseInterface|\Magento\Framework\Controller\Result\Redirect|\Magento\Framework\Controller\ResultInterface
     */
    public function execute()
    {
        $resultRedirect = $this->resultRedirectFactory->create();
        $data = $this->getRequest()->getPostValue();

        if ($data) {
            if (isset($data['status']) && $data['status'] === 'true') {
                $data['status'] = Banner::STATUS_ENABLED;
            }
            if (empty($data['banner_id'])) {
                $data['banner_id'] = null;
            }

            if(isset($data['image'])) {
                $fileName = $data['image'][0]['name'];
                $data['image'] = $fileName;
                $this->imageUploader->moveFileFromTmp($fileName);
            } else {
                $data['image'] = '';
            }

            $model = $this->bannerFactory->create();

            $id = $this->getRequest()->getParam('banner_id');
            if ($id) {
                try {
                    $model = $this->bannerRepository->getById($id);
                } catch (LocalizedException $e) {
                    $this->messageManager->addErrorMessage(__('This banner no longer exists.'));
                    return $resultRedirect->setPath('*/*/');
                }
            }

            $model->setData($data);

            try {
                $this->bannerRepository->save($model);
                $this->messageManager->addSuccessMessage(__('You saved the banner.'));
                $this->dataPersistor->clear('paracrab_banner');
                return $this->processBlockReturn($model, $data, $resultRedirect);
            } catch (LocalizedException $e) {
                $this->messageManager->addErrorMessage($e->getMessage());
            } catch (\Exception $e) {
                $this->messageManager->addExceptionMessage($e, __('Something went wrong while saving the banner.'));
            }

            $this->dataPersistor->set('paracrab_banner', $data);
            return $resultRedirect->setPath('*/*/edit', ['banner_id' => $id]);
        }
    }

    /**
     * @param $model
     * @param $data
     * @param $resultRedirect
     * @return mixed
     */
    private function processBlockReturn($model, $data, $resultRedirect)
    {
        $redirect = $data['back'] ?? 'close';

        if ($redirect ==='continue') {
            $resultRedirect->setPath('*/*/edit', ['banner_id' => $model->getId()]);
        } else if ($redirect === 'close') {
            $resultRedirect->setPath('*/*/');
        }
        return $resultRedirect;
    }

}
  1. Create directories in pub/media like paracrab/images and paracrab/tmp/images
0

Upload the Custom image at Category

  1. Create a InstallData.php file at vendor\Module\Setup and add the below code into the InstallData.php

Create a InstallData.php file on location vendor\Module\Setup

    <?php
    namespace Vendor\Module\Setup;
    
    use Magento\Eav\Setup\EavSetup;
    use Magento\Eav\Setup\EavSetupFactory;
    use Magento\Framework\Setup\InstallDataInterface;
    use Magento\Framework\Setup\ModuleContextInterface;
    use Magento\Framework\Setup\ModuleDataSetupInterface;
    use Magento\Eav\Model\Entity\Attribute\ScopedAttributeInterface;
    
    /**
     * @codeCoverageIgnore
     */
    class InstallData implements InstallDataInterface
    {
        /**
         * EAV setup factory.
         *
         * @var EavSetupFactory
         */
        private $_eavSetupFactory;
        protected $categorySetupFactory;
    
        /**
         * Init.
         *
         * @param EavSetupFactory $eavSetupFactory
         */
        public function __construct(EavSetupFactory $eavSetupFactory, \Magento\Catalog\Setup\CategorySetupFactory $categorySetupFactory)
        {
            $this->_eavSetupFactory = $eavSetupFactory;
            $this->categorySetupFactory = $categorySetupFactory;
        }
    
        /**
         * {@inheritdoc}
         *
         * @SuppressWarnings(PHPMD.ExcessiveMethodLength)
         */
        public function install(
            ModuleDataSetupInterface $setup,
            ModuleContextInterface $context
        ) {
            /** @var EavSetup $eavSetup */
            $eavSetup = $this->_eavSetupFactory->create(['setup' => $setup]);
            $setup = $this->categorySetupFactory->create(['setup' => $setup]);         
            $setup->addAttribute(
                \Magento\Catalog\Model\Category::ENTITY, 'custom_catimg', [
                    'type' => 'varchar',
                    'label' => 'Custom category image',
                    'input' => 'image',
                    'backend' => 'Magento\Catalog\Model\Category\Attribute\Backend\Image',
                    'required' => false,
                    'sort_order' => 9,
                    'global' => \Magento\Eav\Model\Entity\Attribute\ScopedAttributeInterface::SCOPE_STORE,
                    'group' => 'General Information',
                ]
            );
        }
    }
  1. Create a category_form.xml file into vendor\Module\view\adminhtml\ui_component and write down the below code In this file, you have to change the field name as per your attribute code and url as per your controller like path="module/category_catimg/upload"/ there are module is the route.xml in etc/adminhtml/route.xml name
    <?xml version="1.0" encoding="UTF-8"?>
    <form xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Ui:etc/ui_configuration.xsd">
        <fieldset name="content">
            <field name="custom_catimg">
                <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">Custom 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">40</item>
                        <item name="uploaderConfig" xsi:type="array">
                            <item name="url" xsi:type="url" path="module/category_catimg/upload"/>
                        </item>
                    </item>
                </argument>
            </field>
        </fieldset>
    </form>
  1. Now add the below code into the Vendor/Module/etc/di.xml
        <type name="Vendor\Module\Controller\Adminhtml\Category\Image\Upload">
            <arguments>
                <argument name="imageUploader" xsi:type="object">Magento\Catalog\CategoryImageUpload</argument>
            </arguments>
        </type>
        <virtualType name="Magento\Catalog\CategoryImageUpload" type="Magento\Catalog\Model\ImageUploader">
            <arguments>
                <argument name="baseTmpPath" xsi:type="string">catalog/tmp/category</argument>
                <argument name="basePath" xsi:type="string">catalog/category</argument>
                <argument name="allowedExtensions" xsi:type="array">
                    <item name="jpg" xsi:type="string">jpg</item>
                    <item name="jpeg" xsi:type="string">jpeg</item>
                    <item name="gif" xsi:type="string">gif</item>
                    <item name="png" xsi:type="string">png</item>
                </argument>
            </arguments>
        </virtualType>
        <preference for="Magento\Catalog\Model\Category\DataProvider" type="Vendor\Module\Model\Category\DataProvider" />
  1. Create Upload.php file into Vendor/Module/Controller/Adminhtml/Category/Image and write down the below code
    <?php
    namespace Vendor\Module\Controller\Adminhtml\Category\Image;
    
    use Magento\Framework\Controller\ResultFactory;
    
    /**
     * Agorae Adminhtml Category Image Upload Controller
     */
    class Upload extends \Magento\Backend\App\Action
    {
        /**
         * Image uploader
         *
         * @var \Magento\Catalog\Model\ImageUploader
         */
        protected $imageUploader;
    
        /**
         * Uploader factory
         *
         * @var \Magento\MediaStorage\Model\File\UploaderFactory
         */
        private $uploaderFactory;
    
        /**
         * Media directory object (writable).
         *
         * @var \Magento\Framework\Filesystem\Directory\WriteInterface
         */
        protected $mediaDirectory;
    
        /**
         * Store manager
         *
         * @var \Magento\Store\Model\StoreManagerInterface
         */
        protected $storeManager;
    
        /**
         * Core file storage database
         *
         * @var \Magento\MediaStorage\Helper\File\Storage\Database
         */
        protected $coreFileStorageDatabase;
    
        /**
         * @var \Psr\Log\LoggerInterface
         */
        protected $logger;
    
        /**
         * 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,
            \Magento\MediaStorage\Model\File\UploaderFactory $uploaderFactory,
            \Magento\Framework\Filesystem $filesystem,
            \Magento\Store\Model\StoreManagerInterface $storeManager,
            \Magento\MediaStorage\Helper\File\Storage\Database $coreFileStorageDatabase,
            \Psr\Log\LoggerInterface $logger
        ) {
            parent::__construct($context);
            $this->imageUploader = $imageUploader;
            $this->uploaderFactory = $uploaderFactory;
            $this->mediaDirectory = $filesystem->getDirectoryWrite(\Magento\Framework\App\Filesystem\DirectoryList::MEDIA);
            $this->storeManager = $storeManager;
            $this->coreFileStorageDatabase = $coreFileStorageDatabase;
            $this->logger = $logger;
        }
    
        /**
         * Check admin permissions for this controller
         *
         * @return boolean
         */
        protected function _isAllowed()
        {
            return $this->_authorization->isAllowed('Vendor_Module::category');
        }
    
        /**
         * Upload file controller action
         *
         * @return \Magento\Framework\Controller\ResultInterface
         */
        public function execute()
        {
            try {
                $result = $this->imageUploader->saveFileToTmpDir('custom_catimg');
                $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) {
                $result = ['error' => $e->getMessage(), 'errorcode' => $e->getCode()];
            }
            return $this->resultFactory->create(ResultFactory::TYPE_JSON)->setData($result);
        }
    }
  1. Create Upload.php file on location Vendor/Module/Controller/Adminhtml/Category/Image
    <?php
    namespace Vendor\Module\Controller\Adminhtml\Category\Image;
    
    use Magento\Framework\Controller\ResultFactory;
    
    /**
     * Agorae Adminhtml Category Image Upload Controller
     */
    class Upload extends \Magento\Backend\App\Action
    {
        /**
         * Image uploader
         *
         * @var \Magento\Catalog\Model\ImageUploader
         */
        protected $imageUploader;
    
        /**
         * Uploader factory
         *
         * @var \Magento\MediaStorage\Model\File\UploaderFactory
         */
        private $uploaderFactory;
    
        /**
         * Media directory object (writable).
         *
         * @var \Magento\Framework\Filesystem\Directory\WriteInterface
         */
        protected $mediaDirectory;
    
        /**
         * Store manager
         *
         * @var \Magento\Store\Model\StoreManagerInterface
         */
        protected $storeManager;
    
        /**
         * Core file storage database
         *
         * @var \Magento\MediaStorage\Helper\File\Storage\Database
         */
        protected $coreFileStorageDatabase;
    
        /**
         * @var \Psr\Log\LoggerInterface
         */
        protected $logger;
    
        /**
         * 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,
            \Magento\MediaStorage\Model\File\UploaderFactory $uploaderFactory,
            \Magento\Framework\Filesystem $filesystem,
            \Magento\Store\Model\StoreManagerInterface $storeManager,
            \Magento\MediaStorage\Helper\File\Storage\Database $coreFileStorageDatabase,
            \Psr\Log\LoggerInterface $logger
        ) {
            parent::__construct($context);
            $this->imageUploader = $imageUploader;
            $this->uploaderFactory = $uploaderFactory;
            $this->mediaDirectory = $filesystem->getDirectoryWrite(\Magento\Framework\App\Filesystem\DirectoryList::MEDIA);
            $this->storeManager = $storeManager;
            $this->coreFileStorageDatabase = $coreFileStorageDatabase;
            $this->logger = $logger;
        }
    
        /**
         * Check admin permissions for this controller
         *
         * @return boolean
         */
        protected function _isAllowed()
        {
            return $this->_authorization->isAllowed('Vendor_Module::category');
        }
    
        /**
         * Upload file controller action
         *
         * @return \Magento\Framework\Controller\ResultInterface
         */
        public function execute()
        {
            try {
                $result = $this->imageUploader->saveFileToTmpDir('custom_catimg');
                $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) {
                $result = ['error' => $e->getMessage(), 'errorcode' => $e->getCode()];
            }
            return $this->resultFactory->create(ResultFactory::TYPE_JSON)->setData($result);
        }
    }
  1. Create DataProvider.php file on location Vendor\Module\Model\Category and write down the below code
    <?php
    namespace Vendor\Module\Model\Category;
     
    class DataProvider extends \Magento\Catalog\Model\Category\DataProvider
    {
     
        protected function getFieldsMap()
        {
            $fields = parent::getFieldsMap();
            $fields['content'][] = 'custom_catimg'; // custom image field
            
            return $fields;
        }
    }

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.