How to use Plugin, Preference to rewrite Block, Model, Controller, Helper in Magento 2

Method 1: Using Plugin

BLOCK OVERRIDE

Directory

app/code/VendorName/ModuleName/etc/di.xml

Content for this file

<?xml version="1.0"?>
 
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
    <type name="Magento\Catalog\Block\Product\View">
        <plugin name="VendorName-modulename-product-block" type="VendorName\ModuleName\Plugin\ProductPlugin" sortOrder="5" />
    </type>
</config>

Create ProductPlugin.php

app/code/VendorName/ModuleName/Plugin/ProductPlugin.php

Content for this file

<?php
 
namespace VendorName\ModuleName\Plugin;
 
class ProductPlugin
{    
    public function beforeGetProduct(\Magento\Catalog\Block\Product\View $subject)
    {
        // logging to test override    
        $logger = \Magento\Framework\App\ObjectManager::getInstance()->get('\Psr\Log\LoggerInterface');
        $logger->debug(__METHOD__ . ' - ' . __LINE__);        
    }
    
    public function afterGetProduct(\Magento\Catalog\Block\Product\View $subject, $result)
    {
        // logging to test override    
        $logger = \Magento\Framework\App\ObjectManager::getInstance()->get('\Psr\Log\LoggerInterface');
        $logger->debug(__METHOD__ . ' - ' . __LINE__);
        
        return $result;
    }
    
    public function aroundGetProduct(\Magento\Catalog\Block\Product\View $subject, \Closure $proceed)
    {
        // logging to test override    
        $logger = \Magento\Framework\App\ObjectManager::getInstance()->get('\Psr\Log\LoggerInterface');
        $logger->debug(__METHOD__ . ' - ' . __LINE__);
        
        // call the core observed function
        $returnValue = $proceed(); 
        
        // logging to test override        
        $logger->debug(__METHOD__ . ' - ' . __LINE__);
        
        return $returnValue;
    }    
}
?>

MODEL OVERRIDE

Directory

app/code/VendorName/ModuleName/etc/di.xml

Content for this file

<?xml version="1.0"?>
 
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
    <type name="Magento\Catalog\Model\Product">
        <plugin name="VendorName-modulename-product-model" type="VendorName\ModuleName\Plugin\ProductPlugin" sortOrder="1" />
    </type>    
</config>

Create ProductPlugin.php

app/code/VendorName/ModuleName/Plugin/ProductPlugin.php

Content for this file

<?php
 
namespace VendorName\ModuleName\Plugin;
 
class ProductPlugin
{    
    public function beforeSetName(\Magento\Catalog\Model\Product $subject, $name)
    {
        // logging to test override    
        $logger = \Magento\Framework\App\ObjectManager::getInstance()->get('\Psr\Log\LoggerInterface');
        $logger->debug('Model Override Test before');
        
        return $name;
    }
            
    public function afterGetName(\Magento\Catalog\Model\Product $subject, $result)
    {            
        // logging to test override    
        $logger = \Magento\Framework\App\ObjectManager::getInstance()->get('\Psr\Log\LoggerInterface');
        $logger->debug('Model Override Test after');
        
        return $result;
    }    
}
?>

CONTROLLER OVERRIDE

Directory

app/code/VendorName/ModuleName/etc/di.xml

Content for this file

<?xml version="1.0"?>
 
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">    
    <type name="Magento\Catalog\Controller\Product\View">
        <plugin name="VendorNameModuleNameControllerProductView" type="VendorName\ModuleName\Plugin\ProductPlugin" sortOrder="10"/>
    </type>
</config>

Create ProductPlugin.php

app/code/VendorName/ModuleName/Plugin/ProductPlugin.php

Content for this file

<?php
 
namespace VendorName\ModuleName\Plugin;
 
class ProductPlugin
{        
    public function aroundExecute(\Magento\Catalog\Controller\Product\View $subject, \Closure $proceed)
    {
        // logging to test override    
        $logger = \Magento\Framework\App\ObjectManager::getInstance()->get('\Psr\Log\LoggerInterface');
        $logger->debug(__METHOD__ . ' - ' . __LINE__);
        
        // call the core observed function
        $returnValue = $proceed(); 
        
        // logging to test override        
        $logger->debug(__METHOD__ . ' - ' . __LINE__);
        
        return $returnValue;
    }
}
?>

HELPER OVERRIDE

Directory

app/code/VendorName/ModuleName/etc/di.xml

Content for this file
 
<?xml version="1.0"?>
 
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">    
    <type name="Magento\Catalog\Helper\Data">
        <plugin name="VendorNameModuleNameHelperData" type="VendorName\ModuleName\Plugin\ProductPlugin" sortOrder="10"/>
    </type>
</config>

Create ProductPlugin.php

app/code/VendorName/ModuleName/Plugin/ProductPlugin.php

Content for this file

<?php
 
namespace VendorName\ModuleName\Plugin;
 
class ProductPlugin
{    
    public function aroundGetProduct(\Magento\Catalog\Helper\Data $subject, \Closure $proceed)
    {
        // logging to test override    
        $logger = \Magento\Framework\App\ObjectManager::getInstance()->get('\Psr\Log\LoggerInterface');
        $logger->debug(__METHOD__ . ' - ' . __LINE__);
        
        // call the core observed function
        $returnValue = $proceed(); 
        
        // logging to test override        
        $logger->debug(__METHOD__ . ' - ' . __LINE__);
        
        return $returnValue;
    }
}
?>

Method 2: Using Preference

BLOCK OVERRIDE

Directory

app/code/VendorName/ModuleName/etc/di.xml

Content for this file

<?xml version="1.0"?>
 
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
    <preference for="Magento\Catalog\Block\Product\View" type="VendorName\ModuleName\Block\Catalog\Product\View" />
</config>

Create View.php

app/code/VendorName/ModuleName/Block/Catalog/Product/View.php

Content for this file

<?php
 
namespace VendorName\ModuleName\Block\Catalog\Product;
 
class View extends \Magento\Catalog\Block\Product\View
{
    /**
     * Retrieve current product model
     *
     * @return \Magento\Catalog\Model\Product
     */
    public function getProduct()
    {
        // logging to test override    
        $logger = \Magento\Framework\App\ObjectManager::getInstance()->get('\Psr\Log\LoggerInterface');
        $logger->debug('Block Override Test');
        
        if (!$this->_coreRegistry->registry('product') && $this->getProductId()) {
            $product = $this->productRepository->getById($this->getProductId());
            $this->_coreRegistry->register('product', $product);
        }
        return $this->_coreRegistry->registry('product');
    }
}
?>

MODEL OVERRIDE

app/code/VendorName/ModuleName/etc/di.xml

Content for this file

<?xml version="1.0"?>
 
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">    
    <preference for="Magento\Catalog\Model\Product" type="VendorName\ModuleName\Model\Catalog\Product" />
</config>

Create Product.php

app/code/VendorName/ModuleName/Model/Catalog/Product.php

Content for this file

<?php
 
namespace VendorName\ModuleName\Model\Catalog;
 
class Product extends \Magento\Catalog\Model\Product
{    
    /**
     * Get product name
     *
     * @return string
     * @codeCoverageIgnoreStart
     */
    public function getName()
    {        
        // logging to test override    
        $logger = \Magento\Framework\App\ObjectManager::getInstance()->get('\Psr\Log\LoggerInterface');
        $logger->debug('Model Override Test');
    
        return $this->_getData(self::NAME);
    }
}
?>

CONTROLLER OVERRIDE

Directory

app/code/VendorName/ModuleName/etc/di.xml

Content for this file

<?xml version="1.0"?>
 
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">    
    <preference for="Magento\Catalog\Controller\Product\View" type="VendorName\ModuleName\Controller\Catalog\Product\View" />
</config>

Create View.php

app/code/VendorName/ModuleName/Controller/Product/View.php

Content for this file

<?php
 
namespace VendorName\ModuleName\Controller\Catalog\Product;
 
class View extends \Magento\Catalog\Controller\Product\View
{    
    /**
     * Product view action
     *
     * @return \Magento\Framework\Controller\Result\Forward|\Magento\Framework\Controller\Result\Redirect
     */
    public function execute()
    {
        // logging to test override    
        $logger = \Magento\Framework\App\ObjectManager::getInstance()->get('\Psr\Log\LoggerInterface');
        $logger->debug('Controller Override Test');
        
        // Get initial data from request
        $categoryId = (int) $this->getRequest()->getParam('category', false);
        $productId = (int) $this->getRequest()->getParam('id');
        $specifyOptions = $this->getRequest()->getParam('options');
 
        if ($this->getRequest()->isPost() && $this->getRequest()->getParam(self::PARAM_NAME_URL_ENCODED)) {
            $product = $this->_initProduct();
            if (!$product) {
                return $this->noProductRedirect();
            }
            if ($specifyOptions) {
                $notice = $product->getTypeInstance()->getSpecifyOptionMessage();
                $this->messageManager->addNotice($notice);
            }
            if ($this->getRequest()->isAjax()) {
                $this->getResponse()->representJson(
                    $this->_objectManager->get('Magento\Framework\Json\Helper\Data')->jsonEncode([
                        'backUrl' => $this->_redirect->getRedirectUrl()
                    ])
                );
                return;
            }
            $resultRedirect = $this->resultRedirectFactory->create();
            $resultRedirect->setRefererOrBaseUrl();
            return $resultRedirect;
        }
 
        // Prepare helper and params
        $params = new \Magento\Framework\DataObject();
        $params->setCategoryId($categoryId);
        $params->setSpecifyOptions($specifyOptions);
 
        // Render page
        try {
            $page = $this->resultPageFactory->create(false, ['isIsolated' => true]);
            $this->viewHelper->prepareAndRender($page, $productId, $this, $params);
            return $page;
        } catch (\Magento\Framework\Exception\NoSuchEntityException $e) {
            return $this->noProductRedirect();
        } catch (\Exception $e) {
            $this->_objectManager->get('Psr\Log\LoggerInterface')->critical($e);
            $resultForward = $this->resultForwardFactory->create();
            $resultForward->forward('noroute');
            return $resultForward;
        }
    }    
}
?>

HELPER OVERRIDE

Directory

app/code/VendorName/ModuleName/etc/di.xml

Content for this file

<?xml version="1.0"?>
 
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
    <preference for="Magento\Catalog\Helper\Data" type="VendorName\ModuleName\Helper\Catalog\Data" />
</config>

Create Data.php

app/code/VendorName/ModuleName/Helper/Catalog/Data.php

Content for this file

<?php
 
namespace VendorName\ModuleName\Helper\Catalog;
 
class Data extends \Magento\Catalog\Helper\Data
{    
    /**
     * Retrieve current Product object
     *
     * @return \Magento\Catalog\Model\Product|null
     */
    public function getProduct()
    {
        // logging to test override    
        $logger = \Magento\Framework\App\ObjectManager::getInstance()->get('\Psr\Log\LoggerInterface');
        $logger->debug('Helper Override Test');
        
        return $this->_coreRegistry->registry('current_product');
    }
}
?>


If you need any kind of help you can visit TheOnlineHelper