Magento 2 display out of stock products at the end of the list page.

You can display out of stock product at end of catalog page in Magento 2 using just simple way. All the Out of stock product will be displayed at end of listing page.

You need to create module for display out of stock product at end of the page.

Create registration.php and module.xml file for creating a module. I hope you have created both file for define module,

For Collection of product generate from Magento\CatalogSearch\Model\ResourceModel\Fulltext\Collection file. We need to create a plugin for load() function. we need to set our custom condition for out of stock product to beforeLoad() function.

Create a di.xml file,

Path, app/code/Rbj/OutOfStock/etc/di.xml

<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
    <!--  out of stock product at end of list -->
    <type name="Magento\CatalogSearch\Model\ResourceModel\Fulltext\Collection">
        <plugin name="Rbj_OutOfStock::OutofstockEnd" type="Rbj\OutOfStock\Plugin\Product\ProductList\Toolbar"/>
    </type>
</config>

Need to override Stock.php file from Magento\CatalogInventory\Helper\Stock class.

Create Toolbar.php file, File Path, app/code/Rbj/OutOfStock/Plugin/Product/ProductList/Toolbar.php

<?php
/**
 * @author Rakesh Jesadiya
 * @package Rbj_OutOfStock
 */

namespace Rbj\OutOfStock\Plugin\Product\ProductList;

class Toolbar
{
    /**
     * @param \Magento\CatalogSearch\Model\ResourceModel\Fulltext\Collection $subject
     * @param bool $printQuery
     * @param bool $logQuery
     * @return array
     */
    public function beforeLoad(\Magento\CatalogSearch\Model\ResourceModel\Fulltext\Collection $subject, $printQuery = false, $logQuery = false)
    {
        $orderBy = $subject->getSelect()->getPart(\Zend_Db_Select::ORDER);
        $outOfStockOrderBy = array('is_salable DESC');
        /* reset default product collection filter */
        $subject->getSelect()->reset(\Zend_Db_Select::ORDER);
        $subject->getSelect()->order($outOfStockOrderBy);

        return [$printQuery, $logQuery];
    }
}

Clear Cache and Check in front. All the Out of stock product will display at end of listing page.

How to override cart/item/default.phtml in Magento 2?

For override default.phtml file in Magento 2, We need to create the plugin for it. We need to override Magento\Checkout\Block\Cart\AbstractCart Block file to override default.phtml in the module.
create the file at the location in your module.

I have created a module with Rbj/CartItem as {Namespace/Modulename},
app/code/Rbj/CartItem/etc/di.xml file,

<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
    <!-- override cart/item/default.phtml file -->
    <type name="Magento\Checkout\Block\Cart\AbstractCart">
        <plugin name="item-test" type="Rbj\CartItem\Plugin\Cart\AbstractCart" sortOrder="1"/>
    </type>
</config>

Create plugin file at below location in your module,
app/code/Rbj/CartItem/Plugin/Cart/AbstractCart.php

<?php
namespace Rbj\CartItem\Plugin\Cart;
class AbstractCart
{
    /*
    *   Override cart/item/default.phtml file
    *   \Magento\Checkout\Block\Cart\AbstractCart $subject
    *   $result
    */
    public function afterGetItemRenderer(\Magento\Checkout\Block\Cart\AbstractCart $subject, $result)
    {
        $result->setTemplate('Rbj_CartItem::cart/item/default.phtml');
        return $result;
    }
}

Create template file in your module view folder,
app/code/Rbj/CartItem/view/frontend/templates/cart/item/default.phtml
Keep your content in default.phtml file to override Cart module default template.

How to fetch getUrl() in Plugin or Observer file in magento 2?

By default you cant call $this->getUrl() method in Plugin or Observer file. When you need to call getUrl() function of Magento in plugin or observer file you need to pass dependancy as Magento\Framework\UrlInterface to construct() method.

public function __construct(
    \Magento\Framework\UrlInterface $urlBuilder
) {
    $this->urlBuilder = $urlBuilder;
}

Now In plugin or Observer function we can get getUrl() as below way,
$this->urlBuilder->getUrl(‘sales/order/view’, [‘order_id’ => 1]);

Run below command for get effect of our Dependancy Injection to code,

php bin/magento setup:di:compile

Above url will return as,
http://{yoururl.com}/admin/sales/order/view/order_id/1/