Magento 2 - Using a Data Upgrade Script to Create an Attribute in a New Attribute Set

4th Mar 2018 Olha Syzova

When you migrate to Magento or are moving a fresh set of data into a new product catalog, capturing your product attributes in meaningful groups is a good idea. An attribute is a specific feature or variable that makes a configuration of a product different from others. T-shirts have brands, sizes and colors. Jackets have brands, sizes and colors. If a new product attribute applies to all products in your catalog, add it to the Default attribute set. If your apparel store also sells necklaces and those come in a chain length, you may want to create a necklace attribute set to hold the chain specific attributes. This de-clutters your admin and your data model, making things easier to understand and work with.

Let's start with creating an attribute that describes the general property Brand and then assign it to the Default attribute set.

Сreate Product Attribute With Options

/**
 * Create Product Attributes Specifications
 *
 * @param EavSetup $eavSetup
 */
public function createProductAttributeWithOptions($eavSetup)
{
    $options = ['Chanel', 'Gucci'];
    $attributeCode = 'brand';
    $this->removeAttributeOptions($attributeCode, $options);
    $eavSetup->addAttribute(
        Product::ENTITY,
        $attributeCode,
        [
            'type'                    => 'int',
            'label'                   => 'Brand',
            'input'                   => 'select',
            'required'                => false,
            'sort_order'              => 240,
            'global'                  => Attribute::SCOPE_GLOBAL,
            'group'                   => 'Specifications',
            'user_defined'            => true,
            'used_in_product_listing' => true,
            'visible_on_front'        => true,
            'option'                  => ['values' => $options]
        ]
    );
}

Don't forget to check if you might be inserting duplicate data. The default Magento database will let you do this so we need to catch this in the code.

Remove Attribute Options

/**
 * Remove custom attribute options
 *
 * @param string $attributeCode
 * @param array  $options
 */
protected function removeAttributeOptions($attributeCode, $options)
{
    /** @var AbstractAttribute $attribute */
    $attribute = $this->eavConfig->getAttribute(Product::ENTITY, $attributeCode);
    if ($attribute && $attributeId = $attribute->getAttributeId()) {
        $attributeOptions = $this->attributeOptionManagement->getItems(Product::ENTITY, $attributeId);
        /* if attribute option already exists, remove it */
        foreach ($attributeOptions as $option) {
            if (in_array($option->getLabel(), $options)) {
                $this->attributeOptionManagement->delete(Product::ENTITY, $attributeId, $option->getValue());
            }
        }
    }
}

Now we should create the Necklace attribute set:

Create Attruibute Sets

/**
 * Create custom attribute set
 *
 * @param EavSetup $eavSetup
 */
public function createAttributeSet($eavSetup)
{
    $entityTypeId = $eavSetup->getEntityTypeId(Product::ENTITY);
    $defaultSetId = $eavSetup->getDefaultAttributeSetId($entityTypeId);
    $attributeSetName = 'Necklace';
    /** @var AttributeSet $attributeSet */
    $attributeSet = $this->attributeSetFactory->create();
    $attributeSet->setAttributeSetName($attributeSetName);
    $attributeSet->setEntityTypeId($entityTypeId);
    $attributeSet->setSortOrder(200);
    $this->attributeSetManagement->create($attributeSet, $defaultSetId);
}

Add Attributes used in creating our Necklace Configurable Product

Next step is creating Configurable Product options attributes on which Simple products will be based. Metal Color could be associated with different types of jewelry as ring, earring, necklace. Metal Color attribute is assigned to the Default attribute set so it will be available for most products. Chain Length attribute is assigned to the Necklace attribute set and will be available only for products created with the Necklace attribute set.

So for example, a customer buying a ring would choose Metal Color and a customer buying a necklace would choose Metal Color and Chain Length.

Create Product Configurable Options Attributes

 /**
 * Create Product Configurable options on which Simple products will be based
 *
 * @param EavSetup $eavSetup
 */
public function createProductConfigurableOptionsAttributes($eavSetup)
{
    $productTypes = join(',', [Type::TYPE_SIMPLE, Type::TYPE_VIRTUAL, Configurable::TYPE_CODE]);
    $entityTypeId = $eavSetup->getEntityTypeId(Product::ENTITY);

    // Default attribute set
    $options = ['Silver', 'Gold', 'Multi-coloured'];
    $attributeCode = 'metal_color';
    $this->removeAttributeOptions($attributeCode, $options);
    $eavSetup->addAttribute(
        Product::ENTITY,
        $attributeCode,
        [
            'type'                       => 'int',
            'label'                      => 'Metal Color',
            'input'                      => 'select',
            'required'                   => false,
            'sort_order'                 => 500,
            'global'                     => Attribute::SCOPE_GLOBAL,
            'group'                      => 'General',
            'user_defined'               => true,
            'searchable'                 => true,
            'filterable'                 => true,
            'comparable'                 => true,
            'visible_in_advanced_search' => true,
            'is_used_in_grid'            => true,
            'is_visible_in_grid'         => false,
            'is_filterable_in_grid'      => true,
            'used_in_product_listing'    => true,
            'option'                     => ['values' => $options]
        ]
    );

    // Custom attribute set
    $options = [40, 45, 50];
    $attributeCode = 'chain_length';
    $this->removeAttributeOptions($attributeCode, $options);
    $eavSetup->addAttribute(
        Product::ENTITY,
        $attributeCode,
        [
            'type'                       => 'int',
            'label'                      => 'Chain Length',
            'input'                      => 'select',
            'required'                   => false,
            'sort_order'                 => 501,
            'global'                     => Attribute::SCOPE_GLOBAL,
            'group'                      => '',
            'user_defined'               => true,
            'searchable'                 => true,
            'filterable'                 => true,
            'comparable'                 => true,
            'visible_in_advanced_search' => true,
            'is_used_in_grid'            => true,
            'is_visible_in_grid'         => false,
            'is_filterable_in_grid'      => true,
            'used_in_product_listing'    => true,
            'option'                     => ['values' => $options],
            'apply_to'                   => $productTypes
        ]
    );
    $attributeSetId = $eavSetup->getAttributeSetId($entityTypeId, 'Necklace');
    $attributeGroupId = $eavSetup->getAttributeGroupId($entityTypeId, $attributeSetId, 'Default');
    $eavSetup->addAttributeToSet($entityTypeId, $attributeSetId, $attributeGroupId, $attributeCode);
}