Change Product Custom Option Renderer – Magento Custom Options

custom-options

I have custom options that are added to certain products dynamically using the catalog_controller_product_view event and my own observer.

Related: How to add dynamic Select Custom Options in Observer

I'd like to now use an option renderer other than the default. Ideally, I'd like to set my own type field to the option when created so that it uses my own value, ie:

$optionModel = Mage::getModel('catalog/product_option')
    ...
    ->setType('my_option_type')
    ...

This, of course, requires my custom option type to have an associated Block, Model, etc. This also seems to require rewriting the Mage_Catalog_Model_Product_Option class to include my custom option type.

Unfortunately, the Magento team didn't think these option renderers would have been useful as templates, as the markup is essentially all created in the getValuesHtml() method inside the option's associated block class (ie. Mage_Catalog_Block_Product_View_Options_Type_Select)

How can I set my own renderer (preferably as a template, none of this sloppy getValuesHtml() stuff) to a custom option that is created dynamically on product view?

Really, all I need to do is add some additional data attributes to each option value's input element.

Best Answer

Even tho custom option renderers can be added via layout update by calling addOptionRenderer on product.info.options block, using custom types will never work without rewriting getGroupByType method inside Mage_Catalog_Model_Product_Option class.

You can trick Magento to show your custom type on product view page by doing something like this in local.xml

<catalog_product_view>
        <reference name="product.info.options.wrapper">
            <block type="foo_bar/options" name="product.info.options" as="product_options" template="catalog/product/view/options.phtml">
                <action method="addOptionRenderer"><type>text</type><block>catalog/product_view_options_type_text</block><template>catalog/product/view/options/type/text.phtml</template></action>
                <action method="addOptionRenderer"><type>file</type><block>catalog/product_view_options_type_file</block><template>catalog/product/view/options/type/file.phtml</template></action>
                <action method="addOptionRenderer"><type>select</type><block>catalog/product_view_options_type_select</block><template>catalog/product/view/options/type/select.phtml</template></action>
                <action method="addOptionRenderer"><type>date</type><block>catalog/product_view_options_type_date</block><template>catalog/product/view/options/type/date.phtml</template></action>
                <action method="addOptionRenderer"><type>test</type><block>foo_bar/options_test</block><template>foo_bar/options/test.phtml</template></action>
            </block>
        </reference>
    </catalog_product_view>

Block class:

class Foo_Bar_Block_Options extends Mage_Catalog_Block_Product_View_Options
{
    public function getOptionHtml(Mage_Catalog_Model_Product_Option $option)
    {
        if ($option->getType() == 'test') {
            $renderer = $this->getOptionRender(
                $option->getType()
            );
        } else {
            $renderer = $this->getOptionRender(
                $this->getGroupOfOption($option->getType())
            );
        }

        if (is_null($renderer['renderer'])) {
            $renderer['renderer'] = $this->getLayout()->createBlock($renderer['block'])
                ->setTemplate($renderer['template']);
        }

        return $renderer['renderer']
            ->setProduct($this->getProduct())
            ->setOption($option)
            ->toHtml();
    }
}

And this will work until you try to add to cart because that is when getGroupByType is called again and we get a nice error message. :)