Hiding “Out of Stock” items in Layered Navigation
Updated 9/28/09
See the latest post in this series: Yet Another “Hiding Out-Of-Stock Products” Update, for an update that fixes advanced search, tags, up-sells, cross-sells, etc..
Updated 7/23/09
Updated once again to add support for filtering search results. (Added CatalogSearch/Model/Layer.php, moved Model/Layer.php to Catalog/Model/Layer.php, updated config.xml)
My previous post about “Hiding Out of Stock Items in Magento” had one pretty major downfall, in that it did not handle the product counts in the layered navigation. In response to a forum post regarding this I looked into fixing my original solution and have come up with a more concise and complete approach which I present now as a replacement to my original InStockOnly module.
Rather than observe an event we are going to simply overload the Mage_Catalog_Model_Layer->prepareProductCollection method which, as it turns out, serves as the basis for all of the catalog product collections including the product lists and the layered navigation product counts!
My module is called Lucky_InStockOnly for lack of a better name.
Here is the code for app/code/local/Lucky/InStockOnly/Catalog/Model/Layer.php:
<?php
class Lucky_InStockOnly_Catalog_Model_Layer extends Mage_Catalog_Model_Layer {
/**
* Add a statusInStock requirement for visibility
*/
public function prepareProductCollection($collection){
parent::prepareProductCollection($collection);
$collection->joinField(
'stock_status',
'cataloginventory/stock_status',
'stock_status',
'product_id=entity_id', array(
'stock_status' => Mage_CatalogInventory_Model_Stock_Status::STATUS_IN_STOCK,
'website_id' => Mage::app()->getWebsite()->getWebsiteId(),
)
);
return $this;
}
}
We do the same thing for CatalogSearch so that search results also hide out of stock items. It turns out the API is consistent here and the code is identical except for the class names.
app/code/local/Lucky/InStockOnly/CatalogSearch/Model/Layer.php
<?php
class Lucky_InStockOnly_CatalogSearch_Model_Layer extends Mage_CatalogSearch_Model_Layer {
/**
* Add a statusInStock requirement for visibility
*/
public function prepareProductCollection($collection){
parent::prepareProductCollection($collection);
$collection->joinField(
'stock_status',
'cataloginventory/stock_status',
'stock_status',
'product_id=entity_id', array(
'stock_status' => Mage_CatalogInventory_Model_Stock_Status::STATUS_IN_STOCK,
'website_id' => Mage::app()->getWebsite()->getWebsiteId(),
)
);
return $this;
}
}
Now we simply setup our module config file to overload the catalog classes of the same names:
app/code/local/Lucky/InStockOnly/etc/config.xml
<?xml version="1.0"?>
<config>
<global>
<models>
<catalog>
<rewrite>
<layer>Lucky_InStockOnly_Catalog_Model_Layer</layer>
</rewrite>
</catalog>
<catalogsearch>
<rewrite>
<layer>Lucky_InStockOnly_CatalogSearch_Model_Layer</layer>
</rewrite>
</catalogsearch>
</models>
</global>
</config>
And of course we need to enable the module (same as first version):
app/etc/modules/Lucky_InStockOnly.xml
<config>
<modules>
<Lucky_InStockOnly>
<active>true</active>
<codePool>local</codePool>
</Lucky_InStockOnly>
</modules>
</config>
You will need to refresh your cache and possibly rebuild the catalog and layered navigation indicies, then you are done! All out of stock products should be hidden, and the counts in the layered navigation should correctly indicate the number of items that are in-stock.