Back to Blogs
Adding a Customer Attribute Programmatically in Magento 2
May 18, 2017
3 mins
builtmighty
Store admins often need more specific information about their customers than Magento offers by default. Here we’ll outline the steps to add a new customer attribute programatically. We’ll use a common example for stores that work with contractors and need extra user field for “Contractor Number”. This example can record and track the number each time a user registered. Below are the steps we took to enable that functionality for them.
The first step you’ll want to take is to create a module, allowing you to use a installer script.
Create a module.xml and registration.php to register your module. In our example, we used the module file: app/code/builtmighty/Example/etc/module.xml
<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Module/etc/module.xsd">
<module name="builtmighty_Example" setup_version="1.0.0" />
</config>
In our example, we used the registration file: app/code/builtmighty/Example/registration.php
<?php
\Magento\Framework\Component\ComponentRegistrar::register(
\Magento\Framework\Component\ComponentRegistrar::MODULE,
'builtmighty_Example',
__DIR__
);
This will register your module in Magento. To activate it, run php bin/magento module:enable builtmighty_Example.
Your next step will be to create the install script in the Setup directory. In our example, we used the file: app/code/builtmighty/Example/Setup/InstallData.php
<?php
namespace builtmighty\Example\Setup;
use Magento\Framework\Setup\InstallDataInterface;
use Magento\Framework\Setup\ModuleDataSetupInterface;
use Magento\Framework\Setup\ModuleContextInterface;
class InstallData implements InstallDataInterface {
private $_eavSetupFactory;
private $_attributeRepository;
public function __construct(
\Magento\Eav\Setup\EavSetupFactory $eavSetupFactory,
\Magento\Eav\Model\AttributeRepository $attributeRepository,
)
{
$this->_eavSetupFactory = $eavSetupFactory;
$this->_attributeRepository = $attributeRepository;
}
public function install( ModuleDataSetupInterface $setup, ModuleContextInterface $context )
{
$eavSetup = $this->_eavSetupFactory->create(['setup' => $setup]);
// add customer_attribute to customer
$eavSetup->removeAttribute(\Magento\Customer\Model\Customer::ENTITY, 'customer_attribute');
$eavSetup->addAttribute(
\Magento\Customer\Model\Customer::ENTITY, 'customer_attribute', [
'type' => 'varchar',
'label' => 'Customer Attribute',
'input' => 'text',
'required' => false,
'system' => 0,
'global' => \Magento\Eav\Model\Entity\Attribute\ScopedAttributeInterface::SCOPE_STORE,
'sort_order' => '200'
]
);
// allow customer_attribute attribute to be saved in the specific areas
$attribute = $this->_attributeRepository->get('customer', 'customer_attribute');
$setup->getConnection()
->insertOnDuplicate(
$setup->getTable('customer_form_attribute'),
[
['form_code' => 'adminhtml_customer', 'attribute_id' => $attribute->getId()],
['form_code' => 'customer_account_create', 'attribute_id' => $attribute->getId()],
['form_code' => 'customer_account_edit', 'attribute_id' => $attribute->getId()],
]
);
}
}
Adding only the customer attribute will display it in the backend, but, when you try and save it, nothing will happen. You need to add rows into the customer_form_attribute table to allow the attribute to be saved in different locations. The three areas we want are below:
Unfortunately adding rows into this table will not add the associated inputs on the frontend. You will have to add the inputs into the additional forms.
In addition, the only getChildHtml that could be used to add these to prevent from overriding the template is the form_additional_info block. This would be perfect, if it wasn’t in the same fieldset as the passwords, which is hidden by default. To overcome this we will have to override the templates in our own theme.
Copy vendor/magento/module-customer/view/frontend/templates/form/edit.phtml to app/design/frontend/builtmighty/example/Magento_Customer/templates/form/edit.phtml and add the following code to line 29.
<div class="field custom_attribute">
<label class="label" for="customer_attribute”><span><?php /* @escapeNotVerified */ echo __('Custom Attribute') ?></span></label>
<div class="control">
<input type="text" id="customer_attribute" name="customer_attribute" value="<?php echo $block->escapeHtml($block->getCustomer()->getCustomAttribute('customer_attribute')->getValue()) ?>" title="<?php /* @escapeNotVerified */ echo __('Custom Attribute') ?>" class="input-text" autocomplete="off" />
</div>
</div>
Copy vendor/magento/module-customer/view/frontend/templates/form/register.phtml to app/design/frontend/builtmighty/example/Magento_Customer/templates/form/register.phtml and add the following code to line 49.
<div class="field custom_attribute”>
<label class="label" for="customer_attribute"><span><?php /* @escapeNotVerified */ echo __('Custom Attribute') ?></span></label>
<div class="control">
<input type="text" id="customer_attribute" name="customer_attribute" value="<?php echo $block->escapeHtml($block->getFormData()->getCustomerAttribute()) ?>" title="<?php /* @escapeNotVerified */ echo __('Custom Attribute') ?>" class="input-text" autocomplete="off">
</div>
</div>
Now, when you go to register or edit your information via the account edit page, you will see a new field called Custom Attribute. This field will be updated when the user changes it, thanks to the rows that we added into customer_form_attribute.
If you have questions specifically about Magento 2, we recommend reading our article Moving from Magento 1 to Magento 2: All Your Questions Answered. Our team is comprised of Magento experts, so if you’d like someone to help out with your next project, we’d love to talk to you. Get in touch today at [email protected].
If it sounds like we might be a good fit, send us a message. We’ll get back to you within 24 hours. And then we can hit the ground running.