0

I have created a module to upload custom bundle product images but how I can save them in catalog_product_bundle_selection table?

enter image description here

8
  • Any suggestion will be appreciated
    – Amit Kumar
    Commented Jan 16, 2023 at 7:59
  • Hello Amit can you share your module with me Commented Jan 30, 2023 at 8:37
  • Its not ready yet
    – Amit Kumar
    Commented Feb 1, 2023 at 5:06
  • yes your incomplete module share with me Commented Feb 1, 2023 at 10:36
  • @AmitKumar what is your Magento version? I asking this because it is a different code for Magento version >= 2.4.3 and < 2.4.3, I'll share the code for both versions but I'll share the code for your Magento version first. @Rahil Shaikh I'll share with you a complete tutorial to implement adding bundle selection image feature soon.
    – Tu Van
    Commented Feb 6, 2023 at 4:43

2 Answers 2

2

In this post, I'll give instructions on how to create and save a custom image in the bundle product selection step-by-step.

For the purposes of this tutorial Magetu is the name of the vendor associated with a module named BundleSelectionImage.

  1. Create registration.php:
    File path: app/code/Magetu/BundleSelectionImage/registration.php
<?php

use Magento\Framework\Component\ComponentRegistrar;

ComponentRegistrar::register(ComponentRegistrar::MODULE, 'Magetu_BundleSelectionImage', __DIR__);

  1. Create module.xml:
    File path: app/code/Magetu/BundleSelectionImage/etc/module.xml
<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Module/etc/module.xsd">
    <module name="Magetu_BundleSelectionImage">
        <sequence>
            <module name="Magento_Bundle"/>
            <module name="Magento_Catalog"/>
        </sequence>
    </module>
</config>

  1. Create db_schema.xml to add a new column for bundle selection image in catalog_product_bundle_selection table.

File path: app/code/Magetu/BundleSelectionImage/etc/db_schema.xml

<?xml version="1.0"?>
<schema xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:noNamespaceSchemaLocation="urn:magento:framework:Setup/Declaration/Schema/etc/schema.xsd">
    <table name="catalog_product_bundle_selection">
        <column xsi:type="varchar" name="selection_image" nullable="true" length="255" comment="Selection Image"/>
    </table>
</schema>
  1. Create the di.xml file to:
  • define a modifier to modify bundle selection structure to add the selection image field
  • config the Upload class
  • override Magento\Bundle\Model\LinkManagement class to save the bundle selection image value

File path: app/code/Magetu/BundleSelectionImage/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">
    <virtualType name="Magento\Catalog\Ui\DataProvider\Product\Form\Modifier\Pool">
        <arguments>
            <argument name="modifiers" xsi:type="array">
                <item name="bundle_selection_image" xsi:type="array">
                    <item name="class" xsi:type="string">Magetu\BundleSelectionImage\Ui\DataProvider\Product\Form\Modifier\SelectionImage</item>
                    <item name="sortOrder" xsi:type="number">181</item><!-- run after core bundle modifier -->
                </item>
            </argument>
        </arguments>
    </virtualType>

    <virtualType name="Magetu\BundleSelectionImage\ImageUpload" type="Magento\Catalog\Model\ImageUploader">
        <arguments>
            <argument name="baseTmpPath" xsi:type="string">catalog/tmp/product/selection_images</argument>
            <argument name="basePath" xsi:type="string">catalog/product/selection_images</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>
                <item name="svg" xsi:type="string">svg</item>
                <item name="svgz" xsi:type="string">svgz</item>
                <item name="webp" xsi:type="string">webp</item>
                <item name="avif" xsi:type="string">avif</item>
                <item name="avifs" xsi:type="string">avifs</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>
                <item name="svg" xsi:type="string">image/svg+xml</item>
                <item name="svgz" xsi:type="string">image/svg+xml</item>
                <item name="webp" xsi:type="string">image/webp</item>
                <item name="avif" xsi:type="string">image/avif</item>
                <item name="avifs" xsi:type="string">image/avif-sequence</item>
            </argument>
        </arguments>
    </virtualType>

    <type name="Magetu\BundleSelectionImage\Controller\Adminhtml\Product\Image\Upload">
        <arguments>
            <argument name="imageUploader" xsi:type="object">Magetu\BundleSelectionImage\ImageUpload</argument>
        </arguments>
    </type>

    <preference for="Magento\Bundle\Model\LinkManagement" type="Magetu\BundleSelectionImage\Model\LinkManagement"/>

    <type name="Magetu\BundleSelectionImage\Model\LinkManagement">
        <arguments>
            <argument name="imageUploader" xsi:type="object">Magetu\BundleSelectionImage\ImageUpload</argument>
        </arguments>
    </type>
</config>

  1. Create routes.xml to use the upload controller.

File path: app/code/Magetu/BundleSelectionImage/etc/adminhtml/routes.xml

<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:App/etc/routes.xsd">
    <router id="admin">
        <route id="bundleselectionimage" frontName="bundleselectionimage">
            <module name="Magetu_BundleSelectionImage" before="Magento_Backend"/>
        </route>
    </router>
</config>

  1. Create a modifier class which is defined in di.xml in step 4 in order to modify bundle selection structure to add the selection image field:

File path: app/code/Magetu/BundleSelectionImage/Ui/DataProvider/Product/Form/Modifier/SelectionImage.php

<?php
namespace Magetu\BundleSelectionImage\Ui\DataProvider\Product\Form\Modifier;

use Magento\Bundle\Model\Product\Type;
use Magento\Bundle\Model\ResourceModel\Selection as SelectionResource;
use Magento\Bundle\Model\SelectionFactory;
use Magento\Bundle\Ui\DataProvider\Product\Form\Modifier\BundlePanel;
use Magento\Catalog\Model\Category\FileInfo;
use Magento\Catalog\Model\Locator\LocatorInterface;
use Magento\Catalog\Ui\DataProvider\Product\Form\Modifier\AbstractModifier;
use Magento\Framework\UrlInterface;

class SelectionImage extends AbstractModifier
{
    public const FIELD_IMAGE = 'selection_image';

    /**
     * @var LocatorInterface
     */
    private $locator;

    /**
     * @var UrlInterface
     */
    private $urlBuilder;

    /**
     * @var FileInfo
     */
    private $fileInfo;

    /**
     * @var SelectionFactory
     */
    private $selectionFactory;

    /**
     * @var SelectionResource
     */
    private $selectionResource;

    public function __construct(
        LocatorInterface $locator,
        UrlInterface $urlBuilder,
        FileInfo $fileInfo,
        SelectionFactory $selectionFactory,
        SelectionResource $selectionResource
    ) {
        $this->locator = $locator;
        $this->urlBuilder = $urlBuilder;
        $this->fileInfo = $fileInfo;
        $this->selectionFactory = $selectionFactory;
        $this->selectionResource = $selectionResource;
    }

    /**
     * {@inheritdoc}
     *
     * Converts selection image data to acceptable for rendering format
     * Display selection image
     */
    public function modifyData(array $data)
    {
        $product = $this->locator->getProduct();
        $modelId = $product->getId();
        $isBundleProduct = $product->getTypeId() === Type::TYPE_CODE;
        if ($isBundleProduct && $modelId) {
            $selectionModel = $this->selectionFactory->create();
            foreach ($data[$modelId][BundlePanel::CODE_BUNDLE_OPTIONS][BundlePanel::CODE_BUNDLE_OPTIONS] as &$option) {
                foreach ($option['bundle_selections'] as &$selection) {
                    $this->selectionResource->load($selectionModel, $selection['selection_id']);
                    $selectionImage = $selectionModel->getData('selection_image');
                    if ($selectionImage !== null && $this->fileInfo->isExist($selectionImage)) {
                        $stat = $this->fileInfo->getStat($selectionImage);
                        $mime = $this->fileInfo->getMimeType($selectionImage);

                        // phpcs:ignore Magento2.Functions.DiscouragedFunction
                        $imageUrl = $product->getStore()->getBaseUrl() . $selectionImage;
                        $imageRendering = [];
                        $imageRendering[0]['name'] = basename($selectionImage);
                        $imageRendering[0]['url'] = $imageUrl;
                        $imageRendering[0]['size'] = $stat['size'];
                        $imageRendering[0]['type'] = $mime;

                        $selectionModel->setData('selection_image', $imageRendering);
                    }
                    $selection['selection_image'] = $selectionModel->getData('selection_image');
                }
            }
        }

        return $data;
    }

    /**
     * Add selection image field
     *
     * @param array $meta
     * @return array
     */
    public function modifyMeta(array $meta) {
        if ($this->locator->getProduct()->getTypeId() === Type::TYPE_CODE) {
            $groupCode = BundlePanel::CODE_BUNDLE_DATA;
            $meta[$groupCode]['children']['bundle_options']['children']['record']['children']
            ['product_bundle_container']['children']['bundle_selections']
            ['children']['record']['children'][static::FIELD_IMAGE] = $this->getSelectionImageFieldConfig();
        }

        return $meta;
    }

    /**
     * Get selection image field config
     *
     * @return array
     */
    private function getSelectionImageFieldConfig()
    {
        return [
            'arguments' => [
                'data' => [
                    'config' => [
                        'componentType' => 'imageUploader',
                        'formElement' => 'imageUploader',
                        'template' => 'Magetu_BundleSelectionImage/form/element/uploader/image',
                        'fileInputName' => static::FIELD_IMAGE,
                        'uploaderConfig' => [
                            'url' => $this->urlBuilder->getUrl(
                                'bundleselectionimage/product_image/upload'
                            ),
                        ],
                        'dataScope' => static::FIELD_IMAGE,
                        'sortOrder' => 129,// Before the last field (action_delete)
                    ],
                ],
            ],
        ];
    }
}

  1. Create image uploader html file to upload the selection image file:

File path: app/code/Magetu/BundleSelectionImage/view/adminhtml/web/template/form/element/uploader/image.html

<!--
/**
 * Custom template for upload image file in bundle selection,
 * based on Magento_Ui::form/element/uploader/image.html
 *
 * NOTE: the variable name of the upload file input name should not be declared as 'inputName'
 * to allow the upload controller get the file
 */
-->
<div class="admin__field" visible="visible" css="$data.additionalClasses">
    <div class="admin__field-control" css="'_with-tooltip': $data.tooltip">
        <div class="file-uploader image-uploader" data-role="drop-zone" css="_loading: isLoading">
            <div class="file-uploader-area">
                <input type="file" afterRender="onElementRender" attr="id: uid, name: fileInputName, multiple: isMultipleFiles" disable="disabled" />
                <label class="file-uploader-button action-default" attr="for: uid, disabled: disabled" disable="disabled" translate="'Upload'"></label>
                <render args="fallbackResetTpl" if="$data.showFallbackReset && $data.isDifferedFromDefault"></render>
                <p class="image-upload-requirements">
                    <span if="$data.maxFileSize">
                        <span translate="'Maximum file size'"></span>: <text args="formatSize($data.maxFileSize)"></text>.
                    </span>
                    <span if="$data.allowedExtensions">
                        <span translate="'Allowed file types'"></span>: <text args="getAllowedFileExtensionsInCommaDelimitedFormat()"></text>.
                    </span>
                </p>
            </div>

            <render args="tooltipTpl" if="$data.tooltip"></render>

            <div class="admin__field-note" if="$data.notice" attr="id: noticeId">
                <span html="notice"></span>
            </div>

            <label class="admin__field-error" if="error" attr="for: uid" text="error"></label>

            <each args="data: value, as: '$file'" render="$parent.getPreviewTmpl($file)"></each>

            <div if="!hasData()" class="image image-placeholder" click="triggerImageUpload">
                <div class="file-uploader-summary product-image-wrapper">
                    <div class="file-uploader-spinner image-uploader-spinner"></div>
                    <p class="image-placeholder-text" translate="'Browse to find or drag image here'"></p>
                </div>
            </div>
        </div>
        <render args="$data.service.template" if="$data.hasService()"></render>
    </div>
</div>

  1. Create the uploader controller to handle upload the selection image file:

File path: app/code/Magetu/BundleSelectionImage/Controller/Adminhtml/Product/Image/Upload.php

<?php
namespace Magetu\BundleSelectionImage\Controller\Adminhtml\Product\Image;

use Magento\Backend\App\Action as BackendAction;
use Magento\Backend\App\Action\Context;
use Magento\Catalog\Model\ImageUploader;
use Magento\Framework\App\Action\HttpPostActionInterface;
use Magento\Framework\Controller\ResultFactory;
use Magento\Framework\Controller\ResultInterface;

/**
 * The bundle selection image upload controller
 */
class Upload extends BackendAction implements HttpPostActionInterface
{
    /**
     * Authorization level of a basic admin session
     *
     * @see _isAllowed()
     */
    public const ADMIN_RESOURCE = 'Magento_Catalog::products';

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

    public function __construct(
        Context $context,
        ImageUploader $imageUploader
    ) {
        parent::__construct($context);
        $this->imageUploader = $imageUploader;
    }

    /**
     * Upload selection image file controller action
     */
    public function execute(): ResultInterface
    {
        $imageId = $this->_request->getParam('param_name', 'selection_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);
    }
}

  1. Create LinkManagement model class to override Magento\Bundle\Model\LinkManagement class to save the bundle selection image value in the database:
    File path: app/code/Magetu/BundleSelectionImage/Model/LinkManagement.php

Due to Magento 2.4.3 replacing the code of method to map product link to bundle selection model, the content for LinkManagement model class should be different:

  • For Magento version >= 2.4.3
<?php
namespace Magetu\BundleSelectionImage\Model;

use Magento\Bundle\Api\Data\LinkInterface;
use Magento\Bundle\Api\Data\LinkInterfaceFactory;
use Magento\Bundle\Model\ResourceModel\Bundle;
use Magento\Bundle\Model\ResourceModel\BundleFactory;
use Magento\Bundle\Model\ResourceModel\Option\CollectionFactory;
use Magento\Bundle\Model\Selection;
use Magento\Bundle\Model\SelectionFactory;
use Magento\Catalog\Api\Data\ProductInterface;
use Magento\Catalog\Api\ProductRepositoryInterface;
use Magento\Catalog\Model\ImageUploader;
use Magento\Catalog\Model\Product;
use Magento\Framework\Api\DataObjectHelper;
use Magento\Framework\EntityManager\MetadataPool;
use Magento\Framework\Exception\CouldNotSaveException;
use Magento\Framework\Exception\InputException;
use Magento\Framework\Exception\NoSuchEntityException;
use Magento\Framework\Message\Manager as MessageManager;
use Magento\Store\Model\StoreManagerInterface;

class LinkManagement extends \Magento\Bundle\Model\LinkManagement
{
    /**
     * @var StoreManagerInterface
     */
    private $storeManager;

    /**
     * @var MetadataPool
     */
    private $metadataPool;

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

    /**
     * @var MessageManager
     */
    private $messageManager;

    public function __construct(
        ProductRepositoryInterface $productRepository,
        LinkInterfaceFactory $linkFactory,
        SelectionFactory $bundleSelection,
        BundleFactory $bundleFactory,
        CollectionFactory $optionCollection,
        StoreManagerInterface $storeManager,
        DataObjectHelper $dataObjectHelper,
        MetadataPool $metadataPool,
        ImageUploader $imageUploader,
        MessageManager $messageManager
    ) {
        parent::__construct(
            $productRepository,
            $linkFactory,
            $bundleSelection,
            $bundleFactory,
            $optionCollection,
            $storeManager,
            $dataObjectHelper,
            $metadataPool
        );
        $this->storeManager = $storeManager;
        $this->metadataPool = $metadataPool;
        $this->imageUploader = $imageUploader;
        $this->messageManager = $messageManager;
    }

    /**
     * This method has same content as in the parent class
     * Declare it here to allow override mapProductLinkToBundleSelectionModel which is private
     *
     * @inheritDoc
     */
    public function saveChild(
        $sku,
        LinkInterface $linkedProduct
    ) {
        $product = $this->productRepository->get($sku, true);
        if ($product->getTypeId() != Product\Type::TYPE_BUNDLE) {
            throw new InputException(
                __('The product with the "%1" SKU isn\'t a bundle product.', [$product->getSku()])
            );
        }

        /** @var Product $linkProductModel */
        $linkProductModel = $this->productRepository->get($linkedProduct->getSku());
        if ($linkProductModel->isComposite()) {
            throw new InputException(__('The bundle product can\'t contain another composite product.'));
        }

        if (!$linkedProduct->getId()) {
            throw new InputException(__('The product link needs an ID field entered. Enter and try again.'));
        }

        /** @var Selection $selectionModel */
        $selectionModel = $this->bundleSelection->create();
        $selectionModel->load($linkedProduct->getId());
        if (!$selectionModel->getId()) {
            throw new InputException(
                __(
                    'The product link with the "%1" ID field wasn\'t found. Verify the ID and try again.',
                    [$linkedProduct->getId()]
                )
            );
        }
        $selectionModel = $this->mapProductLinkToBundleSelectionModel(
            $selectionModel,
            $linkedProduct,
            $product,
            (int)$linkProductModel->getId()
        );

        try {
            $selectionModel->save();
        } catch (\Exception $e) {
            throw new CouldNotSaveException(__('Could not save child: "%1"', $e->getMessage()), $e);
        }

        return true;
    }

    /**
     * This method has same content as in the parent class
     * Declare it here to allow override mapProductLinkToBundleSelectionModel which is private
     *
     * @inheritDoc
     */
    public function addChild(
        ProductInterface $product,
                         $optionId,
        LinkInterface $linkedProduct
    ) {
        if ($product->getTypeId() != Product\Type::TYPE_BUNDLE) {
            throw new InputException(
                __('The product with the "%1" SKU isn\'t a bundle product.', $product->getSku())
            );
        }

        $linkField = $this->metadataPool->getMetadata(ProductInterface::class)->getLinkField();

        $options = $this->optionCollection->create();

        $options->setIdFilter($optionId);
        $options->setProductLinkFilter($product->getData($linkField));

        $existingOption = $options->getFirstItem();

        if (!$existingOption->getId()) {
            throw new InputException(
                __(
                    'Product with specified sku: "%1" does not contain option: "%2"',
                    [$product->getSku(), $optionId]
                )
            );
        }

        /* @var $resource Bundle */
        $resource = $this->bundleFactory->create();
        $selections = $resource->getSelectionsData($product->getData($linkField));
        /** @var Product $linkProductModel */
        $linkProductModel = $this->productRepository->get($linkedProduct->getSku());
        if ($linkProductModel->isComposite()) {
            throw new InputException(__('The bundle product can\'t contain another composite product.'));
        }

        if ($selections) {
            foreach ($selections as $selection) {
                if ($selection['option_id'] == $optionId &&
                    $selection['product_id'] == $linkProductModel->getEntityId() &&
                    $selection['parent_product_id'] == $product->getData($linkField)) {
                    if (!$product->getCopyFromView()) {
                        throw new CouldNotSaveException(
                            __(
                                'Child with specified sku: "%1" already assigned to product: "%2"',
                                [$linkedProduct->getSku(), $product->getSku()]
                            )
                        );
                    }

                    return $this->bundleSelection->create()->load($linkProductModel->getEntityId());
                }
            }
        }

        $selectionModel = $this->bundleSelection->create();
        $selectionModel = $this->mapProductLinkToBundleSelectionModel(
            $selectionModel,
            $linkedProduct,
            $product,
            (int)$linkProductModel->getEntityId()
        );

        $selectionModel->setOptionId($optionId);

        try {
            $selectionModel->save();
            $resource->addProductRelation($product->getData($linkField), $linkProductModel->getEntityId());
        } catch (\Exception $e) {
            throw new CouldNotSaveException(__('Could not save child: "%1"', $e->getMessage()), $e);
        }

        return (int)$selectionModel->getId();
    }

    /**
     * Fill selection model with product link data.
     * Save selection image value
     *
     * @param Selection $selectionModel
     * @param LinkInterface $productLink
     * @param ProductInterface $parentProduct
     * @param int $linkedProductId
     * @return Selection
     * @throws NoSuchEntityException
     */
    private function mapProductLinkToBundleSelectionModel(
        Selection $selectionModel,
        LinkInterface $productLink,
        ProductInterface $parentProduct,
        int $linkedProductId
    ): Selection {
        $linkField = $this->metadataPool->getMetadata(ProductInterface::class)->getLinkField();
        $selectionModel->setProductId($linkedProductId);
        $selectionModel->setParentProductId($parentProduct->getData($linkField));
        if ($productLink->getSelectionId() !== null) {
            $selectionModel->setSelectionId($productLink->getSelectionId());
        }
        if ($productLink->getOptionId() !== null) {
            $selectionModel->setOptionId($productLink->getOptionId());
        }
        if ($productLink->getPosition() !== null) {
            $selectionModel->setPosition($productLink->getPosition());
        }
        if ($productLink->getQty() !== null) {
            $selectionModel->setSelectionQty($productLink->getQty());
        }
        if ($productLink->getPriceType() !== null) {
            $selectionModel->setSelectionPriceType($productLink->getPriceType());
        }
        if ($productLink->getPrice() !== null) {
            $selectionModel->setSelectionPriceValue($productLink->getPrice());
        }
        if ($productLink->getCanChangeQuantity() !== null) {
            $selectionModel->setSelectionCanChangeQty($productLink->getCanChangeQuantity());
        }
        if ($productLink->getIsDefault() !== null) {
            $selectionModel->setIsDefault($productLink->getIsDefault());
        }
        $selectionModel->setWebsiteId((int)$this->storeManager->getStore($parentProduct->getStoreId())->getWebsiteId());

        // Start customize
        $selectionImage = null;
        if ($productLink->getSelectionImage() !== null) {
            $selectionImage = $this->getSelectionImage($productLink->getSelectionImage());
        }
        $selectionModel->setSelectionImage($selectionImage);
        // End customize

        return $selectionModel;
    }

    /**
     * Move uploaded selection image file and get selection image path
     * @param $selectionImageData
     * @return string|null
     * @throws NoSuchEntityException
     */
    private function getSelectionImage($selectionImageData)
    {
        $selectionImage = null;
        $store = $this->storeManager->getStore();
        $baseMediaDir = $store->getBaseMediaDir();
        $imageName = $selectionImageData[0]['name'];
        if (isset($selectionImageData[0]['tmp_name'])) {
            // Save new uploaded selection image
            try {
                $newImgRelativePath = $this->imageUploader->moveFileFromTmp($imageName, true);
                $selectionImage = $baseMediaDir . '/' . $newImgRelativePath;
            } catch (\Exception $e) {
                $message = __('Saving selection image: ') . $e->getMessage();
                $this->messageManager->addErrorMessage($message);
            }
        } else {
            // Save existing selection image
            /**
             * It was converted in Modifier for rendering in the admin interface:
             * Magetu\BundleSelectionImage\Ui\DataProvider\Product\Form\Modifier\SelectionImage::modifyData
             */
            $selectionImage = $baseMediaDir . '/' . $this->imageUploader->getBasePath() . '/' . $imageName;
        }

        return $selectionImage;
    }
}

Full module directory structure

The module is now complete. Your module’s directory structure under app/code should look like the following:

Magetu
|-- BundleSelectionImage
    |
    |-- Controller
    |   |-- Adminhtml
    |       |-- Product
    |           |-- Image
    |               |-- Upload.php
    |-- etc
    |   |-- adminhtml
    |   |   |-- di.xml
    |   |   |-- routes.xml
    |   |-- db_schema.xml
    |   |-- module.xml
    |-- Model
    |   |-- LinkManagement.php
    |-- Ui
    |   |-- DataProvider
    |       |-- Product
    |           |-- Form
    |               |-- Modifier
    |                   |-- SelectionImage.php
    |-- view
    |   |-- adminhtml
    |       |-- web
    |           |-- template
    |               |-- form
    |                   |-- element
    |                       |-- uploader
    |                           |-- image.html
    |-- registration.php

Installing the module

Run the following commands to register the module, upgrade database, compile code and deploy static content:

bin/magento setup:upgrade
bin/magento setup:di:compile
bin/magento setup:static-content:deploy -f

enter image description here

5
  • 1
    Its working perfectly, Thank you
    – Amit Kumar
    Commented Feb 20, 2023 at 5:15
  • 1
    You're welcome. Glad to hear that!
    – Tu Van
    Commented Feb 20, 2023 at 7:48
  • 1
    I am getting below error for all other product type in admin panel when edit The "componentType" configuration parameter is required for the "bundle-items" component, Any idea ?
    – Amit Kumar
    Commented Feb 24, 2023 at 6:39
  • 1
    Correction public function modifyMeta(array $meta) { $product = $this->locator->getProduct(); $isBundleProduct = $product->getTypeId() === Type::TYPE_CODE; if ($isBundleProduct) { $groupCode = BundlePanel::CODE_BUNDLE_DATA; $meta[$groupCode]['children']['bundle_options']['children']['record']['children'] ['product_bundle_container']['children']['bundle_selections'] ['children']['record']['children'][static::FIELD_IMAGE] = $this->getSelectionImageFieldConfig(); } return $meta; }
    – Amit Kumar
    Commented Feb 24, 2023 at 7:48
  • 1
    @AmitKumar good catch. Cheers!
    – Tu Van
    Commented Feb 24, 2023 at 10:50
0

Try this code:

First you need to override below file.

After that you can get bundle option images from below code.

=> app/design/frontend/Vendor/Theme_Name/Magento_Bundle/templates/catalog/product/view/type/bundle/option/radio.phtml

          <?php
             $_imageHelper = \Magento\Framework\App\ObjectManager::getInstance()->get('Magento\Catalog\Helper\Image');

             $image = $_imageHelper->init($_selection, 'small_image', ['type' => 'small_image'])->keepAspectRatio(true)->resize('50', '50')->getUrl(); ?>

                <label class="label" 
                       for="bundle-option-<?= /* @escapeNotVerified */ $_option->getId() ?>-<?= /* @escapeNotVerified */ $_selection->getSelectionId() ?>">
                    <div class="bundle-option-image"><img src="<?php echo $image; ?>" /></div>
                </label>
        <?php endforeach; ?>

I hope this is work for you.

1
  • 1
    Thank you for your comment but how I can save custom image in database?? Actually I know how to use that custom image on frontend
    – Amit Kumar
    Commented Feb 1, 2023 at 5:07

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.