2

I want to create custom product image attribute in magento2.2.5?

Created a custom product image attribute but not able to save the image

/var/www/html/magento2/app/code/Amy/ImageUploader/Model/Attribute/Product/Image.php

<?php

namespace Amy\ImageUploader\Model\Attribute\Product;

use Magento\Framework\App\Filesystem\DirectoryList;

class Image extends \Magento\Eav\Model\Entity\Attribute\Backend\AbstractBackend {

    protected $_uploaderFactory;
    protected $_filesystem;
    protected $_fileUploaderFactory;
    protected $_logger;

    public function __construct(
        \Psr\Log\LoggerInterface $logger,
        \Magento\Framework\Filesystem $filesystem,
        \Magento\MediaStorage\Model\File\UploaderFactory $fileUploaderFactory
    ) {
        $this->_filesystem = $filesystem;
        $this->_fileUploaderFactory = $fileUploaderFactory;
        $this->_logger = $logger;
    }

    public function beforeSave($object)
    {
        //echo $this->getAttribute()->getName();
        //Out Put: custom_product_image
        //echo '<br>';
        //var_dump($object->getData($this->getAttribute()->getName()));
        //Out Put: NULL
        //var_dump($this->getAttribute()->getName() . '_additional_data');
        //Out Put: NULL
        //var_dump($object->getData('name'));
        //Out Put: string(16) "Joust Duffle Bag"
        //exit;
        $value = $object->getData($this->getAttribute()->getName() . '_additional_data');
        echo"aaa";
        exit;

        if (empty($value) && empty($_FILES)) {
            return $this;
        }

        if (is_array($value) && !empty($value['delete'])) {
            $object->setData($this->getAttribute()->getName(), '');
            $this->getAttribute()->getEntity()->saveAttribute($object, $this->getAttribute()->getName());
            return $this;
        }

        $path = $this->_filesystem->getDirectoryRead(DirectoryList::MEDIA)->getAbsolutePath('catalog/product/');

        try {

            $uploader = $this->_fileUploaderFactory->create(['fileId' => $this->getAttribute()->getName()]);
            $uploader->setAllowedExtensions(['jpg', 'jpeg', 'gif', 'png']);
            $uploader->setAllowRenameFiles(true);
            $result = $uploader->save($path);

            $object->setData($this->getAttribute()->getName(), $result['file']);
            $this->getAttribute()->getEntity()->saveAttribute($object, $this->getAttribute()->getName());
        } catch (\Exception $e) {
            if ($e->getCode() != \Magento\MediaStorage\Model\File\Uploader::TMP_NAME_EMPTY) {
                $this->_logger->critical($e);
            }
        }

        return $this;
    } }

Any help would be appreciated.

  • You can create new product Media attribute from admin – Amit Naraniwal Feb 26 at 9:31
1

create Attribute

<?php

namespace Vendorname\Modulename\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;

/**
 * @codeCoverageIgnore
 */
class InstallData implements InstallDataInterface
{
    /**
     * EAV setup factory
     *
     * @var EavSetupFactory
     */
    private $eavSetupFactory;


    /**
     * Init
     *
     * @param EavSetupFactory $eavSetupFactory
     */
    public function __construct(EavSetupFactory $eavSetupFactory)
    {
        $this->eavSetupFactory = $eavSetupFactory;
    }

    /**
     * {@inheritdoc}
     * @SuppressWarnings(PHPMD.ExcessiveMethodLength)
     */
    public function install(ModuleDataSetupInterface $setup, ModuleContextInterface $context)
    {
        /** @var EavSetup $eavSetup */
        $eavSetup = $this->eavSetupFactory->create(['setup' => $setup]);
        if (version_compare($context->getVersion(), '1.0.0') < 0) {


            $eavSetup->removeAttribute(\Magento\Catalog\Model\Category::ENTITY, 'product_banner');


            $eavSetup->addAttribute(\Magento\Catalog\Model\Product :: ENTITY, 'category_banner', [
                    'type' => 'varchar',
                    'label' => 'Category Banner',
                    'input' => 'image',
                    'backend' => 'Vendorname\Modulename\Model\Product\Attribute\Backend\Bannerimage',
                    'required' => false,
                    'sort_order' => 110,
                    'global' => \Magento\Eav\Model\Entity\Attribute\ScopedAttributeInterface::SCOPE_GLOBAL,
                    'group' => 'General Information',
                    "default" => "",
                    "class" => "",
                    "note" => ""
                ]
            );

        }

    }
}

Extends Uploder

namespace Vendorname\Module name\Controller\Adminhtml\Product\Imageuploader\Productbanner;

use Magento\Framework\Controller\ResultFactory;

/**
 * Class Upload
 */
class Productbanner extends \Magento\Catalog\Controller\Adminhtml\Category\Image\Upload
{
    /**
     * Image uploader
     *
     * @var \Magento\Catalog\Model\ImageUploader
     */
    protected $imageUploader;

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

    /**
     * Upload file controller action
     *
     * @return \Magento\Framework\Controller\ResultInterface
     */
    public function execute()
    {
        try {
            $result = $this->imageUploader->saveFileToTmpDir('product_banner');
            $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);
    }
}

view/adminhtml/ui_component/product_form.xml

<field name="product_banner" sortOrder="40" formElement="fileUploader">
        <argument name="data" xsi:type="array">
            <item name="config" xsi:type="array">
                <item name="source" xsi:type="string">product</item>
            </item>
        </argument>
        <settings>
            <elementTmpl>ui/form/element/uploader/uploader</elementTmpl>
            <dataType>string</dataType>
            <label translate="true">Product Banner</label>
            <visible>true</visible>
            <required>false</required>
        </settings>
        <formElements>
            <fileUploader>
                <settings>
                    <required>false</required>
                    <uploaderConfig>
                        <param xsi:type="url" name="url" path="path_to_your admin_controller"/>
                    </uploaderConfig>
                    <previewTmpl>Magento_Catalog/image-preview</previewTmpl>
                </settings>
            </fileUploader>
        </formElements>
    </field>

etc/adminhtml/di.xml

<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
    <type name="Vendorname\Modulename\Controller\Adminhtml\Productbanner\Imageuploader\Productbanner\Classname">
        <arguments>
            <argument name="imageUploader" xsi:type="object">Vendorname\Modulename\Virtualtypename</argument>
        </arguments>
    </type>
    <virtualType name="Vendorname\Modulename\\Virtualtypename" type="Magento\Catalog\Model\ImageUploader">
        <arguments>
            <argument name="baseTmpPath" xsi:type="string">catalog/tmp/product</argument>
            <argument name="basePath" xsi:type="string">catalog/product/Banner</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\Product\DataProvider" type="Vendorname\Modulename\Model\Product\DataProvider" />
</config>

In Model/Product/DataProvider.php get The Data from attribute You can also use after before save method to customise

0

I'm not really sure what you are trying to achieve here. Depending on the purpose of this attribute, you're going to use a different approach.

Option 1: Image uploader button

There is no "Image Upload" input type, so if you really want a button to upload images on the product page, you're going to need to do some customization.

You're going to have to make a module with an InstallData.php and add an attribute via the Magento\Eav\Setup\EavSetupFactory. This attribute is going to need a frontend model and a backend model.

Here is a draft of how the file might look like:

<?php

namespace Vendor\CustomModule\Setup;

use Magento\Framework\Setup\ModuleContextInterface;
use Magento\Framework\Setup\ModuleDataSetupInterface;
use Magento\Framework\Setup\InstallDataInterface;
use Magento\Eav\Setup\EavSetupFactory;
use Magento\Catalog\Model\Product;

class InstallData implements InstallDataInterface
{
    private $eavSetupFactory;

    public function __construct(EavSetupFactory $eavSetupFactory)
    {
        $this->eavSetupFactory = $eavSetupFactory;
    }

    public function install(ModuleDataSetupInterface $setup, ModuleContextInterface $context)
    {
        $eavSetup = $this->eavSetupFactory->create(['setup' => $setup]);
        $eavSetup->addAttribute(Product::ENTITY, 'custom_image_uploader', [
            'type' => 'varchar',
            'label' => 'Custom Image Uploader',
            'input' => 'text',
            'frontend' => \Vendor\CustomModule\Frontend\ImageUploader::class,
            'backend' => \Vendor\CustomModule\Backend\ImageUploader::class,
            'visible' => true,
            'required' => false,
            'sort_order' => 103,
            'global' => \Magento\Eav\Model\Entity\Attribute\ScopedAttributeInterface::SCOPE_WEBSITE,
            'group' => 'General'
        ]);
    }
}

Option 2: Image Role

Another approach might be to add an extra image role to your Images & Videos. You can easily add this by adding a new attribute in Stores -> Product. Fill in the fields to your liking, but make sure that the Catalog Input Type for Store Owner is set on Media Image. Save it and you will be able to assign images to your custom image role on your product page.

[EDIT]

In case your opting for option 1, your backend model should look similar to this

namespace Vendor\CustomModule\Model\Config\Backend;

use Magento\Framework\App\Config\ScopeConfigInterface;
use Magento\Config\Model\Config\Backend\File\RequestData\RequestDataInterface;
use Magento\Config\Model\Config\Backend\Image;
use Magento\Framework\App\Cache\TypeListInterface;
use Magento\Framework\App\Request\Http;
use Magento\Framework\Data\Collection\AbstractDb;
use Magento\Framework\Filesystem;
use Magento\Framework\Model\Context;
use Magento\Framework\Model\ResourceModel\AbstractResource;
use Magento\Framework\Registry;
use Magento\MediaStorage\Model\File\UploaderFactory;

class ImageUpload extends Image
{
    /**
     * The tail part of directory path for uploading
     */

    const UPLOAD_DIR = 'vendor/images';
    protected $uploadDirExtend = '';

    /**
     * Upload max file size in kilobytes
     *
     * @var int
     */
    protected $_maxFileSize = 2048;

    /**
     * @var Http
     */
    private $http;

    /**
     * Return path to directory for upload file
     *
     * @param Context $context
     * @param Registry $registry
     * @param ScopeConfigInterface $config
     * @param TypeListInterface $cacheTypeList
     * @param UploaderFactory $uploaderFactory
     * @param RequestDataInterface $requestData
     * @param Filesystem $filesystem
     * @param AbstractResource|null $resource
     * @param AbstractDb|null $resourceCollection
     * @param Http $http
     * @param array $data
     */

    public function __construct(
        Context $context,
        Registry $registry,
        ScopeConfigInterface $config,
        TypeListInterface $cacheTypeList,
        UploaderFactory $uploaderFactory,
        RequestDataInterface $requestData,
        Filesystem $filesystem,
        AbstractResource $resource = null,
        AbstractDb $resourceCollection = null,
        Http $http,
        array $data = []
    )
    {
        parent::__construct($context, $registry, $config, $cacheTypeList, $uploaderFactory, $requestData, $filesystem, $resource, $resourceCollection, $data);
        $this->http = $http;
    }

    /**
     * Return path to directory for upload file
     *
     * @return string
     */
    protected function _getUploadDir()
    {
        return $this->_mediaDirectory->getAbsolutePath($this->_appendScopeInfo(self::UPLOAD_DIR . $this->uploadDirExtend));
    }

    /**
     * Makes a decision about whether to add info about the scope
     *
     * @return boolean
     */
    protected function _addWhetherScopeInfo()
    {
        return true;
    }

    /**
     * Save uploaded file before saving config value
     *
     * Save changes and delete file if "delete" option passed
     *
     * @return $this
     */
    public function beforeSave()
    {
        $value = $this->getValue();
        $files = $this->http->getFiles();

        if (isset($value)) {
            $deleteFlag = is_array($value) && !empty($value['delete']);
            if (isset($files['groups'])) {
                $fileTmpName = $files['groups'][$this->getGroupId()]['fields'][$this->getField()]['value'];
                if ($this->getOldValue() && ($fileTmpName || $deleteFlag)) {
                    $this->_mediaDirectory->delete(self::UPLOAD_DIR . '/' . $this->getOldValue());
                }
            }
        }
        return parent::beforeSave();
    }

    protected function _getAllowedExtensions()
    {
        return ['jpg', 'jpeg', 'png', 'svg'];
    }
}
  • I have tried your option 1, the image attribute is displaying perfectly in admin. But I am not able to save the image. – Amy Feb 26 at 14:16
  • That's probably because your backend model isn't working properly. I'll edit my post once I got it working. – Matthias_CompactCode Feb 26 at 14:47
  • Okay thank you, will be waiting for your answer. – Amy Feb 26 at 14:55
  • I have updated my post. If you want more support, we can always help you through our website. – Matthias_CompactCode Feb 26 at 16:22
  • Again not able to save the image. – Amy Feb 27 at 5:50

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.