How to update attribute option (update label for a store) programmatically?
-
You didn't specify which type of attribute it is, a product attribute ? or a customer attribute?– Vivek KumarCommented Dec 9, 2017 at 13:04
-
Product attribute– RDKCommented 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– Murtuza Zabuawala ♦Commented 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– RDKCommented Dec 11, 2017 at 14:58
5 Answers
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);
-
Yep I've implemented this feature with help of direct queries to the DB.– RDKCommented Dec 13, 2017 at 13:39
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();
}
-
hi @Rustem, $option->setLabel($optionLabel); is updated only in admin, but not indefault store view Commented Dec 14, 2018 at 13:22
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' => ''
]
);
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
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.
-
1Could you please show me the exact line that updates the label of an existing option? Commented Jul 5, 2018 at 10:13