“Use Default Value” for Multi Select Attributes Doesn’t Save for Store Scope View in Magento 2 Commerce (Enterprise) Edition

A few days ago I worked on a very interesting issue for a client in Magento 2 Commerce Edition. Basically, they have some multi-select product attributes and these attributes allow the admin user to add different values depending on the Store View because when these attributes were created, they were set to Store View in the Scope field.

Product Attribute Edit Page

However, whenever the admin user switched to a specific store view on the product edit page, on the admin panel, marked the field Use Default Value for any of these multi-select attributes, and clicked on the Save button, the field always returned unmarked and the multi-select attribute value didn’t change.

Pretty interesting, huh?

To reproduce this issue, you have to create a custom multi-select attribute like the one above and assign it to any attribute set. After this, edit any product on the admin page and keep the scope to the All Store Views. This is the default Ccope.

Now you can save any data on this attribute and save the product.

Now, switch to a specific store view.

Now, unmark the Use Default Value below this field and choose different values for it.

Hit the save button to save the product and wait to see the result when the page reloads.

See? Nothing happened!

After some time debugging it, it turned out to be a bug in Magento Commerce. This only happens in the Commerce edition because the bug resides in a module that is only present in the paid version of Magento. A module called Magento_CustomerCustomAttributes (Composer Package: magento/module-customer-custom-attributes).

For those who have access to this platform, if you open the following class and check the following method…

\Magento\CustomerCustomAttributes\Plugin\Catalog\UpdateMultiselectAttributes::afterInitializeFromData

It’s actually a plugin that is bound to

Here is the source code of this plugin class.

<?php
/**
 * Copyright © Magento, Inc. All rights reserved.
 * See COPYING.txt for license details.
 */
declare(strict_types=1);

namespace Magento\CustomerCustomAttributes\Plugin\Catalog;

use Magento\Catalog\Api\Data\ProductInterface;
use Magento\Catalog\Controller\Adminhtml\Product\Initialization\Helper;

/**
 * Updates multiselect attributes for product data
 */
class UpdateMultiselectAttributes
{
    /**
     * Update empty multiselect attributes for product data
     *
     * @param Helper $subject
     * @param ProductInterface $product
     * @return ProductInterface
     * @SuppressWarnings(PHPMD.UnusedFormalParameter)
     */
    public function afterInitializeFromData(Helper $subject, ProductInterface $product): ProductInterface
    {
        $productData = $product->getData();
        $attributes = $product->getAttributes();
        foreach ($attributes as $attrKey => $attribute) {
            if ($attribute->getFrontendInput() === 'multiselect') {
                if (array_key_exists($attrKey, $productData) && $productData[$attrKey] == null) {
                    $product->setData($attrKey, '');
                }
            }
        }
        return $product;
    }
}

Pay attention to the following conditional, on line 32:

if (array_key_exists($attrKey, $productData) && $productData[$attrKey] == null)

If the attribute is equal to null, then the attribute value becomes an empty string (''), so that an empty string is saved into the database.

I figured out that, whenever you mark the Use Default Value for any particular attribute and save the product from the product admin panel, the value that is set to this particular attribute is false (a boolean value), so that Magento knows the particular registry in the database for that particular attribute value, product, and store view must be deleted from the EAV tables (one of these below).

For instance.

The first row from the picture above represents the default value for All Store Views while the second one represents the value specific to the Portuguese Store View, in my example.

If the second one doesn’t exist…

Then the attribute shows the value properly, with the Use Default Value marked.

For deleting this row from the database, Magento needs to set the values for these attributes as false whenever the product is saved, so the EAV module removes these values from the database. The final class and method responsible for this are the following:

\Magento\Eav\Model\ResourceModel\AttributePersistor::processDeletes

However, what that plugin above does, is convert these false values into empty strings ('').

That said, the issue is with the following conditional:

$productData[$attrKey] == null

In this case, when $productData[$attrKey] is equal to false, it returns true. (Really? Are you serious?)

If we change the conditional to the following, the issue is gone and we’ll be able to use the Default Value for these attributes again.

$productData[$attrKey] === null

Solution

To fix this, create a patch, like the following.

--- a/vendor/magento/module-customer-custom-attributes/Plugin/Catalog/UpdateMultiselectAttributes.php
+++ b/vendor/magento/module-customer-custom-attributes/Plugin/Catalog/UpdateMultiselectAttributes.php
@@ -29,7 +29,7 @@
         $attributes = $product->getAttributes();
         foreach ($attributes as $attrKey => $attribute) {
             if ($attribute->getFrontendInput() === 'multiselect') {
-                if (array_key_exists($attrKey, $productData) && $productData[$attrKey] == null) {
+                if (array_key_exists($attrKey, $productData) && $productData[$attrKey] === null) {
                     $product->setData($attrKey, '');
                 }
             }

And apply it via composer.

{
    "name": "magento/project-enterprise-edition",
    "description": "eCommerce Platform for Growth (Enterprise Edition)",
    "type": "project",
    ....
    "extra": {
        ...
        "patches": {
            ...
            "magento/module-customer-custom-attributes": {
                "Use default value for multiselect attributes doesn't save for store scope views": "patches/composer/use-default-value-for-multiselect-products-attributes-does-not-save-for-store-scope-views.patch"
            }
        }
    }
}

If you don’t know how to apply a patch via composer, check this repository.

https://github.com/cweagans/composer-patches

And the documentation page.

https://docs.cweagans.net/composer-patches/

It’s a fantastic composer plugin created by Cameron Eagans (thanks bro!).

I hope this blog post helps you.

-Tiago

2 thoughts on ““Use Default Value” for Multi Select Attributes Doesn’t Save for Store Scope View in Magento 2 Commerce (Enterprise) Edition

Leave a comment