Magento2: Category Image Use Default fails

Created on 10 Nov 2017  路  10Comments  路  Source: magento/magento2

In multi store view scenario setting an image for a category under the "All Store Views" view by default does not create an entry in catalog_category_entity_varchar table which is correct. Moving into another store view (non root) and opening the same category it shows that it is using "Use Default" for the category image, which is also correct.
If the user chooses to save the category (without changing the category image) the system creates a new entry in catalog_category_entity_varchar for the store view.
This causes considerable issues hereafter, including the category no longer falling back to default image. In fact the code picks up the value and treats it as valid and continues as if the value is correct. Furthermore, the "Use Default" is no longer maintainable (reverts to off on every save).

Preconditions

  1. Magento 2.2.1
  2. PHP 7.0.22

Steps to reproduce

  1. Multiple store views
  2. Set image for "All Store Views" for a category
  3. Save without changing the category image for the same category on another store view.

Expected result

  1. Save category should respect the Use Default flag.
  2. Save category should with Use Default should not be creating a new row in the database.

Actual result

  1. Save category creates a entry in catalog_category_entity_varchar
  2. Category assumes null as the correct value not longer respecting "Use Default".

The code that I've seen thus far suggests that a value for the image of a category is respected as a valid value for the store view. I also saw that the varchar type is "nullable" acceptable for "use_default" when saving the category.

The only feedback I can give here in terms of code is that the latest versions (2.1.9+) try to implement a use default functionality for this field and fails to properly manage it by setting it to which is mean to be treated as the "use default" flag but in essence reads it back as a valid value (not a flag).

Clear Description Format is valid needs update

Most helpful comment

When i looked at @georgios-2317 solution and checked the code i saw there is a event in place to fix this without rewriting the entire class. The event is called catalog_category_prepare_save and is called before the Use default Value loop in the Save.php. This code will fix the issue without the rewrite:

public function execute(\Magento\Framework\Event\Observer $observer)
{
    /** @var Category $category */
    $category = $observer->getEvent()->getCategory();
    $categoryPostData = $observer->getEvent()->getRequest()->getPostValue();

    if(empty($categoryPostData)){
        return;
    }

    /**
     * Check "Use Default Value" checkboxes values
     */
    if (isset($categoryPostData['use_default']) && !empty($categoryPostData['use_default'])) {
        foreach ($categoryPostData['use_default'] as $attributeCode => $attributeValue) {
            if (empty($attributeValue)) {
                continue;
            }
            /** @var Attribute $attribute */
            $attribute = $category->getAttributes()[$attributeCode];
            if($attribute->isStatic()){
                continue;
            }
            if(!in_array($attribute->getBackendType(), ['varchar', 'text', 'datetime'])){
                continue;
            }
            $attribute->setIsRequired(false);
            $category->setData($attributeCode, false);
            $category->lockAttribute($attributeCode);
        }
    }

}

All 10 comments

The issue extends to "Display Mode" field as well (haven't dug in the code).

The following (stupid) change addresses the issue for now for the image field.
I fear say that the whole "Use Default" feature wasn't very well thought out.

\Magento\Catalog\Controller\Adminhtml\Category\Save  

            /**
             * Check "Use Default Value" checkboxes values
             */
            if (isset($categoryPostData['use_default']) && !empty($categoryPostData['use_default'])) {
                foreach ($categoryPostData['use_default'] as $attributeCode => $attributeValue) {
                    if ($attributeValue) {
                        if ($attributeCode=="image" || $attributeCode=="display_mode")
                            $category->setData($attributeCode, false);
                        else
                            $category->setData($attributeCode, null);
                    }
                }
            }

Update:

_(previous post deprecated)_

There is some mixup in logic in Magento EAV Use Default as mentioned above allowing null to be treated as a valid value for some attribute types but when saving the attribute values when Use Default is set, sets it to null, in essence not maintaining the condition for detecting Use Default.

What I ended up doing is to flag values with Use Default for row deletion from EAV table.

This is essence (for non-default store views):

  1. Keeps the database row count to minimal
  2. Treats missing rows as Use Default
  3. Allows null as valid values when row exists

I cleaned by database tables from all null values (what a bloat) and then overrode
Save.php (replaced completely due to private scope of functions and variables) to force the new handling of Use Default:

DELETE FROM catalog_category_entity_varchar WHERE ISNULL(value) AND store_id<>0;
DELETE FROM catalog_category_entity_int WHERE ISNULL(value) AND store_id<>0;
DELETE FROM catalog_category_entity_text WHERE ISNULL(value) AND store_id<>0;
DELETE FROM catalog_category_entity_decimal WHERE ISNULL(value) AND store_id<>0;
DELETE FROM catalog_category_entity_datetime WHERE ISNULL(value) AND store_id<>0;
            /**
             * Check "Use Default Value" checkboxes values
             */
            if (isset($categoryPostData['use_default']) && !empty($categoryPostData['use_default'])) {
                foreach ($categoryPostData['use_default'] as $attributeCode => $attributeValue) {
                    if ($attributeValue) {
                        /** @var Attribute $attribute */
                        $attribute = $category->getAttributes()[$attributeCode];
                        // Handle static variables
                        if (!$attribute->isStatic()) {
                            // Bypass checks for 'is-required'
                            $attribute->setIsRequired(false);
                            // For non-numberic types set the value to 'false' to trigger their removal from the db
                            if ($attribute->getBackendType() == "varchar" || $attribute->getBackendType() == "text" || $attribute->getBackendType() == "datetime") {
                                $category->setData($attributeCode, false);
                            } else {
                                // For numeric values set the data to 'null', in hope that they are deleted.
                                 $category->setData($attributeCode, null);
                            }
                        } else {
                            // This was the original behavior which we fall back for static attributes
                            $category->setData($attributeCode, null);
                        }

                    }
                }
            }

All checks and tests thus far suggest the needed functionality is back.

@georgios-2317, thank you for your report.
We've created internal ticket(s) MAGETWO-83735 to track progress on the issue.

Did anyone find a 100% sure solution?
I tried @georgios-2317 solution, it seems to work, but it forces us to rewrite the whole method.
I still see the ticket in branch [2.3-develop] "todo" part but the project itself is closed....

Just bumped into this issue today (Magento 2.2.3). What's the update on this? Is @ georgios-2317 solution currently the only viable (although I would prefer to do it with a plugin afterExecute() for example).

It would be nice if we changed the title of the issue to reflect the broader problem : The fact that we can't use null values to set store-level attribute to the global-level attribute using repositories.

When i looked at @georgios-2317 solution and checked the code i saw there is a event in place to fix this without rewriting the entire class. The event is called catalog_category_prepare_save and is called before the Use default Value loop in the Save.php. This code will fix the issue without the rewrite:

public function execute(\Magento\Framework\Event\Observer $observer)
{
    /** @var Category $category */
    $category = $observer->getEvent()->getCategory();
    $categoryPostData = $observer->getEvent()->getRequest()->getPostValue();

    if(empty($categoryPostData)){
        return;
    }

    /**
     * Check "Use Default Value" checkboxes values
     */
    if (isset($categoryPostData['use_default']) && !empty($categoryPostData['use_default'])) {
        foreach ($categoryPostData['use_default'] as $attributeCode => $attributeValue) {
            if (empty($attributeValue)) {
                continue;
            }
            /** @var Attribute $attribute */
            $attribute = $category->getAttributes()[$attributeCode];
            if($attribute->isStatic()){
                continue;
            }
            if(!in_array($attribute->getBackendType(), ['varchar', 'text', 'datetime'])){
                continue;
            }
            $attribute->setIsRequired(false);
            $category->setData($attributeCode, false);
            $category->lockAttribute($attributeCode);
        }
    }

}

Hi @engcom-Delta. Thank you for working on this issue.
Looks like this issue is already verified and confirmed. But if you want to validate it one more time, please, go though the following instruction:

  • [ ] 1. Add/Edit Component: XXXXX label(s) to the ticket, indicating the components it may be related to.
  • [ ] 2. Verify that the issue is reproducible on 2.4-develop branch

    Details- Add the comment @magento give me 2.4-develop instance to deploy test instance on Magento infrastructure.
    - If the issue is reproducible on 2.4-develop branch, please, add the label Reproduced on 2.4.x.
    - If the issue is not reproducible, add your comment that issue is not reproducible and close the issue and _stop verification process here_!

  • [ ] 3. If the issue is not relevant or is not reproducible any more, feel free to close it.


Hi @jeroenkosse Unfortunately, I am not able to reproduce issue you described on 2.4-develop
Steps to reproduce:

  • Multiple store views:

    • Default Store View


    • Second Store View


    • Third Store View

      image

  • Create category cat1 and set image for Category Image
  • Change store view
  • Edit Description section and save category

Actual result:
:heavy_check_mark: Image is present on category edit page on each store view with checked "Use Default Value"
image

:heavy_check_mark: No new records are created after category was saved.
image

Are you still facing this issue on the latest 2.4-develop?

@jeroenkosse, we are closing this issue due to inactivity. If you'd like to update it, please reopen the issue.

Was this page helpful?
0 / 5 - 0 ratings