Enabling Linked Field Configuration for your Magento Module

In supplementing your Magento installation with custom functionality to support the unique needs of your business, you may find yourself dissatisfied with the range of admin form input field types available for use in your module’s configuration section. Magento, by default, provides several different field types at your disposal such as ‘text‘ fields, ‘time‘ selection, ‘textarea‘ input, drop-down ‘select‘, ‘radio‘ buttons, ‘password‘ fields, ‘note‘s, ‘multiselect‘, ‘multiline‘ input, ‘link‘s, ‘label‘s, ‘image‘ uploads, ‘file‘ uploads, ‘date‘ selection, and ‘checkbox‘es. Each of these, however, offers only single input control.

We recently encountered the need to use dynamic linked text input in a module in order to associate specific hex colour codes with the colour labels present on the Magento colour attribute. Dynamic refers to how a user can add new configuration items as a series of rows made up of column input fields. Linked field, here, refers to a series of attributes considered as a single element, much like an array of values.

In this tutorial, you will learn how to support this input method in your Magento module’s configuration.

Step 1: Declare a New Module

For the purposes of this tutorial, our module will be called “MyTutorialModule” and belong to the “Demac” namespace of the “local” codepool. Declare this new module in the “app/etc/modules” directory, by creating a new Demac_MyTutorialModule.xml file as follows:

<?xml version="1.0"?>
<config>
<modules>
<Demac_MyTutorialModule>
<active>true</active>
<codePool>local</codePool>
</Demac_MyTutorialModule>
</modules>
</config>

Step 2: Prepare the Module Directory

Before proceeding, ensure that the following folder structure and accompanying files exist within the “app/code/local” directory. These are only the minimum files required to demonstrate the functionality previous outlined. Your own module may extend this and require additional code.

  • Demac/

    • MyTutorialModule/

      • Block/

        • LinkedAttributes.php
      • etc/

        • adminhtml.xml
        • config.xml
        • system.xml
      • Helper/

        • Data.php

Step 3: Define XML Documents

Inside adminhtml.xml, define the document as follows so that the configuration is visible within the admin panel:

<?xml version="1.0"?>
<config>
<acl>
<resources>
<admin>
<children>
<system>
<children>
<config>
<children>
<demac_mytutorialmodule translate="title" module="demac_mytutorialmodule">
<title>Demac My Tutorial Module</title>
<sort_order>200</sort_order>
</demac_mytutorialmodule>
</children>
</config>
</children>
</system>
</children>
</admin>
</resources>
</acl>
</config>

Inside config.xml, define the document as follows in order to tell Magento to use certain helper classes and blocks within our module:

<?xml version="1.0"?>
<config>
<modules>
<Demac_MyTutorialModule>
<version>0.1.0</version>
</Demac_MyTutorialModule>
</modules>
<global>
<blocks>
<demac_mytutorialmodule>
<class>Demac_MyTutorialModule_Blocks</class>
</demac_mytutorialmodule>
</blocks>
<helpers>
<demac_mytutorialmodule>
<class>Demac_MyTutorialModule_Helper</class>
</demac_mytutorialmodule>
</helpers>
</global>
</config>

Inside system.xml, define the document as follows in order to add the necessary sections, groups, tabs, and fields for the admin configuration of our module:

<?xml version="1.0"?>
<config>
<tabs>
<demac_tab translate="label" module="demac_mytutorialmodule">
<label>Demac Media</label>
<sort_order>300</sort_order>
</demac_tab>
</tabs>
<sections>
<demac_mytutorialmodule translate="label" module="demac_mytutorialmodule">
<label>My Tutorial Module Configuration</label>
<tab>demac_tab</tab>
<frontend_type>text</frontend_type>
<sort_order>200</sort_order>
<show_in_default>1</show_in_default>
<show_in_website>1</show_in_website>
<show_in_store>1</show_in_store>
<groups>
<general translate="label">
<label>My Tutorial Module Settings</label>
<frontend_type>text</frontend_type>
<sort_order>4</sort_order>
<show_in_default>1</show_in_default>
<show_in_website>1</show_in_website>
<show_in_store>1</show_in_store>
<expanded>true</expanded>
<fields>
<colour_to_hex_attributes translate="comment">
<label>Colour attribute hex code associations</label>
<frontend_model>demac_myTutorialModule_block_linkedAttributes</frontend_model>
<backend_model>adminhtml/system_config_backend_serialized_array</backend_model>
<sort_order>25</sort_order>
<show_in_default>1</show_in_default>
<show_in_website>1</show_in_website>
<show_in_store>1</show_in_store>
<comment></comment>
</colour_to_hex_attributes>
</fields>
</general>
</groups>
</demac_mytutorialmodule>
</sections>
</config>

There are a couple of items here that should be pointed out. First, is the frontend_model element, which is the class path of the Block file we created earlier. This class prepares the dynamic grid with which the end user will interact. Second, is the backend_model, which says this input field is of the serialized array type. Our input form produces an array of serialized data.

Step 4: Define the Helper Class

Inside Helper/Data.php, create the Helper class as follows:

<?php

class Demac_MyTutorialModule_Helper_Data extends Mage_Core_Helper_Abstract
{

}

This class is empty, but present, in order to facilitate the translation attributes we have specified in the earlier .xml files. Without this class, Magento will produce errors stating that it cannot instantiate a helper.

Step 5: Define the Block – Out Frontend Model

The following code, within Block/LinkedAttributes.php, produces a dynamic multi-column grid, where the first column is pre-populated with all available labels from Magento’s colour attribute via drop-down selection.


<?php

class Demac_MyTutorialModule_Block_LinkedAttributes extends Mage_Adminhtml_Block_System_Config_Form_Field_Array_Abstract
{
    protected $magentoOptions;

    public function __construct()
    {
        // create columns
        $this->addColumn('magento', array(
            'label' => Mage::helper('adminhtml')->__('Magento colour attribute'),
            'size' => 28,
        ));
        $this->addColumn('hex', array(
            'label' => Mage::helper('adminhtml')->__('Hex code'),
            'size' => 28
        ));
        $this->_addAfter = false;
        $this->_addButtonLabel = Mage::helper('adminhtml')->__('Add linked attribute');

        parent::__construct();
        $this->setTemplate('demac/mytutorialmodule/system/config/form/field/array_dropdown.phtml');

        // custom options, from 'color' attribute
        $attribute = Mage::getSingleton('eav/config')->getAttribute('catalog_product', 'color');
        if ($attribute->usesSource()) {
            $magentoAttributes = $attribute->getSource()->getAllOptions(false);
        }

        $this->magentoOptions = array();
        foreach ($magentoAttributes as $att => $innerArray) {
            $this->magentoOptions[$innerArray['value']] = $innerArray['label'];
        }
        asort($this->magentoOptions); // sort labels alphabetically
    }

    protected function _renderCellTemplate($columnName)
    {
        if (empty($this->_columns[$columnName])) {
            throw new Exception('Wrong column name specified.');
        }
        $column = $this->_columns[$columnName];
        $inputName = $this->getElement()->getName() . '[#{_id}][' . $columnName . ']';

        if ($columnName == 'magento') {
            $rendered = '<select name="' . $inputName . '">';
            foreach ($this->magentoOptions as $att => $name) {
                $rendered .= '<option value="' . $att . '">' . $name . '</option>';
            }
            $rendered .= '</select>';
        } else {
            return '<input type="text" name="' . $inputName . '" value="#{' . $columnName . '}" ' . ($column['size'] ? 'size="' . $column['size'] . '"' : '') . '/>';
        }

        return $rendered;
    }
}

In the __construct(), the protected $magentoOptions variable is an array of colour labels as pulled from Magento’s colour attribute. You can add a member for each column you would like to include. A template file was also set shortly after. It contains the html markup of the dynamic grid as well as the JavaScript control for its operation. It is heavily adapted from Magento’s array.phtml in app/design/adminhtmldefault/default/template/system/config/form/field.

Step 6: Create a Layout File for Our Module

Navigate to ‘app/design/adminhtml/default/default/template/system/config/form/field‘, and copy the file array.phtml.

Paste the file in ‘app/design/adminhtml/default/default/template/demac/mytutorialmodule/system/config/form/field/‘ and rename it ‘array_dropdown.phtml‘ to match the template we set in our Block earlier.

The only addition to be made to this file is this insertion at Line 111, before <?php if ($this->_addAfter):?>:


// set the selected drop-down list item
<?php foreach ($this->_columns as $columnName => $column):?>
var options = $$('td.' + templateData._id + '-' + '<?php echo $columnName?>' + ' option');
for (var index = 0; index < options.length; ++index) {
    var option = options[index]
    if (option.getAttribute('value') == templateData.<?php echo $columnName?>) {
        option.selected = true
    }
}
<?php endforeach;?>

Step 7: Activate Your New Module

With all these files in place, you can now activate and use the module. Through the Admin Panel, refresh your cache and then log out and back in to activate the module.

Step 8: Configure the Module

The purpose of this example module is to associate a hex code with a colour label. With the module built and activated, we can now test this functionality. Navigate to ‘System > Configuration > Demac Media > My Tutorial Module Configuration’. Click the “Add linked attribute” button. A row will appear. In the left column, you can select a colour label. This is populated with the values from Magento’s colour attribute. In the right column, you can type the corresponding hex code you would like to associate with the label. In the screenshot below we have mapped #ff9900 to the colour “Orange”.

my_tutorial_module_configuration

Step 9: Using the Linked Attribute

Elsewhere, in a template for instance, you can access this serialized array of configurable values with the following statement:

$configArray = unserialize(Mage::getStoreConfig('demac_mytutorialmodule/general/colour_to_hex_attributes', Mage::app()->getStore()));

Note that we are unserializing the array here. Then, for some loaded product, $product, one way we can get the hex colour that corresponds to $product->getColor() is as follows:


foreach ($configArray as $configColor) {
    if ($configColor['magento'] == $product->getColor()) {
        echo($configColor['hex'];
    }
}

Recall that ‘magento‘ and ‘hex‘ were used when defining these columns in our block. You can make use of the element as you see you fit.

I hope you can make use of this configurable input type to expand the functionality of Magento attributes when it may be too limited for your business purposes.

If you have any questions, please leave a comment on this blog or contact me directly at jliotta@demacmedia.com