Magento 2.2.4 : Add custom checkbox in product image details in admin

The question:

I added the custom checkbox in product image details page.

But, when I check it’s not selected and not saved after saving records. I want to do like as Hide from Product Page checkbox working.

https://codesolution.info/wp-content/uploads/2022/07/iwgcx.png

The Solutions:

Below are the methods you can try. The first solution is probably the best. Try others if the first one doesn’t work. Senior developers aren’t just copying/pasting – they read the methods carefully & apply them wisely to each case.

Method 1

Follow this step for checkbox checked and save value in database :

=> Create InstallSchema.php on below path for add custom field in database :

/app/code/CompanyName/ModuleName/Setup

<?php
namespace CompanyNameModuleNameSetup;

use MagentoFrameworkSetupInstallSchemaInterface;
use MagentoFrameworkSetupModuleContextInterface;
use MagentoFrameworkSetupSchemaSetupInterface;

class InstallSchema implements InstallSchemaInterface {
    public function install(SchemaSetupInterface $setup, ModuleContextInterface $context) {
        $installer = $setup;
        $installer->startSetup();
        /**
         * [$tableName catalog_product_option]
         * @var [catalog_product_option]
         */
        $tableName = $setup->getTable('catalog_product_entity_media_gallery_value');

        if ($setup->getConnection()->isTableExists($tableName) == true) {
            $columns = [
                'displayimage' => [
                    'type' => MagentoFrameworkDBDdlTable::TYPE_SMALLINT,
                    'length' => 5,
                    'nullable' => false,
                    'comment' => 'Display Image',
                    'default' => '0',
                ],
            ];
            $connection = $setup->getConnection();
            foreach ($columns as $name => $definition) {
                $connection->addColumn($tableName, $name, $definition);
            }
        }

        $installer->endSetup();
    }
}

=> Create events.xml file on this below path for add events catalog_product_save_after and catalog_product_gallery_prepare_layout

/app/code/CompanyName/ModuleName/etc/adminhtml

<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Event/etc/events.xsd">
    <event name="catalog_product_save_after">
        <observer name="validate" instance="CompanyNameModuleNameObserverProductSaveAfter" />
    </event>
    <event name="catalog_product_gallery_prepare_layout">
        <observer name="change_template" disabled="true"/>
        <observer name="custom_change_template" instance="CompanyNameModuleNameObserverChangeTemplateObserver" />
    </event> 
</config>

=> Create ChangeTemplateObserver.php file for prepare layout of product gallery :

/app/code/CompanyName/ModuleName/Observer

<?php

namespace CompanyNameModuleNameObserver;

use MagentoFrameworkEventObserverInterface;

class ChangeTemplateObserver implements ObserverInterface {

    public function execute(MagentoFrameworkEventObserver $observer) {
        $observer->getBlock()->setTemplate('CompanyName_ModuleName::helper/gallery.phtml');
    }
}

=> Create gallery.phtml on the below path for make layout of product gallery :

/app/code/CompanyName/ModuleName/view/adminhtml/templates/helper

<?php
/**
 * Copyright © Magento, Inc. All rights reserved.
 * See COPYING.txt for license details.
 */

// @codingStandardsIgnoreFile

/** @var $block MagentoCatalogBlockAdminhtmlProductHelperFormGalleryContent */
$elementName = $block->getElement()->getName() . '[images]';
$formName = $block->getFormName();
?>
<div id="<?= $block->getHtmlId() ?>"
     class="gallery"
     data-mage-init='{"productGallery":{"template":"#<?= $block->getHtmlId() ?>-template"}}'
     data-parent-component="<?= $block->escapeHtml($block->getData('config/parentComponent')) ?>"
     data-images="<?= $block->escapeHtml($block->getImagesJson()) ?>"
     data-types="<?= $block->escapeHtml(
         $this->helper('MagentoFrameworkJsonHelperData')->jsonEncode($block->getImageTypes())
     ) ?>"
    >
    <?php if (!$block->getElement()->getReadonly()) {?>
        <div class="image image-placeholder">
            <?= $block->getUploaderHtml() ?>
            <div class="product-image-wrapper">
                <p class="image-placeholder-text">
                    <?= /* @escapeNotVerified */ __('Browse to find or drag image here') ?>
                </p>
            </div>
        </div>
    <?php } ?>
    <?php foreach ($block->getImageTypes() as $typeData) {
    ?>
        <input name="<?= $block->escapeHtml($typeData['name']) ?>"
               data-form-part="<?= /* @escapeNotVerified */ $formName ?>"
               class="image-<?= $block->escapeHtml($typeData['code']) ?>"
               type="hidden"
               value="<?= $block->escapeHtml($typeData['value']) ?>"/>
    <?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="<?= /* @escapeNotVerified */ $elementName ?>[<%- data.file_id %>][position]"
                   value="<%- data.position %>"
                   data-form-part="<?= /* @escapeNotVerified */ $formName ?>"
                   class="position"/>
            <input type="hidden"
                   name="<?= /* @escapeNotVerified */ $elementName ?>[<%- data.file_id %>][file]"
                   data-form-part="<?= /* @escapeNotVerified */ $formName ?>"
                   value="<%- data.file %>"/>
            <input type="hidden"
                   name="<?= /* @escapeNotVerified */ $elementName ?>[<%- data.file_id %>][value_id]"
                   data-form-part="<?= /* @escapeNotVerified */ $formName ?>"
                   value="<%- data.value_id %>"/>
            <input type="hidden"
                   name="<?= /* @escapeNotVerified */ $elementName ?>[<%- data.file_id %>]"
                   data-form-part="<?= /* @escapeNotVerified */ $formName ?>"
                   value="<%- data.label %>"/>
            <input type="hidden"
                   name="<?= /* @escapeNotVerified */ $elementName ?>[<%- data.file_id %>][disabled]"
                   data-form-part="<?= /* @escapeNotVerified */ $formName ?>"
                   value="<%- data.disabled %>"/>
            <input type="hidden"
                   name="<?= /* @escapeNotVerified */ $elementName ?>[<%- data.file_id %>][displayimage]"
                   data-form-part="<?= /* @escapeNotVerified */ $formName ?>"
                   value="<%- data.displayimage %>"/>
            <input type="hidden"
                   name="<?= /* @escapeNotVerified */ $elementName ?>[<%- data.file_id %>][media_type]"
                   data-form-part="<?= /* @escapeNotVerified */ $formName ?>"
                   value="image"/>
            <input type="hidden"
                   name="<?= /* @escapeNotVerified */ $elementName ?>[<%- data.file_id %>][removed]"
                   data-form-part="<?= /* @escapeNotVerified */ $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="<?= /* @escapeNotVerified */ __('Delete image') ?>">
                    <span>
                        <?= /* @escapeNotVerified */ __('Delete image') ?>
                    </span>
                    </button>
                    <div class="draggable-handle"></div>
                </div>
                <div class="image-fade"><span><?= /* @escapeNotVerified */ __('Hidden') ?></span></div>
            </div>


            <div class="item-description">
                <div class="item-title" data-role="img-title"><%- data.label %></div>
                <div class="item-size">
                  <span data-role="image-dimens"></span>, <span data-role="image-size"><%- data.sizeLabel %></span>
                </div>
            </div>

            <ul class="item-roles" data-role="roles-labels">
                <?php
                foreach ($block->getImageTypes() as $typeData) {
                    ?>
                    <li data-role-code="<?php /* @escapeNotVerified */ echo $block->escapeHtml(
                        $typeData['code']
                    ) ?>" class="item-role item-role-<?php /* @escapeNotVerified */ echo $block->escapeHtml(
                        $typeData['code']
                    ) ?>">
                        <?= /* @escapeNotVerified */ $block->escapeHtml($typeData['label']) ?>
                    </li>
                    <?php
                }
                ?>
            </ul>
        </div>
    </script>

    <script data-role="img-dialog-container-tmpl" type="text/x-magento-template">
      <div class="image-panel" data-role="dialog">
      </div>
    </script>

    <script data-role="img-dialog-tmpl" type="text/x-magento-template">
            <div class="image-panel-preview">
                <img src="<%- data.url %>" alt="<%- data.label %>" />
            </div>
            <div class="image-panel-controls">
                <strong class="image-name"><%- data.label %></strong>

                <fieldset class="admin__fieldset fieldset-image-panel">
                    <div class="admin__field field-image-description">
                        <label class="admin__field-label" for="image-description">
                            <span><?= /* @escapeNotVerified */ __('Alt Text') ?></span>
                        </label>

                        <div class="admin__field-control">
                            <textarea data-role="image-description"
                                      rows="3"
                                      class="admin__control-textarea"
                                      name="<?php /* @escapeNotVerified */
                                      echo $elementName
                                      ?>[<%- data.file_id %>]"><%- data.label %></textarea>
                        </div>
                    </div>

                    <div class="admin__field field-image-role">
                        <label class="admin__field-label">
                            <span><?= /* @escapeNotVerified */ __('Role') ?></span>
                        </label>
                        <div class="admin__field-control">
                            <ul class="multiselect-alt">
                                <?php
                                foreach ($block->getMediaAttributes() as $attribute) :
                                    ?>
                                    <li class="item">
                                        <label>
                                            <input class="image-type"
                                                   data-role="type-selector"
                                                   data-form-part="<?= /* @escapeNotVerified */ $formName ?>"
                                                   type="checkbox"
                                                   value="<?php /* @escapeNotVerified */ echo $block->escapeHtml(
                                                       $attribute->getAttributeCode()
                                                   ) ?>"
                                                />
                                            <?php /* @escapeNotVerified */ echo $block->escapeHtml(
                                                $attribute->getFrontendLabel()
                                            ) ?>
                                        </label>
                                    </li>
                                <?php
                                endforeach;
                                ?>
                            </ul>
                        </div>
                    </div>

                    <div class="admin__field admin__field-inline field-image-size" data-role="size">
                        <label class="admin__field-label">
                            <span><?= /* @escapeNotVerified */ __('Image Size') ?></span>
                        </label>
                        <div class="admin__field-value" data-message="<?= /* @escapeNotVerified */ __('{size}') ?>"></div>
                    </div>

                    <div class="admin__field admin__field-inline field-image-resolution" data-role="resolution">
                        <label class="admin__field-label">
                            <span><?= /* @escapeNotVerified */ __('Image Resolution') ?></span>
                        </label>
                        <div class="admin__field-value" data-message="<?= /* @escapeNotVerified */ __('{width}^{height} px') ?>"></div>
                    </div>

                    <div class="admin__field field-image-hide">
                        <div class="admin__field-control">
                            <div class="admin__field admin__field-option">
                                <input type="checkbox"
                                       id="hide-from-product-page"
                                       data-role="visibility-trigger"
                                       data-form-part="<?= /* @escapeNotVerified */ $formName ?>"
                                       value="1"
                                       class="admin__control-checkbox"
                                       name="<?= /* @escapeNotVerified */ $elementName ?>[<%- data.file_id %>][disabled]"
                                <% if (data.disabled == 1) { %>checked="checked"<% } %> />

                                <label for="hide-from-product-page" class="admin__field-label">
                                    <?= /* @escapeNotVerified */ __('Hide from Product Page') ?>
                                </label>
                            </div>
                        </div>
                    </div>

                    <div class="admin__field field-display-image">
                        <div class="admin__field-control">
                            <div class="admin__field admin__field-option">
                                <input type="checkbox"
                                       id="display-image-from-product-page-<%- data.file_id %>"
                                       data-role="visibility-trigger-display-image"
                                       data-form-part="<?= /* @escapeNotVerified */ $formName ?>"
                                       value="1"
                                       class="admin__control-checkbox"
                                       name="<?= /* @escapeNotVerified */ $elementName ?>[<%- data.file_id %>][displayimage]"
                                <% if (data.displayimage == 1) { %>checked="checked"<% } %> />

                                <label for="display-image-from-product-page-<%- data.file_id %>" class="admin__field-label">
                                    <?= /* @escapeNotVerified */ __('Display Image') ?>
                                </label>
                            </div>
                        </div>
                    </div>
                </fieldset>
            </div>
    </script>
    <?= $block->getChildHtml('new-video') ?>
</div>
<script>
    jQuery('body').trigger('contentUpdated');
</script>

=> Create ProductSaveAfter.php observer on this below path for save custom field value in databse :

/app/code/CompanyName/ModuleName/Observer

<?php
namespace CompanyNameModuleNameObserver;

use MagentoFrameworkEventObserverInterface;
use MagentoStoreModelStoreManagerInterface;

class ProductSaveAfter implements ObserverInterface
{
    protected $_objectManager;
    protected $messageManager;
    protected $_productmetalFactory;
    protected $_productdiamondFactory;
    protected $_productstoneFactory;
    protected $_eavConfig;
    protected $stonestore;
    protected $scopeConfig;
    protected $storeManager;

    public function __construct(
        MagentoFrameworkAppConfigScopeConfigInterface $scopeConfig,
        MagentoFrameworkObjectManagerInterface $objectManager,
        MagentoFrameworkAppRequestInterface $request,
        MagentoEavModelConfig $eavConfig,
        StoreManagerInterface $storeManager,
        MagentoFrameworkMessageManagerInterface $messageManager
    ) {
        $this->_objectManager = $objectManager;
        $this->_request = $request;
        $this->scopeConfig = $scopeConfig;
        $this->_eavConfig = $eavConfig;
        $this->storeManager = $storeManager;
        $this->messageManager = $messageManager;
    }
    public function execute(MagentoFrameworkEventObserver $observer)
    {
        $data = $this->_request->getParams();
        $objectManager = MagentoFrameworkAppObjectManager::getInstance();
        $array_element = 0;
        $images = $data['product']['media_gallery']['images'];
        foreach ($images as $value) {
            if ($value['value_id'] == "") {
                $array_element++;
            }
        }

        $productCollection = $objectManager->create('MagentoCatalogModelResourceModelProductCollectionFactory');
        $collection = $productCollection->create();
        $collection->getSelect()->join(
            array('value_entity' => $collection->getTable('catalog_product_entity_media_gallery_value')),
            'e.entity_id = value_entity.entity_id',
            array('value_id')
        );
        $collection->getSelect()->join(
            array('value_data' => $collection->getTable('catalog_product_entity_media_gallery')),
            'value_entity.value_id = value_data.value_id',
            array('value')
        );
        $product = $collection->addFieldToFilter('entity_id', ['eq' => $data['id']]);
        $collection_updated = array_slice($product->getData(), "-" . $array_element, $array_element, true);
        $new_image_id = [];
        foreach ($collection_updated as $key => $value) {
            $new_image_id[] = $value['value_id'];
        }
        try
        {
            $getDisplayImage = [];
            $resource = $objectManager->get('MagentoFrameworkAppResourceConnection');
            $connection = $resource->getConnection();
            $tableName = $resource->getTableName('catalog_product_entity_media_gallery_value');
            foreach ($images as $image) {
                if ($image['removed'] != "") {
                    $sql = "DELETE FROM " . $tableName . " WHERE value_id =" . $image['value_id'];
                    $connection->query($sql);
                }
                if ($image['value_id'] == "") {
                    if (!isset($image['store_id']) || $image['store_id'] == "") {
                        $store_id = '0';
                    } else {
                        $store_id = $image['store_id'];
                    }
                    $getDisplayImage[] = $image['displayimage'];
                } else {
                    $sql = "update " . $tableName . " set displayimage = " . $image['displayimage'] . " where value_id = " . $image['value_id'];
                    $connection->query($sql);
                }
            }

            if ($array_element > 0) {
                $count = 0;
                foreach ($collection_updated as $key1 => $value1) {
                    $collection_updated[$key1]['new_displayimage'] = $getDisplayImage[$count];
                    $count++;
                    $sql = "update " . $tableName . " set displayimage  = " . $collection_updated[$key1]['new_displayimage'] . " where value_id = " . $collection_updated[$key1]['value_id'];
                    $connection->query($sql);
                }
            }
        } catch (MagentoFrameworkExceptionLocalizedException $e) {
            $this->messageManager->addError($e->getMessage());
        } catch (RuntimeException $e) {
            $this->messageManager->addError($e->getMessage());
        } catch (Exception $e) {
            $this->messageManager->addError($e->getMessage());
        }
    }
}

=> Create di.xml file on this below path for override module :

/app/code/CompanyName/ModuleName/etc

<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
<preference for="MagentoCatalogModelResourceModelProductGallery" type="CompanyNameModuleNameModelResourceModelProductGallery" />
</config>

=> Create Gallery.php file on this below path for override module :

/app/code/CompanyName/ModuleName/Model/ResourceModel/Product

<?php
/**
 * Copyright © Magento, Inc. All rights reserved.
 * See COPYING.txt for license details.
 */
namespace CompanyNameModuleNameModelResourceModelProduct;

use MagentoStoreModelStore;

/**
 * Catalog product media gallery resource model.
 *
 * @api
 * @since 101.0.0
 */
class Gallery extends MagentoCatalogModelResourceModelProductGallery {
  public function createBatchBaseSelect($storeId, $attributeId) {
    $linkField = $this->metadata->getLinkField();

    $positionCheckSql = $this->getConnection()->getCheckSql(
      'value.position IS NULL',
      'default_value.position',
      'value.position'
    );

    $mainTableAlias = $this->getMainTableAlias();

    $select = $this->getConnection()->select()->from(
      [$mainTableAlias => $this->getMainTable()],
      [
        'value_id',
        'file' => 'value',
        'media_type',
      ]
    )->joinInner(
      ['entity' => $this->getTable(self::GALLERY_VALUE_TO_ENTITY_TABLE)],
      $mainTableAlias . '.value_id = entity.value_id',
      [$linkField]
    )->joinLeft(
      ['value' => $this->getTable(self::GALLERY_VALUE_TABLE)],
      implode(
        ' AND ',
        [
          $mainTableAlias . '.value_id = value.value_id',
          $this->getConnection()->quoteInto('value.store_id = ?', (int) $storeId),
          'value.' . $linkField . ' = entity.' . $linkField,
        ]
      ),
      ['label', 'position', 'disabled', 'displayimage']
    )->joinLeft(
      ['default_value' => $this->getTable(self::GALLERY_VALUE_TABLE)],
      implode(
        ' AND ',
        [
          $mainTableAlias . '.value_id = default_value.value_id',
          $this->getConnection()->quoteInto('default_value.store_id = ?', Store::DEFAULT_STORE_ID),
          'default_value.' . $linkField . ' = entity.' . $linkField,
        ]
      ),
      ['label_default' => 'label', 'position_default' => 'position', 'disabled_default' => 'disabled', 'displayimage_default' => 'displayimage']
    )->where(
      $mainTableAlias . '.attribute_id = ?',
      $attributeId
    )->where(
      $mainTableAlias . '.disabled = 0'
    )->order(
      $positionCheckSql . ' ' . MagentoFrameworkDBSelect::SQL_ASC
    );

    return $select;
  }
}

=> Now, override product-gallery.js file. So, create requirejs-config.js on this below path for add custom js :

/app/code/CompanyName/ModuleName/view/adminhtml

var config = {
    "map": {
        "*": {
            productGallery: "CompanyName_ModuleName/js/product-gallery",
        }
    }
}

=> Create product-gallery.js file on this below path :

/app/code/CompanyName/ModuleName/view/adminhtml/web/js

/**
 * Copyright © Magento, Inc. All rights reserved.
 * See COPYING.txt for license details.
 */

/**
 * @api
 */
define([
    'jquery',
    'underscore',
    'mage/template',
    'uiRegistry',
    'jquery/ui',
    'baseImage',
    'productGallery'
], function ($, _, mageTemplate, registry) {
    'use strict';


});

Then,

=> Add this line after line no 195 :

'displayimage': imageData.displayimage ? imageData.displayimage : 0,

=> Add this function after line no 515 :

$dialog.on('change', '[data-role=visibility-trigger-displayimage]', $.proxy(function (e) {
                var imageData = $dialog.data('imageData');

                this.element.trigger('updateVisibility', {
                    disabled : $("#hide-from-product-page").is(':checked'),
                    displayimage : $("#virtual-displayimage-from-product-page-"+imageData.file_id).is(':checked'),
                    imageData: imageData
                });
            }, this));

=> Add this function after line no 620 :

displayimage = +data.displayimage,

=> Add this function after line no 628 :

$imageContainer.find('[name*="displayimage"]').val(displayimage);
imageData.displayimage = displayimage;


All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0

Leave a Comment