Back to Top

How to add media gallery field using ui-component for the admin custom form in Magento2.

Updated 12 January 2024

What is the ui-component in magento2:

Basically, we are using UI components in magento2 to create the Grids, Forms, Dialogs and etc. And we can easily be designed the form and grid for the user interface And we can easily add multiple types of fields to the form. So help of this blog we want to add the media gallery field on the admin custom ui-component form.

Media Gallery:

To upload multiple images at the same time from one field in the form.

Step1: We need to create the layout file to define the ui component form in view/adminhtml/layout/routename_controllername_actionname.xml:

Searching for an experienced
Magento 2 Company ?
Find out More
<?xml version="1.0"?>
<page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd">
    <update handle="styles"/>
    <update handle="editor"/>
	<body>
	    <referenceBlock name="menu">
	        <action method="setActive">
   		    <argument name="itemId" xsi:type="string">
                        VendorName_ModuleName::businesslisting
                    </argument>
		</action>
	    </referenceBlock>
	    <referenceBlock name="page.title">
	        <action method="setTitleClass">
		    <argument name="class" xsi:type="string">
                        complex
                    </argument>
		</action>
	    </referenceBlock>
            <referenceContainer name="content">
		<uiComponent name="business_form"/>
	    </referenceContainer>
	</body>
</page>

Step2: Create the ui-component form and we need to write below code to add the media gallery field:

<fieldset name="gallery">
    <argument name="data" xsi:type="array">
        <item name="config" xsi:type="array">
            <item name="collapsible" xsi:type="boolean">true</item>
            <item name="label" xsi:type="string" translate="true">
                Media Gallery
            </item>
            <item name="sortOrder" xsi:type="number">22</item>
        </item>    
    </argument>
    <container name="gallery" >
        <argument name="data" xsi:type="array">
            <item name="config" xsi:type="array">
                <item name="sortOrder" xsi:type="number">10</item>
            </item>
        </argument>
        <htmlContent name="gallery">
            <argument name="block" xsi:type="object">
VendorName\ModuleName\Block\Adminhtml\Listing\Helper\Form\Gallery
            </argument>
        </htmlContent>
    </container>
</fieldset>

Step3: Create the block file, VendorName\ModuleName\Block\Adminhtml\Listing\Helper\Form\Gallery.php

<?php
namespace 
VendorName\ModuleName\Block\Adminhtml\Listing\Helper\Form;

use Magento\Framework\Registry;

class Gallery extends \Magento\Framework\View\Element\AbstractBlock
{
    /**
     * Gallery field name suffix
     *
     * @var string
     */
    protected $fieldNameSuffix = 'business_list';

    /**
     * Gallery html id
     *
     * @var string
     */
    protected $htmlId = 'media_gallery';

    /**
     * Gallery name
     *
     * @var string
     */
    protected $name = 'media_gallery';

    /**
     * Html id for data scope
     *
     * @var string
     */
    protected $image = 'image';

    /**
     * @var string
     */
    protected $formName = 'business_form';

    /**
     * @var \Magento\Framework\Data\Form
     */
    protected $form;

    /**
     * @var Registry
     */
    protected $registry;

    /**
     * @var \VendorName\ModuleName\Model\BusinessListFactory     */
    protected $businessListFactory;

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

    /**
     * @param \Magento\Framework\View\Element\Context $context
     * @param Registry $registry
     * @param \Magento\Framework\Data\Form $form
     * @param array $data
     */
    public function __construct(
        \Magento\Framework\View\Element\Context $context,
        Registry $registry,
        \Magento\Framework\Data\Form $form,
        \VendorName\ModuleName\Model\BusinessListFactory $businessListFactory,
        \Magento\Store\Model\StoreManagerInterface $storeManager,
        $data = []
    ) {
        $this->registry = $registry;
        $this->form = $form;
        $this->businessListFactory = $businessListFactory;
        $this->storeManager = $storeManager;
        parent::__construct($context, $data);
    }

    /**
     * @return string
     */
    public function getElementHtml()
    {
        return $this->getContentHtml();
    }

    /**
     * Get product images
     *
     * @return array|null
     */
    public function getImages()
    {
        $result = [];
        $gallery = [];
        $id = $this->registry->registry('id');
        $businessList = $this->businessListFactory->create()->getCollection()->addFieldToFilter('entity_id', $id)->getFirstItem();
        $mediaUrl = $this->storeManager->getStore()->getBaseUrl(\Magento\Framework\UrlInterface::URL_TYPE_MEDIA);
        if ($businessList->getMediaGallery()) {
            $gallery = explode(";", $businessList->getMediaGallery());
        }
        if (count($gallery)) {
            $result['images'] = [];
            $position = 1;
            foreach ($gallery as $image) {
                $label = str_replace("business/business/mediagallery/","",$image);
                $result['images'][] = [
                    'value_id' => $image,
                    'file' => $image,
                    'label' => $label,
                    'position' => $position,
                    'url' => $mediaUrl.$image,
                ];
                $position++;
            }
        }

        return $result;
    }

    /**
     * Prepares content block
     *
     * @return string
     */
    public function getContentHtml()
    {
        $content = $this->getChildBlock('content');
        if (!$content) {
            $content = $this->getLayout()->createBlock(      \VendorName\ModuleName\Block\Adminhtml\Listing\Helper\Form\Gallery\Content::class,
                '',
                [
                    'config' => [
                        'parentComponent' => 'business_form.business_form.block_gallery.block_gallery'
                    ]
                ]
            );
        }

        $content
            ->setId($this->getHtmlId() . '_content')
            ->setElement($this)
            ->setFormName($this->formName);
        $galleryJs = $content->getJsObjectName();
        $content->getUploader()->getConfig()->setMegiaGallery($galleryJs);
        return $content->toHtml();
    }

    /**
     * @return string
     */
    protected function getHtmlId()
    {
        return $this->htmlId;
    }

    /**
     * @return string
     */
    public function getName()
    {
        return $this->name;
    }

    /**
     * @return string
     */
    public function getFieldNameSuffix()
    {
        return $this->fieldNameSuffix;
    }

    /**
     * @return string
     */
    public function getDataScopeHtmlId()
    {
        return $this->image;
    }

    /**
     * @return string
     */
    public function toHtml()
    {
        return $this->getElementHtml();
    }
}

Step4: Create another block file to pass the phtml path: VendorName\ModuleName\Block\Adminhtml\Listing\Helper\Form\Gallery\Content.php

<?php
namespace VendorName\ModuleName\Block\Adminhtml\Listing\Helper\Form\Gallery;

use Magento\Framework\App\ObjectManager;
use Magento\Backend\Block\Media\Uploader;
use Magento\Framework\View\Element\AbstractBlock;

class Content extends \Magento\Backend\Block\Widget
{
    /**
     * @var string
     */
    protected $_template = 'business/form/gallery.phtml';

    /**
     * @var \Magento\Framework\Json\EncoderInterface
     */
    protected $_jsonEncoder;

    /**
     * @var ImageUploadConfigDataProvider
     */
    private $imageUploadConfigDataProvider;

    /**
     * Content constructor.
     * @param \Magento\Backend\Block\Template\Context $context
     * @param \Magento\Framework\Json\EncoderInterface $jsonEncoder
     * @param array $data
     * @param null $imageUploadConfigDataProvider
     */
    public function __construct(
        \Magento\Backend\Block\Template\Context $context,
        \Magento\Framework\Json\EncoderInterface $jsonEncoder,
        array $data = [],
        $imageUploadConfigDataProvider = null
    ) {
        $this->_jsonEncoder = $jsonEncoder;
        parent::__construct($context, $data);
        try {
            /* Try for old magento version where ImageUploadConfigDataProvider does not exist */
            if (class_exists(\Magento\Backend\Block\DataProviders\ImageUploadConfig::class)) {
                $this->imageUploadConfigDataProvider = $imageUploadConfigDataProvider
                    ?: ObjectManager::getInstance()->get(\Magento\Backend\Block\DataProviders\ImageUploadConfig::class);
            } elseif (class_exists(\Magento\Backend\Block\DataProviders\UploadConfig::class)) {
                /* Workaround for Magento 2.2.8 */
                $this->imageUploadConfigDataProvider = ObjectManager::getInstance()->get(
                    \Magento\Backend\Block\DataProviders\UploadConfig::class
                );
            }
        } catch (\Exception $e) {
            return;
        }
    }

    /**
     * @return AbstractBlock
     */
    protected function _prepareLayout()
    {
        $this->addChild(
            'uploader',
            \Magento\Backend\Block\Media\Uploader::class,
            ['image_upload_config_data' => $this->imageUploadConfigDataProvider]
        );

        $this->getUploader()->getConfig()->setUrl(
            $this->_urlBuilder->getUrl('business/listing_upload/gallery')
        )->setFileField(
            'image'
        )->setFilters(
            [
                'images' => [
                    'label' => __('Images (.gif, .jpg, .png)'),
                    'files' => ['*.gif', '*.jpg', '*.jpeg', '*.png'],
                ],
            ]
        );

        $this->_eventManager->dispatch('business_listing_gallery_prepare_layout', ['block' => $this]);

        return parent::_prepareLayout();
    }

    /**
     * Retrieve uploader block
     *
     * @return Uploader
     */
    public function getUploader()
    {
        return $this->getChildBlock('uploader');
    }

    /**
     * Retrieve uploader block html
     *
     * @return string
     */
    public function getUploaderHtml()
    {
        return $this->getChildHtml('uploader');
    }

    /**
     * @return string
     */
    public function getJsObjectName()
    {
        return $this->getHtmlId() . 'JsObject';
    }

    /**
     * @return string
     */
    public function getAddImagesButton()
    {
        return $this->getButtonHtml(
            __('Add New Images'),
            $this->getJsObjectName() . '.showUploader()',
            'add',
            $this->getHtmlId() . '_add_images_button'
        );
    }

    /**
     * @return string
     */
    public function getImagesJson()
    {
        $value = $this->getElement()->getImages();
        if (is_array($value) &&
            array_key_exists('images', $value) &&
            is_array($value['images']) &&
            count($value['images'])
        ) {
            $images = $this->sortImagesByPosition($value['images']);

            return $this->_jsonEncoder->encode($images);
        }
        return '[]';
    }

    /**
     * Sort images array by position key
     *
     * @param array $images
     * @return array
     */
    private function sortImagesByPosition($images)
    {
        if (is_array($images)) {
            usort($images, function ($imageA, $imageB) {
                return ($imageA['position'] < $imageB['position']) ? -1 : 1;
            });
        }
        return $images;
    }
}

Step5: Create the phtml file to declare the js content and file: /view/adminhtml/templates/business/form/gallery.phtml

<?php
/** @var $block \VendorName\ModuleName\Block\Adminhtml\Listing\Helper\Form\Gallery\Content */
$elementName = $block->getElement()->getName() . '[images]';
$formName = $block->getFormName();
?>
<div id="<?= $block->getHtmlId() ?>"
     class="gallery"
     data-mage-init='{"VendorName_ModuleName/js/post-gallery":{"template":"#<?= $block->getHtmlId() ?>-template"}}'     data-parent-component="<?= $block->escapeHtml($block->getData('config/parentComponent')) ?>"
     data-images="<?= $block->escapeHtml($block->getImagesJson()) ?>"
     data-types="{}"
    >
    <?php if (!$block->getElement()->getReadonly()) {?>
        <div class="image image-placeholder">
            <?= $block->getUploaderHtml(); ?>
            <div class="product-image-wrapper">
                <p class="image-placeholder-text">
                    <?=  $block->escapeHtml(__('Browse to find or drag image here')); ?>
                </p>
            </div>
        </div>
    <?php } ?>

    <script id="<?= $block->getHtmlId() ?>-template" type="text/x-magento-template">
        <div class="image item<% if (data.disabled == 1) { %> hidden-for-front<% } %>"
             data-role="image">
            <input type="hidden"
                   name="<?= $block->escapeHtml($elementName) ?>[<%- data.file_id %>][position]"
                   value="<%- data.position %>"
                   data-form-part="<?= $block->escapeHtml($formName) ?>"
                   class="position"/>
            <input type="hidden"
                   name="<?= $block->escapeHtml($elementName) ?>[<%- data.file_id %>][file]"
                   data-form-part="<?= $block->escapeHtml($formName) ?>"
                   value="<%- data.file %>"/>
            <input type="hidden"
                   name="<?= $block->escapeHtml($elementName) ?>[<%- data.file_id %>][value_id]"
                   data-form-part="<?= $block->escapeHtml($formName) ?>"
                   value="<%- data.value_id %>"/>
            <input type="hidden"
                   name="<?= $block->escapeHtml($elementName) ?>[<%- data.file_id %>][label]"
                   data-form-part="<?= $block->escapeHtml($formName) ?>"
                   value="<%- data.label %>"/>
            <input type="hidden"
                   name="<?= $block->escapeHtml($elementName) ?>[<%- data.file_id %>][disabled]"
                   data-form-part="<?= $block->escapeHtml($formName) ?>"
                   value="<%- data.disabled %>"/>
            <input type="hidden"
                   name="<?= $block->escapeHtml($elementName) ?>[<%- data.file_id %>][media_type]"
                   data-form-part="<?= $block->escapeHtml($formName) ?>"
                   value="image"/>
            <input type="hidden"
                   name="<?= $block->escapeHtml($elementName) ?>[<%- data.file_id %>][removed]"
                   data-form-part="<?= $block->escapeHtml($formName) ?>"
                   value=""
                   class="is-removed"/>

            <div class="product-image-wrapper">
                <img class="product-image"
                     data-role="image-element"
                     src="<%- data.url %>"
                     alt="<%- data.label %>"/>

                <div class="actions">
                    <button type="button"
                            class="action-remove"
                            data-role="delete-button"
                            title="<?= $block->escapeHtml(__('Delete image')) ?>">
                    <span>
                        <?= $block->escapeHtml(__('Delete image')) ?>
                    </span>
                    </button>
                    <div class="draggable-handle"></div>
                </div>
                <div class="image-fade">
                    <span><?= $block->escapeHtml(__('Hidden')) ?></span>
                </div>
            </div>

            <div class="item-description">
                <div class="item-title" data-role="img-title"><%- data.label %></div>
            </div>
        </div>
    </script>
</div>
<script>
    jQuery('body').trigger('contentUpdated');
</script>

Step6: Create the js file to write the js code: view/adminhtml/web/js/post-gallery.js

define([
    'jquery',
    'underscore',
    'mage/template',
    'uiRegistry',
    'productGallery',
    'jquery-ui-modules/core',
    'jquery-ui-modules/widget',
    'baseImage'
], function ($, _, mageTemplate, registry, productGallery) {
    'use strict';
    $.widget('mage.productGallery', $.mage.productGallery, {
        _showDialog: function (imageData) {}
    });
    return $.mage.productGallery;
});

After created above files we need to run these commands from our end:

php bin/magento setup:di:compile

php bin/magento setup:static-content:deploy

php bin/magento cache:flush

Media Gallery field using ui-component

Step7: After create the field then we can save the multiple image through this code:

<?php
namespace VendorName\ModuleName\Controller\Adminhtml\Upload\Image;

use Magento\Framework\Controller\ResultFactory;

/**
 * Business media image upload controller
 */
abstract class Action extends \Magento\Catalog\Controller\Adminhtml\Category\Image\Upload
{
    /**
     * File key
     *
     * @var string
     */
    protected $_fileKey;

    public function execute()
    {
        try {
            $result = $this->imageUploader->saveFileToTmpDir($this->_fileKey);

            $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);
    }
}
<?php
namespace VendorName\ModuleName\Controller\Adminhtml\Listing\Upload;

use VendorName\ModuleName\Controller\Adminhtml\Upload\Image\Action;

/**
 * busimess gallery image upload controller
 */
class Gallery extends Action
{
    /**
     * File key
     *
     * @var string
     */
    protected $_fileKey = 'image';
}

VendorName\ModuleName\Controller\Adminhtml\Listing\Save.php

<?php

namespace VendorName\ModuleName\Controller\Adminhtml\Listing;

use Magento\Backend\App\Action;
use Magento\Backend\App\Action\Context;
use Magento\Framework\View\Result\PageFactory;
use Magento\Framework\App\Filesystem\DirectoryList;
use Magento\Framework\Filesystem;
use Magento\Framework\Filesystem\Driver\File;

class Save extends Action
{
    /**
     * @var Magento\Framework\View\Result\PageFactory
     */
    protected $resultPageFactory;

    /**
     * @var \Magento\Backend\Model\View\Result\ForwardFactory
     */
    protected $resultForwardFactory;

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

    /**
     * @var \Magento\Framework\Filesystem\Driver\File
     */
    protected $fileDriver;

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

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

    /**
     * @var Webkul\Businessform\Model\BusinessListFactory */
    protected $businessListFactory;

    /**
     * @var \Magento\Framework\Registry
     */
    protected $coreRegistry = null;

    /**
     * @param Context $context
     * @param PageFactory $resultPageFactory
     * @param \Magento\Backend\Model\View\Result\ForwardFactory $resultForwardFactory
     * @param Filesystem $filesystem
     * @param \Magento\MediaStorage\Helper\File\Storage\Database $coreFileStorageDatabase
     * @param File $fileDriver
     * @param \VendorName\ModuleName\Model\BusinessListFactory $businessListFactory
     * @param \Magento\Framework\Registry $coreRegistry
     */
    public function __construct(
        Context $context,
        PageFactory $resultPageFactory,
        \Magento\Backend\Model\View\Result\ForwardFactory $resultForwardFactory,
        Filesystem $filesystem,
        \Magento\MediaStorage\Helper\File\Storage\Database $coreFileStorageDatabase,
        File $fileDriver,
        \VendorName\ModuleName\Model\BusinessListFactory $businessListFactory,
        \Magento\Framework\Registry $coreRegistry
    ) {
        parent::__construct($context);
        $this->resultPageFactory = $resultPageFactory;
        $this->resultForwardFactory = $resultForwardFactory;
        $this->fileDriver = $fileDriver;
        $this->filesystem = $filesystem;
        $this->mediaDirectory = $filesystem->getDirectoryWrite(DirectoryList::MEDIA);
        $this->coreFileStorageDatabase = $coreFileStorageDatabase;
        $this->businessListFactory = $businessListFactory;
        $this->coreRegistry = $coreRegistry;
    }

    /**
     * Save Media Gallery Data
     *
     * @return \Magento\Framework\App\Response\Http
     */
    public function execute()
    {
        $resultRedirect = $this->resultRedirectFactory->create();
        $originalRequestData = $this->getRequest()->getPostValue();
        $galleryArray = $this->uploadMediaGallery($originalRequestData);
        if(!empty($galleryArray)){
            $mediaGallery = implode(';',$galleryArray);
            $data['media_gallery'] = $mediaGallery;
            $businessList = $this->businessListFactory->create();
            $businessList->setData($data)->save();
            $id = $businessList->getId();
            $this->coreRegistry->register("entity_id", $id);
            $this->messageManager->addSuccess("Gallery data has been saved.");
            return $resultRedirect->setPath('*/*/edit',['entity_id'=> $id]);
        } else{
            $this->messageManager->addError(
                __('Something went wrong while saving the media gallery.')
            );
            return $resultRedirect->setPath('*/*/edit');
        }
       
    }

    /**
     * Upload MediaGallery
     *
     * @return array Data
     */
    public function uploadMediaGallery($data)
    {
        $bannerimageDirPath = $this->mediaDirectory->getAbsolutePath("business/business/mediagallery");
        $tmp = $this->mediaDirectory->getAbsolutePath("business/business/mediagallery/tmp");
        if (!$this->fileDriver->isExists($bannerimageDirPath)) {
            $this->fileDriver->createDirectory($bannerimageDirPath, 0777);
            $this->fileDriver->createDirectory($tmp, 0777);
        }
        $gallery = [];
        if (!empty($data['media_gallery']['images'])) {
            $images = $data['media_gallery']['images'];
            foreach ($images as $image) {
                if (empty($image['removed'])) {
                    if (!empty($image['value_id'])) {
                        $gallery[] = $image['value_id'];
                    } elseif (!empty($image['file'])) {
                        $originalImageName = $image['file'];
                        $imageName = $originalImageName;
                        $basePath = "business/business/mediagallery";
                        $baseTmpImagePath = "catalog/tmp/category/" . $imageName;
                        $baseImagePath = $basePath . "/" . $imageName;
                        $mediaPath = $this->filesystem->getDirectoryRead(DirectoryList::MEDIA)->getAbsolutePath();
                        $baseImageAbsolutePath = $mediaPath . $baseImagePath;
                        $i = 1;
                        while (file_exists($baseImageAbsolutePath)) {
                            $i++;
                            $p = mb_strrpos($originalImageName, '.');
                            if (false !== $p) {
                                $imageName = mb_substr($originalImageName, 0, $p) . $i .  mb_substr($originalImageName, $p);
                            } else {
                                $imageName = $originalImageName . $i;
                            }
                            $baseImagePath = $basePath . "/" . $imageName;
                            $baseImageAbsolutePath = $mediaPath . $baseImagePath;
                        }
                        $this->coreFileStorageDatabase->copyFile(
                            $baseTmpImagePath,
                            $baseImagePath
                        );
                        $this->mediaDirectory->renameFile(
                            $baseTmpImagePath,
                            $baseImagePath
                        );

                        $gallery[] = $baseImagePath;
                    }
                }
            }
        }
        return $gallery;
    }
}

After uploading the images will show in the form:

blog

Thanks.

. . .

Leave a Comment

Your email address will not be published. Required fields are marked*


3 comments

  • Guillermo Siperman
  • Munassir Alam (Moderator)
  • Akshaya
  • Back to Top

    Message Sent!

    If you have more details or questions, you can reply to the received confirmation email.

    Back to Home