First of all...nice question. Got me really interested.
Here is an example on how you can create an attribute that has a custom renderer (template) and the value is saved serialized.
For this example I created an attribute that will have 2 text inputs, but you can basically put anything in there.
I recommend creating a custom module to handle your attribute.
Let's call this extension Easylife_Attr
.
You will need the following files.
app/etc/module/Easylife_Attr.xml
- the declaration file.
<?xml version="1.0"?>
<config>
<modules>
<Easylife_Attr>
<codePool>local</codePool>
<active>true</active>
<depends>
<Mage_Catalog /><!-- should depend on mage_catalog-->
<Mage_Adminhtml /><!-- should depend on mage_adminhtml-->
</depends>
</Easylife_Attr>
</modules>
</config>
app/code/local/Easylife/Attr/etc/config.xml
- the configuration file
<?xml version="1.0"?>
<config>
<modules>
<Easylife_Attr>
<version>0.0.1</version>
</Easylife_Attr>
</modules>
<global>
<resources>
<easylife_attr_setup>
<setup>
<module>Easylife_Attr</module>
<class>Mage_Catalog_Model_Resource_Setup</class><!-- use the catalog setup so you can add your attribute -->
</setup>
</easylife_attr_setup>
</resources>
<models>
<easylife_attr>
<class>Easylife_Attr_Model</class>
</easylife_attr>
</models>
<blocks>
<easylife_attr>
<class>Easylife_Attr_Block</class>
</easylife_attr>
</blocks>
</global>
<adminhtml>
<events>
<adminhtml_catalog_product_edit_prepare_form><!-- event needed to add a template to a certain attribute -->
<observers>
<easylife>
<class>Easylife_Attr_Model_Observer</class>
<method>convertCustomValues</method>
</easylife>
</observers>
</adminhtml_catalog_product_edit_prepare_form>
</events>
</adminhtml>
</config>
app/code/local/Easylife/Attr/sql/easylife_attr_setup/install-0.0.1.php
- the install script. It will add your attribute
<?php
$this->addAttribute('catalog_product', 'custom_values', array(
'group' => 'Custom values', //the tab name where the attribute will be placed
'input' => 'textarea', //this is not really important
'type' => 'text', //attribute type should be text to support long values
'label' => 'Custom values', //the attribute label
'backend' => 'easylife_attr/custom', //a custom backend model that will handle serialization and deserialization
'visible' => true,
'required' => false,
'visible_on_front' => true,
'global' => Mage_Catalog_Model_Resource_Eav_Attribute::SCOPE_GLOBAL, //scope can be anything but if it's not global you will need some changes to support store view values
));
Now the fun part.
app/code/local/Easylife/Attr/Model/Observer.php
- the observe that will change the attribute template
<?php
class Easylife_Attr_Model_Observer {
public function convertCustomValues($observer) {
$form = $observer->getEvent()->getForm();
$customValues = $form->getElement('custom_values');
if ($customValues) {
$customValues->setRenderer(
Mage::app()->getLayout()->createBlock('easylife_attr/adminhtml_product_custom')
); //set a custom renderer to your attribute
}
}
}
app/code/local/Easylife/Attr/Block/Adminhtml/Product/Custom.php
- the custom renderer block
<?php
class Easylife_Attr_Block_Adminhtml_Product_Custom
extends Mage_Adminhtml_Block_Widget
implements Varien_Data_Form_Element_Renderer_Interface {
public function __construct()
{
$this->setTemplate('easylife_attr/product/custom.phtml'); //set a template
}
public function render(Varien_Data_Form_Element_Abstract $element) {
$this->setElement($element);
return $this->toHtml();
}
}
app/design/adminhtml/default/default/template/easylife_attr/product/custom.phtml
- the template for the attribute.
<?php
$_htmlId = $this->getElement()->getHtmlId();
$_htmlClass = $this->getElement()->getClass();
$_htmlName = $this->getElement()->getName();
$_readonly = $this->getElement()->getReadonly();
$value = $this->getElement()->getValue();
//get the values for the 2 text elements
$someField = (isset($value['some_field']) ? $value['some_field'] : '');
$otherField = (isset($value['other_field']) ? $value['other_field'] : '');
?>
<tr> <!-- should be wrapped in a tr element to fit in the admin template -->
<td class="label"><?php echo $this->getElement()->getLabel(); ?></td>
<td colspan="10" class="grid">
<table cellspacing="0" class="data border">
<col width="120" />
<col />
<thead>
<tr class="headings">
<th><?php echo $this->__('Some field')?></th>
<th><?php echo $this->__('Other Field')?></th>
</tr>
</thead>
<tbody id="<?php echo $_htmlId; ?>_container"></tbody>
<tfoot>
<tr>
<td><input type="text" name="<?php echo $_htmlName; ?>[some_field]" value="<?php echo $someField?>"<?php echo ($_readonly) ? ' readonly="readonly"' : ''?>> </td>
<td><input type="text" name="<?php echo $_htmlName; ?>[other_field]" value="<?php echo $otherField?>"<?php echo ($_readonly) ? ' readonly="readonly"' : ''?>></td>
</tr>
</tfoot>
</table>
</td>
</tr>
app/code/local/Easylife/Attr/Model/Custom.php
- the model that handles the serialization and deserialization.
<?php
class Easylife_Attr_Model_Custom extends Mage_Eav_Model_Entity_Attribute_Backend_Abstract{
public function beforeSave($object)
{
//before sabing the product check if the attribute `custom_values` is array.
//if it is, serialize it for saving in the db
$attributeCode = $this->getAttribute()->getAttributeCode();
$data = $object->getData($attributeCode);
if (is_array($data)) {
$data = array_filter($data);
$object->setData($attributeCode, serialize($data));
}
return parent::beforeSave($object);
}
public function afterLoad($object) {
//after loading the product, check if the value for custom_values is not an array. If it's not try to unserialize the value.
$attributeCode = $this->getAttribute()->getAttributeCode();
$data = $object->getData($attributeCode);
if (!is_array($data)) {
$object->setData($attributeCode, @unserialize($data));
}
return parent::afterLoad($object);
}
}
That's it. Here is how the attribute would look in the backend:
Your module dont seem to follow the default magento standard at Magento - Wiki - Custom Module with Custom Database Table.
Then issue seem to have something to do with your form post action or missing form tag
You seem to be missing this file. View browser source and look to see if you form is present with an id="edit_form"
/app/code/local/<Namespace>/<Module>/Block/Adminhtml/<Module>/Edit/Form.php
<?php
class <Namespace>_<Module>_Block_Adminhtml_<Module>_Edit_Form extends Mage_Adminhtml_Block_Widget_Form
{
protected function _prepareForm()
{
$form = new Varien_Data_Form(array(
'id' => 'edit_form',
'action' => $this->getUrl('*/*/save', array('id' => $this->getRequest()->getParam('id'))),
'method' => 'post')
);
$form->setUseContainer(true);
$this->setForm($form);
return parent::_prepareForm();
}
}
Best Answer
Set the current store by name: