Unfortunately this doesn't work as easy as you thought (and I'd hoped). The first reason why this doesn't work is because you are extending a class that belongs to the system configuration part of the admin, not to the Catalog part of the admin.
The second reason why this isn't simple is because there is no built-in support for serialized arrays as an attribute for categories. Fortuntately, this is the case for products (notably the group & tier price attributes).
I've followed the logic of these product attributes and put something together that works. Eventually, it'll look like this;
First, we need to add an attribute to Magento that belongs to a category. I'll assume you know how to do this programatically so for proof of concepts' sake, I'll put the query here. I'm assuming your extension is called Your_Module.
INSERT INTO eav_attribute SET entity_type_id = 3, attribute_code = 'serialize_array', backend_model = 'your_module/category_attribute_backend_serializearray', backend_type = 'text', frontend_input = 'text', frontend_label = 'Serialize Array';
Then find the attribute ID for this attribute and run this query;
INSERT INTO eav_entity_attribute SET entity_type_id = 3, attribute_set_id = 3, attribute_group_id = 4, attribute_id = ATTRIBUTE_ID_HERE, sort_order = 100;
Now we'll have a nice attribute on the category page. But it isn't configurable like you'd like, it's still a normal text field.
We'll now create the logic needed to show, store and retrieve the serialized array.
First, we'll need to create the backend model. We need this because we need to serialize the array when its being saved by using the beforeSave() function.
<?php
class Your_Module_Model_Category_Attribute_Backend_Serializearray
extends Mage_Eav_Model_Entity_Attribute_Backend_Abstract
{
public function beforeSave($object)
{
$object->setData('serialize_array', serialize($object->getData('serialize_array')));
}
}
Next, we'll need to create a form renderer to show the HTML that will make up the select elements and the table.
<?php
class Your_Module_Block_Catalog_Form_Renderer_Attribute_SerializeArray
extends Mage_Adminhtml_Block_Catalog_Form_Renderer_Fieldset_Element
{
public function __construct()
{
$this->setTemplate('your/module/serialize_array.phtml');
}
public function getOptions() {
return array(
array('name' => 'Option 1'),
array('name' => 'Option 2')
);
}
public function getOtherOptions() {
return array('Other Option 1', 'Other Option 2');
}
public function getValues() {
$_category = Mage::registry('current_category');
$array = $_category->getSerializeArray();
if($array) {
return unserialize($array);
}
return array();
}
public function getElementHtml()
{
$element = $this->getElement();
if(!$element->getValue()) {
return parent::getElementHtml();
}
$element->setOnkeyup("onUrlkeyChanged('" . $element->getHtmlId() . "')");
$element->setOnchange("onUrlkeyChanged('" . $element->getHtmlId() . "')");
$data = array(
'name' => $element->getData('name') . '_create_redirect',
'disabled' => true,
);
$hidden = new Varien_Data_Form_Element_Hidden($data);
$hidden->setForm($element->getForm());
$storeId = $element->getForm()->getDataObject()->getStoreId();
$data['html_id'] = $element->getHtmlId() . '_create_redirect';
$data['label'] = Mage::helper('catalog')->__('Create Permanent Redirect for old URL');
$data['value'] = $element->getValue();
$data['checked'] = Mage::helper('catalog')->shouldSaveUrlRewritesHistory($storeId);
$checkbox = new Varien_Data_Form_Element_Checkbox($data);
$checkbox->setForm($element->getForm());
return parent::getElementHtml() . '<br/>' . $hidden->getElementHtml() . $checkbox->getElementHtml() . $checkbox->getLabelHtml();
}
protected function _prepareLayout()
{
$button = $this->getLayout()->createBlock('adminhtml/widget_button')
->setData(array(
'label' => Mage::helper('catalog')->__('Add Option'),
'onclick' => 'return serializeArrayControl.addItem()',
'class' => 'add'
));
$button->setName('add_serialize_array_item_button');
$this->setChild('add_button', $button);
return parent::_prepareLayout();
}
public function getAddButtonHtml()
{
return $this->getChildHtml('add_button');
}
}
We'll also need the actual HTML. Create the template file
app/design/adminhtml/base/default/template/your/module/serialize_array.phtml
with this HTML;
<?php
/** @var $this Your_Module_Block_Catalog_Form_Renderer_Attribute_SerializeArray */
$_htmlId = $this->getElement()->getHtmlId();
$_htmlClass = $this->getElement()->getClass();
$_htmlName = $this->getElement()->getName();
$_readonly = $this->getElement()->getReadonly();
$_showFirstColumn = true;
?>
<tr>
<td class="label"><?php echo $this->getElement()->getLabel(); ?></td>
<td colspan="10" class="grid tier">
<table cellspacing="0" class="data border" id="serialize_array_table">
<?php if ($_showFirstColumn) : ?>
<col width="135" />
<?php endif; ?>
<col width="120" />
<col />
<col width="1" />
<thead>
<tr class="headings">
<th <?php if (!$_showFirstColumn): ?>style="display: none;"<?php endif; ?>><?php echo Mage::helper('catalog')->__('First Option'); ?></th>
<th><?php echo Mage::helper('catalog')->__('Second Option'); ?></th>
<th><?php echo Mage::helper('catalog')->__('Free field'); ?></th>
<th class="last"><?php echo Mage::helper('catalog')->__('Action'); ?></th>
</tr>
</thead>
<tbody id="<?php echo $_htmlId; ?>_container"></tbody>
<tfoot>
<tr>
<td <?php if (!$_showFirstColumn): ?>style="display: none;"<?php endif; ?>></td>
<td colspan="4" class="a-right"><?php echo $this->getAddButtonHtml(); ?></td>
</tr>
</tfoot>
</table>
<script type="text/javascript">
//<![CDATA[
var serializeArrayRowTemplate = '<tr>'
+ '<td<?php if (!$_showFirstColumn): ?> style="display:none"<?php endif; ?>>'
+ '<select class="<?php echo $_htmlClass; ?> required-entry" name="<?php echo $_htmlName; ?>[{{index}}][first_option]" id="serialize_array_row_{{index}}_first_option">'
<?php foreach ($this->getOptions() as $_websiteId => $_info) : ?>
+ '<option value="<?php echo $_websiteId; ?>"><?php echo $this->jsQuoteEscape($this->escapeHtml($_info['name'])); ?><?php if (!empty($_info['currency'])) : ?> [<?php echo $this->escapeHtml($_info['currency']); ?>]<?php endif; ?></option>'
<?php endforeach; ?>
+ '</select></td>'
+ '<td><select class="<?php echo $_htmlClass; ?> custgroup required-entry" name="<?php echo $_htmlName; ?>[{{index}}][second_option]" id="serialize_array_row_{{index}}_second_option">'
<?php foreach ($this->getOtherOptions() as $_groupId => $_groupName): ?>
+ '<option value="<?php echo $_groupId; ?>"><?php echo $this->jsQuoteEscape($this->escapeHtml($_groupName)); ?></option>'
<?php endforeach; ?>
+ '</select></td>'
+ '<td><input class="<?php echo $_htmlClass; ?> required-entry" type="text" name="<?php echo $_htmlName; ?>[{{index}}][freefield]" value="{{freefield}}" id="serialize_array_row_{{index}}_freefield" /></td>'
+ '<td class="last"><input type="hidden" name="<?php echo $_htmlName; ?>[{{index}}][delete]" class="delete" value="" id="serialize_array_row_{{index}}_delete" />'
+ '<button title="<?php echo $this->jsQuoteEscape(Mage::helper('catalog')->__('Delete')); ?>" type="button" class="scalable delete icon-btn delete-product-option" id="serialize_array_row_{{index}}_delete_button" onclick="return serializeArrayControl.deleteItem(event);">'
+ '<span><?php echo $this->jsQuoteEscape(Mage::helper('catalog')->__('Delete')); ?></span></button></td>'
+ '</tr>';
var serializeArrayControl = {
template: new Template(serializeArrayRowTemplate, new RegExp('(^|.|\\r|\\n)({{\\s*(\\w+)\\s*}})', '')),
itemsCount: 0,
addItem : function () {
<?php if ($_readonly): ?>
if (arguments.length < 3) {
return;
}
<?php endif; ?>
var data = {
first_option: '', // default value
second_option: '', // default value
freefield: '', // default value
readOnly: false,
index: this.itemsCount++
};
if(arguments.length >= 3) {
data.first_option = arguments[0];
data.second_option = arguments[1];
data.freefield = arguments[2];
}
if (arguments.length == 4) {
data.readOnly = arguments[3];
}
Element.insert($('<?php echo $_htmlId; ?>_container'), {
bottom : this.template.evaluate(data)
});
$('serialize_array_row_' + data.index + '_first_option').setValue(data.first_option);
$('serialize_array_row_' + data.index + '_second_option').setValue(data.second_option);
$('serialize_array_row_' + data.index + '_freefield').setValue(data.freefield);
if (data.readOnly == '1') {
['first_option', 'second_option', 'freefield', 'delete'].each(function(element_suffix) {
$('serialize_array_row_' + data.index + '_' + element_suffix).disabled = true;
});
$('serialize_array_row_' + data.index + '_delete_button').hide();
}
<?php if ($_readonly): ?>
$('<?php echo $_htmlId; ?>_container').select('input', 'select').each(this.disableElement);
$('<?php echo $_htmlId; ?>_container').up('table').select('button').each(this.disableElement);
<?php else: ?>
$('<?php echo $_htmlId; ?>_container').select('input', 'select').each(function(element) {
Event.observe(element, 'change', element.setHasChanges.bind(element));
});
<?php endif; ?>
},
disableElement: function(element) {
element.disabled = true;
element.addClassName('disabled');
},
deleteItem: function(event) {
var tr = Event.findElement(event, 'tr');
if (tr) {
Element.select(tr, '.delete').each(function(element) {
element.value='1';
});
Element.select(tr, ['input', 'select']).each(function(element) {
element.hide();
});
Element.hide(tr);
Element.addClassName(tr, 'no-display template');
}
return false;
}
};
<?php foreach ($this->getValues() as $_item) : ?>
serializeArrayControl.addItem('<?php echo $_item['first_option']; ?>', '<?php echo $_item['second_option']; ?>', '<?php echo $_item['freefield']; ?>');
<?php endforeach; ?>
<?php if ($_readonly) : ?>
$('<?php echo $_htmlId; ?>_container').up('table').select('button')
.each(serializeArrayControl.disableElement);
<?php endif; ?>
//]]>
</script>
</td></tr>
There might be some useless/nonsensical cruft in this HTML since I copied it from
app/design/adminhtml/default/default/template/catalog/product/edit/price/group.phtml
and adjusted it a bit.
Clear your cache, reindex (if you're using catalog flat tables) and you should be good to go!