1

SOLVED :: 15.9.17 (the following code works on a fresh Magento 2.1.7 installation; tested on Luma theme)

I am struggling with the override of this particular core block

Magento\Catalog\Block\Product\View\Options\Type\Select

Here is my module structure:

├── <VendorName>
|   ├── <ModuleName>
|   |   ├── Block/
|   |   |   ├── Product/
|   |   |   |   ├── View/
|   |   |   |   |   ├── Options/
|   |   |   |   |   |   ├── Type/
|   |   |   |   |   |   |   └── Select.php
|   |   ├── etc/ 
|   |   |   └── di.xml
|   |   |   └── module.xml
|   |   ├── view/
|   |   |   ├── frontend/
|   |   |   |   ├── templates/
|   |   |   |   |   ├── product/
|   |   |   |   |   |   ├── view/
|   |   |   |   |   |   |   ├── options/
|   |   |   |   |   |   |   |   ├── type/
|   |   |   |   |   |   |   |   |   └── select.phtml
|   |   └── registration.php

The registration.php

    <?php

\Magento\Framework\Component\ComponentRegistrar::register(
    \Magento\Framework\Component\ComponentRegistrar::MODULE,
    'VendorName_ModuleName',
    __DIR__
);

The module.xml

    <?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Module/etc/module.xsd">
        <module name="VendorName_ModuleName" setup_version="1.0.0">
            <sequence>
                <module name="Magento_Catalog"/>
            </sequence>
        </module>
</config>

The di.xml

    <?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
    <preference for="Magento\Catalog\Block\Product\View\Options\Type\Select" type="VendorName\ModuleName\Block\Product\View\Options\Type\Select" />
</config>

The select.phtml (copied as it is from vendor/magento folder)

<?php
/**
 * Copyright © 2013-2017 Magento, Inc. All rights reserved.
 * See COPYING.txt for license details.
 */

// @codingStandardsIgnoreFile

?>

<?php /* @var $block \Magento\Catalog\Block\Product\View\Options\Type\Select */ ?>
<?php
$_option = $block->getOption();
$class = ($_option->getIsRequire()) ? ' required' : '';
?>
<div class="field<?php /* @escapeNotVerified */ echo $class; ?>">
    <label class="label" for="select_<?php /* @escapeNotVerified */ echo $_option->getId() ?>">
        <span><?php echo  $block->escapeHtml($_option->getTitle()) ?></span>
    </label>
    <div class="control">
        <?php echo $block->getValuesHtml() ?>
        <?php if ($_option->getIsRequire()): ?>
            <?php if ($_option->getType() == \Magento\Catalog\Model\Product\Option::OPTION_TYPE_RADIO || $_option->getType() == \Magento\Catalog\Model\Product\Option::OPTION_TYPE_CHECKBOX): ?>
                <span id="options-<?php /* @escapeNotVerified */ echo $_option->getId() ?>-container"></span>
            <?php endif; ?>
        <?php endif;?>
    </div>
</div>

The Select.php (I removed the custom logic here, as I think not relevant in this context)

<?php
namespace VendorName\ModuleName\Block\Product\View\Options\Type;

class Select extends \Magento\Catalog\Block\Product\View\Options\AbstractOptions 

{

   public function getValuesHtml()
    {
    // My Custom Code
    }
}

According to https://magento.stackexchange.com/a/112847/51071 I was expecting to succesfully override the block after having activated the module and run setup:di:compile, but nothing happened.

Does anyone has a clue what am I missing here in order to make the module working properly? Any help is much appreciated.

0

3 Answers 3

1


Above answers helped me but it did not work for me as it is.
This is what I did to override block \Magento\Catalog\Block\Product\View\Options\Type\Select.php

File - [Vendor][Module]\etc\di.xml

<type name="Magento\Catalog\Block\Product\View\Options\Type\Select">
    <plugin name="[Vendor]_[Module]_select" sortOrder="10"
            type="[Vendor]\[Module]\Block\Product\View\Options\Type\Select"/>
</type>

File - [Vendor][Module]\Block\Product\View\Options\Type\Select.php

<?php

namespace [Vendor]\[Module]\Block\Product\View\Options\Type;

class Select extends \Magento\Catalog\Block\Product\View\Options\AbstractOptions
{

 public function afterGetValuesHtml(\Magento\Catalog\Block\Product\View\Options\Type\Select $subject, $result)
 {
    $_option = $subject->getOption();
    $configValue = $subject->getProduct()->getPreconfiguredValues()->getData('options/' . $_option->getId());
    $store = $subject->getProduct()->getStore();

    $subject->setSkipJsReloadPrice(1);
    // Remove inline prototype onclick and onchange events

    if ($_option->getType() == \Magento\Catalog\Model\Product\Option::OPTION_TYPE_DROP_DOWN ||
        $_option->getType() == \Magento\Catalog\Model\Product\Option::OPTION_TYPE_MULTIPLE
    ) {
        $require = $_option->getIsRequire() ? ' required' : '';

        $extraParams = '';
        $select = $subject->getLayout()->createBlock(
            'Magento\Framework\View\Element\Html\Select'
        )->setData(
            [
                'id' => 'select_' . $_option->getId(),
                'class' => $require . ' product-custom-option admin__control-select'
            ]
        );
        if ($_option->getType() == \Magento\Catalog\Model\Product\Option::OPTION_TYPE_DROP_DOWN) {
            // Code changes start
            if($_option->getIsSize()){
                $select->setName('options[' . $_option->getid() . ']')->addOption('', __('Select a Size'));
            }
            else if($_option->getIsCut()){
                $select->setName('options[' . $_option->getid() . ']')->addOption('', __('Select a Cut'));
            }
            else{
                $select->setName('options[' . $_option->getid() . ']')->addOption('', __('Select an Option'));
            }
            // Code changes end
        } else {
            $select->setName('options[' . $_option->getid() . '][]');
            $select->setClass('multiselect admin__control-multiselect' . $require . ' product-custom-option');
        }
        foreach ($_option->getValues() as $_value) {
            $priceStr = $subject->_formatPrice(
                [
                    'is_percent' => $_value->getPriceType() == 'percent',
                    'pricing_value' => $_value->getPrice($_value->getPriceType() == 'percent'),
                ],
                false
            );
            $select->addOption(
                $_value->getOptionTypeId(),
                $_value->getTitle() . ' ' . strip_tags($priceStr) . '',
                ['price' => $subject->pricingHelper->currencyByStore($_value->getPrice(true), $store, false)]
            );
        }
        if ($_option->getType() == \Magento\Catalog\Model\Product\Option::OPTION_TYPE_MULTIPLE) {
            $extraParams = ' multiple="multiple"';
        }
        if (!$subject->getSkipJsReloadPrice()) {
            $extraParams .= ' onchange="opConfig.reloadPrice()"';
        }
        $extraParams .= ' data-selector="' . $select->getName() . '"';
        $select->setExtraParams($extraParams);

        if ($configValue) {
            $select->setValue($configValue);
        }

        return $select->getHtml();
    }

    if ($_option->getType() == \Magento\Catalog\Model\Product\Option::OPTION_TYPE_RADIO ||
        $_option->getType() == \Magento\Catalog\Model\Product\Option::OPTION_TYPE_CHECKBOX
    ) {
        $selectHtml = '<div class="options-list nested" id="options-' . $_option->getId() . '-list">';
        $require = $_option->getIsRequire() ? ' required' : '';
        $arraySign = '';
        switch ($_option->getType()) {
            case \Magento\Catalog\Model\Product\Option::OPTION_TYPE_RADIO:
                $type = 'radio';
                $class = 'radio admin__control-radio';
                if (!$_option->getIsRequire()) {
                    $selectHtml .= '<div class="field choice admin__field admin__field-option">' .
                        '<input type="radio" id="options_' .
                        $_option->getId() .
                        '" class="' .
                        $class .
                        ' product-custom-option" name="options[' .
                        $_option->getId() .
                        ']"' .
                        ' data-selector="options[' . $_option->getId() . ']"' .
                        ($subject->getSkipJsReloadPrice() ? '' : ' onclick="opConfig.reloadPrice()"') .
                        ' value="" checked="checked" /><label class="label admin__field-label" for="options_' .
                        $_option->getId() .
                        '"><span>' .
                        __('None') . '</span></label></div>';
                }
                break;
            case \Magento\Catalog\Model\Product\Option::OPTION_TYPE_CHECKBOX:
                $type = 'checkbox';
                $class = 'checkbox admin__control-checkbox';
                $arraySign = '[]';
                break;
        }
        $count = 1;
        foreach ($_option->getValues() as $_value) {
            $count++;

            $priceStr = $subject->_formatPrice(
                [
                    'is_percent' => $_value->getPriceType() == 'percent',
                    'pricing_value' => $_value->getPrice($_value->getPriceType() == 'percent'),
                ]
            );

            $htmlValue = $_value->getOptionTypeId();
            if ($arraySign) {
                $checked = is_array($configValue) && in_array($htmlValue, $configValue) ? 'checked' : '';
            } else {
                $checked = $configValue == $htmlValue ? 'checked' : '';
            }

            $dataSelector = 'options[' . $_option->getId() . ']';
            if ($arraySign) {
                $dataSelector .= '[' . $htmlValue . ']';
            }

            $selectHtml .= '<div class="field choice admin__field admin__field-option' .
                $require .
                '">' .
                '<input type="' .
                $type .
                '" class="' .
                $class .
                ' ' .
                $require .
                ' product-custom-option"' .
                ($subject->getSkipJsReloadPrice() ? '' : ' onclick="opConfig.reloadPrice()"') .
                ' name="options[' .
                $_option->getId() .
                ']' .
                $arraySign .
                '" id="options_' .
                $_option->getId() .
                '_' .
                $count .
                '" value="' .
                $htmlValue .
                '" ' .
                $checked .
                ' data-selector="' . $dataSelector . '"' .
                ' price="' .
                $subject->pricingHelper->currencyByStore($_value->getPrice(true), $store, false) .
                '" />' .
                '<label class="label admin__field-label" for="options_' .
                $_option->getId() .
                '_' .
                $count .
                '"><span>' .
                $_value->getTitle() .
                '</span> ' .
                $priceStr .
                '</label>';
            $selectHtml .= '</div>';
        }
        $selectHtml .= '</div>';

        return $selectHtml;
    }
 }
}

Important things to note here -
After copying \Magento\Catalog\Block\Product\View\Options\Type\Select.php to [Vendor][Module]\Block\Product\View\Options\Type\Select.php, you must do following.

  1. Change the namespace to [Vendor]\[Module]\Block\Product\View\Options\Type;
  2. Replace public function getValuesHtml() to public function afterGetValuesHtml(\Magento\Catalog\Block\Product\View\Options\Type\Select $subject, $result)
  3. Replace $this to $subject

Hope this helps.

0

This should work if your script is being run in Magento i have done something similar with this block so can confirm it works

<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
    <preference for="Magento\Catalog\Block\Product\View\Options\Type\Select" type="VendorName\ModuleName\Block\Product\View\Options\Type\Select" />
</config>
0

2 problems on your code:

  1. You placed registration.php in the wrong place. You should place it under <VendorName>/<ModuleName>
  2. In di.xml, you wrote the code which should be placed in module.xml. Instead, you should replace di.xml into the following code:

    <?xml version="1.0"?>
    <config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
        <preference for="Magento\Catalog\Block\Product\View\Options\Type\Select" type="VendorName\ModuleName\Block\Product\View\Options\Type\Select" />
    </config>
    

After that, your code should work.

===Update 13 Sep 2017===

Add one point:

  1. There are no parent::__construct on this class. You can simply delete whole __construct function.
8
  • Thanks for checking. 'registration.php' was actually in the right place already. I have misspelled the schema in the question though (will be editing it) I have corrected as you suggested the code into 'di.xml' and 'module.xml', but unfortunately still the block has not overriden.
    – amdev
    Sep 12, 2017 at 17:42
  • See my edited di.xml
    – PY Yick
    Sep 13, 2017 at 2:17
  • Vendor_Module path is correct in my di.xml
    – amdev
    Sep 13, 2017 at 8:16
  • See my update answer
    – PY Yick
    Sep 13, 2017 at 8:38
  • Thank you, you are right, I confirm that the constructor is not essential here. Unfortunately thought, I can't get the module to work. I have updated the question with the correct code, but still no result. The module runs on a fresh Magenbto 2.1.7 installation. I don't understand why this block is not overriden.
    – amdev
    Sep 14, 2017 at 20:35

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

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