0

I have the following class:

\Magento\Bundle\Block\Catalog\Product\View\Type\Bundle\Option\Select

I would like to add another method to it. Then I would like this template file to call that method (ie. I want to create a template file and block in my module and use this template to display):

app/code/Magento/Bundle/view/frontend/templates/catalog/product/view/type/bundle/option/select.phtml

I have created and registered the module but I am unsure where to begin.

I think the only way to modify core classes is by creating a plugin.

But wait we want to add an additional function to a block, so just changing the result of a function or overriding it entirely is not going to work for us. So modification is not good enough we need to extend that class.

1

Looks like this block not very extensible in magento2. Can we add more extensibility using plugins?

\Magento\Bundle\Block\Catalog\Product\View\Type\Bundle\Option\Select

this block is renderer for bundle product option types (as well as radio, checkboxes and etc)

<block class="Magento\Bundle\Block\Catalog\Product\View\Type\Bundle" name="product.info.bundle.options" as="type_bundle_options" template="catalog/product/view/type/bundle/options.phtml" before="-">
    <block class="Magento\Bundle\Block\Catalog\Product\View\Type\Bundle\Option\Select" name="product.info.bundle.options.select" as="select"/>
    <block class="Magento\Bundle\Block\Catalog\Product\View\Type\Bundle\Option\Multi" name="product.info.bundle.options.multi" as="multi"/>
    <block class="Magento\Bundle\Block\Catalog\Product\View\Type\Bundle\Option\Radio" name="product.info.bundle.options.radio" as="radio"/>
    <block class="Magento\Bundle\Block\Catalog\Product\View\Type\Bundle\Option\Checkbox" name="product.info.bundle.options.checkbox" as="checkbox"/>
</block>

There is render method for options in parent block

/**
 * Get html for option
 *
 * @param Option $option
 * @return string
 */
public function getOptionHtml(Option $option)
{
    $optionBlock = $this->getChildBlock($option->getType());
    if (!$optionBlock) {
        return __('There is no defined renderer for "%1" option type.', $option->getType());
    }
    return $optionBlock->setOption($option)->toHtml();
}

This method find option renderer by type from child blocks, using child aliases as type identifier and render option html using block as renderer.

There are same ways to add your custom renderer:

  1. Preference for base option renderer (bad way)
  2. Block childs modification (using xml layout or code)
  3. Option renderer builder(getOptionHtml) pluginization (i think, that best way)

Lets try implement pluginization of renderer builder.

  1. Create around plugin on \Magento\Bundle\Block\Catalog\Product\View\Type\Bundle::getOptionHtml()
  2. Add renderer mapping functionality

Plugin code:

/**
 * Around get option html.
 *
 * @param Bundle $subject
 * @param \Closure $proceed
 * @param Option $option
 * @return \Magento\Framework\Phrase
 */
public function aroundGetOptionHtml(
    \Magento\Bundle\Block\Catalog\Product\View\Type\Bundle $subject,
    \Closure $proceed,
    \Magento\Bundle\Model\Option $option
) {
    $renderersMap = (array)$subject->getData('renderers');
    if (isset($renderersMap[$option->getType()])) {
        $rendererBlockName = $renderersMap[$option->getType()];
        $renderer = $this->getChildBlock($rendererBlockName);
        if ($renderer) {
            return $renderer->setOption($option)->toHtml();
        }
    }

    return $proceed($option);
}
  1. Add your custom renderer to type mapping using layout

catalog_product_view_type_bundle.xml

<referenceBlock name="product.info.bundle.options">
    <arguments>
        <argument name="renderers" xsi:type="array">
            <item name="select" xsi:type="string">my-custom-select-alias</item>
        </argument>
    </arguments>
    <block class="Magento\CustomBundle\Block\Catalog\Product\View\Type\Bundle\Option\Select" name="my-custom-block-name" as="my-custom-select-alias"/>
</referenceBlock>
| improve this answer | |
  • How did you find this layout xml? <block class="Magento\Bundle\Block\Catalog\Product\View\Type\Bundle"? Did you use template path hints? – stephen Jan 6 '17 at 12:52
  • 1
    I found layout file by block type Magento\Bundle\Block\Catalog\Product\View\Type\Bundle\Option\Select, after this i found parent xml tag with type Magento\Bundle\Block\Catalog\Product\View\Type\Bundle‌ – Max Jan 6 '17 at 13:35
  • I'm not too sure what this code is actually doing? I am also not sure why the bundle options layout xml needs to be changed. – stephen Jan 9 '17 at 9:25
  • i am getting blank array in $renderersMap why ? – Mukesh Prajapati Oct 6 '18 at 7:57
  • @Max i am getting blank array in $renderersMap why? – Mukesh Prajapati Oct 10 '18 at 10:34

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.