How to add Customer Attribute and show it in Registration page

First of all, let's  create a basic Module  with  module.xml registration.php and composer.json

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="Armmage_CustomerAttributeBusinessType">
        <sequence>
            <module name="Magento_Customer"/>
        </sequence>
    </module>
</config>

registration.php

<?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="Armmage_CustomerAttributeBusinessType">
        <sequence>
            <module name="Magento_Customer"/>
        </sequence>
    </module>
</config>

 composer.json

{
    "name": "armmage/module-customerattributebusinesstype",
    "description": "Adding  customer attribute  business  type and assiging  customer to a group",
    "type": "magento2-module",
    "license": "GPL-3.0",
    "authors": [
        {
            "name": "Mage2Gen",
            "email": "[email protected]"
        }
    ],
    "minimum-stability": "dev",
    "require": {},
    "autoload": {
        "files": [
            "registration.php"
        ],
        "psr-4": {
            "Armmage\\CustomerAttributeBusinessType\\": ""
        }
    }
}

Then let's create an attribute AddBusinessTypeCustomerAttribute.php

Please get your  attention that the source is not default and  we  have cllass to specify  what we need as vaules

/**
 * Copyright © Copyright (c) ArmMage LLC. All rights reserved.
 * See COPYING.txt for license details.
 */

declare(strict_types=1);

namespace Armmage\CustomerAttributeBusinessType\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 AddBusinessTypeCustomerAttribute implements DataPatchInterface, PatchRevertableInterface
{

    /**
     * @var ModuleDataSetupInterface
     */
    private $moduleDataSetup;
    /**
     * @var CustomerSetup
     */
    private $customerSetupFactory;
    /**
     * @var SetFactory
     */
    private $attributeSetFactory;

    /**
     * Constructor
     *
     * @param ModuleDataSetupInterface $moduleDataSetup
     * @param CustomerSetupFactory $customerSetupFactory
     * @param SetFactory $attributeSetFactory
     */
    public function __construct(
        ModuleDataSetupInterface $moduleDataSetup,
        CustomerSetupFactory $customerSetupFactory,
        SetFactory $attributeSetFactory
    ) {
        $this->moduleDataSetup = $moduleDataSetup;
        $this->customerSetupFactory = $customerSetupFactory;
        $this->attributeSetFactory = $attributeSetFactory;
    }

    /**
     * {@inheritdoc}
     */
    public function apply()
    {
        $this->moduleDataSetup->getConnection()->startSetup();
        /** @var CustomerSetup $customerSetup */
        $customerSetup = $this->customerSetupFactory->create(['setup' => $this->moduleDataSetup]);
        $customerEntity = $customerSetup->getEavConfig()->getEntityType(Customer::ENTITY);
        $attributeSetId = $customerEntity->getDefaultAttributeSetId();

        /** @var $attributeSet Set */
        $attributeSet = $this->attributeSetFactory->create();
        $attributeGroupId = $attributeSet->getDefaultGroupId($attributeSetId);

        $customerSetup->addAttribute(
            Customer::ENTITY,
            'business_type',
            [
                'label' => 'Individual Company',
                'input' => 'select',
                'type' => 'int',
                'source' => 'Armmage\CustomerAttributeBusinessType\Model\Customer\Attribute\Source\BusinessType',
                'required' => true,
                'position' => 333,
                '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, 'business_type');
        $attribute->addData([
            'used_in_forms' => [
                'adminhtml_customer',
                'customer_account_create'
            ]
        ]);
        $attribute->addData([
            'attribute_set_id' => $attributeSetId,
            'attribute_group_id' => $attributeGroupId

        ]);
        $attribute->save();

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

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

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

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

    /**
     * {@inheritdoc}
     */
    public static function getDependencies()
    {
        return [];
    }
}
In the Custom model to get an option, the options are extended form AbstractSource
and it is not in the usual way
/**
 * Copyright © Copyright (c) ArmMage LLC. All rights reserved.
 * See COPYING.txt for license details.
 */

declare(strict_types=1);

namespace Armmage\CustomerAttributeBusinessType\Model\Customer\Attribute\Source;

class BusinessType extends \Magento\Eav\Model\Entity\Attribute\Source\AbstractSource
{

    /**
     * getAllOptions
     *
     * @return array
     */
    public function getAllOptions()
    {
        if ($this->_options === null) {
            $this->_options = [
                ['value' => 'individual', 'label' => __('Individual')],
                ['value' => 'company', 'label' => __('Company')]
            ];
        }
        return $this->_options;
    }
}

We need also to share this attribute  like  an extension attribute

etc/extension_attributes.xml

<?xml version="1.0" ?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Api/etc/extension_attributes.xsd">
    <extension_attributes for="Magento\Customer\Api\Data\CustomerInterface">
        <attribute code="business_type" type="string"/>
    </extension_attributes>
</config>

So now  frontend  and a widget  like  another  register fields have  more similar data 
as in Magento 

namespace Armmage\CustomerAttributeBusinessType\Block\Widget\Customer;

use Magento\Customer\Api\CustomerMetadataInterface;
use Magento\Customer\Api\CustomerRepositoryInterface;
use Magento\Customer\Api\Data\CustomerInterface;
use Magento\Customer\Api\Data\OptionInterface;
use Magento\Customer\Block\Widget\AbstractWidget;
use Magento\Framework\View\Element\Template\Context;
use Magento\Customer\Helper\Address;

/**
 * Block to render customer's gender attribute
 *
 * @SuppressWarnings(PHPMD.DepthOfInheritance)
 */
class AccountType extends AbstractWidget
{
    /**
     * @var \Magento\Customer\Model\Session
     */
    protected $_customerSession;

    /**
     * @var CustomerRepositoryInterface
     */
    protected $customerRepository;

    /**
     * Create an instance of the BusinessType widget
     *
     * @param \Magento\Framework\View\Element\Template\Context $context
     * @param \Magento\Customer\Helper\Address $addressHelper
     * @param CustomerMetadataInterface $customerMetadata
     * @param CustomerRepositoryInterface $customerRepository
     * @param \Magento\Customer\Model\Session $customerSession
     * @param array $data
     */
    public function __construct(
        Context $context,
        Address $addressHelper,
        CustomerMetadataInterface $customerMetadata,
        CustomerRepositoryInterface $customerRepository,
        \Magento\Customer\Model\Session $customerSession,
        array $data = []
    ) {
        $this->_customerSession = $customerSession;
        $this->customerRepository = $customerRepository;
        parent::__construct($context, $addressHelper, $customerMetadata, $data);
        $this->_isScopePrivate = true;
    }

    /**
     * Initialize block
     *
     * @return void
     */
    public function _construct()
    {
        parent::_construct();
        $this->setTemplate('Armmage_CustomerAttributeBusinessType::widget/account_type.phtml');
    }

    /**
     * Check if BusinessType attribute enabled in system
     *
     * @return bool
     */
    public function isEnabled()
    {
        return $this->_getAttribute('business_type');
    }

    /**
     * Check if BusinessType attribute marked as required
     *
     * @return bool
     */
    public function isRequired()
    {
        return $this->_getAttribute('business_type') ? (bool)$this->_getAttribute('business_type')->isRequired() : false;
    }

    /**
     * Retrieve store attribute label
     *
     * @param string $attributeCode
     *
     * @return string
     */
    public function getStoreLabel($attributeCode)
    {
        $attribute = $this->_getAttribute($attributeCode);
        return $attribute ? __($attribute->getStoreLabel()) : '';
    }

    /**
     * Get current customer from session
     *
     * @return CustomerInterface
     */
    public function getCustomer()
    {
        return $this->customerRepository->getById($this->_customerSession->getCustomerId());
    }

    /**
     * Returns options from BusinessType attribute
     *
     * @return OptionInterface[]
     */
    public function getBusinessTypeOptions()
    {
        return $this->_getAttribute('business_type')->getOptions();
    }
}

And  Also to implement  logic  on save  we have several methods  but at this time  we are choosing  

observer method  , get  your  attention that  you can also use  PLUGIN

<?xml version="1.0" ?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Event/etc/events.xsd">
    <event name="customer_register_success">
        <observer name="armmage_businesstype_observer_customer_register_success" instance="Armmage\CustomerAttributeBusinessType\Observer\Customer\RegisterSuccess"/>
    </event>
</config>

and  also here is our observer 

/**
 * Copyright © Copyright (c) ArmMage LLC. All rights reserved.
 * See COPYING.txt for license details.
 */

declare(strict_types=1);

namespace Armmage\CustomerAttributeBusinessType\Observer\Customer;

use Magento\Framework\Event\Observer;
use Magento\Framework\Event\ObserverInterface;
use Magento\Customer\Api\CustomerRepositoryInterface;

class RegisterSuccess implements ObserverInterface
{
    const GROUP_ID = 2;

    private $customerRepository;
    private $request;

    public function __construct(
        \Magento\Framework\App\RequestInterface $request,
        CustomerRepositoryInterface $customerRepository
    ) {
        $this->request = $request;
        $this->customerRepository = $customerRepository;
    }
    /**
     * Execute observer
     *
     * @param Observer $observer
     * @return void
     */
    public function execute(
        Observer $observer
    ) {

        $type = $this->request->getParam('business_type');
        if ($type == "company") {
            $id = $observer->getEvent()->getCustomer()->getId();
            if (isset($id)) {
                $customer = $this->customerRepository->getById($id);
                $customer->setGroupId(self::GROUP_ID);
                $this->customerRepository->save($customer);
            }
        }
    }
}

You can see this here some kind of not Magento styled code, We have not completed styling because we want you to fix them and also read and do

not  only copy  paste  the code , 

If you have any questions  don't  hesitate to leave  comments  we  will answer  in an 10 hours 

Greetings!!!



Ready to elevate your e-commerce business?

Discuss your business objectives with us. Get in touch today to explore ways we can assist in reaching them.

Copyright © 2021-present ArmMage Inc. All rights reserved.