2

I have enabled Show out of stock products in the admin Inventory section.

I have to show all in stock and out of stock products of one category(id=10 and its subcategory) in list and search result page. by hiding all out of stock products in remaining categories(But should show all in-stock products).

So when we are in category page(id is 10) need to show all in_stock and out of stock,

category page(id is not 10), Need to show only in_stock products.

If in the search result page, have to show both in_stock and out_of_stock(only from category id 10).

I used the below plugin.

Vendor\Module\etc\di.xml

<type name="Magento\CatalogSearch\Model\Search\IndexBuilder">
  <plugin name="Custom_Layernavigation::CustomLayernavigation"
  type="Vendor\Module\Plugin\CatalogSearch\Model\Search\IndexBuilder" />
</type>

Then Vendor\Module\Plugin\CatalogSearch\Model\Search\IndexBuilder.php

<?php
use Magento\Framework\Search\RequestInterface;

class IndexBuilder {    
protected $_request;
protected $_categoryHelper;
 protected $_logger;

public function __construct(
    \Magento\Catalog\Model\ResourceModel\Product\CollectionFactory $productCollectionFactory,
    \Magento\Catalog\Helper\Category $categoryHelper,
    \Magento\Framework\App\Request\Http $request,
    \Psr\Log\LoggerInterface $logger
) {
    $this->_productCollectionFactory   = $productCollectionFactory;
    $this->_categoryHelper = $categoryHelper;
    $this->_request = $request;
    $this->_logger = $logger;
}

public function aroundBuild($subject, callable $proceed, RequestInterface $request) {
    $select = $proceed($request);

    $collection = $this->_productCollectionFactory->create();
    $collection->addAttributeToSelect('*');     
    $collection->joinField(
        'qty', 'cataloginventory_stock_item', 'qty', 'product_id=entity_id', '{{table}}.stock_id=1', 'left'
    );
    $collection->addAttributeToFilter('qty',['gt'=>0])->load();
    $collection->getSelect()
        ->join(array('cat_index'=> 'catalog_category_product_index_store1'), "cat_index.product_id = e.entity_id")
        ->where('cat_index.category_id <> 10');

    return $select;
  }
}

Can someone update me on how to implement this functionality? I am unable to write a join query to match the above requirement. Please check and update me about this. Thanks for the help.

2 Answers 2

1

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

2
  • I have a problem with count and pagination using this method. So for example I have 13 SKUs with 12 per page. On page 1 I see SKUs 1 to 11. On page 2 I see 1 SKU. So the OOS SKU has been removed from the listing but not considered in count or pagination. Did you have a similar issue? Commented Jun 10, 2022 at 23:39
  • I am facing same issue(the one you mentioned in your comment), did you find any solutions for it?
    – Korbin
    Commented Oct 20, 2022 at 13:30
0

Try to do using afterPlugin method by this below way :

<?php

namespace Vendor\Module\Plugin\CatalogSearch\Model\Search;

class IndexBuilder
{
    /**
     * @var \Magento\Store\Model\StoreManagerInterface
     */
    protected $storeManager;

    public function __construct(
        \Magento\Store\Model\StoreManagerInterface $storeManager
    ) {
        $this->storeManager = $storeManager;
    }

    public function afterBuild($subject, $result)
    {
        if(your_category_id){
            $connection = $result->getConnection();
            $result->joinLeft(
                ['stock_status_filter' => $connection->getTableName('cataloginventory_stock_status')],
                'search_index.entity_id = stock_status_filter.product_id'
                . $connection->quoteInto(
                    ' AND stock_status_filter.website_id IN (?, 0)',
                    $this->storeManager->getWebsite()->getId()
                ),
                []
            );
            return $result;
        } else {
            return $result;
        }
    }
}

Make sure display out of stock products configuration enabled.

Hope, Maybe it's helpful for you.

5
  • hi @Rohan, Thanks for the answer, but the above code may work only for category page, I can use registry and get the current category and use it, but in search result page this will fail, this will not come inside if condition Commented Feb 26, 2020 at 4:59
  • Okay. wait please. Commented Feb 26, 2020 at 5:16
  • Did you created any plugin for Magento\Catalog\Model\Layer ? Commented Feb 26, 2020 at 5:20
  • No i have not created any plugin for that? But i am using Bss layered navigation extension, they have re-written it Commented Feb 26, 2020 at 5:22
  • Also I checked ur code now only for categories, problem is out of stock products showing for all other categories also we have to show only in_stock for other categories except one category(there both in_stock and out_of_stock) should show Commented Feb 26, 2020 at 5:52

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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