I would like to add an extra text area in a new column next to the label column in the product images tab: https://gyazo.com/c3d4333045991aea0a70c242bdfba454

I tried to create a new attribute and assign it, here is what it gives: https://gyazo.com/bdb76f694b41a3f02df24549adfefb7a

So unfortunately, it doesn't add a new column next to the label one.

How to achieve this ?

Many thanks !

1 Answer 1


1. Extend Table catalog_product_entity_media_gallery_value with a setup Script

$installer = Mage::getResourceModel('catalog/setup', 'catalog_setup');

        'type'     => Varien_Db_Ddl_Table::TYPE_TEXT,
        'nullable' => true,
        'default'  => null,
        'comment'  => 'YOUR FIELD',
        'after'    => 'label'


2. Rewrite Ressource Model

Rewrite Method _getLoadGallerySelect() in Class Mage_Catalog_Model_Resource_Product_Attribute_Backend_Media to add your new Field to both Joins

    array('value' => $this->getTable(self::GALLERY_VALUE_TABLE)),
    $adapter->quoteInto('main.value_id = value.value_id AND value.store_id = ?', (int)$storeId),
    array('label','position', 'YOURFIELD', 'disabled')
->joinLeft( // Joining default values
    array('default_value' => $this->getTable(self::GALLERY_VALUE_TABLE)),
    'main.value_id = default_value.value_id AND default_value.store_id = 0',
        'label_default' => 'label',
        'position_default' => 'position',
        'disabled_default' => 'disabled',
        'YOURFIELD_default' => 'YOURFIELD'

3. Rewrite Model

Rewrite Method afterLoad() and updateImage() in Class Mage_Catalog_Model_Product_Attribute_Backend_Media to add your new Field to Arrays

$localAttributes = array('label', 'position', 'disabled', 'YOURFIELD');


$fieldsMap = array(
    'label'    => 'label',
    'position' => 'position',
    'disabled' => 'disabled',
    'exclude'  => 'disabled'

4. Change Adminhtml Template

You habe to replace the Template with your version where you add your textarea app/design/adminhtml/default/default/template/catalog/product/helper/gallery.phtml

 * Magento
 * This source file is subject to the Academic Free License (AFL 3.0)
 * that is bundled with this package in the file LICENSE_AFL.txt.
 * It is also available through the world-wide-web at this URL:
 * http://opensource.org/licenses/afl-3.0.php
 * If you did not receive a copy of the license and are unable to
 * obtain it through the world-wide-web, please send an email
 * to [email protected] so we can send you a copy immediately.
 * Do not edit or add to this file if you wish to upgrade Magento to newer
 * versions in the future. If you wish to customize Magento for your
 * needs please refer to http://www.magento.com for more information.
 * @category    design
 * @package     default_default
 * @copyright   Copyright (c) 2006-2016 X.commerce, Inc. and affiliates (http://www.magento.com)
 * @license     http://opensource.org/licenses/afl-3.0.php  Academic Free License (AFL 3.0)
 * Template for block Mage_Adminhtml_Block_Catalog_Product_Helper_Form_Gallery_Content
$_block = $this;
/* @var $_block Mage_Adminhtml_Block_Catalog_Product_Helper_Form_Gallery_Content */
<div id="<?php echo $_block->getHtmlId() ?>" >
<ul class="messages">
    <li class="notice-msg">
            <?php echo Mage::helper('catalog')->__('Image type and information need to be specified for each store view.'); ?>
<div class="grid">
<table cellspacing="0" class="data border" id="<?php echo $_block->getHtmlId() ?>_grid" width="100%">
    <col width="25%" />
    <col width="25%"/>
    <col width="25%" />
    <?php foreach ($_block->getImageTypes() as $typeId=>$type): ?>
    <col />
    <?php endforeach; ?>
    <col width="70" />
    <col width="70" />
        <tr class="headings">
            <th><?php echo Mage::helper('catalog')->__('Image') ?></th>
            <th><?php echo Mage::helper('catalog')->__('Label') ?></th>
            <th><?php echo Mage::helper('catalog')->__('Alt text') ?></th>
            <th><?php echo Mage::helper('catalog')->__('Sort Order') ?></th>
            <?php foreach ($_block->getImageTypes() as $typeId=>$type): ?>
            <th><?php echo $type['label'] ?></th>
            <?php endforeach; ?>
            <th><?php echo Mage::helper('catalog')->__('Exclude') ?></th>
            <th class="last"><?php echo Mage::helper('catalog')->__('Remove') ?></th>
    <tbody id="<?php echo $_block->getHtmlId() ?>_list">
        <tr id="<?php echo $_block->getHtmlId() ?>_template" class="template no-display">
                <td class="cell-image"><div class="place-holder" onmouseover="<?php echo $_block->getJsObjectName(); ?>.loadImage('__file__')"><span><?php echo Mage::helper('catalog')->__('Roll Over for preview') ?></span></div><img src="<?php echo $this->getSkinUrl('images/spacer.gif')?>" width="100" style="display:none;" alt="" /></td>
                <td class="cell-label"><input type="text" <?php if($_block->getElement()->getReadonly()):?> disabled="disabled"<?php endif;?> class="input-text" onkeyup="<?php echo $_block->getJsObjectName(); ?>.updateImage('__file__')" onchange="<?php echo $_block->getJsObjectName(); ?>.updateImage('__file__')" /></td>
                <td class="cell-alttext"><input type="text" <?php if($_block->getElement()->getReadonly()):?> disabled="disabled"<?php endif;?> class="input-text" onkeyup="<?php echo $_block->getJsObjectName(); ?>.updateImage('__file__')" onchange="<?php echo $_block->getJsObjectName(); ?>.updateImage('__file__')" /></td>
                <td class="cell-position"><input type="text" <?php if($_block->getElement()->getReadonly()):?> disabled="disabled"<?php endif;?> class="input-text validate-number" onkeyup="<?php echo $_block->getJsObjectName(); ?>.updateImage('__file__')" onchange="<?php echo $_block->getJsObjectName(); ?>.updateImage('__file__')" /></td>
                <?php foreach ($_block->getImageTypes() as $typeId=>$type): ?>
                <td class="cell-<?php echo $typeId ?> a-center"><input <?php if($_block->getElement()->getAttributeReadonly($typeId)) :?> disabled="disabled" <?php endif;?> type="radio" name="<?php echo $type['field'] ?>" onclick="<?php echo $_block->getJsObjectName(); ?>.setProductImages('__file__')" value="__file__" /></td>
                <?php endforeach; ?>
                <td class="cell-disable a-center"><input type="checkbox" <?php if($_block->getElement()->getReadonly()):?> disabled="disabled"<?php endif;?> onclick="<?php echo $_block->getJsObjectName(); ?>.updateImage('__file__')" /></td>
                <td class="cell-remove a-center last"><input type="checkbox" <?php if($_block->getElement()->getReadonly()):?> disabled="disabled"<?php endif;?> onclick="<?php echo $_block->getJsObjectName(); ?>.updateImage('__file__')" /></td>
        <?php if($_block->hasUseDefault()): ?>
        <tr id="<?php echo $_block->getHtmlId() ?>_default">
                <td><?php echo Mage::helper('catalog')->__('Use Default Value') ?></td>
                <?php foreach ($_block->getMediaAttributes() as $_attribute): ?>
                <td class="a-center">
                <?php if($_block->getElement()->canDisplayUseDefault($_attribute)): ?>
                <input class="default-checkbox" name="use_default[]" type="checkbox" <?php if($_block->getElement()->getAttributeReadonly($_attribute->getAttributeCode())):?> disabled="disabled" <?php endif;?>  onclick="<?php echo $_block->getJsObjectName(); ?>.updateUseDefault()"
<?php if($_block->getElement()->usedDefault($_attribute)): ?>checked<?php endif; ?> value="<?php echo $_attribute->getAttributeCode() ?>" />
                <?php endif ?>
                <?php endforeach; ?>
                <td class="last">&nbsp;</td>
    <?php endif ?>
        <tr id="<?php echo $_block->getHtmlId() ?>-image-0">
                <td class="cell-image"><?php echo Mage::helper('catalog')->__('No image') ?></td>
                <td class="cell-label"><input type="hidden" />&nbsp;</td>
                <td class="cell-alttext"><input type="hidden" />&nbsp;</td>
                <td class="cell-position"><input type="hidden" />&nbsp;</td>
                <?php foreach ($_block->getImageTypes() as $typeId=>$type): ?>
                <td class="cell-<?php echo $typeId ?> a-center"><input type="radio" <?php if($_block->getElement()->getAttributeReadonly($typeId)) :?> disabled="disabled" <?php endif;?> name="<?php echo $type['field'] ?>" onclick="<?php echo $_block->getJsObjectName(); ?>.setProductImages('no_selection')" value="no_selection" /></td>
                <?php endforeach; ?>
                <td class="cell-disable"><input type="hidden" />&nbsp;</td>
                <td class="cell-remove last"><input type="hidden" />&nbsp;</td>
<?php if (!$_block->getElement()->getReadonly()):?>
            <td colspan="100" class="last" style="padding:8px">
                <?php echo Mage::helper('catalog')->__('Maximum width and height dimension for upload image is %s.', Mage::getStoreConfig(Mage_Catalog_Helper_Image::XML_NODE_PRODUCT_MAX_DIMENSION)); ?>
                <?php echo $_block->getUploaderHtml() ?>
<?php endif;?>
<input type="hidden" id="<?php echo $_block->getHtmlId() ?>_save" name="<?php echo $_block->getElement()->getName() ?>[images]" value="<?php echo $_block->escapeHtml($_block->getImagesJson()) ?>" />
<input type="hidden" id="<?php echo $_block->getHtmlId() ?>_save_image" name="<?php echo $_block->getElement()->getName() ?>[values]" value="<?php echo $_block->escapeHtml($_block->getImagesValuesJson()) ?>" />
<script type="text/javascript">
var <?php echo $_block->getJsObjectName(); ?>;
        // overwrite updateVisulatisation from product.js
        Product.Gallery.prototype.updateVisualisation = function (file) {
            var image = this.getImageByFile(file);
            this.getFileElement(file, 'cell-label input').value = image.label;
            this.getFileElement(file, 'cell-alttext input').value = (image.alttext ? image.alttext : '') ;
            this.getFileElement(file, 'cell-position input').value = image.position;
            this.getFileElement(file, 'cell-remove input').checked = (image.removed == 1);
            this.getFileElement(file, 'cell-disable input').checked = (image.disabled == 1);
                function (pair) {
                    if (this.imagesValues[pair.key] == file) {
                            'cell-' + pair.key + ' input').checked = true;

        // overwrite updateImage from product.js
        Product.Gallery.prototype.updateImage = function (file) {
            var index = this.getIndexByFile(file);
            this.images[index].label = this.getFileElement(file, 'cell-label input').value;
            this.images[index].alttext = this.getFileElement(file, 'cell-alttext input').value;
            this.images[index].position = this.getFileElement(file, 'cell-position input').value;
            this.images[index].removed = (this.getFileElement(file, 'cell-remove input').checked ? 1 : 0);
            this.images[index].disabled = (this.getFileElement(file, 'cell-disable input').checked ? 1 : 0);
            this.getElement('save').value = Object.toJSON(this.images);

        <?php echo $_block->getJsObjectName(); ?> = new Product.Gallery('<?php echo $_block->getHtmlId() ?>', <?php echo $_block->getImageTypesJson() ?>);


There is a lot of Javascript at the bottom the render the correct fields. In our project is jQuery included. If you don't have jQuery in your adminhtml you have to refactor the javascript part

5 Save Data

Now you can register an Observer an listen on the Event catalog_product_save_after. You get the Data via the Observer

$images = $observer->getEvent()->getProduct()->getData('media_gallery');

You have to foreach through every image and save the field in the Gallery

  • I have followed these steps, all the thing are working good,but i am unable to get data can you please share gallery.phtml code how to put there field ?
    – Kanika
    Jan 30, 2017 at 12:12
  • I updated my answer
    – Pawel
    Jan 31, 2017 at 19:40
  • We can also override Mage_Catalog_Model_Product_Attribute_Backend_Media model class and in afterSave function just add your field name in $data variable $data['YOUR_FIELD'] = $image['YOUR_FIELD']; Apr 3, 2017 at 13:00

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.