Magento 2: Create new customer attribute

Updated . Posted . Visible to the public.

How to create a new custom attribute to Customer

This article explain the custom customer attribute creation and showing that in account creation and account edit

Magento Customer module is developed with EAV attributes
if a attribute is created by admin in back-end, the it is a system attribute but if it is created with script then it is custom attribute.

Following example shows that creating new dropdown attribute for customer.

Steps:

  1. Create a DataPatch class
<?php
/**
 * CreateAgeGroupAttribute
 *
 * @copyright Copyright © 2021 Vasan. All rights reserved.
 * @author    survasp@gmail.com
 */

namespace Vasan\Customer\Setup\Patch\Data;


use Magento\Eav\Model\Entity\Attribute\Source\Boolean;
use Magento\Framework\Setup\Patch\DataPatchInterface;
use Magento\Framework\Setup\ModuleDataSetupInterface;
use Magento\Customer\Setup\CustomerSetupFactory;
use Magento\Eav\Model\Entity\Attribute\SetFactory as AttributeSetFactory;
use Magento\Framework\Setup\Patch\PatchInterface;
use Magento\Customer\Model\Customer;
use Vasan\Customer\Model\Config\Source\AgeGroup;

class CreateAgeGroupAttribute implements DataPatchInterface
{
    /**
     * @var ModuleDataSetupInterface
     */
    protected $moduleDataSetup;

    /**
     * @var CustomerSetupFactory
     */
    protected $customerSetupFactory;

    /**
     * @var AttributeSetFactory
     */
    protected $attributeSetFactory;

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

    /**
     * Get array of patches that have to be executed prior to this.
     *
     * Example of implementation:
     *
     * [
     *      \Vendor_Name\Module_Name\Setup\Patch\Patch1::class,
     *      \Vendor_Name\Module_Name\Setup\Patch\Patch2::class
     * ]
     *
     * @return string[]
     */
    public static function getDependencies()
    {
        return [];
    }

    /**
     * Get aliases (previous names) for the patch.
     *
     * @return string[]
     */
    public function getAliases()
    {
        return [];
    }

    /**
     * Creating the age_group eav attribute.
     *
     * @ingeritdoc
     */
    public function apply()
    {
        $customerSetup = $this->customerSetupFactory->create(['setup' => $this->moduleDataSetup]);
        $customerEntity = $customerSetup->getEavConfig()->getEntityType(Customer::ENTITY);
        $attributeSetId = $customerEntity->getDefaultAttributeSetId();

        $attributeSet = $this->attributeSetFactory->create();
        $attributeDefaultGroupId = $attributeSet->getDefaultGroupId($attributeSetId);
        $customerSetup->removeAttribute(Customer::ENTITY, 'age_group');
        $customerSetup->addAttribute(Customer::ENTITY, 'age_group',
            [
                'type' => 'int',
                'label' => 'Age Group',
                'input' => 'select',
                'required' => true,
                'visible' => true,
                'source' => AgeGroup::class,
                'backend' => '',
                'user_defined' => false,
                'is_user_defined' => false,
                'sort_order' => 999,
                'is_used_in_grid' => true,
                'is_visible_in_grid' => true,
                'is_filterable_in_grid' => true,
                'is_searchable_in_grid' => true,
                'position' => 999,
                'default' => 0,
                'system' => 0,
            ]
        );

        $ageGroup = $customerSetup->getEavConfig()->getAttribute('customer', 'age_group');

        if ($ageGroup->getId()) {
            $ageGroup->addData([
                'attribute_set_id' => $attributeSetId,
                'attribute_group_id' => $attributeDefaultGroupId,
                'used_in_forms' => ['adminhtml_customer','customer_account_create', 'customer_account_edit']
            ]);
            $ageGroup->save();
        }
    }
}

  1. Create a Source class
<?php
/**
 * AgeGroup
 *
 * @copyright Copyright © 2021 Vasan. All rights reserved.
 * @author    survasp@gmail.com
 */

namespace Vasan\Customer\Model\Config\Source;


class AgeGroup extends \Magento\Eav\Model\Entity\Attribute\Source\AbstractSource
{
    const CHILDREN_VALUE = 0;
    const YOUTH_VALUE = 1;
    const ADULTS_VALUE = 2;
    const SENIORS_VALUE = 3;

    /**
     * Get all options
     *
     * @return array
     */
    public function getAllOptions()
    {
        $this->_options = [
            ['label' => __('Children'), 'value' => self::CHILDREN_VALUE],
            ['label' => __('Youth'), 'value' => self::YOUTH_VALUE],
            ['label' => __('Adults'), 'value' => self::ADULTS_VALUE],
            ['label' => __('Seniors'), 'value'=> self::SENIORS_VALUE]
        ];

        return $this->_options;
    }

}
  1. Create a customer create layout xml file show the attribute in customer account creation.
<?xml version="1.0" encoding="UTF-8"?>
<!--
/**
 * customer_account_create
 *
 * @copyright Copyright © 2021 Vasan. All rights reserved.
 * @author    survasp@gmail.com
 */
-->
<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="customer_creat_age_group" template="Vasan_Customer::create/agegroup.phtml">
                <arguments>
                    <argument name="view_model" xsi:type="object">
                        Vasan\Customer\ViewModel\AgeGroup
                    </argument>
                </arguments>
            </block>
        </referenceContainer>
    </body>
</page>
  1. Create a customer update layout xml file to edit the saved attribute value.
<?xml version="1.0"?>
<!--
/**
 * Copyright © Magento, Inc. All rights reserved.
 * See COPYING.txt for license details.
 */
-->
<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\Customer\Block\Account\Dashboard" name="customer_edit_age_group" template="Vasan_Customer::edit/agegroup.phtml" >
                <arguments>
                    <argument name="view_model" xsi:type="object">
                        Vasan\Customer\ViewModel\AgeGroup
                    </argument>
                </arguments>
            </block>
        </referenceContainer>
    </body>
</page>

  1. Create a phtml files for create and edit.

For create

<?php
/**
 * agegroup
 *
 * @copyright Copyright © 2021 Vasan. All rights reserved.
 * @author    survasp@gmail.com
 */
?>

<?php

    $ageGroupOptions = $block->getViewModel()->getOptions();
?>
<div class="field choice required">
<select id="age_group"
        name="age_group"
        title="<?= $escaper->escapeHtml(__('Age Group')) ?>"
        data-validate="{required:true}"
        class="select">
    <?php foreach ($ageGroupOptions as $option): ?>
        <option value="<?= $option['value'] ?>" >
            <?= $option['label']?>
        </option>
    <?php endforeach;?>
</select>
</div>

For edit

<?php
/**
 * agegroup
 *
 * @copyright Copyright © 2021 Vasan. All rights reserved.
 * @author    survasp@gmail.com
 */
?>

<?php
    /** @var \Magento\Customer\Block\Account\Dashboard $block */
    $selectedGroup = $block->getCustomer()->getCustomAttribute('age_group')->getValue();

    $ageGroupOptions = $block->getViewModel()->getOptions();
?>
<div class="field choice required">
<select id="age_group"
        name="age_group"
        title="<?= $escaper->escapeHtml(__('Age Group')) ?>"
        data-validate="{required:true}"
        class="select">
    <?php foreach ($ageGroupOptions as $option): ?>
        <option value="<?= $option['value'] ?>" <?php if ($option['value'] == $selectedGroup) :  ?> selected <?php endif;?>>
            <?= $option['label']?>
        </option>
    <?php endforeach;?>
</select>
</div>
  1. ViewModel class for block logic
<?php
/**
 * AgeGroup
 *
 * @copyright Copyright © 2021 Vasan. All rights reserved.
 * @author    survasp@gmail.com
 */

namespace Vasan\Customer\ViewModel;


use Magento\Framework\View\Element\Block\ArgumentInterface;
use Vasan\Customer\Model\Config\Source\AgeGroup as SourceAgeGroup;

class AgeGroup implements ArgumentInterface
{
    /**
     * @var SourceAgeGroup
     */
    protected $sourceAgeGroup;

    /**
     * @param SourceAgeGroup $sourceAgeGroup
     */
    public function __construct(SourceAgeGroup $sourceAgeGroup)
    {
        $this->sourceAgeGroup = $sourceAgeGroup;
    }

    /**
     * Get the Age group options.
     *
     * @return array|array[]
     */
    public function getOptions()
    {
        return $this->sourceAgeGroup->getAllOptions();
    }
}

vasan
Last edit
vasan
Posted by vasan to vasan's deck (2021-12-05 13:52)