Magento2 - programmatically add product attribute options












28















What is the right(official) way to programmatically add product attribute option in M2?
E.g. for manufacturer product attribute. Obviously existing option would be matched by "Admin" title value.










share|improve this question



























    28















    What is the right(official) way to programmatically add product attribute option in M2?
    E.g. for manufacturer product attribute. Obviously existing option would be matched by "Admin" title value.










    share|improve this question

























      28












      28








      28


      11






      What is the right(official) way to programmatically add product attribute option in M2?
      E.g. for manufacturer product attribute. Obviously existing option would be matched by "Admin" title value.










      share|improve this question














      What is the right(official) way to programmatically add product attribute option in M2?
      E.g. for manufacturer product attribute. Obviously existing option would be matched by "Admin" title value.







      magento2






      share|improve this question













      share|improve this question











      share|improve this question




      share|improve this question










      asked Feb 29 '16 at 13:00









      werdwerd

      255147




      255147






















          4 Answers
          4






          active

          oldest

          votes


















          42














          Here's the approach I've come up with for handling attribute options. Helper class:



          <?php
          namespace MyModuleHelper;

          class Data extends MagentoFrameworkAppHelperAbstractHelper
          {
          /**
          * @var MagentoCatalogApiProductAttributeRepositoryInterface
          */
          protected $attributeRepository;

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

          /**
          * @var MagentoEavModelEntityAttributeSourceTableFactory
          */
          protected $tableFactory;

          /**
          * @var MagentoEavApiAttributeOptionManagementInterface
          */
          protected $attributeOptionManagement;

          /**
          * @var MagentoEavApiDataAttributeOptionLabelInterfaceFactory
          */
          protected $optionLabelFactory;

          /**
          * @var MagentoEavApiDataAttributeOptionInterfaceFactory
          */
          protected $optionFactory;

          /**
          * Data constructor.
          *
          * @param MagentoFrameworkAppHelperContext $context
          * @param MagentoCatalogApiProductAttributeRepositoryInterface $attributeRepository
          * @param MagentoEavModelEntityAttributeSourceTableFactory $tableFactory
          * @param MagentoEavApiAttributeOptionManagementInterface $attributeOptionManagement
          * @param MagentoEavApiDataAttributeOptionLabelInterfaceFactory $optionLabelFactory
          * @param MagentoEavApiDataAttributeOptionInterfaceFactory $optionFactory
          */
          public function __construct(
          MagentoFrameworkAppHelperContext $context,
          MagentoCatalogApiProductAttributeRepositoryInterface $attributeRepository,
          MagentoEavModelEntityAttributeSourceTableFactory $tableFactory,
          MagentoEavApiAttributeOptionManagementInterface $attributeOptionManagement,
          MagentoEavApiDataAttributeOptionLabelInterfaceFactory $optionLabelFactory,
          MagentoEavApiDataAttributeOptionInterfaceFactory $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 MagentoCatalogApiDataProductAttributeInterface
          */
          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 MagentoFrameworkExceptionLocalizedException
          */
          public function createOrGetId($attributeCode, $label)
          {
          if (strlen($label) < 1) {
          throw new MagentoFrameworkExceptionLocalizedException(
          __('Label for %1 must not be empty.', $attributeCode)
          );
          }

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

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

          /** @var MagentoEavModelEntityAttributeOptionLabel $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(
          MagentoCatalogModelProduct::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 MagentoCatalogModelResourceModelEavAttribute $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 MagentoEavModelEntityAttributeSourceTable $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;
          }
          }


          Then, either in the same class or including it via dependency injection, you can add or get your option ID by calling createOrGetId($attributeCode, $label).



          For example, if you inject MyModuleHelperData as $this->moduleHelper, then you can call:



          $manufacturerId = $this->moduleHelper->createOrGetId('manufacturer', 'ABC Corp');


          If 'ABC Corp' is an existing manufacturer, it will pull the ID. If not, it will add it.



          UPDATED 2016-09-09: Per Ruud N., the original solution used CatalogSetup, which resulted in a bug starting in Magento 2.1. This revised solution bypasses that model, creating the option and label explicitly. It should work on 2.0+.






          share|improve this answer


























          • Thanks! I guess this is not the "official" way of solving the issue, right? However I was not able to find any actual reference to product attribute option management in Magento2 source itself.

            – werd
            Feb 29 '16 at 15:27






          • 2





            It's as official as you're going to get. All of the lookups and option adding go through core Magento. My class is just a wrapper for those core methods that makes them easier to use.

            – Ryan Hoerr
            Feb 29 '16 at 15:35











          • Thanks Ryan H. it's very useful piece of code. Actually I have a question. If option is added to store with id 0 (admin) it will be rendered with the same label in front in store f.e. with id 1. What can I do to change label for frontend? Just 1 => 'something else'? If I have done it adopting this tutorial: http://magentorex.com/magento-get-product-attributes-option-id-from-option-label/ But function getting option id, only returns ids of attributes for store 1 (frontend) and not for admin.

            – Bartosz Kubicki
            Jun 17 '16 at 17:48






          • 1





            Hi Ryan, you shouldn't set the value on the option, this is the internal id magento uses and I found out the hard way that if you set the value to a string value with a leading number like '123 abc corp' it causes some serious problems due to the implementation of MagentoEavModelResourceModelEntityAttribute::_processAttributeOptions. See for yourself, if you remove the $option->setValue($label); statement from your code, it will save the option, then when you fetch it Magento will return the value from an auto-increment on the eav_attribute_option table.

            – quickshiftin
            Sep 12 '16 at 19:37






          • 1





            if I add this in a foreach function, in the second iteration I will get the error "MagentoEavModelEntityAttributeOptionManagement::setOptionValue() must be of the type string, object given"

            – JELLEJ
            Dec 12 '18 at 14:57



















          10














          Using the MagentoEavSetupEavSetupFactory or even the MagentoCatalogSetupCategorySetupFactory class may lead to the following problem: https://github.com/magento/magento2/issues/4896.



          The classes you should use:



          protected $_logger;

          protected $_attributeRepository;

          protected $_attributeOptionManagement;

          protected $_option;

          protected $_attributeOptionLabel;

          public function __construct(
          PsrLogLoggerInterface $logger,
          MagentoEavModelAttributeRepository $attributeRepository,
          MagentoEavApiAttributeOptionManagementInterface $attributeOptionManagement,
          MagentoEavApiDataAttributeOptionLabelInterface $attributeOptionLabel,
          MagentoEavModelEntityAttributeOption $option
          ){
          $this->_logger = $logger;
          $this->_attributeRepository = $attributeRepository;
          $this->_attributeOptionManagement = $attributeOptionManagement;
          $this->_option = $option;
          $this->_attributeOptionLabel = $attributeOptionLabel;
          }


          Then in your function do something like this:



           $attribute_id = $this->_attributeRepository->get('catalog_product', 'your_attribute')->getAttributeId();
          $options = $this->_attributeOptionManagement->getItems('catalog_product', $attribute_id);
          /* if attribute option already exists, remove it */
          foreach($options as $option) {
          if ($option->getLabel() == $oldname) {
          $this->_attributeOptionManagement->delete('catalog_product', $attribute_id, $option->getValue());
          }
          }

          /* new attribute option */
          $this->_option->setValue($name);
          $this->_attributeOptionLabel->setStoreId(0);
          $this->_attributeOptionLabel->setLabel($name);
          $this->_option->setLabel($this->_attributeOptionLabel);
          $this->_option->setStoreLabels([$this->_attributeOptionLabel]);
          $this->_option->setSortOrder(0);
          $this->_option->setIsDefault(false);
          $this->_attributeOptionManagement->add('catalog_product', $attribute_id, $this->_option);





          share|improve this answer



















          • 1





            Thanks, you are correct. I've updated my answer accordingly. Note that $attributeOptionLabel and $option are ORM classes; you should not inject them directly. The proper approach is to inject their factory class, then create an instance as needed. Also note you aren't using the API data interfaces consistently.

            – Ryan Hoerr
            Sep 9 '16 at 14:55






          • 3





            Hi @Rudd, see my comment on Ryan's answer. You don't want to call $option->setValue() as that is for an internal magento option_id field on the eav_attribute_option table.

            – quickshiftin
            Sep 12 '16 at 19:42











          • Thank you. That's what I found out too. Will edit my answer accordingly.

            – Ruud N.
            Sep 14 '16 at 5:49



















          8














          tested on Magento 2.1.3.



          I didn't find any workable way how to create attribute with options at once. So initially we need to create an attribute and then add options for it.



          Inject following class MagentoEavSetupEavSetupFactory



           $setup->startSetup();

          /** @var MagentoEavSetupEavSetup $eavSetup */
          $eavSetup = $this->eavSetupFactory->create(['setup' => $setup]);


          Create new attribute:



          $eavSetup->addAttribute(
          'catalog_product',
          $attributeCode,
          [
          'type' => 'varchar',
          'input' => 'select',
          'required' => false,
          ...
          ],
          );


          Add custom options.



          Function addAttribute doesn't return anything useful which can be used in future. So after attribute creation we need to retrieve attribute object by ourself. !!!Important We need it because function expects only attribute_id, but don't want to work with attribute_code.



          In that case we need to get attribute_id and pass it to attribute creation function.



          $attributeId = $eavSetup->getAttributeId('catalog_product', 'attribute_code');


          Then we need to generate options array in the way magento expects:



          $options = [
          'values' => [
          'sort_order1' => 'title1',
          'sort_order2' => 'title2',
          'sort_order3' => 'title3',
          ],
          'attribute_id' => 'some_id',
          ];


          As example:



          $options = [
          'values' => [
          '1' => 'Red',
          '2' => 'Yellow',
          '3' => 'Green',
          ],
          'attribute_id' => '32',
          ];


          And pass it to function:



          $eavSetup->addAttributeOption($options);





          share|improve this answer































            -3














            This is NOT an answer. Just a workaround.



            It assumes that you have access to Magento Backend using browser and you are on the edit attribute page (url looks like admin/catalog/product_attribute/edit/attribute_id/XXX/key..)



            Go to Browser console (CTRL + SHIFT + J on chrome)
            and paste the following code after changing the array mimim.



            $jq=new jQuery.noConflict();
            var mimim=["xxx","yyy","VALUES TO BE ADDED"];
            $jq.each(mimim,function(a,b){
            $jq("#add_new_option_button").click();
            $jq("#manage-options-panel tbody tr:last-child td:nth-child(3) input").val(b);
            });


            -- tested on Magento 2.2.2



            Detailed article - https://tutes.in/how-to-manage-magento-2-product-attribute-values-options-using-console/






            share|improve this answer





















            • 1





              This is a terrible long term solution. You can't reliably expect those selectors to stay the same. This is a workaround at best, if it actually works as expected.

              – domdambrogia
              Apr 21 '18 at 0:24











            • @domdambrogia agree. It is a workaround.

              – th3pirat3
              Apr 23 '18 at 17:26











            Your Answer








            StackExchange.ready(function() {
            var channelOptions = {
            tags: "".split(" "),
            id: "479"
            };
            initTagRenderer("".split(" "), "".split(" "), channelOptions);

            StackExchange.using("externalEditor", function() {
            // Have to fire editor after snippets, if snippets enabled
            if (StackExchange.settings.snippets.snippetsEnabled) {
            StackExchange.using("snippets", function() {
            createEditor();
            });
            }
            else {
            createEditor();
            }
            });

            function createEditor() {
            StackExchange.prepareEditor({
            heartbeatType: 'answer',
            autoActivateHeartbeat: false,
            convertImagesToLinks: false,
            noModals: true,
            showLowRepImageUploadWarning: true,
            reputationToPostImages: null,
            bindNavPrevention: true,
            postfix: "",
            imageUploader: {
            brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
            contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
            allowUrls: true
            },
            onDemand: true,
            discardSelector: ".discard-answer"
            ,immediatelyShowMarkdownHelp:true
            });


            }
            });














            draft saved

            draft discarded


















            StackExchange.ready(
            function () {
            StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fmagento.stackexchange.com%2fquestions%2f103934%2fmagento2-programmatically-add-product-attribute-options%23new-answer', 'question_page');
            }
            );

            Post as a guest















            Required, but never shown

























            4 Answers
            4






            active

            oldest

            votes








            4 Answers
            4






            active

            oldest

            votes









            active

            oldest

            votes






            active

            oldest

            votes









            42














            Here's the approach I've come up with for handling attribute options. Helper class:



            <?php
            namespace MyModuleHelper;

            class Data extends MagentoFrameworkAppHelperAbstractHelper
            {
            /**
            * @var MagentoCatalogApiProductAttributeRepositoryInterface
            */
            protected $attributeRepository;

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

            /**
            * @var MagentoEavModelEntityAttributeSourceTableFactory
            */
            protected $tableFactory;

            /**
            * @var MagentoEavApiAttributeOptionManagementInterface
            */
            protected $attributeOptionManagement;

            /**
            * @var MagentoEavApiDataAttributeOptionLabelInterfaceFactory
            */
            protected $optionLabelFactory;

            /**
            * @var MagentoEavApiDataAttributeOptionInterfaceFactory
            */
            protected $optionFactory;

            /**
            * Data constructor.
            *
            * @param MagentoFrameworkAppHelperContext $context
            * @param MagentoCatalogApiProductAttributeRepositoryInterface $attributeRepository
            * @param MagentoEavModelEntityAttributeSourceTableFactory $tableFactory
            * @param MagentoEavApiAttributeOptionManagementInterface $attributeOptionManagement
            * @param MagentoEavApiDataAttributeOptionLabelInterfaceFactory $optionLabelFactory
            * @param MagentoEavApiDataAttributeOptionInterfaceFactory $optionFactory
            */
            public function __construct(
            MagentoFrameworkAppHelperContext $context,
            MagentoCatalogApiProductAttributeRepositoryInterface $attributeRepository,
            MagentoEavModelEntityAttributeSourceTableFactory $tableFactory,
            MagentoEavApiAttributeOptionManagementInterface $attributeOptionManagement,
            MagentoEavApiDataAttributeOptionLabelInterfaceFactory $optionLabelFactory,
            MagentoEavApiDataAttributeOptionInterfaceFactory $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 MagentoCatalogApiDataProductAttributeInterface
            */
            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 MagentoFrameworkExceptionLocalizedException
            */
            public function createOrGetId($attributeCode, $label)
            {
            if (strlen($label) < 1) {
            throw new MagentoFrameworkExceptionLocalizedException(
            __('Label for %1 must not be empty.', $attributeCode)
            );
            }

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

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

            /** @var MagentoEavModelEntityAttributeOptionLabel $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(
            MagentoCatalogModelProduct::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 MagentoCatalogModelResourceModelEavAttribute $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 MagentoEavModelEntityAttributeSourceTable $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;
            }
            }


            Then, either in the same class or including it via dependency injection, you can add or get your option ID by calling createOrGetId($attributeCode, $label).



            For example, if you inject MyModuleHelperData as $this->moduleHelper, then you can call:



            $manufacturerId = $this->moduleHelper->createOrGetId('manufacturer', 'ABC Corp');


            If 'ABC Corp' is an existing manufacturer, it will pull the ID. If not, it will add it.



            UPDATED 2016-09-09: Per Ruud N., the original solution used CatalogSetup, which resulted in a bug starting in Magento 2.1. This revised solution bypasses that model, creating the option and label explicitly. It should work on 2.0+.






            share|improve this answer


























            • Thanks! I guess this is not the "official" way of solving the issue, right? However I was not able to find any actual reference to product attribute option management in Magento2 source itself.

              – werd
              Feb 29 '16 at 15:27






            • 2





              It's as official as you're going to get. All of the lookups and option adding go through core Magento. My class is just a wrapper for those core methods that makes them easier to use.

              – Ryan Hoerr
              Feb 29 '16 at 15:35











            • Thanks Ryan H. it's very useful piece of code. Actually I have a question. If option is added to store with id 0 (admin) it will be rendered with the same label in front in store f.e. with id 1. What can I do to change label for frontend? Just 1 => 'something else'? If I have done it adopting this tutorial: http://magentorex.com/magento-get-product-attributes-option-id-from-option-label/ But function getting option id, only returns ids of attributes for store 1 (frontend) and not for admin.

              – Bartosz Kubicki
              Jun 17 '16 at 17:48






            • 1





              Hi Ryan, you shouldn't set the value on the option, this is the internal id magento uses and I found out the hard way that if you set the value to a string value with a leading number like '123 abc corp' it causes some serious problems due to the implementation of MagentoEavModelResourceModelEntityAttribute::_processAttributeOptions. See for yourself, if you remove the $option->setValue($label); statement from your code, it will save the option, then when you fetch it Magento will return the value from an auto-increment on the eav_attribute_option table.

              – quickshiftin
              Sep 12 '16 at 19:37






            • 1





              if I add this in a foreach function, in the second iteration I will get the error "MagentoEavModelEntityAttributeOptionManagement::setOptionValue() must be of the type string, object given"

              – JELLEJ
              Dec 12 '18 at 14:57
















            42














            Here's the approach I've come up with for handling attribute options. Helper class:



            <?php
            namespace MyModuleHelper;

            class Data extends MagentoFrameworkAppHelperAbstractHelper
            {
            /**
            * @var MagentoCatalogApiProductAttributeRepositoryInterface
            */
            protected $attributeRepository;

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

            /**
            * @var MagentoEavModelEntityAttributeSourceTableFactory
            */
            protected $tableFactory;

            /**
            * @var MagentoEavApiAttributeOptionManagementInterface
            */
            protected $attributeOptionManagement;

            /**
            * @var MagentoEavApiDataAttributeOptionLabelInterfaceFactory
            */
            protected $optionLabelFactory;

            /**
            * @var MagentoEavApiDataAttributeOptionInterfaceFactory
            */
            protected $optionFactory;

            /**
            * Data constructor.
            *
            * @param MagentoFrameworkAppHelperContext $context
            * @param MagentoCatalogApiProductAttributeRepositoryInterface $attributeRepository
            * @param MagentoEavModelEntityAttributeSourceTableFactory $tableFactory
            * @param MagentoEavApiAttributeOptionManagementInterface $attributeOptionManagement
            * @param MagentoEavApiDataAttributeOptionLabelInterfaceFactory $optionLabelFactory
            * @param MagentoEavApiDataAttributeOptionInterfaceFactory $optionFactory
            */
            public function __construct(
            MagentoFrameworkAppHelperContext $context,
            MagentoCatalogApiProductAttributeRepositoryInterface $attributeRepository,
            MagentoEavModelEntityAttributeSourceTableFactory $tableFactory,
            MagentoEavApiAttributeOptionManagementInterface $attributeOptionManagement,
            MagentoEavApiDataAttributeOptionLabelInterfaceFactory $optionLabelFactory,
            MagentoEavApiDataAttributeOptionInterfaceFactory $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 MagentoCatalogApiDataProductAttributeInterface
            */
            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 MagentoFrameworkExceptionLocalizedException
            */
            public function createOrGetId($attributeCode, $label)
            {
            if (strlen($label) < 1) {
            throw new MagentoFrameworkExceptionLocalizedException(
            __('Label for %1 must not be empty.', $attributeCode)
            );
            }

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

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

            /** @var MagentoEavModelEntityAttributeOptionLabel $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(
            MagentoCatalogModelProduct::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 MagentoCatalogModelResourceModelEavAttribute $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 MagentoEavModelEntityAttributeSourceTable $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;
            }
            }


            Then, either in the same class or including it via dependency injection, you can add or get your option ID by calling createOrGetId($attributeCode, $label).



            For example, if you inject MyModuleHelperData as $this->moduleHelper, then you can call:



            $manufacturerId = $this->moduleHelper->createOrGetId('manufacturer', 'ABC Corp');


            If 'ABC Corp' is an existing manufacturer, it will pull the ID. If not, it will add it.



            UPDATED 2016-09-09: Per Ruud N., the original solution used CatalogSetup, which resulted in a bug starting in Magento 2.1. This revised solution bypasses that model, creating the option and label explicitly. It should work on 2.0+.






            share|improve this answer


























            • Thanks! I guess this is not the "official" way of solving the issue, right? However I was not able to find any actual reference to product attribute option management in Magento2 source itself.

              – werd
              Feb 29 '16 at 15:27






            • 2





              It's as official as you're going to get. All of the lookups and option adding go through core Magento. My class is just a wrapper for those core methods that makes them easier to use.

              – Ryan Hoerr
              Feb 29 '16 at 15:35











            • Thanks Ryan H. it's very useful piece of code. Actually I have a question. If option is added to store with id 0 (admin) it will be rendered with the same label in front in store f.e. with id 1. What can I do to change label for frontend? Just 1 => 'something else'? If I have done it adopting this tutorial: http://magentorex.com/magento-get-product-attributes-option-id-from-option-label/ But function getting option id, only returns ids of attributes for store 1 (frontend) and not for admin.

              – Bartosz Kubicki
              Jun 17 '16 at 17:48






            • 1





              Hi Ryan, you shouldn't set the value on the option, this is the internal id magento uses and I found out the hard way that if you set the value to a string value with a leading number like '123 abc corp' it causes some serious problems due to the implementation of MagentoEavModelResourceModelEntityAttribute::_processAttributeOptions. See for yourself, if you remove the $option->setValue($label); statement from your code, it will save the option, then when you fetch it Magento will return the value from an auto-increment on the eav_attribute_option table.

              – quickshiftin
              Sep 12 '16 at 19:37






            • 1





              if I add this in a foreach function, in the second iteration I will get the error "MagentoEavModelEntityAttributeOptionManagement::setOptionValue() must be of the type string, object given"

              – JELLEJ
              Dec 12 '18 at 14:57














            42












            42








            42







            Here's the approach I've come up with for handling attribute options. Helper class:



            <?php
            namespace MyModuleHelper;

            class Data extends MagentoFrameworkAppHelperAbstractHelper
            {
            /**
            * @var MagentoCatalogApiProductAttributeRepositoryInterface
            */
            protected $attributeRepository;

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

            /**
            * @var MagentoEavModelEntityAttributeSourceTableFactory
            */
            protected $tableFactory;

            /**
            * @var MagentoEavApiAttributeOptionManagementInterface
            */
            protected $attributeOptionManagement;

            /**
            * @var MagentoEavApiDataAttributeOptionLabelInterfaceFactory
            */
            protected $optionLabelFactory;

            /**
            * @var MagentoEavApiDataAttributeOptionInterfaceFactory
            */
            protected $optionFactory;

            /**
            * Data constructor.
            *
            * @param MagentoFrameworkAppHelperContext $context
            * @param MagentoCatalogApiProductAttributeRepositoryInterface $attributeRepository
            * @param MagentoEavModelEntityAttributeSourceTableFactory $tableFactory
            * @param MagentoEavApiAttributeOptionManagementInterface $attributeOptionManagement
            * @param MagentoEavApiDataAttributeOptionLabelInterfaceFactory $optionLabelFactory
            * @param MagentoEavApiDataAttributeOptionInterfaceFactory $optionFactory
            */
            public function __construct(
            MagentoFrameworkAppHelperContext $context,
            MagentoCatalogApiProductAttributeRepositoryInterface $attributeRepository,
            MagentoEavModelEntityAttributeSourceTableFactory $tableFactory,
            MagentoEavApiAttributeOptionManagementInterface $attributeOptionManagement,
            MagentoEavApiDataAttributeOptionLabelInterfaceFactory $optionLabelFactory,
            MagentoEavApiDataAttributeOptionInterfaceFactory $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 MagentoCatalogApiDataProductAttributeInterface
            */
            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 MagentoFrameworkExceptionLocalizedException
            */
            public function createOrGetId($attributeCode, $label)
            {
            if (strlen($label) < 1) {
            throw new MagentoFrameworkExceptionLocalizedException(
            __('Label for %1 must not be empty.', $attributeCode)
            );
            }

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

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

            /** @var MagentoEavModelEntityAttributeOptionLabel $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(
            MagentoCatalogModelProduct::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 MagentoCatalogModelResourceModelEavAttribute $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 MagentoEavModelEntityAttributeSourceTable $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;
            }
            }


            Then, either in the same class or including it via dependency injection, you can add or get your option ID by calling createOrGetId($attributeCode, $label).



            For example, if you inject MyModuleHelperData as $this->moduleHelper, then you can call:



            $manufacturerId = $this->moduleHelper->createOrGetId('manufacturer', 'ABC Corp');


            If 'ABC Corp' is an existing manufacturer, it will pull the ID. If not, it will add it.



            UPDATED 2016-09-09: Per Ruud N., the original solution used CatalogSetup, which resulted in a bug starting in Magento 2.1. This revised solution bypasses that model, creating the option and label explicitly. It should work on 2.0+.






            share|improve this answer















            Here's the approach I've come up with for handling attribute options. Helper class:



            <?php
            namespace MyModuleHelper;

            class Data extends MagentoFrameworkAppHelperAbstractHelper
            {
            /**
            * @var MagentoCatalogApiProductAttributeRepositoryInterface
            */
            protected $attributeRepository;

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

            /**
            * @var MagentoEavModelEntityAttributeSourceTableFactory
            */
            protected $tableFactory;

            /**
            * @var MagentoEavApiAttributeOptionManagementInterface
            */
            protected $attributeOptionManagement;

            /**
            * @var MagentoEavApiDataAttributeOptionLabelInterfaceFactory
            */
            protected $optionLabelFactory;

            /**
            * @var MagentoEavApiDataAttributeOptionInterfaceFactory
            */
            protected $optionFactory;

            /**
            * Data constructor.
            *
            * @param MagentoFrameworkAppHelperContext $context
            * @param MagentoCatalogApiProductAttributeRepositoryInterface $attributeRepository
            * @param MagentoEavModelEntityAttributeSourceTableFactory $tableFactory
            * @param MagentoEavApiAttributeOptionManagementInterface $attributeOptionManagement
            * @param MagentoEavApiDataAttributeOptionLabelInterfaceFactory $optionLabelFactory
            * @param MagentoEavApiDataAttributeOptionInterfaceFactory $optionFactory
            */
            public function __construct(
            MagentoFrameworkAppHelperContext $context,
            MagentoCatalogApiProductAttributeRepositoryInterface $attributeRepository,
            MagentoEavModelEntityAttributeSourceTableFactory $tableFactory,
            MagentoEavApiAttributeOptionManagementInterface $attributeOptionManagement,
            MagentoEavApiDataAttributeOptionLabelInterfaceFactory $optionLabelFactory,
            MagentoEavApiDataAttributeOptionInterfaceFactory $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 MagentoCatalogApiDataProductAttributeInterface
            */
            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 MagentoFrameworkExceptionLocalizedException
            */
            public function createOrGetId($attributeCode, $label)
            {
            if (strlen($label) < 1) {
            throw new MagentoFrameworkExceptionLocalizedException(
            __('Label for %1 must not be empty.', $attributeCode)
            );
            }

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

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

            /** @var MagentoEavModelEntityAttributeOptionLabel $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(
            MagentoCatalogModelProduct::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 MagentoCatalogModelResourceModelEavAttribute $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 MagentoEavModelEntityAttributeSourceTable $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;
            }
            }


            Then, either in the same class or including it via dependency injection, you can add or get your option ID by calling createOrGetId($attributeCode, $label).



            For example, if you inject MyModuleHelperData as $this->moduleHelper, then you can call:



            $manufacturerId = $this->moduleHelper->createOrGetId('manufacturer', 'ABC Corp');


            If 'ABC Corp' is an existing manufacturer, it will pull the ID. If not, it will add it.



            UPDATED 2016-09-09: Per Ruud N., the original solution used CatalogSetup, which resulted in a bug starting in Magento 2.1. This revised solution bypasses that model, creating the option and label explicitly. It should work on 2.0+.







            share|improve this answer














            share|improve this answer



            share|improve this answer








            edited Sep 12 '16 at 20:35

























            answered Feb 29 '16 at 14:54









            Ryan HoerrRyan Hoerr

            8,61953144




            8,61953144













            • Thanks! I guess this is not the "official" way of solving the issue, right? However I was not able to find any actual reference to product attribute option management in Magento2 source itself.

              – werd
              Feb 29 '16 at 15:27






            • 2





              It's as official as you're going to get. All of the lookups and option adding go through core Magento. My class is just a wrapper for those core methods that makes them easier to use.

              – Ryan Hoerr
              Feb 29 '16 at 15:35











            • Thanks Ryan H. it's very useful piece of code. Actually I have a question. If option is added to store with id 0 (admin) it will be rendered with the same label in front in store f.e. with id 1. What can I do to change label for frontend? Just 1 => 'something else'? If I have done it adopting this tutorial: http://magentorex.com/magento-get-product-attributes-option-id-from-option-label/ But function getting option id, only returns ids of attributes for store 1 (frontend) and not for admin.

              – Bartosz Kubicki
              Jun 17 '16 at 17:48






            • 1





              Hi Ryan, you shouldn't set the value on the option, this is the internal id magento uses and I found out the hard way that if you set the value to a string value with a leading number like '123 abc corp' it causes some serious problems due to the implementation of MagentoEavModelResourceModelEntityAttribute::_processAttributeOptions. See for yourself, if you remove the $option->setValue($label); statement from your code, it will save the option, then when you fetch it Magento will return the value from an auto-increment on the eav_attribute_option table.

              – quickshiftin
              Sep 12 '16 at 19:37






            • 1





              if I add this in a foreach function, in the second iteration I will get the error "MagentoEavModelEntityAttributeOptionManagement::setOptionValue() must be of the type string, object given"

              – JELLEJ
              Dec 12 '18 at 14:57



















            • Thanks! I guess this is not the "official" way of solving the issue, right? However I was not able to find any actual reference to product attribute option management in Magento2 source itself.

              – werd
              Feb 29 '16 at 15:27






            • 2





              It's as official as you're going to get. All of the lookups and option adding go through core Magento. My class is just a wrapper for those core methods that makes them easier to use.

              – Ryan Hoerr
              Feb 29 '16 at 15:35











            • Thanks Ryan H. it's very useful piece of code. Actually I have a question. If option is added to store with id 0 (admin) it will be rendered with the same label in front in store f.e. with id 1. What can I do to change label for frontend? Just 1 => 'something else'? If I have done it adopting this tutorial: http://magentorex.com/magento-get-product-attributes-option-id-from-option-label/ But function getting option id, only returns ids of attributes for store 1 (frontend) and not for admin.

              – Bartosz Kubicki
              Jun 17 '16 at 17:48






            • 1





              Hi Ryan, you shouldn't set the value on the option, this is the internal id magento uses and I found out the hard way that if you set the value to a string value with a leading number like '123 abc corp' it causes some serious problems due to the implementation of MagentoEavModelResourceModelEntityAttribute::_processAttributeOptions. See for yourself, if you remove the $option->setValue($label); statement from your code, it will save the option, then when you fetch it Magento will return the value from an auto-increment on the eav_attribute_option table.

              – quickshiftin
              Sep 12 '16 at 19:37






            • 1





              if I add this in a foreach function, in the second iteration I will get the error "MagentoEavModelEntityAttributeOptionManagement::setOptionValue() must be of the type string, object given"

              – JELLEJ
              Dec 12 '18 at 14:57

















            Thanks! I guess this is not the "official" way of solving the issue, right? However I was not able to find any actual reference to product attribute option management in Magento2 source itself.

            – werd
            Feb 29 '16 at 15:27





            Thanks! I guess this is not the "official" way of solving the issue, right? However I was not able to find any actual reference to product attribute option management in Magento2 source itself.

            – werd
            Feb 29 '16 at 15:27




            2




            2





            It's as official as you're going to get. All of the lookups and option adding go through core Magento. My class is just a wrapper for those core methods that makes them easier to use.

            – Ryan Hoerr
            Feb 29 '16 at 15:35





            It's as official as you're going to get. All of the lookups and option adding go through core Magento. My class is just a wrapper for those core methods that makes them easier to use.

            – Ryan Hoerr
            Feb 29 '16 at 15:35













            Thanks Ryan H. it's very useful piece of code. Actually I have a question. If option is added to store with id 0 (admin) it will be rendered with the same label in front in store f.e. with id 1. What can I do to change label for frontend? Just 1 => 'something else'? If I have done it adopting this tutorial: http://magentorex.com/magento-get-product-attributes-option-id-from-option-label/ But function getting option id, only returns ids of attributes for store 1 (frontend) and not for admin.

            – Bartosz Kubicki
            Jun 17 '16 at 17:48





            Thanks Ryan H. it's very useful piece of code. Actually I have a question. If option is added to store with id 0 (admin) it will be rendered with the same label in front in store f.e. with id 1. What can I do to change label for frontend? Just 1 => 'something else'? If I have done it adopting this tutorial: http://magentorex.com/magento-get-product-attributes-option-id-from-option-label/ But function getting option id, only returns ids of attributes for store 1 (frontend) and not for admin.

            – Bartosz Kubicki
            Jun 17 '16 at 17:48




            1




            1





            Hi Ryan, you shouldn't set the value on the option, this is the internal id magento uses and I found out the hard way that if you set the value to a string value with a leading number like '123 abc corp' it causes some serious problems due to the implementation of MagentoEavModelResourceModelEntityAttribute::_processAttributeOptions. See for yourself, if you remove the $option->setValue($label); statement from your code, it will save the option, then when you fetch it Magento will return the value from an auto-increment on the eav_attribute_option table.

            – quickshiftin
            Sep 12 '16 at 19:37





            Hi Ryan, you shouldn't set the value on the option, this is the internal id magento uses and I found out the hard way that if you set the value to a string value with a leading number like '123 abc corp' it causes some serious problems due to the implementation of MagentoEavModelResourceModelEntityAttribute::_processAttributeOptions. See for yourself, if you remove the $option->setValue($label); statement from your code, it will save the option, then when you fetch it Magento will return the value from an auto-increment on the eav_attribute_option table.

            – quickshiftin
            Sep 12 '16 at 19:37




            1




            1





            if I add this in a foreach function, in the second iteration I will get the error "MagentoEavModelEntityAttributeOptionManagement::setOptionValue() must be of the type string, object given"

            – JELLEJ
            Dec 12 '18 at 14:57





            if I add this in a foreach function, in the second iteration I will get the error "MagentoEavModelEntityAttributeOptionManagement::setOptionValue() must be of the type string, object given"

            – JELLEJ
            Dec 12 '18 at 14:57













            10














            Using the MagentoEavSetupEavSetupFactory or even the MagentoCatalogSetupCategorySetupFactory class may lead to the following problem: https://github.com/magento/magento2/issues/4896.



            The classes you should use:



            protected $_logger;

            protected $_attributeRepository;

            protected $_attributeOptionManagement;

            protected $_option;

            protected $_attributeOptionLabel;

            public function __construct(
            PsrLogLoggerInterface $logger,
            MagentoEavModelAttributeRepository $attributeRepository,
            MagentoEavApiAttributeOptionManagementInterface $attributeOptionManagement,
            MagentoEavApiDataAttributeOptionLabelInterface $attributeOptionLabel,
            MagentoEavModelEntityAttributeOption $option
            ){
            $this->_logger = $logger;
            $this->_attributeRepository = $attributeRepository;
            $this->_attributeOptionManagement = $attributeOptionManagement;
            $this->_option = $option;
            $this->_attributeOptionLabel = $attributeOptionLabel;
            }


            Then in your function do something like this:



             $attribute_id = $this->_attributeRepository->get('catalog_product', 'your_attribute')->getAttributeId();
            $options = $this->_attributeOptionManagement->getItems('catalog_product', $attribute_id);
            /* if attribute option already exists, remove it */
            foreach($options as $option) {
            if ($option->getLabel() == $oldname) {
            $this->_attributeOptionManagement->delete('catalog_product', $attribute_id, $option->getValue());
            }
            }

            /* new attribute option */
            $this->_option->setValue($name);
            $this->_attributeOptionLabel->setStoreId(0);
            $this->_attributeOptionLabel->setLabel($name);
            $this->_option->setLabel($this->_attributeOptionLabel);
            $this->_option->setStoreLabels([$this->_attributeOptionLabel]);
            $this->_option->setSortOrder(0);
            $this->_option->setIsDefault(false);
            $this->_attributeOptionManagement->add('catalog_product', $attribute_id, $this->_option);





            share|improve this answer



















            • 1





              Thanks, you are correct. I've updated my answer accordingly. Note that $attributeOptionLabel and $option are ORM classes; you should not inject them directly. The proper approach is to inject their factory class, then create an instance as needed. Also note you aren't using the API data interfaces consistently.

              – Ryan Hoerr
              Sep 9 '16 at 14:55






            • 3





              Hi @Rudd, see my comment on Ryan's answer. You don't want to call $option->setValue() as that is for an internal magento option_id field on the eav_attribute_option table.

              – quickshiftin
              Sep 12 '16 at 19:42











            • Thank you. That's what I found out too. Will edit my answer accordingly.

              – Ruud N.
              Sep 14 '16 at 5:49
















            10














            Using the MagentoEavSetupEavSetupFactory or even the MagentoCatalogSetupCategorySetupFactory class may lead to the following problem: https://github.com/magento/magento2/issues/4896.



            The classes you should use:



            protected $_logger;

            protected $_attributeRepository;

            protected $_attributeOptionManagement;

            protected $_option;

            protected $_attributeOptionLabel;

            public function __construct(
            PsrLogLoggerInterface $logger,
            MagentoEavModelAttributeRepository $attributeRepository,
            MagentoEavApiAttributeOptionManagementInterface $attributeOptionManagement,
            MagentoEavApiDataAttributeOptionLabelInterface $attributeOptionLabel,
            MagentoEavModelEntityAttributeOption $option
            ){
            $this->_logger = $logger;
            $this->_attributeRepository = $attributeRepository;
            $this->_attributeOptionManagement = $attributeOptionManagement;
            $this->_option = $option;
            $this->_attributeOptionLabel = $attributeOptionLabel;
            }


            Then in your function do something like this:



             $attribute_id = $this->_attributeRepository->get('catalog_product', 'your_attribute')->getAttributeId();
            $options = $this->_attributeOptionManagement->getItems('catalog_product', $attribute_id);
            /* if attribute option already exists, remove it */
            foreach($options as $option) {
            if ($option->getLabel() == $oldname) {
            $this->_attributeOptionManagement->delete('catalog_product', $attribute_id, $option->getValue());
            }
            }

            /* new attribute option */
            $this->_option->setValue($name);
            $this->_attributeOptionLabel->setStoreId(0);
            $this->_attributeOptionLabel->setLabel($name);
            $this->_option->setLabel($this->_attributeOptionLabel);
            $this->_option->setStoreLabels([$this->_attributeOptionLabel]);
            $this->_option->setSortOrder(0);
            $this->_option->setIsDefault(false);
            $this->_attributeOptionManagement->add('catalog_product', $attribute_id, $this->_option);





            share|improve this answer



















            • 1





              Thanks, you are correct. I've updated my answer accordingly. Note that $attributeOptionLabel and $option are ORM classes; you should not inject them directly. The proper approach is to inject their factory class, then create an instance as needed. Also note you aren't using the API data interfaces consistently.

              – Ryan Hoerr
              Sep 9 '16 at 14:55






            • 3





              Hi @Rudd, see my comment on Ryan's answer. You don't want to call $option->setValue() as that is for an internal magento option_id field on the eav_attribute_option table.

              – quickshiftin
              Sep 12 '16 at 19:42











            • Thank you. That's what I found out too. Will edit my answer accordingly.

              – Ruud N.
              Sep 14 '16 at 5:49














            10












            10








            10







            Using the MagentoEavSetupEavSetupFactory or even the MagentoCatalogSetupCategorySetupFactory class may lead to the following problem: https://github.com/magento/magento2/issues/4896.



            The classes you should use:



            protected $_logger;

            protected $_attributeRepository;

            protected $_attributeOptionManagement;

            protected $_option;

            protected $_attributeOptionLabel;

            public function __construct(
            PsrLogLoggerInterface $logger,
            MagentoEavModelAttributeRepository $attributeRepository,
            MagentoEavApiAttributeOptionManagementInterface $attributeOptionManagement,
            MagentoEavApiDataAttributeOptionLabelInterface $attributeOptionLabel,
            MagentoEavModelEntityAttributeOption $option
            ){
            $this->_logger = $logger;
            $this->_attributeRepository = $attributeRepository;
            $this->_attributeOptionManagement = $attributeOptionManagement;
            $this->_option = $option;
            $this->_attributeOptionLabel = $attributeOptionLabel;
            }


            Then in your function do something like this:



             $attribute_id = $this->_attributeRepository->get('catalog_product', 'your_attribute')->getAttributeId();
            $options = $this->_attributeOptionManagement->getItems('catalog_product', $attribute_id);
            /* if attribute option already exists, remove it */
            foreach($options as $option) {
            if ($option->getLabel() == $oldname) {
            $this->_attributeOptionManagement->delete('catalog_product', $attribute_id, $option->getValue());
            }
            }

            /* new attribute option */
            $this->_option->setValue($name);
            $this->_attributeOptionLabel->setStoreId(0);
            $this->_attributeOptionLabel->setLabel($name);
            $this->_option->setLabel($this->_attributeOptionLabel);
            $this->_option->setStoreLabels([$this->_attributeOptionLabel]);
            $this->_option->setSortOrder(0);
            $this->_option->setIsDefault(false);
            $this->_attributeOptionManagement->add('catalog_product', $attribute_id, $this->_option);





            share|improve this answer













            Using the MagentoEavSetupEavSetupFactory or even the MagentoCatalogSetupCategorySetupFactory class may lead to the following problem: https://github.com/magento/magento2/issues/4896.



            The classes you should use:



            protected $_logger;

            protected $_attributeRepository;

            protected $_attributeOptionManagement;

            protected $_option;

            protected $_attributeOptionLabel;

            public function __construct(
            PsrLogLoggerInterface $logger,
            MagentoEavModelAttributeRepository $attributeRepository,
            MagentoEavApiAttributeOptionManagementInterface $attributeOptionManagement,
            MagentoEavApiDataAttributeOptionLabelInterface $attributeOptionLabel,
            MagentoEavModelEntityAttributeOption $option
            ){
            $this->_logger = $logger;
            $this->_attributeRepository = $attributeRepository;
            $this->_attributeOptionManagement = $attributeOptionManagement;
            $this->_option = $option;
            $this->_attributeOptionLabel = $attributeOptionLabel;
            }


            Then in your function do something like this:



             $attribute_id = $this->_attributeRepository->get('catalog_product', 'your_attribute')->getAttributeId();
            $options = $this->_attributeOptionManagement->getItems('catalog_product', $attribute_id);
            /* if attribute option already exists, remove it */
            foreach($options as $option) {
            if ($option->getLabel() == $oldname) {
            $this->_attributeOptionManagement->delete('catalog_product', $attribute_id, $option->getValue());
            }
            }

            /* new attribute option */
            $this->_option->setValue($name);
            $this->_attributeOptionLabel->setStoreId(0);
            $this->_attributeOptionLabel->setLabel($name);
            $this->_option->setLabel($this->_attributeOptionLabel);
            $this->_option->setStoreLabels([$this->_attributeOptionLabel]);
            $this->_option->setSortOrder(0);
            $this->_option->setIsDefault(false);
            $this->_attributeOptionManagement->add('catalog_product', $attribute_id, $this->_option);






            share|improve this answer












            share|improve this answer



            share|improve this answer










            answered Aug 1 '16 at 14:55









            Ruud N.Ruud N.

            12117




            12117








            • 1





              Thanks, you are correct. I've updated my answer accordingly. Note that $attributeOptionLabel and $option are ORM classes; you should not inject them directly. The proper approach is to inject their factory class, then create an instance as needed. Also note you aren't using the API data interfaces consistently.

              – Ryan Hoerr
              Sep 9 '16 at 14:55






            • 3





              Hi @Rudd, see my comment on Ryan's answer. You don't want to call $option->setValue() as that is for an internal magento option_id field on the eav_attribute_option table.

              – quickshiftin
              Sep 12 '16 at 19:42











            • Thank you. That's what I found out too. Will edit my answer accordingly.

              – Ruud N.
              Sep 14 '16 at 5:49














            • 1





              Thanks, you are correct. I've updated my answer accordingly. Note that $attributeOptionLabel and $option are ORM classes; you should not inject them directly. The proper approach is to inject their factory class, then create an instance as needed. Also note you aren't using the API data interfaces consistently.

              – Ryan Hoerr
              Sep 9 '16 at 14:55






            • 3





              Hi @Rudd, see my comment on Ryan's answer. You don't want to call $option->setValue() as that is for an internal magento option_id field on the eav_attribute_option table.

              – quickshiftin
              Sep 12 '16 at 19:42











            • Thank you. That's what I found out too. Will edit my answer accordingly.

              – Ruud N.
              Sep 14 '16 at 5:49








            1




            1





            Thanks, you are correct. I've updated my answer accordingly. Note that $attributeOptionLabel and $option are ORM classes; you should not inject them directly. The proper approach is to inject their factory class, then create an instance as needed. Also note you aren't using the API data interfaces consistently.

            – Ryan Hoerr
            Sep 9 '16 at 14:55





            Thanks, you are correct. I've updated my answer accordingly. Note that $attributeOptionLabel and $option are ORM classes; you should not inject them directly. The proper approach is to inject their factory class, then create an instance as needed. Also note you aren't using the API data interfaces consistently.

            – Ryan Hoerr
            Sep 9 '16 at 14:55




            3




            3





            Hi @Rudd, see my comment on Ryan's answer. You don't want to call $option->setValue() as that is for an internal magento option_id field on the eav_attribute_option table.

            – quickshiftin
            Sep 12 '16 at 19:42





            Hi @Rudd, see my comment on Ryan's answer. You don't want to call $option->setValue() as that is for an internal magento option_id field on the eav_attribute_option table.

            – quickshiftin
            Sep 12 '16 at 19:42













            Thank you. That's what I found out too. Will edit my answer accordingly.

            – Ruud N.
            Sep 14 '16 at 5:49





            Thank you. That's what I found out too. Will edit my answer accordingly.

            – Ruud N.
            Sep 14 '16 at 5:49











            8














            tested on Magento 2.1.3.



            I didn't find any workable way how to create attribute with options at once. So initially we need to create an attribute and then add options for it.



            Inject following class MagentoEavSetupEavSetupFactory



             $setup->startSetup();

            /** @var MagentoEavSetupEavSetup $eavSetup */
            $eavSetup = $this->eavSetupFactory->create(['setup' => $setup]);


            Create new attribute:



            $eavSetup->addAttribute(
            'catalog_product',
            $attributeCode,
            [
            'type' => 'varchar',
            'input' => 'select',
            'required' => false,
            ...
            ],
            );


            Add custom options.



            Function addAttribute doesn't return anything useful which can be used in future. So after attribute creation we need to retrieve attribute object by ourself. !!!Important We need it because function expects only attribute_id, but don't want to work with attribute_code.



            In that case we need to get attribute_id and pass it to attribute creation function.



            $attributeId = $eavSetup->getAttributeId('catalog_product', 'attribute_code');


            Then we need to generate options array in the way magento expects:



            $options = [
            'values' => [
            'sort_order1' => 'title1',
            'sort_order2' => 'title2',
            'sort_order3' => 'title3',
            ],
            'attribute_id' => 'some_id',
            ];


            As example:



            $options = [
            'values' => [
            '1' => 'Red',
            '2' => 'Yellow',
            '3' => 'Green',
            ],
            'attribute_id' => '32',
            ];


            And pass it to function:



            $eavSetup->addAttributeOption($options);





            share|improve this answer




























              8














              tested on Magento 2.1.3.



              I didn't find any workable way how to create attribute with options at once. So initially we need to create an attribute and then add options for it.



              Inject following class MagentoEavSetupEavSetupFactory



               $setup->startSetup();

              /** @var MagentoEavSetupEavSetup $eavSetup */
              $eavSetup = $this->eavSetupFactory->create(['setup' => $setup]);


              Create new attribute:



              $eavSetup->addAttribute(
              'catalog_product',
              $attributeCode,
              [
              'type' => 'varchar',
              'input' => 'select',
              'required' => false,
              ...
              ],
              );


              Add custom options.



              Function addAttribute doesn't return anything useful which can be used in future. So after attribute creation we need to retrieve attribute object by ourself. !!!Important We need it because function expects only attribute_id, but don't want to work with attribute_code.



              In that case we need to get attribute_id and pass it to attribute creation function.



              $attributeId = $eavSetup->getAttributeId('catalog_product', 'attribute_code');


              Then we need to generate options array in the way magento expects:



              $options = [
              'values' => [
              'sort_order1' => 'title1',
              'sort_order2' => 'title2',
              'sort_order3' => 'title3',
              ],
              'attribute_id' => 'some_id',
              ];


              As example:



              $options = [
              'values' => [
              '1' => 'Red',
              '2' => 'Yellow',
              '3' => 'Green',
              ],
              'attribute_id' => '32',
              ];


              And pass it to function:



              $eavSetup->addAttributeOption($options);





              share|improve this answer


























                8












                8








                8







                tested on Magento 2.1.3.



                I didn't find any workable way how to create attribute with options at once. So initially we need to create an attribute and then add options for it.



                Inject following class MagentoEavSetupEavSetupFactory



                 $setup->startSetup();

                /** @var MagentoEavSetupEavSetup $eavSetup */
                $eavSetup = $this->eavSetupFactory->create(['setup' => $setup]);


                Create new attribute:



                $eavSetup->addAttribute(
                'catalog_product',
                $attributeCode,
                [
                'type' => 'varchar',
                'input' => 'select',
                'required' => false,
                ...
                ],
                );


                Add custom options.



                Function addAttribute doesn't return anything useful which can be used in future. So after attribute creation we need to retrieve attribute object by ourself. !!!Important We need it because function expects only attribute_id, but don't want to work with attribute_code.



                In that case we need to get attribute_id and pass it to attribute creation function.



                $attributeId = $eavSetup->getAttributeId('catalog_product', 'attribute_code');


                Then we need to generate options array in the way magento expects:



                $options = [
                'values' => [
                'sort_order1' => 'title1',
                'sort_order2' => 'title2',
                'sort_order3' => 'title3',
                ],
                'attribute_id' => 'some_id',
                ];


                As example:



                $options = [
                'values' => [
                '1' => 'Red',
                '2' => 'Yellow',
                '3' => 'Green',
                ],
                'attribute_id' => '32',
                ];


                And pass it to function:



                $eavSetup->addAttributeOption($options);





                share|improve this answer













                tested on Magento 2.1.3.



                I didn't find any workable way how to create attribute with options at once. So initially we need to create an attribute and then add options for it.



                Inject following class MagentoEavSetupEavSetupFactory



                 $setup->startSetup();

                /** @var MagentoEavSetupEavSetup $eavSetup */
                $eavSetup = $this->eavSetupFactory->create(['setup' => $setup]);


                Create new attribute:



                $eavSetup->addAttribute(
                'catalog_product',
                $attributeCode,
                [
                'type' => 'varchar',
                'input' => 'select',
                'required' => false,
                ...
                ],
                );


                Add custom options.



                Function addAttribute doesn't return anything useful which can be used in future. So after attribute creation we need to retrieve attribute object by ourself. !!!Important We need it because function expects only attribute_id, but don't want to work with attribute_code.



                In that case we need to get attribute_id and pass it to attribute creation function.



                $attributeId = $eavSetup->getAttributeId('catalog_product', 'attribute_code');


                Then we need to generate options array in the way magento expects:



                $options = [
                'values' => [
                'sort_order1' => 'title1',
                'sort_order2' => 'title2',
                'sort_order3' => 'title3',
                ],
                'attribute_id' => 'some_id',
                ];


                As example:



                $options = [
                'values' => [
                '1' => 'Red',
                '2' => 'Yellow',
                '3' => 'Green',
                ],
                'attribute_id' => '32',
                ];


                And pass it to function:



                $eavSetup->addAttributeOption($options);






                share|improve this answer












                share|improve this answer



                share|improve this answer










                answered Feb 23 '17 at 7:46









                zhartaunikzhartaunik

                2,65511444




                2,65511444























                    -3














                    This is NOT an answer. Just a workaround.



                    It assumes that you have access to Magento Backend using browser and you are on the edit attribute page (url looks like admin/catalog/product_attribute/edit/attribute_id/XXX/key..)



                    Go to Browser console (CTRL + SHIFT + J on chrome)
                    and paste the following code after changing the array mimim.



                    $jq=new jQuery.noConflict();
                    var mimim=["xxx","yyy","VALUES TO BE ADDED"];
                    $jq.each(mimim,function(a,b){
                    $jq("#add_new_option_button").click();
                    $jq("#manage-options-panel tbody tr:last-child td:nth-child(3) input").val(b);
                    });


                    -- tested on Magento 2.2.2



                    Detailed article - https://tutes.in/how-to-manage-magento-2-product-attribute-values-options-using-console/






                    share|improve this answer





















                    • 1





                      This is a terrible long term solution. You can't reliably expect those selectors to stay the same. This is a workaround at best, if it actually works as expected.

                      – domdambrogia
                      Apr 21 '18 at 0:24











                    • @domdambrogia agree. It is a workaround.

                      – th3pirat3
                      Apr 23 '18 at 17:26
















                    -3














                    This is NOT an answer. Just a workaround.



                    It assumes that you have access to Magento Backend using browser and you are on the edit attribute page (url looks like admin/catalog/product_attribute/edit/attribute_id/XXX/key..)



                    Go to Browser console (CTRL + SHIFT + J on chrome)
                    and paste the following code after changing the array mimim.



                    $jq=new jQuery.noConflict();
                    var mimim=["xxx","yyy","VALUES TO BE ADDED"];
                    $jq.each(mimim,function(a,b){
                    $jq("#add_new_option_button").click();
                    $jq("#manage-options-panel tbody tr:last-child td:nth-child(3) input").val(b);
                    });


                    -- tested on Magento 2.2.2



                    Detailed article - https://tutes.in/how-to-manage-magento-2-product-attribute-values-options-using-console/






                    share|improve this answer





















                    • 1





                      This is a terrible long term solution. You can't reliably expect those selectors to stay the same. This is a workaround at best, if it actually works as expected.

                      – domdambrogia
                      Apr 21 '18 at 0:24











                    • @domdambrogia agree. It is a workaround.

                      – th3pirat3
                      Apr 23 '18 at 17:26














                    -3












                    -3








                    -3







                    This is NOT an answer. Just a workaround.



                    It assumes that you have access to Magento Backend using browser and you are on the edit attribute page (url looks like admin/catalog/product_attribute/edit/attribute_id/XXX/key..)



                    Go to Browser console (CTRL + SHIFT + J on chrome)
                    and paste the following code after changing the array mimim.



                    $jq=new jQuery.noConflict();
                    var mimim=["xxx","yyy","VALUES TO BE ADDED"];
                    $jq.each(mimim,function(a,b){
                    $jq("#add_new_option_button").click();
                    $jq("#manage-options-panel tbody tr:last-child td:nth-child(3) input").val(b);
                    });


                    -- tested on Magento 2.2.2



                    Detailed article - https://tutes.in/how-to-manage-magento-2-product-attribute-values-options-using-console/






                    share|improve this answer















                    This is NOT an answer. Just a workaround.



                    It assumes that you have access to Magento Backend using browser and you are on the edit attribute page (url looks like admin/catalog/product_attribute/edit/attribute_id/XXX/key..)



                    Go to Browser console (CTRL + SHIFT + J on chrome)
                    and paste the following code after changing the array mimim.



                    $jq=new jQuery.noConflict();
                    var mimim=["xxx","yyy","VALUES TO BE ADDED"];
                    $jq.each(mimim,function(a,b){
                    $jq("#add_new_option_button").click();
                    $jq("#manage-options-panel tbody tr:last-child td:nth-child(3) input").val(b);
                    });


                    -- tested on Magento 2.2.2



                    Detailed article - https://tutes.in/how-to-manage-magento-2-product-attribute-values-options-using-console/







                    share|improve this answer














                    share|improve this answer



                    share|improve this answer








                    edited 9 mins ago

























                    answered Oct 14 '17 at 18:18









                    th3pirat3th3pirat3

                    1615




                    1615








                    • 1





                      This is a terrible long term solution. You can't reliably expect those selectors to stay the same. This is a workaround at best, if it actually works as expected.

                      – domdambrogia
                      Apr 21 '18 at 0:24











                    • @domdambrogia agree. It is a workaround.

                      – th3pirat3
                      Apr 23 '18 at 17:26














                    • 1





                      This is a terrible long term solution. You can't reliably expect those selectors to stay the same. This is a workaround at best, if it actually works as expected.

                      – domdambrogia
                      Apr 21 '18 at 0:24











                    • @domdambrogia agree. It is a workaround.

                      – th3pirat3
                      Apr 23 '18 at 17:26








                    1




                    1





                    This is a terrible long term solution. You can't reliably expect those selectors to stay the same. This is a workaround at best, if it actually works as expected.

                    – domdambrogia
                    Apr 21 '18 at 0:24





                    This is a terrible long term solution. You can't reliably expect those selectors to stay the same. This is a workaround at best, if it actually works as expected.

                    – domdambrogia
                    Apr 21 '18 at 0:24













                    @domdambrogia agree. It is a workaround.

                    – th3pirat3
                    Apr 23 '18 at 17:26





                    @domdambrogia agree. It is a workaround.

                    – th3pirat3
                    Apr 23 '18 at 17:26


















                    draft saved

                    draft discarded




















































                    Thanks for contributing an answer to Magento Stack Exchange!


                    • Please be sure to answer the question. Provide details and share your research!

                    But avoid



                    • Asking for help, clarification, or responding to other answers.

                    • Making statements based on opinion; back them up with references or personal experience.


                    To learn more, see our tips on writing great answers.




                    draft saved


                    draft discarded














                    StackExchange.ready(
                    function () {
                    StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fmagento.stackexchange.com%2fquestions%2f103934%2fmagento2-programmatically-add-product-attribute-options%23new-answer', 'question_page');
                    }
                    );

                    Post as a guest















                    Required, but never shown





















































                    Required, but never shown














                    Required, but never shown












                    Required, but never shown







                    Required, but never shown

































                    Required, but never shown














                    Required, but never shown












                    Required, but never shown







                    Required, but never shown







                    Popular posts from this blog

                    What other Star Trek series did the main TNG cast show up in?

                    Berlina muro

                    Berlina aerponto