6

I'm trying to override the module-catalog/Block/Product/View/Options/Type/Select.php class with a new version which includes a few other bits of custom php (adding HTML classes and IDs to the containing DIVs). I am trying to achieve this by creating anew module. Unfortunately, when this new module is enabled, the select options aren't rendered to the product page. The rest of the page is fine, just without the select (checkboxes and radio buttons) options. I think everything looks fine and should work, so I can't understand why the Select.php isn't returning the select options.

Directory structure:

app/
├── Mike/
│   ├── Newselect/
│   │   ├── Block/
│   │   │   ├── Product/
│   │   │   │   ├── View/
│   │   │   │   │   ├── Options/
│   │   │   │   │   │   ├── Type/
│   │   │   │   │   │   │   ├── Select.php
│   │   ├── etc/
│   │   │   ├── di.xml
│   │   │   ├── module.xml
│   │   ├── registration.php
│   │   ├── composer.json

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="Mike\Newselect\Block\Product\View\Options\Type\Select" />
</config>

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="Mike_Newselect" setup_version="1.0.0"/>
</config>

registration.php

<?php
\Magento\Framework\Component\ComponentRegistrar::register(
    \Magento\Framework\Component\ComponentRegistrar::MODULE,
    'Mike_Newselect',
    __DIR__    
);

composer.json

{
    "name": "Mike/Newselect",
    "description": "Update the Select module to add HTML classes and IDs",
    "require": {
        "php": "~5.5.0|~5.6.0|~7.0.0",
        "magento/module-store": "100.0.*",
        "magento/module-eav": "100.0.*",
        "magento/module-cms": "100.0.*",
        "magento/module-indexer": "100.0.*",
        "magento/module-customer": "100.0.*",
        "magento/module-theme": "100.0.*",
        "magento/module-checkout": "100.0.*",
        "magento/module-backend": "100.0.*",
        "magento/module-widget": "100.0.*",
        "magento/module-wishlist": "100.0.*",
        "magento/module-tax": "100.0.*",
        "magento/module-msrp": "100.0.*",
        "magento/module-catalog-inventory": "100.0.*",
        "magento/module-directory": "100.0.*",
        "magento/module-catalog-rule": "100.0.*",
        "magento/module-product-alert": "100.0.*",
        "magento/module-url-rewrite": "100.0.*",
        "magento/module-catalog-url-rewrite": "100.0.*",
        "magento/module-page-cache": "100.0.*",
        "magento/module-quote": "100.0.*",
        "magento/module-config": "100.0.*",
        "magento/module-media-storage": "100.0.*",
        "magento/framework": "100.0.*",
        "magento/module-configurable-product": "100.0.*",
        "magento/module-ui": "100.0.*"
    },
    "suggest": {
        "magento/module-cookie": "100.0.*",
        "magento/module-catalog-sample-data": "Sample Data version:100.0.*"
    },
    "type": "magento2-module",
    "version": "100.0.5",
    "license": [
        "OSL-3.0",
        "AFL-3.0"
    ],
    "autoload": {
        "files": [
            "registration.php"
        ],
        "psr-4": {
            "Magento\\Catalog\\": ""
        }
    }
}

Select.php (this just a copy of the core Select.php file – not updated yet – apart from the Namespace and extending the core class)

<?php
/**
 * Copyright © 2016 Magento. All rights reserved.
 * See COPYING.txt for license details.
 */

/**
 * Product options text type block
 *
 * @author     Magento Core Team <core@magentocommerce.com>
 */

namespace Mike\Newselect\Block\Product\View\Options\Type;

class Select extends \Magento\Catalog\Block\Product\View\Options\Type\Select
{
    /**
     * Return html for control element
     *
     * @return string
     * @SuppressWarnings(PHPMD.CyclomaticComplexity)
     * @SuppressWarnings(PHPMD.NPathComplexity)
     * @SuppressWarnings(PHPMD.ExcessiveMethodLength)
     */
    public function getValuesHtml()
    {
        $_option = $this->getOption();
        $configValue = $this->getProduct()->getPreconfiguredValues()->getData('options/' . $_option->getId());
        $store = $this->getProduct()->getStore();

        $this->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 = $this->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) {
                $select->setName('options[' . $_option->getid() . ']')->addOption('', __('-- Please Select --'));
            } else {
                $select->setName('options[' . $_option->getid() . '][]');
                $select->setClass('multiselect admin__control-multiselect' . $require . ' product-custom-option');
            }
            foreach ($_option->getValues() as $_value) {
                $priceStr = $this->_formatPrice(
                    [
                        'is_percent' => $_value->getPriceType() == 'percent',
                        'pricing_value' => $_value->getPrice($_value->getPriceType() == 'percent'),
                    ],
                    false
                );
                $select->addOption(
                    $_value->getOptionTypeId(),
                    $_value->getTitle() . ' ' . strip_tags($priceStr) . '',
                    ['price' => $this->pricingHelper->currencyByStore($_value->getPrice(true), $store, false)]
                );
            }
            if ($_option->getType() == \Magento\Catalog\Model\Product\Option::OPTION_TYPE_MULTIPLE) {
                $extraParams = ' multiple="multiple"';
            }
            if (!$this->getSkipJsReloadPrice()) {
                $extraParams .= ' onchange="opConfig.reloadPrice()"';
            }
            $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() .
                            ']"' .
                            ($this->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 = $this->_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' : '';
                }

                $selectHtml .= '<div class="field choice admin__field admin__field-option' .
                    $require .
                    '">' .
                    '<input type="' .
                    $type .
                    '" class="' .
                    $class .
                    ' ' .
                    $require .
                    ' product-custom-option"' .
                    ($this->getSkipJsReloadPrice() ? '' : ' onclick="opConfig.reloadPrice()"') .
                    ' name="options[' .
                    $_option->getId() .
                    ']' .
                    $arraySign .
                    '" id="options_' .
                    $_option->getId() .
                    '_' .
                    $count .
                    '" value="' .
                    $htmlValue .
                    '" ' .
                    $checked .
                    ' price="' .
                    $this->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;
        }
    }
}

catalog_product_view.xml

<block class="Magento\Catalog\Block\Product\View\Options\Type\Select" as="select" template="product/view/options/type/select.phtml"/>
  • How I can get the full source code of your module? – Khoa TruongDinh Apr 26 '16 at 14:10
  • I have included all of the code I have in the module, except for the full class. I can include that too? I have add the full Select class. This is all of the code for th module – MikeMason Apr 26 '16 at 14:33
5

First of all, we need to add Constructor injection method to our custom select class: (Edit: we don't need to add Constructor Injection, we need to add the sequence module)

    <?php
    namespace Mike\Newselect\Block\Product\View\Options\Type;

    class Select extends \Magento\Catalog\Block\Product\View\Options\Type\Select
    {
        public function __construct(
            \Magento\Framework\View\Element\Template\Context $context,
            \Magento\Framework\Pricing\Helper\Data $pricingHelper,
            \Magento\Catalog\Helper\Data $catalogData,
            array $data = []
        )
        {
            parent::__construct($context, $pricingHelper, $catalogData, $data);
        }
        .....

We need to add the :

<?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="Mike_Newselect" setup_version="1.0.0">
            <sequence>
                <module name="Magento_Catalog"/>
            </sequence>
        </module>
</config>

http://devdocs.magento.com/guides/v2.1/extension-dev-guide/build/module-load-order.html

Second, copy vendor/magento/module-catalog/view/frontend/templates/product/view/options/type/select.phtml to our custom module app/code/Mike/Newselect/view/frontend/templates/product/view/options/type/select.phtml

  • You're a hero, that worked! For future reference, how did you know which classes needed to be passed to the contructor? – MikeMason Apr 27 '16 at 9:28
  • @MikeMason : I had same issue but I don't have to use constructor. I did override the method and putted view/frontend/templates/product/view/options/type/select.phtml in my module which is working fine. – Sintu Roy Jan 7 '17 at 21:10
  • @SintuRoy you're right! I have just edited my answer. – Khoa TruongDinh Jan 7 '17 at 22:17
  • Thanks, didn't realise I needed the template file in the custom module as well – Alex Jun 15 '17 at 9:18

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.