Magento – Magento2 Product Listing – Show product options

catalogconfigurable-productcustom-optionsmagento2products

I'm working on a new Magento 2 theme at the moment. For this theme I want to show all product options (custom options and options form configurable product) in the product listing. This way the user can quickly add products to it's cart.

I tried adding the product.info block in catalog_category_view.xml and set the product for that block. Options are shown for every product, the problem is that the option shown is only from the first product. So all other products have this options.

— UPDATE —

I managed to show the product options, but the prices are not updated. Can someone point me in the right direction?

<form id='product_addtocart_form_<?php echo $product->getId(); ?>' class="c-product__details__add-to-cart" data-role="tocart-form" action="<?php echo $postParams[ 'action' ]; ?>" method="post">
    <input type="hidden" name="product" value="<?php echo $postParams[ 'data' ][ 'product' ]; ?>">
    <input type="hidden" name="<?php echo Action::PARAM_NAME_URL_ENCODED; ?>" value="<?php echo $postParams[ 'data' ][ Action::PARAM_NAME_URL_ENCODED ]; ?>">
    <?php echo $block->getBlockHtml('formkey') ?>
    <div class="product-options-wrapper" id="product-options-wrapper" data-hasrequired="* Verplichte velden">
        <?php if($product->getTypeId() === 'configurable') : ?>
            <?php foreach($product->getTypeInstance()->getConfigurableAttributes($product) as $attribute) : ?>
                <div class="field">
                    <label class="label" for="select_<?php echo $attribute->getAttributeId(); ?>"><span><?php echo $attribute->getLabel() ?></span></label>
                    <?php $values = $attribute->getOptions(); ?>
                    <div class="control">
                        <select id="select_<?php echo $attribute->getAttributeId() ?>" name="options[<?php echo $attribute->getAttributeId() ?>]" class="product-option product-custom-option-<?php echo $attribute->getAttributeId() ?> admin__control-select" data-selector="options[<?php echo $attribute->getAttributeId() ?>]">
                            <?php foreach($values as $value): ?>

                                <option value="<?php echo $value['value_index'] ?>" price="2"><?php echo  $value['label'] ?></option>
                            <?php endforeach; ?>
                        </select>
                    </div>
                </div>
            <?php endforeach; ?>
        <?php else : ?>
            <?php foreach($customOptions as $option): ?>
                <div class="field">
                    <label class="label" for="select_<?php echo $option->getId(); ?>"><span><?php echo $option->getTitle() ?></span></label>
                    <?php $values = $option->getValues(); ?>
                    <div class="control">
                        <select id="select_<?php echo $option->getId() ?>" data-id="<?php echo $product->getId() ?>" name="options[<?php echo $option->getId() ?>]" class="product-option product-custom-option-<?php echo $product->getId() ?> admin__control-select" data-selector="options[<?php echo $option->getId() ?>]">
                            <?php foreach($values as $value): ?>

                                <option value="<?php echo $value->getData('option_type_id') ?>" price="3"><?php echo $value->getTitle() ?></option>
                            <?php endforeach; ?>
                        </select>
                    </div>
                </div>
            <?php endforeach; ?>
        <?php endif; ?>
        <script>
            require([
                'jquery',
                'Magento_Catalog/js/price-box'
            ], function($){
                var priceBoxes = $('[data-product-id=<?php echo $product->getId(); ?>]');

                priceBoxes = priceBoxes.filter(function(index, elem){
                    return !$(elem).find('.price-from').length;
                });
                var priceBox = priceBoxes.priceBox({'priceConfig': <?php /* @escapeNotVerified */ echo $block->getJsonConfig($product, $customOptions) ?>});

                $('.product-option').on('change', function() {
                    priceBox.trigger('updatePrice');
                });
            });
        </script>
    </div>
    <button type="submit" title="<?php echo $block->escapeHtml(__('Add to Cart')); ?>" class="action tocart primary im">
        <span><?php echo __('Add to cart'); ?></span>
    </button>
</form>

I also implemented the getJsonConfig function in my own ListProduct class.

Best Answer

You can take as an example the module Magento_Swatch.

The block Magento\Swatches\Block\Product\Renderer\Listing\Configurable is added to the block with name category.product.type.details.renderers.

As in here: https://github.com/magento/magento2/blob/develop/app/code/Magento/Swatches/view/frontend/layout/catalog_category_view.xml

The template initialises the JS used on swatches: Magento_Swatches::product/listing/renderer.phtml

https://github.com/magento/magento2/blob/develop/app/code/Magento/Swatches/view/frontend/templates/product/listing/renderer.phtml

And everything important is done into the swatch JS. https://github.com/magento/magento2/blob/develop/app/code/Magento/Swatches/view/frontend/web/js/swatch-renderer.js Like functions: _RenderControls, _RenderFormInput, _EventListener, _UpdatePrice and other. The JS looks big. But it has a lot of code around rendering swatches images that are fetched via AJAX. You probably don't need it, it's easier to implement.

Here, the options (super attributes and associated products) html tags (swatches divs) are created and manipulated. The price is handled here too. In your case you'll have dropdowns.

You'd need to write your own module to implement all above. Theoretically you can add any options from all type of products (bundle, grouped, ..). The cost is performance, since you'd need to load more data into models to every product on a category page that has options.

As an alternative, you can try to set to the configurable/simple associated products non-visual swatches (without images).

Related Topic