Display out of stock product only for specific Category in Magento2
-
07-04-2021 - |
Pergunta
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!!
Solução
To do above things, you need to do this things.
- 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>
- 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;
}
}
Outras dicas
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.
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.
I hope it will helpful for you.