Magento 2 Adding Extension Attributes To Entity

It is impossible for third-party developers to change the API Data interfaces which are defined in the Magento Core code. Nevertheless, most of these entities come with a feature called extension attributes. In this article, I will show you how to add extension attributes to the entity in Magento 2. Let’s see how it done!

Note: Check the interface for the methods getExtensionAttributes() and setExtensionAttributes() to determine if they are available for the entity.

Step 1: Retrieve A Product/ List Of Products From The Magento API {step-1}

To recall a product or a list of products from the Magento API, you need to make an API request to the suitable service (the Product Repository in this case). The response to these requests will returns objects with the following structure:

Product Response

<product>
    <id>1</id>
    <sku>some-sku</sku>
    <custom_attributes><!-- Custom Attributes Data --></custom_attributes>
    <extension_attributes><!-- Here should we add extension attributes data --></extension_attributes>
</product>

Product List Response

<products>
    <item>
        <id>1</id>
        <sku>some-sku</sku>
        <custom_attributes><!-- Custom Attributes Data --></custom_attributes>
        <extension_attributes><!-- Here should we add extension attributes data --></extension_attributes>
    </item>
    <item>
        <id>2</id>
        <sku>some-sku-2</sku>
        <custom_attributes><!-- Custom Attributes Data --></custom_attributes>
        <extension_attributes><!-- Here should we add extension attributes data --></extension_attributes>
    </item>
</products>

Step 2: Add Plugin To Product Repository

Using an after plugin on Product Reposibility is neccessary to add extension attibutes. The plugin need to follow the methods including save, get, getList. We can add scalar which is a simple attribute, and non-scalar which can be shown by Data Object.

public function afterGet
(
    \Magento\Catalog\Api\ProductRepositoryInterface $subject,
    \Magento\Catalog\Api\Data\ProductInterface $entity
) {
    $ourCustomData = $this->customDataRepository->get($entity->getId());

    $extensionAttributes = $entity->getExtensionAttributes(); /** get current extension attributes from entity **/
    $extensionAttributes->setOurCustomData($ourCustomData);
    $entity->setExtensionAttributes($extensionAttributes);

    return $entity;
}

AfterGet plugin:

Here is the simplest way to add extensions without causing a conflict:

  • Firstly, we get the entity’s extension attributes, in case they are already set.
  • Secondly, we add our extension attribute.
  • Finally, we set the extension attribute on the entity with ours included.

    AfterGetList plugin:

    You can do similar to afterGetList.

    AfterSave plugin:

    The afterSave plugin should manipulate the entity data before returning it:

public function afterSave
(
    \Magento\Catalog\Api\ProductRepositoryInterface $subject,
    \Magento\Catalog\Api\Data\ProductInterface $entity
) {
    $extensionAttributes = $entity->getExtensionAttributes(); /** get current extension attributes from entity **/
    $ourCustomData = $extensionAttributes->getOurCustomData();
    $this->customDataRepository->save($ourCustomData);

    return $entity;
}

However, in case some entities don’t have the implementation to fetch extension attribute, you will always retrieve null. Each time when you fetch extension attributes, you need to determine whether they are null or not. If they are null, we need to create them. To prevent such code duplication, we need to create afterGet plugin for our entity with extension attributes.

Let’s assume that the product entity doesn’t have any implementation of extension attributes, so you can view the our plugin, as following:

use Magento\Catalog\Api\Data\ProductExtensionInterface;
use Magento\Catalog\Api\Data\ProductInterface;
use Magento\Catalog\Api\Data\ProductExtensionFactory;

class ProductAttributesLoad
{
    /**
     * @var ProductExtensionFactory
     */
    private $extensionFactory;

    /**
     * @param ProductExtensionFactory $extensionFactory
     */
    public function __construct(ProductExtensionFactory $extensionFactory)
    {
        $this->extensionFactory = $extensionFactory;
    }

    /**
     * Loads product entity extension attributes
     *
     * @param ProductInterface $entity
     * @param ProductExtensionInterface|null $extension
     * @return ProductExtensionInterface
     */
    public function afterGetExtensionAttributes(
        ProductInterface $entity,
        ProductExtensionInterface $extension = null
    ) {
        if ($extension === null) {
            $extension = $this->extensionFactory->create();
        }

        return $extension;
    }
}

Now we need attach our plugin to ProductInterface:

<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
    <type name="Magento\Catalog\Api\Data\ProductInterface">
        <plugin name="ProductExtensionAttributeOperations" type="Magento\Catalog\Plugin\ProductAttributesLoad"/>
    </type>
</config>

Step 3: Configure Extension Attributes

For Scalar Attibutes

You should use below configuration:

<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Api/etc/extension_attributes.xsd">
    <extension_attributes for="Magento\Catalog\Api\Data\ProductInterface">
        <attribute code="first_custom_attribute" type="Magento\SomeModule\Api\Data\CustomDataInterface" />
        <attribute code="second_custom_attribute" type="Magento\SomeModule\Api\Data\CustomDataInterface" />
    </extension_attributes>
</config>

Then, you will get the following result:

<product>
    <id>1</id>
    <sku>some-sku</sku>
    <custom_attributes><!-- Custom Attributes Data --></custom_attributes>
    <extension_attributes>
        <first_custom_attribute>1</first_custom_attribute>
        <second_custom_attribute>2</second_custom_attribute>
    </extension_attributes>
</product>

For Non-scalar Attributes

You should use below configuration:

<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Api/etc/extension_attributes.xsd">
    <extension_attributes for="Magento\Catalog\Api\Data\ProductInterface">
        <attribute code="our_custom_data" type="Magento\SomeModule\Api\Data\CustomDataInterface[]" />
    </extension_attributes>
</config>

Then, you will get the following result:

<product>
    <id>1</id>
    <sku>some-sku</sku>
    <custom_attributes><!-- Custom Attributes Data --></custom_attributes>
    <extension_attributes>
        <our_custom_data>
            <first_custom_attribute>1</first_custom_attribute>
            <second_custom_attribute>2</second_custom_attribute>
        </our_custom_data>
    </extension_attributes>
</product>

Conclusion

Above is the detail instructions for adding extension attributes to entity in Magento 2. I hope that this article is useful for you. If you have any questions or want to discuss any things, feel free to leave a comment below, and I will give back to you!

Enjoyed the tutorial? Spread it to your friends!