Magento – Magento 2: Custom category attribute is missing scope

category-attributemagento2scope

In Magento 2.2.7 I have created a custom attribute (textarea, wysiwyg) for categories.

This is my InstallData

namespace MyVendor\Mods\Setup;

use Magento\Framework\Setup\InstallDataInterface;
use Magento\Framework\Setup\ModuleContextInterface;
use Magento\Framework\Setup\ModuleDataSetupInterface;
use Magento\Eav\Setup\EavSetup;
use Magento\Eav\Setup\EavSetupFactory;

class InstallData implements InstallDataInterface
{
    private $eavSetupFactory;

    /**
     * Constructor
     *
     * @param \Magento\Eav\Setup\EavSetupFactory $eavSetupFactory
     */
    public function __construct(EavSetupFactory $eavSetupFactory)
    {
        $this->eavSetupFactory = $eavSetupFactory;
    }

    /**
     * {@inheritdoc}
     */
    public function install(
        ModuleDataSetupInterface $setup,
        ModuleContextInterface $context
    ) {
        $eavSetup = $this->eavSetupFactory->create(['setup' => $setup]);

        $eavSetup->addAttribute(
            \Magento\Catalog\Model\Category::ENTITY,
            'long_description',
            [
                'type' => 'text',
                'label' => 'Long Description',
                'input' => 'textarea',
                'sort_order' => 5,
                'global' => 0,
                'visible' => true,
                'required' => false,
                'user_defined' => false,
                'default' => null,
                'group' => 'General Information',
                'searchable' => true,
                'is_html_allowed_on_front' => true,
                'wysiwyg_enabled' => true
            ]
        );
    }
}

The setup works fine, the field shows up in the backend and it saves the data I enter.

There are only two issues here and I sense they are connected:

  1. There is no scope. I cannot save different values for different storeviews. 'global' => 0 behaves identical to \Magento\Eav\Model\Entity\Attribute\ScopedAttributeInterface::SCOPE_STORE, I tried both. The value is always global, no matter what.

enter image description here

2. The value is not stored in the category flat tables. The field long_description does not show up in the flat tables at all.

I copied the field's setup from the catalog module's config for the description field (CategorySetup.php):

'description' => [
    'type' => 'text',
    'label' => 'Description',
    'input' => 'textarea',
    'required' => false,
    'sort_order' => 4,
    'global' => \Magento\Eav\Model\Entity\Attribute\ScopedAttributeInterface::SCOPE_STORE,
    'wysiwyg_enabled' => true,
    'is_html_allowed_on_front' => true,
    'group' => 'General Information',
],

What am I missing?

Thank you

EDIT: The attribute shows up in the flat tables after I forced a reindex. I thought the running cronjob would take care of it. Still the scope issue remains.

Best Answer

Ok, this seems to be a bug: https://github.com/magento/magento2/issues/13440

Solution (worked for me): https://github.com/magento/magento2/issues/13440#issuecomment-436712363

\app\code\Vendor\Module\etc\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">
    <type name="Magento\Catalog\Model\Category\DataProvider">
        <plugin name="categoryCustomAttributes" type="Vendor\Module\Plugin\Model\Category\DataProvider" sortOrder="1" disabled="false"/>
    </type>
</config>

\app\code\Vendor\Module\Plugin\Model\Category\DataProvider.php:

namespace Vendor\Module\Plugin\Model\Category;

class DataProvider extends \Magento\Catalog\Model\Category\DataProvider
{
    public function __construct(\Magento\Eav\Model\Config $eavConfig)
    {
        // not sure this is right, as $this->eavConfig is private
          $this->eavConfig = $eavConfig;
    }

    public function afterPrepareMeta(\Magento\Catalog\Model\Category\DataProvider $subject, $result)
    {
        $meta = array_replace_recursive($result, $this->_prepareFieldsMeta(
            $this->_getFieldsMap(),
            $subject->getAttributesMeta($this->eavConfig->getEntityType('catalog_category'))
        ));
        return $meta;
    }

    public function _prepareFieldsMeta($fieldsMap, $fieldsMeta)
    {
        $result = [];
        foreach ($fieldsMap as $fieldSet => $fields) {
            foreach ($fields as $field) {
                if (isset($fieldsMeta[$field])) {
                    $result[$fieldSet]['children'][$field]['arguments']['data']['config'] = $fieldsMeta[$field];
                }
            }
        }
        return $result;
    }

    public function _getFieldsMap()
    {
        $fields = parent::getFieldsMap();
        // Adjust per your needs here
        $fields['content'][] = 'long_description';
        return $fields;
    }
}

Followed by a bin/magento setup:di:compile

Related Topic