Magento 2 : Create Custom Product Attribute Programmatically

Here is how you can create your own custom product attribute, sorted in your custom attribute set, and custom group name as well.

All you have to do is build your attributes array 🙂

<?php
/**
 * @license http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
 * @author Phuong LE <sony@meincode.com> <@>
 * @copyright Copyright (c) 2019 Menincode (http://www.menincode.com)
 */

namespace MyNameSpace\Catalog\Setup;


use Magento\Catalog\Api\AttributeSetManagementInterface;
use Magento\Catalog\Model\Product;
use Magento\Eav\Api\AttributeGroupRepositoryInterface;
use Magento\Eav\Setup\EavSetup;
use Magento\Eav\Setup\EavSetupFactory;
use Magento\Eav\Api\Data\AttributeGroupInterfaceFactory;
use Magento\Eav\Api\Data\AttributeSetInterfaceFactory;
use Magento\Framework\Setup\ModuleContextInterface;
use Magento\Framework\Setup\ModuleDataSetupInterface;
use Magento\Framework\Setup\UpgradeDataInterface;

class UpgradeData implements UpgradeDataInterface
{
    /**
     * @var EavSetupFactory
     */
    private $eavSetupFactory;
    /**
     * @var Product
     */
    private $product;
    /**
     * @var AttributeSetInterfaceFactory
     */
    private $attributeSetFactory;
    /**
     * @var AttributeSetManagementInterface
     */
    private $attributeSetManagement;
    /**
     * @var AttributeGroupInterfaceFactory
     */
    private $attributeGroupFactory;
    /**
     * @var AttributeGroupRepositoryInterface
     */
    private $attributeGroupRepository;
    /**
     * UpgradeData constructor.
     * @param EavSetupFactory $eavSetupFactory
     * @param Product $product
     * @param AttributeSetInterfaceFactory $attributeSetInterfaceFactory
     * @param AttributeSetManagementInterface $attributeSetManagement
     * @param AttributeGroupInterfaceFactory $attributeGroupFactory
     * @param AttributeGroupRepositoryInterface $attributeGroupRepository
     */
    public function __construct(
        EavSetupFactory $eavSetupFactory,
        Product $product,
        AttributeSetInterfaceFactory $attributeSetInterfaceFactory,
        AttributeSetManagementInterface $attributeSetManagement,
        AttributeGroupInterfaceFactory $attributeGroupFactory,
        AttributeGroupRepositoryInterface $attributeGroupRepository
    ) {
        $this->eavSetupFactory = $eavSetupFactory;
        $this->product = $product;
        $this->attributeSetFactory = $attributeSetInterfaceFactory;
        $this->attributeSetManagement = $attributeSetManagement;
        $this->attributeGroupFactory = $attributeGroupFactory;
        $this->attributeGroupRepository = $attributeGroupRepository;
    }

    /**
     * @param ModuleDataSetupInterface $setup
     * @param ModuleContextInterface $context
     * @throws \Magento\Framework\Exception\LocalizedException
     */
    public function upgrade(ModuleDataSetupInterface $setup, ModuleContextInterface $context)
    {
        if (version_compare($context->getVersion(), '0.0.1', '<')) {
            $attributes = [
                'my_custom_attribute' => [
                    'type' => 'int',
                    'label' => 'My Custom Label',
                    'input' => 'select',
                    'source' => 'MyNamespace\MyModule\Model\MyEntity\Config\Source\Options',
                    'filterable' => true,
                    'visible_on_front' => true,
                    'used_in_product_listing' => true,
                    'backend' => ''
                ]
            ];
            $this->createProductAttribute($attributes);
        }

        if (version_compare($context->getVersion(), '0.0.2', '<')) {
            $attributes = [
                'another_custom_attribute' => [
                    'type' => 'varchar',
                    'label' => 'Another Custom Label',
                    'input' => 'text',
                    'source' => '',
                    'filterable' => false,
                    'visible_on_front' => true,
                    'used_in_product_listing' => false,
                    'attribute_group_name' => 'My Custom Attribute Group Name',
                    'backend' => ''
                ],
                'another_custom_attribute_with_option' => [
                    'type' => 'int',
                    'label' => 'Type',
                    'input' => 'select',
                    'source' => '',
                    'filterable' => true,
                    'visible_on_front' => true,
                    'used_in_product_listing' => true,
                    'backend' => '',
                    'options' => [
                        'Option A',
                        'Option B',
                        'Option C',
                        'Option D',
                        'Option E',
                        'Option F'
                    ]
                ],
                'another_custom_attribute_boolean' =>[
                    'type' => 'int',
                    'label' => 'Shown In List',
                    'input' => 'select',
                    'source' => 'Magento\Eav\Model\Entity\Attribute\Source\Boolean',
                    'filterable' => false,
                    'visible_on_front' => false,
                    'used_in_product_listing' => false,
                    'attribute_group_name' => 'Another Custom Attribute Group Name',
                    'attribute_set_name' => 'my custom Attribute Set Name',
                    'backend' => ''
                ],
                'another_custom_attribute_multiselect' => [
                    'type' => 'varchar',
                    'label' => 'Collection',
                    'input' => 'multiselect',
                    'source' => '',
                    'filterable' => true,
                    'visible_on_front' => true,
                    'used_in_product_listing' => true,
                    'options' => [
                        'Collection A',
                        'Collection B',
                        'Collection C',
                        'Collection D',
                    ],
                    'attribute_group_name' => 'Another Custom Attribute Group Name',
                    'backend' => 'Magento\Eav\Model\Entity\Attribute\Backend\ArrayBackend'
                ],
            ];
            $this->createProductAttribute($attributes);
        }
    }

    /**
     * Create Attribute
     * @param $attributes
     * @throws \Magento\Framework\Exception\LocalizedException
     */
    private function createProductAttribute($attributes)
    {
        foreach ($attributes as $attribute => $data) {
            /** @var EavSetup $eavSetup */
            $eavSetup = $this->eavSetupFactory->create();
            $productEntity = \Magento\Catalog\Model\Product::ENTITY;
            $attrSetName = null;
            $attributeGroupId = null;
            /**
             * Initialise Attribute Set Id
             */
            if (isset($data['attribute_set_name'])) {
                $attributeSetId = $eavSetup->getAttributeSetId($productEntity, $data['attribute_set_name']);
                /**
                 * If our attribute set name does not exist, we create it.
                 * By default if Magento does not find an attribute set Id, it returns the default attribute set Id
                 */
                if($attributeSetId == $eavSetup->getDefaultAttributeSetId($productEntity) && $data['attribute_set_name'] != 'Default') {
                    $attrSetName = $data['attribute_set_name'];
                    $this->createAttributeSet($attrSetName);
                    $attributeSetId = $eavSetup->getAttributeSetId($productEntity, $attrSetName);
                }
            } else {
                $attributeSetId = $this->product->getDefaultAttributeSetId();
            }

            /**
             * Initialise Attribute Group Id
             */
            if (isset($data['attribute_group_name'])) {
                $attributeGroupId = $eavSetup->getAttributeGroupId($productEntity, $attributeSetId, $data['attribute_group_name']);
                /**
                 * If our attribute group name does not exist, we create it
                 */
                if($attributeGroupId == $eavSetup->getDefaultAttributeGroupId($productEntity) && $data['attribute_group_name'] != 'General') {
                    $attributeGroupName = $data['attribute_group_name'];
                    $this->createAttributeGroup($attributeGroupName, $attrSetName);
                    $attributeGroupId = $eavSetup->getAttributeGroupId($productEntity, $attributeSetId, $attributeGroupName);
                }
            }
            /**
             * Add attributes to the eav/attribute
             */
            $eavSetup->addAttribute(
                $productEntity,
                $attribute,
                [
                    'group' => $attributeGroupId ? '' : 'General', // Let empty, if we want to set an attribute group id
                    'type' => $data['type'],
                    'backend' => $data['backend'],
                    'frontend' => '',
                    'label' => $data['label'],
                    'input' => $data['input'],
                    'class' => '',
                    'source' => $data['source'],
                    'global' => \Magento\Eav\Model\Entity\Attribute\ScopedAttributeInterface::SCOPE_GLOBAL,
                    'visible' => true,
                    'required' => false,
                    'user_defined' => true,
                    'default' => '',
                    'searchable' => false,
                    'filterable' => $data['filterable'],
                    'comparable' => false,
                    'visible_on_front' => $data['visible_on_front'],
                    'used_in_product_listing' => $data['used_in_product_listing'],
                    'unique' => false
                ]
            );

            /**
             * Set attribute group Id if needed
             */
            if (!is_null($attributeGroupId)) {
                /**
                 * Set the attribute in the right attribute group in the right attribute set
                 */
                $eavSetup->addAttributeToGroup($productEntity, $attributeSetId, $attributeGroupId, $attribute);
            }

            /**
             * Add options if needed
             */
            if (isset($data['options'])) {
                $options = [
                    'attribute_id' => $eavSetup->getAttributeId($productEntity, $attribute),
                    'values' => $data['options']
                ];
                $eavSetup->addAttributeOption($options);
            }
        }
    }

    /**
     * @param $attrSetName
     * @throws \Magento\Framework\Exception\InputException
     * @throws \Magento\Framework\Exception\NoSuchEntityException
     */
    private function createAttributeSet($attrSetName)
    {
        $defaultAttributeSetId = $this->product->getDefaultAttributeSetId();
        $attributeSet = $this->attributeSetFactory->create();
        $attributeSet->setAttributeSetName($attrSetName);
        $this->attributeSetManagement->create($attributeSet, $defaultAttributeSetId);
    }

    /**
     * @param $attributeGroupName
     * @param null $attrSetName
     * @throws \Magento\Framework\Exception\InputException
     * @throws \Magento\Framework\Exception\LocalizedException
     * @throws \Magento\Framework\Exception\NoSuchEntityException
     */
    private function createAttributeGroup($attributeGroupName, $attrSetName = null) {

        /** @var EavSetup $eavSetup */
        $eavSetup = $this->eavSetupFactory->create();
        $productEntity = \Magento\Catalog\Model\Product::ENTITY;

        if ($attrSetName) {
            $this->createAttributeSet($attrSetName);
            $attributeSetId = $eavSetup->getAttributeSetId($productEntity, $attrSetName);
        } else {
            $attributeSetId = $this->product->getDefaultAttributeSetId();
        }

        $attributeGroup = $this->attributeGroupFactory->create();
        $attributeGroup->setAttributeSetId($attributeSetId);
        $attributeGroup->setAttributeGroupName($attributeGroupName);
        $this->attributeGroupRepository->save($attributeGroup);
    }
}
Name (required)Email (required)Website

Leave a Reply