Firstly, let us note that preferences are destructive.

That means to say that you tell the Magento system to use your class instead of the original one. It is akin to a rewrite in Magento 1 and doing such things can make it difficult to other module developers to make changes in the same area of code. Nevertheless, there are use cases for it and an example of one is when you need to add additional functionality to a class that currently does not exist.

Example;

The breadcrumbs block does not have a getCrumbs() method and I wish to add this to allow me to fetch the crumbs later on.

I would argue that this would be useful to have in the core code anyway but this is what we have for now.

You start by telling Magento to use your block class;

Inside your module /etc/frontend/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">
    <preference for="Magento\Theme\Block\Html\Breadcrumbs" type="[Vendor]\[ModuleName]\Block\Theme\Html\Breadcrumbs" />
</config>

This tells Magento that every time the class Magento\Theme\Block\Html\Breadcrumbs is called, use my instance ([Vendor]\[ModuleName]\Block\Theme\Html\Breadcrumbs) instead.

Something I like to do when preferencing a class is to follow the structure of the original.

In this case, I take everything after the [Vendor] part (Theme\Block\Html\Breadcrumbs) and then use that path in my own module.

Next, let’s actually create our new class

In app/code/[codePool]/[Vendor][ModuleName]\Block\Theme\Html\Breadcrumbs.php:

<?php

namespace [Vendor]\[ModuleName]\Block\Theme\Html;

use Magento\Theme\Block\Html;

class Breadcrumbs extends Html\Breadcrumbs
{
    public function getCrumbs()
    {
        return $this->_crumbs;
    }

    protected function _toHtml()
    {
        $this->setModuleName($this->extractModuleName('Magento\Theme\Block\Html\Breadcrumbs'));
        return parent::_toHtml();
    }
}

This is fairly self explanatory.

You only have to look in the parent class to know that the crumbs are stored in the _crumbs var.

Wait, why am i also overwriting the _toHtml() method.

Well, as a consequence of our preference Magento now tries loading the template file from our new module.

This is not what we want.

I still want the original template to be used so you have to reset the module name.

Cool huh?

Code is available on github

  • magento2
  • preferences

Like this post? Share it :)


Related Posts

Back