Extending Third Party Modules in Magento 2

controllersextendmagento2modulethird-party-module

In Magento 2 for themes, it's incredibly easy to extend from a parent. This follows a nice logical hierarchy when inheriting theme .xml and .phtml files. This is clearly defined in the theme.xml.

However in my experience thus far with Magento 2. Modules by nature are (And understandably) entirely encapsulated with their respected module namespaces. Which in most cases, inherit from the Magento 2 Vendor core.

Although when wanting to inherit from a Third party module that may, or may not already extend from the Magento core. As I may have business specific functionality to add.

Say for example, the Third Party namespace and folder structure that extends the a Third Party's Blog:

  • /app/code/[ThirdPartyVendor]/[SimpleBlog]
    • /Block
      • ...
    • /Controller
      • /Post
        • Index.php

This SimpleBlog's core functionality has some awesome features that they've added – although I need to tweak some aspects.

I could just edit directly their Module code (Inside Index.php). Although this obviously would lead to update problems.

So what if I reference the Module from my Own Controller implementation of the Module, of the same name within my Vendor folder?

<?php
/**
 * Fetch the Third Parties' Original Implementation.
**/
require( "/app/code/[ThirdPartyVendor]/[SimpleBlog]/Controller/../Index.php" );

/**
 * My Vendor Namepace
**/
namespace MyVendor\SimpleBlogExtended\Controller\Post;

/**
 * My Class Implemention, Extending upon the original Third Party Class
**/
class Index extends \ThirdPartyVendor\SimpleBlog\Post
{
     //
     public function __construct()
     {
         //Extend the original functionality.
         parent::__construct();
     }

     //
     public function myNewFunctionality()
     {

     }
}
?>

But then this isn't clean, nor would this account for any other dependencies?

The other method I thought of – which is widely documented for extending the core, is di.xml Dictating the objectManager to take a perference of what to inject for a to-be-loaded class. Although this isn't a full module inheritance so to speak.

<config xmlns:xsi="http://www.w3.org/2001/XMLSchema instance="...">
     <preference for="ThirdPartyVendor\SimpleBlog\Controller\Post.."
                 type="MyVendor\SimpleBlogExtended\Controller\Post.." />
</config>

Same methodology could be applied for routes.xml – taking precedence a request.

Apologies that this may seem very broad; but TLDR: Best Practice for extending a Module; not it's themes?

Best Answer

And that's why they created plugins: http://devdocs.magento.com/guides/v2.1/extension-dev-guide/plugins.html

There are three types of plugins (before, around, after), which allow you to run your customizations relative to the function you want to extend.

You're right, using preferences may result in difficulties when upgrading, and should be used if plugins won't cut it.

There's also observers, but (opinion:) I think Magento will want to move away from them and double down on plugins.


Plugins also allow you to set a priority so you, or another vendor aren't stepping over each others toes:

The sortOrder property for plugins determine when their before, after, or around methods get called when several plugins are observing the same method.


Couple of things to be aware of when using plugins:

  • They only work on public functions

  • Using the around plugin can be dangerous because you can completely override the method you're trying to extend, and it can stop other plugins for running:

If the around method does not call the callable, it will prevent the execution of all the plugins next in the chain and the original method call.


If you're more familiar with the frontend, plugins are (also opinion:) kinda like the Mage/utils/wrapper Js module.

Checkout this answer as well: Magento 2 Plugin implementation for js frontend?

Related Topic