Product List: Show out of stock products in the last

In this blog post, we will be sharing how to show out of stock products at last of product listing page.

Assumption: MagePsycho_Productsort is the skeleton module

Steps:
1. Register event: catalog_product_collection_load_before
File: app/code/local/MagePsycho/Productsort/etc/config.xml


...
<frontend>
    <events>
        <catalog_product_collection_load_before>
            <observers>
                <magepsycho_productsort_catalog_product_collection_load_before>
                    <type>singleton</type>
                    <class>magepsycho_productsort/observer</class>
                    <method>catalogProductCollectionLoadBefore</method>
                </magepsycho_productsort_catalog_product_collection_load_before>
            </observers>
        </catalog_product_collection_load_before>
    </events>
</frontend>
...

2. Implement the observer model:
File: app/code/local/MagePsycho/Productsort/Model/Observer.php


<?php
/**
 * @category   MagePsycho
 * @package    MagePsycho_Productsort
 * @author     [email protected]
 * @license    http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
 */
class MagePsycho_Productsort_Model_Observer
{

    public function catalogProductCollectionLoadBefore(Varien_Event_Observer $observer)
    {
        $collection = $observer->getCollection();
        $collection->getSelect()->joinLeft(
            array('_inventory_table'=>$collection->getTable('cataloginventory/stock_item')),
            "_inventory_table.product_id = e.entity_id",
            array('is_in_stock', 'manage_stock')
        );
        $collection->addExpressionAttributeToSelect(
            'on_top',
            '(CASE WHEN (((_inventory_table.use_config_manage_stock = 1) AND (_inventory_table.is_in_stock = 1)) OR  ((_inventory_table.use_config_manage_stock = 0) AND (1 - _inventory_table.manage_stock + _inventory_table.is_in_stock >= 1))) THEN 1 ELSE 0 END)',
            array()
        );
        $collection->getSelect()->order('on_top DESC');
        // Make sure on_top is the first order directive
        $order = $collection->getSelect()->getPart('order');
        array_unshift($order, array_pop($order));
        $collection->getSelect()->setPart('order', $order);
    }
}
Showing Out of Stock products at last
Showing Out of Stock products at last

3. Bingo!