5

I have to show out of stock products only in certain categories by hiding them in all other categories.

used below plugin to implement, that is not working.

Vendor/Module/etc/di.xml

<type name="Magento\Catalog\Model\Layer">
    <plugin name="Vendor_Module_Layer" type="Vendor\Module\Plugin\CatalogInventoryLayer" sortOrder="10" disabled="false"  />
</type>

Then

Vendor/Module/Plugin/CatalogInventoryLayer.php

<?php

namespace Vendor\Module\Plugin;

use Magento\Catalog\Model\Layer as CatalogLayer;
use Magento\Catalog\Model\ResourceModel\Product\Collection as ProductCollection;

class CatalogInventoryLayer {
protected $_logger;
public function __construct( 
    \Psr\Log\LoggerInterface $logger
    ){
        $this->_logger = $logger;
    }
public function aroundPrepareProductCollection(CatalogLayer $subject, \Closure $proceed, $collection)
{
    $writer = new \Zend\Log\Writer\Stream(BP . '/var/log/customlog.log');
    $logger = new \Zend\Log\Logger();
    $logger->addWriter($writer);        
    $categoryId = $subject->getCurrentCategory()->getId();      
    $proceed($collection);
    if ($categoryId == 4){
        $collection->getSelect()->joinLeft(
                 ['_inventory_table' => 'cataloginventory_stock_item'], 
                 "_inventory_table.product_id = e.entity_id", ['is_in_stock']
        );
        $collection->addFieldToFilter('is_in_stock',array('eq'=>'0'));

    }       

    return $this;
    }
  }

Update:

Vendor/Module/etc/di.xml

<type name="Magento\CatalogInventory\Helper\Stock">
  <plugin name="Vendor_Extension_Stock_Helper" type="Vendor\Extension\Plugin\Helper\Stock" sortOrder="10" disabled="false"  />
</type>

Vendor/Module/Plugin/Helper/Stock.php

<?php 
namespace Vendor\Module\Plugin\Helper;
use Magento\CatalogInventory\Model\ResourceModel\Stock\StatusFactory;
class Stock
{    
private $logger;
protected $_registry;
protected $request;
protected $stockStatusResource;
protected $stockStatusFactory;
public function __construct(
    \Psr\Log\LoggerInterface $logger,
    \Magento\Framework\Registry $registry,
    \Magento\Framework\App\Request\Http $request,
    StatusFactory $stockStatusFactory
) {
    $this->logger = $logger;
    $this->_registry = $registry;
    $this->request = $request;
    $this->stockStatusFactory  = $stockStatusFactory;
}
public function aroundAddIsInStockFilterToCollection(\Magento\CatalogInventory\Helper\Stock $subject, \Closure $proceed, $collection)
{
    try{
        $category = $this->_registry->registry('current_category');//get current category
        $currentPage = $this->request->getFullActionName(); //catalogsearch_result_index
        if(!is_null($category) && $currentPage!= 'catalogsearch_result_index')
        {
            $stockFlag = 'has_stock_status_filter';
            $categoryId = $category->getId();                   
            $parentCategoryId =  $category->getParentCategory()->getId();               
            if($categoryId == 10 || $parentCategoryId == 10)
            {
            $resource = $this->getStockStatusResource();                
                $resource->addStockDataToCollection(
                        $collection,
                        false
                ); 
            }
            $collection->setFlag($stockFlag, true);
        } 
        return $this;
    }catch(\Exception $e){
        return $e->getMessage();
        $this->logger->info('--exception--'.$e->getMessage());
    }
}

public function getStockStatusResource(){
    if (empty($this->stockStatusResource)) {
        $this->stockStatusResource = $this->stockStatusFactory->create();
    }
    return $this->stockStatusResource;
   }
}

I have to display them only when we visit some specific categories by hiding them in all other categories

The updated code is working in category page, but search result page out of stock from other categories also visible,

Is there any way to show only out of stock products which belongs to category id '10'.

Can anyone please check and update me if there is any other way to implement the above functionality. Thanks!!

2
  • What's your magento version? Feb 14, 2020 at 11:09
  • @RohanHapani, its 2.3.2
    – Manjunath
    Feb 14, 2020 at 11:15

4 Answers 4

5
+50

To do above things, you need to do this things.

  1. Vendor\Extension\etc\di.xml
<type name="Magento\CatalogInventory\Helper\Stock">
    <plugin name="Vendor_Extension_Stock_Helper" type="Vendor\Extension\Plugin\Helper\Stock" sortOrder="10" disabled="false"  />
</type>
  1. Create the Helper File with arround plugin.

Vendor\Extension\Plugin\Helper\Stock.php

<?php
namespace Vendor\Extension\Plugin\Helper;

class Stock
{    
    public function aroundAddIsInStockFilterToCollection(\Magento\CatalogInventory\Helper\Stock $subject, \Closure $proceed, $collection)
    {
       // Do your Logic Here
        return $returnValue;
    }
}
3
  • hi @Dhiren, this has issue with the count in layer navigation
    – Manjunath
    Feb 25, 2020 at 8:11
  • but the search result page still out of stock products showing for all.
    – Manjunath
    Feb 25, 2020 at 15:47
  • @Manjunath have you sorted out the count layered navigation issue? Aug 31, 2021 at 13:09
2

You should extend the original function ( Magento\CatalogInventory\Model\ProductCollectionStockCondition::apply() ) which is checking the stock configuration.

"Display out of stock products" config in store > Config > catalog > inventory.

You can use preference to extend that apply() function and add additional condition like that.

from:
$this->stockHelper->addIsInStockFilterToCollection($collection);

to:
if(in_array(category_id, ur_list_of_ids))
$this->stockHelper->addIsInStockFilterToCollection($collection);

In this way, you can enable out of stock products in some of the category only.

5
  • it is not so clear, can you update me as answer please, I have to set Display out of stock products as "yes" in admin?
    – Manjunath
    Feb 6, 2020 at 11:51
  • yes, you have to set it as "yes" and extend the original class file which is adding filter based on your config. you can add your category condition in your extended class.
    – Thamo
    Feb 6, 2020 at 11:57
  • if set to yes, the out of stock products will display in all the cats, how can we avoid that
    – Manjunath
    Feb 6, 2020 at 12:03
  • could you update me working code please..
    – Manjunath
    Feb 7, 2020 at 6:29
  • @Manjunath - I dont have working code now. but given the suggestion based on my previous experience.
    – Thamo
    Feb 13, 2020 at 7:23
1

You can display **ONLY Out Of Stock products for particular category page**, first, you need to set configuration for Display Out of Stock Products, Go to Stores > Configuration > Catalog > Inventory > Stock Options->Display Out of Stock Products set as Yes, because for category page and product page product is not visible or not in collection if it's set as No, I'm not sure why Out Of Stock products is not available in Collection without "Display Out of Stock Products" configuration.

But for display Out Of Stock products for a particular category, you can change aroundPrepareProductCollection() as per below or replace your plugin file, I have checked it displays only Out Of Stock product only on the Category page.

<?php
/**
 * Copyright © Magento, Inc. All rights reserved.
 * See COPYING.txt for license details.
 */
namespace Vendor\Module\Plugin;

use Magento\Catalog\Model\Layer as CatalogLayer;

class CatalogInventoryLayer
{
    public function aroundPrepareProductCollection(CatalogLayer $subject, \Closure $proceed, $collection)
    {
        $categoryId = $subject->getCurrentCategory()->getId();
        $writer = new \Zend\Log\Writer\Stream(BP . '/var/log/OutOfStock_Product.log');
        $logger = new \Zend\Log\Logger();
        $logger->addWriter($writer);

        //Get Out Of Stock Products
        $collection->addFieldToSelect('*')
            ->setFlag('has_stock_status_filter', true)
            ->joinField('stock_item', 'cataloginventory_stock_item', 'is_in_stock', 'product_id=entity_id', 'is_in_stock=0');
        $collection->addCategoriesFilter(['eq' => $categoryId]); // Current category filter, it's not require, because PrepareProductCollection() automatically apply filter for current category. 

        $logger->info(print_r($collection->getData(), true));

        return $collection;
    }
}

Out of stock products of Bags category, you can see in screenshots.

enter image description here

enter image description here

I hope it will helpful for you.

13
  • hi @rohit, thanks for the answer, but where u are checking the condition in your answer for particular category? I think u missed it, pls double check once
    – Manjunath
    Feb 25, 2020 at 7:11
  • this is not working, getting exception Column not found: 1054 Unknown column 'e.min_price' in 'field list', Feb 25, 2020 at 8:35
  • Hello @Manjunath, No, I have not missed, because category filter is not require here, because PrepareProductCollection() is call for current category page, and in "vendor/magento/module-catalog/Model/Layer.php" file you can check "prepareProductCollection()" function, we just need to pass collection, it'll automatically apply CURRENT CATEGORY FILTER, I have tested above code it's working fine. Feb 25, 2020 at 9:11
  • "vendor/magento/module-catalog/Model/Layer.php" public function prepareProductCollection($collection) { $this->collectionFilter->filter($collection, $this->getCurrentCategory()); return $this; } If you still apply filter then please check my updated answer. Feb 25, 2020 at 9:11
  • Hello @jafarpinjar, I have tested above code, it's working fine for me. Feb 25, 2020 at 9:11
0

If you're using magento 2.4 then you have to create a plugin for

Magento\Catalog\Model\Layer

We have to set the Go to Stores > Configuration > Catalog > Inventory > Stock Options->Display Out of Stock Products. This is necessary because Magento doesn't load the is_in_stock filters when we set this option to 'NO'. So we can't put our custom work/conditions when it sets to NO I've debugged it completely and well , So first we have to set it to YES , then I've created a plugin for Magento\Catalog\Model\Layer`and I've handled in such a way that it is now working properly. 1- The Out Of Stock and In Stock products will be shown for specified category 2- Other all the categories of the store will only show InStock products according to our requirement.

The code is below:

public function aroundPrepareProductCollection(CatalogLayer $subject, \Closure $proceed, $collection)
{
    // Getting current category Id
    $categoryId = $subject->getCurrentCategory()->getId();
    // Getting specified category whom we wann show OOS products
    $showAllCategoryId = $this->displayBoth->getShowAllCategoryId();

    if($categoryId == $showAllCategoryId) {
        //Get Out Of Stock Products and also In Stock Products of the specified category
        $collection->addFieldToSelect('*')
            ->setFlag('has_stock_status_filter', true)
            ->joinField('stock_item', 'cataloginventory_stock_item', 'is_in_stock', 'product_id=entity_id',
                'is_in_stock=0 || is_in_stock=1');
        // Apply to the collection
        $collection->addCategoriesFilter(['eq' => $categoryId]); // Current category filter, it's not require, because PrepareProductCollection() automatically apply filter for current category.
    }else{
        //Get only In Stock products to the all the categories instead of above specified one
        $collection->addFieldToSelect('*')
            ->setFlag('has_stock_status_filter', true)
            ->joinField('stock_item', 'cataloginventory_stock_item', 'is_in_stock', 'product_id=entity_id',
                'is_in_stock=1');
        //Apply to the collection
        $collection->addCategoriesFilter(['eq' => $categoryId]);
    }
    return $proceed($collection);
}

This has been tested well and working fine for Magento 2.4 EE and CE

1
  • can you share with me complete code of this file ? Aug 26, 2021 at 8:13

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.