How did I deal with the rearrangement of attributes in magento?

A few weeks ago, I switched from our internal e-commerce team to a new mixed line-up of colleagues. I work in cooperation with the internal IT team of the United Fashion Group (UFG) and another external IT company that also works for the client. Together, we’re improving 7 e-shops (in different language versions) managed from one administration. In addition, there will soon be one more. It’s all running on Magento, which is a new challenge for me. 

Magento is an e-commerce platform that allows you to manage multiple online stores from one place. It’s a robust, but mainly well customizable solution that can be edited according to the client’s requirements and needs. It’s therefore particularly suitable for large or growing enterprises. It allows you to manage the entire life cycle of a product (creation, stocking, sale…) but also, for example, smaller functions, such as search engine optimization.

At the time of writing this article (October 2022), there are over 3,300 plugins on the Marketplace for Magento extensions. It should be mentioned that some extensions are free, but others are subject to extra costs. Most extensions are related to Content and Customization, providing, for example, Layered navigation, which allows us to select multiple product attributes simultaneously as part of product filtering in the catalog.

Sometimes you also need a plugin

My first tasks on this platform were “get-to-know-it” ones – adjusting the rounding, adding a new filter to the administration or rearranging the attributes (attributes represent information or properties of objects such as products – the product attributes include, for example, price, manufacturer or color and many others).

Some tasks needed to be solved using plugins, so we’ll now talk about them briefly. In the case of the attribute rearrangement task, the plugins were used because the main functionality is located in the Magento core (by the term Magento core, in this case, we mean the whole Magento, which is installed in the /vendor directory, where no changes are made to the code), or in the corresponding modules, and thus it wasn’t possible to make the necessary changes directly in the given methods.

Types and prefixes

Using the plugins, it’s possible to influence the behavior of the required methods within a specific module and for the needs of the scope (admin/frontend/etc.). This can be achieved by adjusting the input/output parameters or wrapping the method in a kind of “bubble” in which this method will be performed together with the relevant changes. A method which is modified in this way is called an observed method.

There are three types of plugins, such as:

  • Before methods – performed before executing the observed method. They’re used to modify the input arguments of the observed method.
  • After methods – performed after the completion of the observed method. They’re used to modify the result of the observed method.
  • Around methods – performed before and after the execution of the observed method. They’re used to overwrite (modify inputs and the result of) the observed method. It isn’t recommended to use them because they negatively affect performance.

 

An important role in creating plugins is played by the prefix within the name of the new method, which will modify the observed method. This prefix depends on the type of plugin you want to create. When creating a before plugin, the prefix of the new method must be “before”. For the before plugin for the observed foo() method, we would create a method called beforeFoo(). This rule applies by analogy to the after and around plugins.

Sample of the assignment and solution for the attribute rearrangement task:

Within the product catalogue, it’s necessary to change the order of the displayed (acquired) attributes in the administration during the bulk update attributes action. There’s also a list of the first 15 sorted attributes, the order of the other attributes doesn’t matter.

The attributes are displayed in the order in which they are obtained. Based on the assignment, it’s therefore necessary to create a functionality that ensures that the resulting attributes are always sorted according to the requirements when they are obtained. Therefore, we’ll create an after plugin.

As part of the solution, it’s necessary to declare a new plugin for the respective module. In this case, a plugin is defined for the Magento\Catalog\Block\ Adminhtml\Product\Edit\Action\Attribute\Tab\Attributes class, named Custom_Catalog::afterGetAttributes, whose functionality is within the Custom\Catalog\Plugin\RearrangeAttributesPlugin class.

<type name="Magento\Catalog\Block\Adminhtml\Product\Edit\Action\Attribute\Tab\Attributes">
 <plugin name="Custom_Catalog::afterGetAttributes" 
 type="Custom\Catalog\Plugin\RearrangeAttributesPlugin"/>
 </type>

Within this class there’s a functionality ensuring the sorting of attributes according to the requirements of the assignment.

<?php
namespace Custom\Catalog\Plugin;
use Magento\Catalog\Block\Adminhtml\Product\Edit\Action\Attribute\Tab\Attributes;
use Magento\Framework\DataObject;
class RearrangeAttributesPlugin
{
    /**
     * @var string
     */
    private const REARRANGE_ATTRIBUTE_KEY = 'attribute_code';

This value represents the key below which we want the individual attributes in the field to be located. Each attribute has a unique value, which is stored under this key.

    /**
     * @var string
     */
    private const REARRANGE_ATTRIBUTE_ID = 'attribute_id';

This value represents the original key in the attribute field, under which the individual attributes are stored. Specifically, it’s their unique identifier.

    /**
     * @var string[]
     */
    private $rearrangeAttributeKeys = [
        'price',
        'config_price',
        'special_price',
        'special_from_date',
        'special_to_date',
        'cost',
        'update_on_observer',
        'season_report',
        'manufacturer',
        'color_filter',
        'news_from_date',
        'news_to_date',
        'material_description',
        'product_tag',
        'category_report',
    ];

This field contains the first fifteen attribute codes. These values are located under the “attribute_code” key in the attribute field.

    /**
     * @param Attributes $subject
     * @param DataObject[] $result
     *
     * @return DataObject[]
     * @SuppressWarnings(PHPMD.UnusedFormalParameter)
     */
    public function afterGetAttributes(Attributes $subject, array $result): array

Function ensuring the correct sorting of attributes.

    {
        $rearrangeAttributes = [];
        foreach ($result as $key => $attribute) {
            $result[$attribute->getData(self::REARRANGE_ATTRIBUTE_KEY)] = $attribute;
            unset($result[$key]);
        }

The first cycle changes the keys. The new key under which the attribute will be stored is its “attribute_code”.

        foreach ($this->rearrangeAttributeKeys as $attributeKey) {
            if (isset($result[$attributeKey])) {
                $rearrangeAttributes[] = $result[$attributeKey];
                unset($result[$attributeKey]);
            }
        }

The second cycle takes care of filtering the required attributes. Now that the attributes are stored under a different key, quick access to the given attribute is ensured. We then remove the found element from the field. At the end of the cycle, we’ll have an array of ordered attributes and an array of the remaining unordered attributes.

        $result = array_merge($rearrangeAttributes, $result);

Now we’re going to combine these two fields into one. It will start with ordered attributes, followed by the remaining unordered attributes.

        $output = [];
        foreach ($result as $attribute) {
            $output[$attribute->getData(self::REARRANGE_ATTRIBUTE_ID)] = $attribute;
        }

The last cycle takes care of setting the keys. The key under which the attributes will now be stored in the field will be their original key and therefore their “attribute_id”.

        return $output;
    }
}

We deal with such assignments on a daily basis, alone or in a team. Currently, I’m mainly engaged in the preparation of a new e-shop, which we’ll soon add to the other UFG stores. As this is a large-scale project, every new functionality affects everything else and therefore thorough testing is very important.

On the other hand, the advantage of a large project is more space for optimization and code reviews. What’s also great about Magento is that it’s a world-renowned open-source platform, so it’s possible to consult a huge online community on any issue. Moreover, I always have colleagues on hand who are happy to help me.