5

How to update attribute option (update label for a store) programmatically?

enter image description here

4
  • You didn't specify which type of attribute it is, a product attribute ? or a customer attribute? Dec 9, 2017 at 13:04
  • Product attribute
    – RDK
    Dec 10, 2017 at 13:51
  • @RDK can you share your code what you have tried so far so I can help you better way Dec 11, 2017 at 11:42
  • Im working on it, and I see that the best way to do it it's to create/update them is to send query to DB directly
    – RDK
    Dec 11, 2017 at 14:58

5 Answers 5

5
+100

Take a look at \Magento\Eav\Model\ResourceModel\Entity\Attribute::_saveStoreLabels(AbstractModel $object). We can see how to save store lables.

As we can see, we can insert data into table eav_attribute_label directly.

$bind = ['attribute_id' => $object->getId(), 'store_id' => $storeId, 'value' => $label];
$connection->insert($this->getTable('eav_attribute_label'), $bind);
1
  • Yep I've implemented this feature with help of direct queries to the DB.
    – RDK
    Dec 13, 2017 at 13:39
5

I was able to update product attribute option label by using ProductAttributeRepositoryInterface interface.

/**
* @var \Magento\Catalog\Api\ProductAttributeRepositoryInterface
*/
private $productAttributeRepository;

public function updateOption($attributeCode, $optionId, $optionLabel) {
    $attr = $this->productAttributeRepository->get($attributeCode);
    $options = $attr->getOptions();
    $sortOrder = 0;
    foreach ($options as $option) {
        if ($option->getValue() == $optionId) {
            $option->setLabel($optionLabel);
            $option->setSortOrder($sortOrder);
            $attr->setOptions([$option]);
            $this->productAttributeRepository->save($attr);
            break;
        }
        $sortOrder++;
    }
}

You can use setStoreLabels method additionally or instead of setLabel if you want to update labels for several store views.

Also note that the save($attr) is implemented in a way that all option values are deleted and inserted again (eav_attribute_option_value table). And this is what happens when you edit option values via admin page, so I think it's not a real problem.

Another issue here is that Magento doesn't load option's SortOrder parameter (on ver. 2.1.9), so we have to manually calculate the option's sort order. You can also use \Magento\Eav\Model\ResourceModel\Entity\Attribute\Option\CollectionFactory to load actual SortOrder value.

/**
 * @var \Magento\Eav\Model\ResourceModel\Entity\Attribute\Option\CollectionFactory
 */
private $optionCollectionFactory;

...

$collection = $this->optionCollectionFactory->create()->setIdFilter($optionId)->load();
foreach ($collection as $optionResourceModel) {
    $sortOrder = $optionResourceModel->getSortOrder();
}
1
  • hi @Rustem, $option->setLabel($optionLabel); is updated only in admin, but not indefault store view Dec 14, 2018 at 13:22
2

If You Want to Add Attribute with InstallerScript this will Work perfectly.

In Your [Vedor]\[Module]\Setup\InstallData.php

   $eavSetup->addAttribute(
        \Magento\Catalog\Model\Product::ENTITY,
        'myattribute',
        [
            'type' => 'text',
            'backend' => 'Magento\Eav\Model\Entity\Attribute\Backend\ArrayBackend',
            'frontend' => '',
            'label' => 'My Attribute',
            'input' => 'multiselect',
            'class' => '',
    // instead values change your key as value and add your option like below with in `option_1`  array put key as store_id and label as value 
            'option' => ['value' => 
                            [
                             'option_1'=>[
                                  0=>123,    // here 0 is store id and 123 is value
                                  1=>456,
                                  13=>4444,
                                  14=>12121,
                                  15=>1212,
                                  16=>123
                                  ],
                            'option_2'=>[
                                  0=>789,
                                  1=>546,
                                  13=>2211,
                                  14=>32123,
                                  15=>123123123,
                                  16=>5152
                                  ],
                            ],
                           'order'=>//Here We can Set Sort Order For Each Value.
                                 [
                                      'option_1'=>1,
                                      'option_2'=>2
                                 ]
                        ], 
            'global' => \Magento\Eav\Model\Entity\Attribute\ScopedAttributeInterface::SCOPE_STORE,
            'visible' => true,
            'required' => false,
            'user_defined' => true,
            'default' => '',
            'searchable' => false,
            'filterable' => false,
            'comparable' => false,
            'visible_on_front' => false,
            'used_in_product_listing' => true,
            'wysiwyg_enabled' => true,
            'unique' => false,
            'apply_to' => ''
        ]
    );
2

We can updated attribute option (update label for a store) programmatically using following script

I was able to update product attribute option value using this script

// This Function Get Attribute code and Attribute Value.

function getOptionId($atributeCode,$optionValue){
    $objectManager = \Magento\Framework\App\ObjectManager::getInstance(); 
    /*$attributeRepository = $objectManager->create('\Magento\Eav\Model\AttributeRepository');
    $attribute_id = $attributeRepository->get('catalog_product', $atributeCode)->getAttributeId();*/
    $resource = $objectManager->get('Magento\Framework\App\ResourceConnection');
    $connection = $resource->getConnection();
    $eaov = $resource->getTableName('eav_attribute_option_value');
    $eao = $resource->getTableName('eav_attribute_option');
    $ea= $resource->getTableName('eav_attribute');
    $attributeId = $connection->fetchOne("SELECT `attribute_id` FROM $ea WHERE `attribute_code` = '$atributeCode' AND `entity_type_id` = '4'");
    $sql = "select * from $eao join $eaov on $eaov.option_id = $eao.option_id where $eaov.value='$optionValue' AND $eao.attribute_id='$attributeId'";
    $result = $connection->fetchRow($sql);
    return $optionId = isset($result['option_id']) ? $result['option_id']: null;
}

// This Function Get attribute OptionId with help of Attribute code and Attribute Value.

function creatOrGetId($atributeCode,$optionValue)
{
    $optionId = getOptionId($atributeCode,$optionValue);
    $objectManager = \Magento\Framework\App\ObjectManager::getInstance(); 
    if(!$optionId ){
        $attributeRepository = $objectManager->create('\Magento\Eav\Model\AttributeRepository');
        $attributeId = $attributeRepository->get('catalog_product', $atributeCode)->getAttributeId();
        $option = $objectManager->create('\Magento\Eav\Model\Entity\Attribute\Option');
        $attributeOptionLabel = $objectManager->create('\Magento\Eav\Api\Data\AttributeOptionLabelInterface');
        $attributeOptionManagement = $objectManager->create('\Magento\Eav\Api\AttributeOptionManagementInterface');
        $option->setValue($optionValue);
        $attributeOptionLabel->setStoreId(0);
        $attributeOptionLabel->setLabel($optionValue);
        $option->setLabel($attributeOptionLabel);
        $option->setStoreLabels([$attributeOptionLabel]);
        $option->setSortOrder(0);
        $option->setIsDefault(false);
        $attributeOptionManagement->add('catalog_product', $attributeId, $option);
        return $optionId = getOptionId($atributeCode,$optionValue);
    }else{
      return $optionId;
    }
}

//echo "\n================== Created Attribute Option Values =============\n";

$manufacturer = array['aa', 'bb', 'cc', 'dd']
$manufacturerId = creatOrGetId('manufacturer',$manufacturer);

//echo "\n================== Update Attribute Option Values =============\n";

$product->setManufacturer($manufacturerId); // manufacturer of product
1

By the looks of it, it seems you need to update label for product attribute, it can be easily done. Use following helper in your module.

<?php
namespace Vendor\Module\Helper;

class HandleAttribute extends \Magento\Framework\App\Helper\AbstractHelper
{
    /**
     * @var \Magento\Catalog\Api\ProductAttributeRepositoryInterface
     */
    protected $attributeRepository;

    /**
     * @var array
     */
    protected $attributeValues;

    /**
     * @var \Magento\Eav\Model\Entity\Attribute\Source\TableFactory
     */
    protected $tableFactory;

    /**
     * @var \Magento\Eav\Api\AttributeOptionManagementInterface
     */
    protected $attributeOptionManagement;

    /**
     * @var \Magento\Eav\Api\Data\AttributeOptionLabelInterfaceFactory
     */
    protected $optionLabelFactory;

    /**
     * @var \Magento\Eav\Api\Data\AttributeOptionInterfaceFactory
     */
    protected $optionFactory;

    /**
     * Data constructor.
     *
     * @param \Magento\Framework\App\Helper\Context $context
     * @param \Magento\Catalog\Api\ProductAttributeRepositoryInterface $attributeRepository
     * @param \Magento\Eav\Model\Entity\Attribute\Source\TableFactory $tableFactory
     * @param \Magento\Eav\Api\AttributeOptionManagementInterface $attributeOptionManagement
     * @param \Magento\Eav\Api\Data\AttributeOptionLabelInterfaceFactory $optionLabelFactory
     * @param \Magento\Eav\Api\Data\AttributeOptionInterfaceFactory $optionFactory
     */
    public function __construct(
        \Magento\Framework\App\Helper\Context $context,
        \Magento\Catalog\Api\ProductAttributeRepositoryInterface $attributeRepository,
        \Magento\Eav\Model\Entity\Attribute\Source\TableFactory $tableFactory,
        \Magento\Eav\Api\AttributeOptionManagementInterface $attributeOptionManagement,
        \Magento\Eav\Api\Data\AttributeOptionLabelInterfaceFactory $optionLabelFactory,
        \Magento\Eav\Api\Data\AttributeOptionInterfaceFactory $optionFactory
    ) {
        parent::__construct($context);

        $this->attributeRepository = $attributeRepository;
        $this->tableFactory = $tableFactory;
        $this->attributeOptionManagement = $attributeOptionManagement;
        $this->optionLabelFactory = $optionLabelFactory;
        $this->optionFactory = $optionFactory;
    }

    /**
     * Get attribute by code.
     *
     * @param string $attributeCode
     * @return \Magento\Catalog\Api\Data\ProductAttributeInterface
     */
    public function getAttribute($attributeCode)
    {
        return $this->attributeRepository->get($attributeCode);
    }

    /**
     * Find or create a matching attribute option
     *
     * @param string $attributeCode Attribute the option should exist in
     * @param string $label Label to find or add
     * @return int
     * @throws \Magento\Framework\Exception\LocalizedException
     */
    public function createOrGetId($attributeCode, $label)
    {
        if (strlen($label) < 1) {
            throw new \Magento\Framework\Exception\LocalizedException(
                __('Label for %1 must not be empty.', $attributeCode)
            );
        }

        // Does it already exist?
        $optionId = $this->getOptionId($attributeCode, $label);

        if (!$optionId) {
            // If no, add it.

            /** @var \Magento\Eav\Model\Entity\Attribute\OptionLabel $optionLabel */
            $optionLabel = $this->optionLabelFactory->create();
            $optionLabel->setStoreId(0);
            $optionLabel->setLabel($label);

            $option = $this->optionFactory->create();
            $option->setLabel($optionLabel);
            $option->setStoreLabels([$optionLabel]);
            $option->setSortOrder(0);
            $option->setIsDefault(false);

            $this->attributeOptionManagement->add(
                \Magento\Catalog\Model\Product::ENTITY,
                $this->getAttribute($attributeCode)->getAttributeId(),
                $option
            );

            // Get the inserted ID. Should be returned from the installer, but it isn't.
            $optionId = $this->getOptionId($attributeCode, $label, true);
        }

        return $optionId;
    }

    /**
     * Find the ID of an option matching $label, if any.
     *
     * @param string $attributeCode Attribute code
     * @param string $label Label to find
     * @param bool $force If true, will fetch the options even if they're already cached.
     * @return int|false
     */
    public function getOptionId($attributeCode, $label, $force = false)
    {
        /** @var \Magento\Catalog\Model\ResourceModel\Eav\Attribute $attribute */
        $attribute = $this->getAttribute($attributeCode);

        // Build option array if necessary
        if ($force === true || !isset($this->attributeValues[ $attribute->getAttributeId() ])) {
            $this->attributeValues[ $attribute->getAttributeId() ] = [];

            // We have to generate a new sourceModel instance each time through to prevent it from
            // referencing its _options cache. No other way to get it to pick up newly-added values.

            /** @var \Magento\Eav\Model\Entity\Attribute\Source\Table $sourceModel */
            $sourceModel = $this->tableFactory->create();
            $sourceModel->setAttribute($attribute);

            foreach ($sourceModel->getAllOptions() as $option) {
                $this->attributeValues[ $attribute->getAttributeId() ][ $option['label'] ] = $option['value'];
            }
        }

        // Return option ID if exists
        if (isset($this->attributeValues[ $attribute->getAttributeId() ][ $label ])) {
            return $this->attributeValues[ $attribute->getAttributeId() ][ $label ];
        }

        // Return false if does not exist
        return false;
    }
}

call function like createOrGetId('attribute code of your attribute', $params['label for your option']); where you want to update attrbute and it will return id of the option if it has been created and create it if its not there and then return it.

1
  • 1
    Could you please show me the exact line that updates the label of an existing option? Jul 5, 2018 at 10:13

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.