Product attributes are the properties that describe a Magento 2 product — and they help customers compare options and find the right item. This guide covers the full cycle programmatically: creating a custom product attribute, setting its value on a product, and displaying that value on the product page.
Create a Product Attribute Programmatically in Magento 2
Step 1: Create the InstallData File and Configure the Attribute
Create InstallData.php at Mageants/Blog/Setup/InstallData.php. It uses EavSetup to add a new attribute to the product entity:
<?php
namespace Mageants\Blog\Setup;
use Magento\Eav\Setup\EavSetup;
use Magento\Eav\Setup\EavSetupFactory;
use Magento\Framework\Setup\InstallDataInterface;
use Magento\Framework\Setup\ModuleContextInterface;
use Magento\Framework\Setup\ModuleDataSetupInterface;
class InstallData implements InstallDataInterface
{
private $eavSetupFactory;
public function __construct(EavSetupFactory $eavSetupFactory)
{
$this->eavSetupFactory = $eavSetupFactory;
}
public function install(ModuleDataSetupInterface $setup, ModuleContextInterface $context)
{
$eavSetup = $this->eavSetupFactory->create(['setup' => $setup]);
$eavSetup->addAttribute(
\Magento\Catalog\Model\Product::ENTITY,
'my_product_attribute',
[
'type' => 'text',
'label' => 'My Product Attribute',
'input' => 'text',
'global' => \Magento\Eav\Model\Entity\Attribute\ScopedAttributeInterface::SCOPE_GLOBAL,
'visible' => true,
'required' => false,
'user_defined' => true,
'default' => '',
'searchable' => false,
'filterable' => false,
'comparable' => false,
'visible_on_front' => true,
'used_in_product_listing' => true,
'unique' => false,
'apply_to' => ''
]
);
}
}
|
Note: InstallData still works, but it's the legacy setup approach. In new modules the same addAttribute() call goes inside a data patch class implementing \Magento\Framework\Setup\Patch\DataPatchInterface — the mechanism differs, the attribute definition is identical.
Step 2: Deploy and Verify
Run the setup commands, then check the attribute on a product in the admin under Catalog > Products > (edit a product):
php bin/magento setup:upgrade php bin/magento setup:static-content:deploy -f php bin/magento cache:flush |
With visible_on_front set to true, the attribute will also show in the product page's "More Information" tab once it has a value.
Set a Custom Product Attribute Value Programmatically
Step 1: A Helper Method to Update the Value
Inject ProductRepositoryInterface and set the attribute value with setData(), then save:
<?php
namespace Mageants\Blog\Helper;
use Magento\Framework\App\Helper\AbstractHelper;
use Magento\Framework\App\Helper\Context;
use Magento\Catalog\Api\ProductRepositoryInterface;
class Data extends AbstractHelper
{
protected $productRepository;
public function __construct(
Context $context,
ProductRepositoryInterface $productRepository
) {
$this->productRepository = $productRepository;
parent::__construct($context);
}
public function setProductAttributeValue($productId, $attributeValue)
{
$attributeCode = 'my_product_attribute';
$product = $this->productRepository->getById($productId);
$product->setData($attributeCode, $attributeValue);
$this->productRepository->save($product);
}
}
|
Step 2: Call It from a Controller
A controller's entry point is execute() — that's where the helper call goes:
<?php
namespace Mageants\Blog\Controller\Index;
use Magento\Framework\App\Action\Action;
use Magento\Framework\App\Action\Context;
use Mageants\Blog\Helper\Data as ProductAttributeHelper;
class SetValue extends Action
{
protected $helper;
public function __construct(
Context $context,
ProductAttributeHelper $helper
) {
$this->helper = $helper;
parent::__construct($context);
}
public function execute()
{
$productId = 1; // set any product ID
$attributeValue = 'My Product Value'; // set any value
$this->helper->setProductAttributeValue($productId, $attributeValue);
echo 'Attribute value updated.';
}
}
|
Setting Attribute Values in Bulk (No Code)
The code above sets one product at a time — perfect for automation triggered by an event or an integration. But if what you actually need is to populate a custom attribute across hundreds or thousands of existing products, doing it per-product isn't practical. For that, the Import Export Product Attributes extension lets you export your attributes and values to a spreadsheet, edit them in bulk, and re-import — including attribute options and store-scoped values — with no code and no risk of a bad save loop on a big catalog.
Display a Custom Attribute Value on the Product Page
Step 1: Add the Layout File
Create catalog_product_view.xml at Mageants/Blog/view/frontend/layout/catalog_product_view.xml. Note the correct <?xml … ?> declaration:
<?xml version="1.0"?>
<page layout="1column" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd">
<body>
<referenceContainer name="product.info.main">
<block class="Mageants\Blog\Block\Index"
name="product.attribute.value"
template="Mageants_Blog::index.phtml"/>
</referenceContainer>
</body>
</page>
|
Step 2: Create the Block
Create Index.php at Mageants/Blog/Block/Index.php. Inject Registry to read the current product — don't reference $this->registry without injecting it:
<?php
namespace Mageants\Blog\Block;
use Magento\Framework\View\Element\Template;
use Magento\Framework\View\Element\Template\Context;
use Magento\Framework\Registry;
class Index extends Template
{
protected $registry;
public function __construct(
Context $context,
Registry $registry,
array $data = []
) {
$this->registry = $registry;
parent::__construct($context, $data);
}
protected function getCurrentProduct()
{
return $this->registry->registry('current_product');
}
public function getProductAttributeValue()
{
$product = $this->getCurrentProduct();
if (!$product) {
return '';
}
return $product->getResource()
->getAttribute('my_product_attribute')
->getFrontend()
->getValue($product);
}
public function getProductAttributeLabel()
{
$product = $this->getCurrentProduct();
if (!$product) {
return '';
}
return $product->getResource()
->getAttribute('my_product_attribute')
->getFrontend()
->getLabel();
}
}
|
Step 3: Render It in a Template
Create index.phtml at Mageants/Blog/view/frontend/templates/index.phtml:
<?php $value = $block->getProductAttributeValue(); ?>
<?php if ($value) : ?>
<p class="text-base text-clr mb-4">
<strong><?= $block->escapeHtml($block->getProductAttributeLabel()) ?>:</strong>
<?= $block->escapeHtml($value) ?>
</p>
<?php endif; ?>
|
Clear the cache and open a product that has the attribute set — its label and value now appear on the product page.
Conclusion
That's the full lifecycle of a custom product attribute in Magento 2: define it with EavSetup (or a data patch in newer modules), set its value via the product repository, and render it on the storefront through a block and template. Watch the two things the original guide got wrong — the XML declaration must be <?xml ?>, and a controller's method must be execute() — and it all works. For populating values across a large catalog, reach for import/export instead of per-product code. Any trouble with the implementation? Get in touch with us.