6

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

2
  • 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, 2018 at 13:10
  • @Hardik did you get the solution??? if yes can you please post your answer??
    – Asad Khan
    Oct 19, 2019 at 18:47

3 Answers 3

7

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',

        }
    }
};
13
  • What's the name/heirarchy of the last file?
    – dawhoo
    Apr 4, 2018 at 16:09
  • 1
    @dawhoo the last file name/heirarchy is app/code/Ravindra/Custom/view/frontend/requirejs-config.js Jun 9, 2018 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, 2018 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, 2018 at 0:01
  • can you please update the js code also Nov 29, 2018 at 16:08
-2

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
-3

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

change

protected $_skipSaleableCheck = false;

to

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

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