5

this may be a simple question for some - but we havent used stock extensions before.

Question: how can we easily, simply, add the ability to - instead of hiding out of stock simple products (as part of a configurable product) - show out of stock simple products with the addition of "- out of stock" & maybe greyed out in the drop down.

For example:

We sell T-shirts in sizes S, M, L. And for instance L is sold out.

Instead of only showing S, M (in config product)

Showing S, M, L - out of stock (in config product, and out of stock in grey)

this link magento 1.9 version

Now i check magento latest version 2.2.3 not working

  • i went through each and every step of Ravindra but when i upgrade the module, my configurable dropdown on product page doesn't show any more. I have also included the JS files - swatch-renderer.js and configurable.js Can you please help me in this – Hardik Aug 7 '18 at 13:10
  • @Hardik did you get the solution??? if yes can you please post your answer?? – Asad Khan Oct 19 at 18:47
6

app/code/Ravindra/Custom/etc/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="Ravindra_Custom" setup_version="2.2.2">
    </module>
</config>

app/code/Ravindra/Custom/registration.php

<?php

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

app/code/Ravindra/Custom/etc/di.xml

<?xml version="1.0"?>
<!--
/**
 * Copyright © 2015 Magento. All rights reserved.
 * See COPYING.txt for license details.
 */
-->
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">

    <preference for="Magento\Swatches\Block\Product\Renderer\Configurable" type="Ravindra\Custom\Block\Product\View\Type\Configurable" />

    <preference for="Magento\ConfigurableProduct\Model\ConfigurableAttributeData" type="Ravindra\Custom\Model\Rewrite\ConfigurableAttributeData" />
</config>

app/code/Ravindra/Custom/Block/Product/View/Type/Configurable.php

<?php

namespace Ravindra\Custom\Block\Product\View\Type;

use Magento\Catalog\Block\Product\Context;
use Magento\Catalog\Helper\Product as CatalogProduct;
use Magento\ConfigurableProduct\Helper\Data;
use Magento\ConfigurableProduct\Model\ConfigurableAttributeData;
use Magento\Customer\Helper\Session\CurrentCustomer;
use Magento\Framework\Json\EncoderInterface;
use Magento\Framework\Pricing\PriceCurrencyInterface;
use Magento\Catalog\Model\Product;
use Magento\Framework\Stdlib\ArrayUtils;
use Magento\Store\Model\ScopeInterface;
use Magento\Swatches\Helper\Data as SwatchData;
use Magento\Swatches\Helper\Media;
use Magento\Swatches\Model\Swatch;

class Configurable extends \Magento\Swatches\Block\Product\Renderer\Configurable 
{

     public function __construct(
        Context $context,
        ArrayUtils $arrayUtils,
        EncoderInterface $jsonEncoder,
        Data $helper,
        CatalogProduct $catalogProduct,
        CurrentCustomer $currentCustomer,
        PriceCurrencyInterface $priceCurrency,
        ConfigurableAttributeData $configurableAttributeData,
        SwatchData $swatchHelper,
        Media $swatchMediaHelper,
        array $data = []
    ){
         $this->swatchHelper = $swatchHelper;
        $this->swatchMediaHelper = $swatchMediaHelper;
         parent::__construct(
            $context,
            $arrayUtils,
            $jsonEncoder,
            $helper,
            $catalogProduct,
            $currentCustomer,
            $priceCurrency,
            $configurableAttributeData,
            $swatchHelper,
            $swatchMediaHelper,
            $data
        );
    }

    public function getJsonConfig() {
        $store = $this->getCurrentStore();
        $currentProduct = $this->getProduct();

        $regularPrice = $currentProduct->getPriceInfo()->getPrice('regular_price');
        $finalPrice = $currentProduct->getPriceInfo()->getPrice('final_price');

        $options = $this->helper->getOptions($currentProduct, $this->getAllowProducts());
        $attributesData = $this->configurableAttributeData->getAttributesData($currentProduct, $options);

        $config = [
            'attributes' => $attributesData['attributes'],
            'template' => str_replace('%s', '<%- data.price %>', $store->getCurrentCurrency()->getOutputFormat()),
            'optionPrices' => $this->getOptionPrices(),
            'optionStock' => $this->getOptionStocks(),
            'prices' => [
                'oldPrice' => [
                    'amount' => $this->_registerJsPrice($regularPrice->getAmount()->getValue()),
                ],
                'basePrice' => [
                    'amount' => $this->_registerJsPrice(
                        $finalPrice->getAmount()->getBaseAmount()
                    ),
                ],
                'finalPrice' => [
                    'amount' => $this->_registerJsPrice($finalPrice->getAmount()->getValue()),

                ],
            ],

            'productId' => $currentProduct->getId(),
            'chooseText' => __('Choose an Option...'),
            'images' => isset($options['images']) ? $options['images'] : [],
            'index' => isset($options['index']) ? $options['index'] : [],
        ];

        if ($currentProduct->hasPreconfiguredValues() && !empty($attributesData['defaultValues'])) {
            $config['defaultValues'] = $attributesData['defaultValues'];
        }

        $config = array_merge($config, $this->_getAdditionalConfig());

        return $this->jsonEncoder->encode($config);
    }


    /*-----------------------custom code----------------------*/

    protected function getOptionStocks() {
        $stocks = [];
        $objectManager = \Magento\Framework\App\ObjectManager::getInstance();       
        $stockObject=$objectManager->get('Magento\CatalogInventory\Api\StockRegistryInterface');

        foreach ($this->getAllowProducts() as $product) {          
            $productStockObj = $stockObject->getStockItem($product->getId());
            $isInStock = $productStockObj['is_in_stock'];
            $stocks[$product->getId()] = ['stockStatus' => $isInStock];
        }
        return $stocks;
    }

}

app/code/Ravindra/Custom/Block/ConfigurableProduct.php

<?php
/**
 * Copyright © 2015 Magento. All rights reserved.
 * See COPYING.txt for license details.
 */
namespace Ravindra\Custom\Block;

use Magento\Framework\View\Element\Template;

class ConfigurableProduct extends Template
{   
    protected $_storeManager;

    public function __construct(
    \Magento\Framework\View\Element\Template\Context $context,
    array $data = []
    ){ 
        parent::__construct($context, $data);
        $this->_storeManager = $context->getStoreManager();
    }

}

app/code/Ravindra/Custom/Model/Rewrite/ConfigurableAttributeData.php

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

namespace Ravindra\Custom\Model\Rewrite;

use Magento\Catalog\Model\Product;
use Magento\ConfigurableProduct\Model\Product\Type\Configurable\Attribute;

class ConfigurableAttributeData extends \Magento\ConfigurableProduct\Model\ConfigurableAttributeData
{

    protected $eavConfig;

    public function __construct(\Magento\Eav\Model\Config $eavConfig) {
        $this->eavConfig = $eavConfig;
    }

    public function getAttributeOptionsData($attribute, $config) {
        $attributeOptionsData = [];

        $attributeId = $attribute->getAttributeId();

        $objectManager = \Magento\Framework\App\ObjectManager::getInstance();
        $eavModel = $objectManager->create('Magento\Catalog\Model\ResourceModel\Eav\Attribute');
        $attr = $eavModel->load($attributeId);
        $attributeCode=$eavModel->getAttributeCode();


        $attribute = $this->eavConfig->getAttribute('catalog_product', $attributeCode);
        $options = $attribute->getSource()->getAllOptions();


        foreach ($options as $attributeOption) {
            $optionId = $attributeOption['value'];
            $attributeOptionsData[] = [
                'id' => $optionId,
                'label' => $attributeOption['label'],
                'products' => isset($config[$attribute->getAttributeId()][$optionId])
                    ? $config[$attribute->getAttributeId()][$optionId]
                    : [],
            ];
        }
        return $attributeOptionsData;
    }

}

app/code/Ravindra/Custom/view/frontend/layout/catalog_product_view.xml

<?xml version="1.0"?>

<page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" layout="1column" xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd">
    <head>        
        <css src="Ravindra_Custom::css/configurableproduct.css"/>
    </head>    
</page>

app/code/Ravindra/Custom/view/frontend/layout/catalog_product_view_type_configurable.xml

<?xml version="1.0"?>
<!--
/**
 * Copyright © 2015 Magento. All rights reserved.
 * See COPYING.txt for license details.
 */
-->
<page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd">
    <body>
       <referenceBlock name="product.info.configurable">
            <action method='setTemplate'>
                <argument name="template" xsi:type="string">Ravindra_Custom::configurable-available.phtml</argument>
            </action>           
        </referenceBlock>       
    </body>
</page>

app/code/Ravindra/Custom/view/frontend/templates/configurable-available.phtml

   <?php /* @var $block \Magento\Catalog\Block\Product\View\AbstractView */?>
<?php $_product = $block->getProduct() ?>
<?php $stockblock =  $this->getLayout()->createBlock('Ravindra\Custom\Block\ConfigurableProduct'); ?>

<?php if ($block->displayProductStockStatus()): ?>
    <?php if ($_product->isAvailable()): ?>
        <div class="stock available mcs-available" title="<?php /* @escapeNotVerified */ echo __('Availability') ?>">
            <span><?php /* @escapeNotVerified */ echo __('In stock') ?></span>
        </div>
    <?php else: ?>
        <div class="stock unavailable" title="<?php /* @escapeNotVerified */ echo __('Availability') ?>">
            <span><?php /* @escapeNotVerified */ echo __('Out of stock') ?></span>
        </div>

        <div class="ravi-stockalert">   
                <div class="rav-subscriber-title"><?php
                /* @escapeNotVerified */ 


                ?>
                </div>
                <div class="ravi-stockalert-form">      
                    <form name="stockalert_form" id="stockalert_form" method="POST" action="<?php echo $stockblock->getStockalertPostUrl(); ?>" data-mage-init='{"validation":{}}'>
                        <div class="email-stockalert-input">
                            <input class="input-text" type="email" data-validate="{required:true, 'validate-email':true}" type="text" placeholder="Enter email address" name="email" />
                        </div>
                        <input type="hidden" id="cp_product_id" name="product_id" value="<?php echo $_product->getId(); ?>" >
                        <input type="hidden" name="product_name" value="<?php echo $_product->getName(); ?>" >
                        <div class="submit-stockalert-input">
                            <input type="submit" class="stockalert-submit-btn" name="submit" value="subscribe">
                        </div>
                    </form>
                    <div style="clear:both;"></div>
                </div>
            </div>

    <?php endif; ?>

    <div class="mcs-config-product-stockalert" id="mcs-config-product-stockalert" style="display:none;">
        <div class="stock unavailable" title="<?php /* @escapeNotVerified */ echo __('UnAvailability') ?>">
            <span><?php /* @escapeNotVerified */ echo __('Out of stock') ?></span>
        </div>
    </div>

<?php endif; ?>

app/code/Ravindra/Custom/view/frontend/web/css/configurableproduct.css

.email-stockalert-input{
    float:left;
    width: 80%;
}
.submit-stockalert-input {
    width: 20%;
    float: right;
}
.email-stockalert-input input, .submit-stockalert-input input{
    height: 40px;
}
.submit-stockalert-input input{
    float: left;
    width: 100%;
    background: #1979c3;
    border: 1px solid #1979c3;
    color: #ffffff;
    cursor: pointer;
    display: inline-block;
    font-family: 'Open Sans', 'Helvetica Neue', Helvetica, Arial, sans-serif;
    font-weight: 600;
    font-size: 14px;
    text-transform: capitalize;
}
.stockalert-submit-btn:hover{
    background: #333;
    border: 1px solid #333;
}
.ravi-stockalert, .ravi-stockalert-bundle, .ravi-stockalert-group{
    /*text-align: center !important;*/
    margin: 10px 0px;
    border: 1px #ccc solid;
    padding: 10px;
}
.product-info-stock-sku{
    display:block !important;
}
.product-info-price{
    /*width: 55% !important;*/
}
.product-info-main .product-info-price .price-box{
    width: 100%;
    float: left;
}
.product-info-main .product-info-stock-sku{
    float: left;
    min-width: 100%;
    padding-left: 0px;
}
.stock.unavailable{
    text-align:left;
    color:#F00;
    font-size: 16px;
    font-weight: 400 !important;
}
.sku .value, .sku{
    text-align:left;
}
.ravi-stockalert-form {
    margin: 5px 0;
    width: 100%;

}

.page-product-grouped .product-info-price{
    width:100%;
}
.table.grouped .col.item {
   width: 13%;
}
.grouped .email-stockalert-input{
    width: 69%;
}
.grouped .submit-stockalert-input{
    width: 31%
}
.grouped .submit-stockalert-input input{
    font-size: 12px;
}
.grouped .table.grouped .col.qty{
    padding: 11px 0px;
}
.item span, .item strong{
    color: #1979C3;
}
.grouped .product-item-name {
    color: #000 !important;
    font-size: 16px;
}
.rav-subscriber-title {
    text-align: left;
}
.guest_users_message{
    text-align:left;
}

app/code/Ravindra/Custom/view/frontend/requirejs-config.js

var config = {
    map: {
        '*': {

            'Magento_Swatches/js/swatch-renderer':'Ravindra_Custom/js/swatch-renderer', 
            configurable:'Ravindra_Custom/js/configurable',

        }
    }
};
  • What's the name/heirarchy of the last file? – dawhoo Apr 4 '18 at 16:09
  • 1
    @dawhoo the last file name/heirarchy is app/code/Ravindra/Custom/view/frontend/requirejs-config.js – mahmoudismail Jun 9 '18 at 15:12
  • 1
    I have tried the above module for M2 2.2.4 and it does not work, I was wondering if this could be updated to work on M2 2.2.4 – Baber Jul 11 '18 at 11:13
  • I think this is missing the js folder with the two javascript files, swatch-renderer.js and configurable.js. Without those, it doesn't appear that it will work. Can you add those two files to your answer? – Scrivvles Jul 22 '18 at 0:01
  • can you please update the js code also – Hitesh Balpande Nov 29 '18 at 16:08
-1

To be able to activate this configuration

go to Products -> Catalog, there we choose any product and we go to the option of Quantity. Under it, there is the option "advanced inventory", click on it and select the first box that says Use configuration options found under Manage stock.

This configuration will show all the swatches

-1

open the file vendor\magento\module-catalog\Helper\Product.php

change

protected $_skipSaleableCheck = false;

to

 protected $_skipSaleableCheck = true;
  • Diving into vendor is a bad idea. Your change will be overwritten when you do a composer install or update. – Josh Pennington May 22 at 0:52
  • And it will effect simple products too ;) – Korneo Nika Sep 30 at 11:13

protected by Community Aug 7 '18 at 17:03

Thank you for your interest in this question. Because it has attracted low-quality or spam answers that had to be removed, posting an answer now requires 10 reputation on this site (the association bonus does not count).

Would you like to answer one of these unanswered questions instead?

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