This article shows how you can programmatically add or create a new product attribute, product attribute group, and product attribute set in Magento 2.
In this article, we will be looking at the following:
- Create Product Attribute
- Update Product Attribute
- Remove Product Attribute
- Create Product Attribute Group/Tab
- Add Product Attributes to the Attribute Group/Tab
- Create Product Attribute Set
- Add Attribute Group to Attribute Set
- Add Attribute to all Attribute Sets
I will also show how you can add the product attributes from both Install Script and Upgrade Script:
- Add product attribute from Install Script (
InstallData.php
) - Add product attribute from Upgrade Script (
UpgradeData.php
)
The example module name for this article is: Chapagain_ProductAttribute
Add/Create Product Attribute Using the Install Script
Here, we will be creating two product attributes:
- My Custom Text (attribute code:
chapagain_attribute_text_1
) - My Custom SelectBox (attribute code:
chapagain_attribute_select_1
)
app/code/Chapagain/ProductAttribute/Setup/InstallData.php
<?php
namespace Chapagain\ProductAttribute\Setup;
use Magento\Eav\Setup\EavSetupFactory;
use Magento\Framework\Setup\InstallDataInterface;
use Magento\Framework\Setup\ModuleContextInterface;
use Magento\Framework\Setup\ModuleDataSetupInterface;
class InstallData implements InstallDataInterface
{
/**
* EAV setup factory
*
* @var \Magento\Eav\Setup\EavSetupFactory
*/
protected $eavSetupFactory;
/**
* Constructor
*
* @param EavSetupFactory $eavSetupFactory
*/
public function __construct(
EavSetupFactory $eavSetupFactory,
) {
$this->eavSetupFactory = $eavSetupFactory;
}
/**
* {@inheritdoc}
*/
public function install(
ModuleDataSetupInterface $setup,
ModuleContextInterface $context
) {
$setup->startSetup();
$eavSetup = $this->eavSetupFactory->create(['setup' => $setup]);
/**
* Insert/Create a simple text attribute
*/
$eavSetup->addAttribute(
\Magento\Catalog\Model\Product::ENTITY,
'chapagain_attribute_text_1',
[
'type' => 'text',
'backend' => '',
'frontend' => '',
'label' => 'My Custom Text',
'input' => 'text',
'class' => '',
'source' => '',
'global' => \Magento\Eav\Model\Entity\Attribute\ScopedAttributeInterface::SCOPE_STORE, // can also use \Magento\Catalog\Model\ResourceModel\Eav\Attribute::SCOPE_STORE, // scope of the attribute (global, store, website)
'visible' => true,
'required' => true,
'user_defined' => false,
'default' => '',
'searchable' => false,
'filterable' => false,
'comparable' => false,
'visible_on_front' => false,
'used_in_product_listing' => true,
'unique' => false,
'apply_to' => ''
]
);
/**
* Insert/Create a seletbox attribute with custom options
*/
$eavSetup->addAttribute(
\Magento\Catalog\Model\Product::ENTITY,
'chapagain_attribute_select_1',
[
'type' => 'int', // data type to be saved in database table
'backend' => '',
'frontend' => '',
'label' => 'My Custom Selectbox',
'input' => 'select', // form element type displayed in the form
'class' => '',
'source' => 'Chapagain\ProductAttribute\Model\Config\Source\MyCustomOptions',
'global' => \Magento\Eav\Model\Entity\Attribute\ScopedAttributeInterface::SCOPE_STORE, // can also use \Magento\Catalog\Model\ResourceModel\Eav\Attribute::SCOPE_STORE, // scope of the attribute (global, store, website)
'visible' => true,
'required' => true,
'user_defined' => false,
'default' => '',
'searchable' => false,
'filterable' => false,
'comparable' => false,
'visible_on_front' => false,
'used_in_product_listing' => true,
'unique' => false,
'apply_to' => ''
]
);
$setup->endSetup();
}
}
For My Custom Selectbox (chapagain_attribute_select_1
) attribute, we have defined a custom source file: Chapagain\ProductAttribute\Model\Config\Source\MyCustomOptions
Hence, we need to create the source file as well. This class file contains the list of options to be displayed in the select box attribute.
app/code/Chapagain/ProductAttribute/Model/Config/Source/MyCustomOptions.php
<?php
namespace Chapagain\ProductAttribute\Model\Config\Source;
class MyCustomOptions extends \Magento\Eav\Model\Entity\Attribute\Source\AbstractSource
{
/**
* Get all options
*
* @return array
*/
public function getAllOptions()
{
if ($this->_options === null) {
$this->_options = [
['value' => '', 'label' => __('Please Select')],
['value' => '1', 'label' => __('My Option 1')],
['value' => '2', 'label' => __('My Option 2')],
['value' => '3', 'label' => __('My Option 3')],
['value' => '4', 'label' => __('My Option 4')]
];
}
return $this->_options;
}
/**
* Get text of the option value
*
* @param string|integer $value
* @return string|bool
*/
public function getOptionValue($value)
{
foreach ($this->getAllOptions() as $option) {
if ($option['value'] == $value) {
return $option['label'];
}
}
return false;
}
}
Add/Create Product Attribute & Attribute Group Using the Install Script
In the code below, the following are done:
- Create two product attributes:
- My Custom Text (
chapagain_attribute_text_1
) - My Custom Selectbox (
chapagain_attribute_text_1
)
- My Custom Text (
- Create a new product attribute group named My Custom Group
- Assign those two attributes to the newly created attribute group
app/code/Chapagain/ProductAttribute/Setup/InstallData.php
<?php
namespace Chapagain\ProductAttribute\Setup;
use Magento\Eav\Setup\EavSetupFactory;
use Magento\Framework\Setup\InstallDataInterface;
use Magento\Framework\Setup\ModuleContextInterface;
use Magento\Framework\Setup\ModuleDataSetupInterface;
class InstallData implements InstallDataInterface
{
/**
* EAV setup factory
*
* @var \Magento\Eav\Setup\EavSetupFactory
*/
protected $eavSetupFactory;
/**
* Constructor
*
* @param EavSetupFactory $eavSetupFactory
*/
public function __construct(
EavSetupFactory $eavSetupFactory
) {
$this->eavSetupFactory = $eavSetupFactory;
}
/**
* {@inheritdoc}
*/
public function install(
ModuleDataSetupInterface $setup,
ModuleContextInterface $context
) {
$setup->startSetup();
$eavSetup = $this->eavSetupFactory->create(['setup' => $setup]);
/**
* Insert/Create a simple text attribute
*/
$eavSetup->addAttribute(
\Magento\Catalog\Model\Product::ENTITY,
'chapagain_attribute_text_1',
[
'type' => 'text',
'backend' => '',
'frontend' => '',
'label' => 'My Custom Text',
'input' => 'text',
'class' => '',
'source' => '',
'global' => \Magento\Eav\Model\Entity\Attribute\ScopedAttributeInterface::SCOPE_STORE, // can also use \Magento\Catalog\Model\ResourceModel\Eav\Attribute::SCOPE_STORE, // scope of the attribute (global, store, website)
'visible' => true,
'required' => true,
'user_defined' => false,
'default' => '',
'searchable' => false,
'filterable' => false,
'comparable' => false,
'visible_on_front' => false,
'used_in_product_listing' => true,
'unique' => false,
'apply_to' => ''
]
);
/**
* Insert/Create a seletbox attribute with custom options
*/
$eavSetup->addAttribute(
\Magento\Catalog\Model\Product::ENTITY,
'chapagain_attribute_select_1',
[
'type' => 'int', // data type to be saved in database table
'backend' => '',
'frontend' => '',
'label' => 'My Custom Selectbox',
'input' => 'select', // form element type displayed in the form
'class' => '',
'source' => 'Chapagain\ProductAttribute\Model\Config\Source\MyCustomOptions',
'global' => \Magento\Eav\Model\Entity\Attribute\ScopedAttributeInterface::SCOPE_STORE, // can also use \Magento\Catalog\Model\ResourceModel\Eav\Attribute::SCOPE_STORE, // scope of the attribute (global, store, website)
'visible' => true,
'required' => true,
'user_defined' => false,
'default' => '',
'searchable' => false,
'filterable' => false,
'comparable' => false,
'visible_on_front' => false,
'used_in_product_listing' => true,
'unique' => false,
'apply_to' => ''
]
);
// get default attribute set id
$attributeSetId = $eavSetup->getDefaultAttributeSetId(\Magento\Catalog\Model\Product::ENTITY);
$attributeGroupName = 'My Custom Group';
// your custom attribute group/tab
$eavSetup->addAttributeGroup(
\Magento\Catalog\Model\Product::ENTITY,
$attributeSetId,
$attributeGroupName, // attribute group name
100 // sort order
);
// add attribute to group
$eavSetup->addAttributeToGroup(
\Magento\Catalog\Model\Product::ENTITY,
$attributeSetId,
$attributeGroupName, // attribute group
'chapagain_attribute_text_1', // attribute code
10 // sort order
);
// add attribute to group
$eavSetup->addAttributeToGroup(
\Magento\Catalog\Model\Product::ENTITY,
$attributeSetId,
$attributeGroupName, // attribute group
'chapagain_attribute_select_1', // attribute code
20 // sort order
);
$setup->endSetup();
}
}
Add/Create Product Attribute, Attribute Group & Attribute Set Using the Install Script
In the code below, we do the following:
- Create a new attribute set named: MyCustomAttributeSet
- Create a product attribute named My Custom Attr with the attribute code:
chapagain_attribute_2
- Create a new product attribute group named My Custom Group 2 in all the attribute sets present in the Magento store
- Assign the product attribute
chapagain_attribute_2
to the attribute group My Custom Group 2 in all the attribute sets available in the Magento store
app/code/Chapagain/ProductAttribute/Setup/InstallData.php
<?php
namespace Chapagain\ProductAttribute\Setup;
use Magento\Eav\Setup\EavSetupFactory;
use Magento\Eav\Model\Entity\Attribute\SetFactory;
use Magento\Framework\Setup\InstallDataInterface;
use Magento\Framework\Setup\ModuleContextInterface;
use Magento\Framework\Setup\ModuleDataSetupInterface;
class InstallData implements InstallDataInterface
{
/**
* EAV setup factory
*
* @var \Magento\Eav\Setup\EavSetupFactory
*/
protected $eavSetupFactory;
/**
* Attribute set factory
*
* @var SetFactory
*/
protected $attributeSetFactory;
/**
* Constructor
*
* @param EavSetupFactory $eavSetupFactory
* @param SetFactory $attributeSetFactory
*/
public function __construct(
EavSetupFactory $eavSetupFactory,
SetFactory $attributeSetFactory
) {
$this->eavSetupFactory = $eavSetupFactory;
$this->attributeSetFactory = $attributeSetFactory;
}
/**
* {@inheritdoc}
*/
public function install(
ModuleDataSetupInterface $setup,
ModuleContextInterface $context
) {
$setup->startSetup();
$eavSetup = $this->eavSetupFactory->create(['setup' => $setup]);
/**
* Create a New Attribute Set
*/
$attributeSet = $this->attributeSetFactory->create();
$entityTypeId = $eavSetup->getEntityTypeId(\Magento\Catalog\Model\Product::ENTITY);
$attributeSetId = $eavSetup->getDefaultAttributeSetId($entityTypeId); // default attribute set
$data = [
'attribute_set_name' => 'MyCustomAttributeSet',
'entity_type_id' => $entityTypeId,
'sort_order' => 100,
];
$attributeSet->setData($data);
$attributeSet->validate();
$attributeSet->save();
$attributeSet->initFromSkeleton($attributeSetId);
$attributeSet->save();
// add a new attribute
// and assign it to the "MyCustomAttributeSet" attribute set
$eavSetup->addAttribute(
\Magento\Catalog\Model\Product::ENTITY,
'chapagain_attribute_2',
[
'type' => 'text',
'backend' => '',
'frontend' => '',
'label' => 'My Custom Attr',
'input' => 'text',
'class' => '',
'source' => '',
'global' => \Magento\Eav\Model\Entity\Attribute\ScopedAttributeInterface::SCOPE_GLOBAL, // can also use \Magento\Catalog\Model\ResourceModel\Eav\Attribute::SCOPE_STORE, // scope of the attribute (global, store, website)
'visible' => true,
'required' => true,
'user_defined' => false,
'default' => '',
'searchable' => false,
'filterable' => false,
'comparable' => false,
'visible_on_front' => false,
'used_in_product_listing' => true,
'unique' => false,
'apply_to' => '',
'attribute_set' => 'MyCustomAttributeSet' // assigning the attribute to the attribute set "MyCustomAttributeSet"
]
);
/**
* Create a custom attribute group in all attribute sets
* And, Add attribute to that attribute group for all attribute sets
*/
// we are going to add this attribute to all attribute sets
$attributeCode = 'chapagain_attribute_2';
//
$attributeGroupName = 'My Custom Group 2';
// get the catalog_product entity type id/code
$entityTypeId = $eavSetup->getEntityTypeId(\Magento\Catalog\Model\Product::ENTITY);
// get the attribute set ids of all the attribute sets present in your Magento store
$attributeSetIds = $eavSetup->getAllAttributeSetIds($entityTypeId);
foreach ($attributeSetIds as $attributeSetId) {
$eavSetup->addAttributeGroup(
$entityTypeId,
$attributeSetId,
$attributeGroupName,
200 // sort order
);
// get the newly create attribute group id
$attributeGroupId = $eavSetup->getAttributeGroupId($entityTypeId, $attributeSetId, $attributeGroupName);
// add attribute to group
$eavSetup->addAttributeToGroup(
$entityTypeId, // can also use: \Magento\Catalog\Model\Product::ENTITY instead of $entityTypeId
$attributeSetId,
$attributeGroupName, // attribute group
$attributeCode, // this is defined above as 'chapagain_attribute_2
null // sort order, can be integer value like 10 or 30, etc.
);
}
$setup->endSetup();
}
}
Add/Create/Update/Remove Product Attribute Using the Upgrade Script
The following is done in the code below:
- Create a new attribute named: My Yes/No Attribute with the attribute code:
chapagain_attribute_bool_1
- Update the “Frontend Label” of the attribute
chapagain_attribute_text_1
- Remove an attribute with attribute code
your_attribute_code_to_delete
version_compare()
function is used to run the code on each version upgrade
app/code/Chapagain/ProductAttribute/Setup/UpgradeData.php
<?php
namespace Chapagain\ProductAttribute\Setup;
use Magento\Eav\Setup\EavSetupFactory;
use Magento\Framework\Setup\UpgradeDataInterface;
use Magento\Framework\Setup\ModuleContextInterface;
use Magento\Framework\Setup\ModuleDataSetupInterface;
/**
* @codeCoverageIgnore
*/
class UpgradeData implements UpgradeDataInterface
{
/**
* EAV setup factory
*
* @var \Magento\Eav\Setup\EavSetupFactory
*/
protected $eavSetupFactory;
/**
* Constructor
*
* @param EavSetupFactory $eavSetupFactory
*/
public function __construct(
EavSetupFactory $eavSetupFactory
) {
$this->eavSetupFactory = $eavSetupFactory;
}
/**
* {@inheritdoc}
*/
public function upgrade(ModuleDataSetupInterface $setup, ModuleContextInterface $context)
{
$setup->startSetup();
$eavSetup = $this->eavSetupFactory->create(['setup' => $setup]);
/**
* run this code if the module version stored in database is less than 1.0.1
* i.e. the code is run while upgrading the module from version 1.0.0 to 1.0.1
*/
if (version_compare($context->getVersion(), '1.0.1') < 0) {
$eavSetup->addAttribute(
\Magento\Catalog\Model\Product::ENTITY,
'chapagain_attribute_bool_1', // product attribute code
[
'type' => 'int', // datatype of the attribute
'backend' => '',
'frontend' => '',
'label' => 'My Yes/No Attribute', // label of the attribute
'input' => 'select', // form element of the attribute
'class' => '',
'source' => 'Magento\Eav\Model\Entity\Attribute\Source\Boolean', // define the source of the attribute (for select and multiselect attribute input type)
'global' => \Magento\Catalog\Model\ResourceModel\Eav\Attribute::SCOPE_GLOBAL, // scope of the attribute (global, store, website)
'visible' => true,
'required' => false,
'user_defined' => false,
'default' => 0,
'searchable' => false,
'filterable' => false,
'comparable' => false,
'visible_on_front' => false,
'used_in_product_listing' => false,
'unique' => false,
'apply_to' => ''
]
);
}
/**
* here, we are updating the attribute label
* while upgrading to module version 1.0.2
*/
if (version_compare($context->getVersion(), '1.0.2') < 0) {
$eavSetup->updateAttribute(
\Magento\Catalog\Model\Product::ENTITY,
'chapagain_attribute_text_1', // attribute code to update
'frontend_label', // attribute field to update
'My Custom Text Modified' // value to update
);
// Another way to update attribute
$eavSetup->updateAttribute(
\Magento\Catalog\Model\Product::ENTITY,
'chapagain_attribute_select_1', // attribute code
[
'frontend_label' => 'My Selectbox Modified'
// field name => value to update
]
);
}
if (version_compare($context->getVersion(), '1.0.3') < 0) {
/**
* Remove attribute
*/
$eavSetup->removeAttribute(
\Magento\Catalog\Model\Product::ENTITY,
'your_attribute_code_to_delete' // attribute code to remove
);
}
$setup->endSetup();
}
}
Increase the module version number in etc/module.xml
After updating the Upgrade setup code, you also need to ensure that you have upgraded the module version number in your module’s etc/module.xml
file.
Run setup upgrade
Finally, run the setup:upgrade
command that will run the Install/Upgrade Script code above.
php bin/magento setup:upgrade
Hope this helps. Thanks.