How to Create Customer Attribute Programmatically in Magento 2?

Create Magento Customer Attribute Boolean type Programmatically with the help of the Data patch feature.

Let’s create a customer attribute called ‘email_marketing‘ with the type boolean using programmatically and the bool type has only two possible values Yes/No.

You need to create a basic Magento module to create custom attributes for the customer.

We are going with all the required steps to finalize your customer attribute readymade once you follow all the steps given.

Create a registration.php file to register our module. File Path, app/code/Rbj/CustomerAttribute/registration.php

<?php
use Magento\Framework\Component\ComponentRegistrar;

ComponentRegistrar::register(
    ComponentRegistrar::MODULE,
    'Rbj_EmailMarketing',
    __DIR__
);

Create a module.xml file to define our module.

File Path, app/code/Rbj/EmailMarketing/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="Rbj_EmailMarketing">
    <sequence>
      <module name="Magento_Customer"/>
    </sequence>
  </module>
</config>

We have added a dependency to the Customer Module because our module is dependent on the core Magento customer module.

To create a Customer attribute we need to define the InstallData.php file to add an entry in the database of our attribute.

File Path, app/code/Rbj/CustomerAttribute/Setup/Patch/Data/AddEmailMarketingAttribute.php

<?php
declare(strict_types=1);

namespace Rbj\EmailMarketing\Setup\Patch\Data;

use Magento\Customer\Model\Customer;
use Magento\Customer\Setup\CustomerSetup;
use Magento\Customer\Setup\CustomerSetupFactory;
use Magento\Eav\Model\Entity\Attribute\SetFactory;
use Magento\Framework\Setup\ModuleDataSetupInterface;
use Magento\Framework\Setup\Patch\DataPatchInterface;
use Magento\Framework\Setup\Patch\PatchRevertableInterface;

class AddEmailMarketingAttribute implements DataPatchInterface, PatchRevertableInterface
{
    public const CUSTOMER_EMAIL_MARKETING_ATTRIBUTE = 'email_marketing';
    public function __construct(
        private readonly ModuleDataSetupInterface $moduleDataSetup,
        private readonly CustomerSetupFactory $customerSetupFactory,
        private readonly SetFactory $attributeSetFactory
    ) {
    }

    /**
     * {@inheritdoc}
     */
    public function apply(): void
    {
        $this->moduleDataSetup->getConnection()->startSetup();

        $customerSetup = $this->customerSetupFactory->create(['setup' => $this->moduleDataSetup]);
        $customerEntity = $customerSetup->getEavConfig()->getEntityType(Customer::ENTITY);
        $attributeSetId = $customerEntity->getDefaultAttributeSetId();

        $attributeSet = $this->attributeSetFactory->create();
        $attributeGroupId = $attributeSet->getDefaultGroupId($attributeSetId);

        $customerSetup->addAttribute(
            Customer::ENTITY,
            self::CUSTOMER_EMAIL_MARKETING_ATTRIBUTE,
            [
                'label' => 'Email Marketing',
                'input' => 'boolean',
                'type' => 'int',
                'source' => '',
                'required' => false,
                'position' => 300,
                'visible' => true,
                'system' => false,
                'is_used_in_grid' => true,
                'is_visible_in_grid' => true,
                'is_filterable_in_grid' => true,
                'is_searchable_in_grid' => false,
                'backend' => ''
            ]
        );

        $attribute = $customerSetup->getEavConfig()->getAttribute(Customer::ENTITY, self::CUSTOMER_EMAIL_MARKETING_ATTRIBUTE);
        $attribute->addData([
            'used_in_forms' => [
                'adminhtml_customer', 'customer_account_create', 'customer_account_edit'
            ]
        ]);

        $attribute->addData([
            'attribute_set_id' => $attributeSetId,
            'attribute_group_id' => $attributeGroupId

        ]);
        $attribute->save();

        $this->moduleDataSetup->getConnection()->endSetup();
    }

    public function revert(): void
    {
        $this->moduleDataSetup->getConnection()->startSetup();
        /** @var CustomerSetup $customerSetup */
        $customerSetup = $this->customerSetupFactory->create(['setup' => $this->moduleDataSetup]);
        $customerSetup->removeAttribute(Customer::ENTITY, self::CUSTOMER_EMAIL_MARKETING_ATTRIBUTE);

        $this->moduleDataSetup->getConnection()->endSetup();
    }

    /**
     * {@inheritdoc}
     */
    public function getAliases(): array
    {
        return [];
    }

    /**
     * {@inheritdoc}
     */
    public static function getDependencies(): array
    {
        return [];
    }
}

In the above, Patch file, used_in_forms declaration is used to define your attribute visibility scope.

'used_in_forms' => [ 'adminhtml_customer', 'customer_account_create', 'customer_account_edit' ]

We have used our attribute to Admin Panel Customer Form, Front end Create an account page, and Customer Edit page Form.

Now You want to display our custom customer attribute to the customer register page,  For that we need to create customer_account_create.xml to define our custom template that contains the attribute.

Layout Path:

app/code/Rbj/EmailMarketing/view/frontend/layout/customer_account_create.xml

<?xml version="1.0"?>
<page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd">
    <body>
        <referenceContainer name="form.additional.info">
            <block class="Magento\Framework\View\Element\Template" name="email.marketing" template="Rbj_EmailMarketing::marketing.phtml"/>
        </referenceContainer>
    </body>
</page>

In the Layout file, the form.additional.info container is used to define an extra field in the Registration form.

You have to define the template based on the declaration on the layout file to show your attribute on the registration page.

Template File Path: app/code/Rbj/EmailMarketing/view/frontend/templates/marketing.phtml

<fieldset class="fieldset create account">
    <div class="field marketing">
        <input type="checkbox" name="email_marketing" id="email_marketing" title="<?= __('Post') ?>" class="input-text" value="1" autocomplete="off">
        <label class="label" for="email_marketing" >
            <span><?= __('Email Marketing') ?></span>
        </label>
    </div>
</fieldset>

In the template file, We have created a Checkbox field to show/hide attributes based on the user selection value.

All the required steps are completed to create a Customer Attribute.

To install a new module, run the appropriate command in Magento.

php bin/magento setup:upgrade
php bin/magento setup:static-content:deploy -f
php bin/magento indexer:reindex
php bin/magento cache:flush

You can validate your email marketing attribute in the admin panel by just going to, Customers -> All Customers -> Edit any Customer.

You will be able to see the new customer attribute called Email Marketing.

This is the simplest step you need to follow to create a custom customer attribute in Magento 2.