1

I have added the field "Favorite Color" to the Customer entity and added it to the registration form. The field properly stores data, as I can see when logging in as Admin and checking in Customers -> All Customers -> Edit -> Account Information.

However, when the Customer logged in and goes to the Account Information section, that field is empty. The module.xml file does of course list a dependency on Magento_Customer.

I've added the field with this UpgradeData:

public function upgrade(ModuleDataSetupInterface $setup)
{
    $customerSetup = $this->customerSetupFactory->create(['setup' => $setup]);
    $customerEntity = $customerSetup->getEavConfig()->getEntityType('customer');
    $attSetId = $customerEntity->getDefaultAttributeSetId();

    /** @var $attributeSet AttributeSet */
    $attributeSet = $this->attributeSetFactory->create();
    $attGroupId = $attributeSet->getDefaultGroupId($attSetId);

    $customerSetup->addAttribute(Customer::ENTITY, $attribute['code'], [
        'label' => 'Favorite Color',
        'type' => 'varchar',
        'input' => 'text',
        'required' => false,
        'visible' => true,
        'user_defined' => true,
        'position' =>999,
        'system' => 0,
    ]);

    $attribute = $customerSetup->getEavConfig()->getAttribute(Customer::ENTITY, $attribute['code'])->addData([
        'attribute_set_id' => $attSetId,
        'attribute_group_id' => $attGroupId,
        'used_in_forms' => ['adminhtml_checkout', 'adminhtml_customer', 'adminhtml_customer_address', 'customer_account_create', 'customer_account_edit', 'customer_address_edit', 'customer_register_address'],
    ]);

    $attribute->save();
}

I use the following layout to add a template to the account creation form:

<?xml version="1.0"?>
<page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" layout="1column" 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="dotan_customer_form_additional_info" template="Dotan_Customer::form/customer_account_create_additional_info.phtml">
            </block>
        </referenceContainer>
    </body>
</page>

And a near-identical layout to add a template to the account edit form:

<?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="dotan_customer_form_edit_additional_info" template="Dotan_Customer::form/customer_account_edit_additional_info.phtml">
            </block>
        </referenceContainer>
    </body>
</page>

Here is the template added to the account creation form:

<div class="field favorite_color">
    <label for="favorite_color" class="label"><span><?php /* @escapeNotVerified */ echo __('Favorite Color') ?></span></label>
    <div class="control">
        <input type="text" name="favorite_color" id="favorite_color" title="Favorite Color" value="" class="input-text" type="text" />
    </div>
</div>

And the identical template added to the account edit form:

<div class="field favorite_color">
    <label for="favorite_color" class="label"><span><?php /* @escapeNotVerified */ echo __('Favorite Color') ?></span></label>
    <div class="control">
        <input type="text" name="favorite_color" id="favorite_color" title="Favorite Color" value="" class="input-text" type="text" />
    </div>
</div>

I suspect that I need to add the fields' content to the account edit form template. But does that need to be done manually, via e.g. a block that fetches the values from the database?

I've looked at many tutorials online but none of them mention the need for such a block. And the information is being provided in the Adminhtml area's Customer -> Account Information, so I suspect that there is some built-in functionality to provide that information to the Customer's own Account Information page as well.

1 Answer 1

4

Your HTML input field is currently set to empty so the page shows your field as empty is the correct behavior.
<input type="text" name="favorite_color" id="favorite_color" title="Favorite Color" value="" class="input-text" type="text" />

Take a look at vendor/magento/module-customer/view/frontend/templates/form/edit.phtml to know how Magento populate data into customer attribute fields (Firstname, Lastname, Dob, Taxvat, Gender):

Let's get Taxvat for example:

<?php $_taxvat = $block->getLayout()->createBlock(\Magento\Customer\Block\Widget\Taxvat::class) ?>

<?= $_taxvat->setTaxvat($block->getCustomer()->getTaxvat())->toHtml() ?>

In this code, Magento declares $_taxvat = creates Magento\Customer\Block\Widget\Taxvat block.
Then passing Taxvat to that block. Finally, it renders HTML content for Taxvat by toHtml() method.

Back to your code, you are referring to form.additional.info container, it will put your custom attribute field (Favorite Color) after Change Password field which I think is not a good place.
Your custom attribute (Favorite Color) should be put after Gender field or somewhere related. To achieve that, override vendor/magento/module-customer/view/frontend/templates/form/edit.phtml

You can't get custom customer attribute values from Magento\Customer\Api\Data\CustomerInterface like Magento default customer attributes (Firstname, Lastname, Dob, Taxvat, Gender,...) so you have to implement another approach to show your custom customer attribute to frontend. That is create a new child block inside customer_edit block and declare a ViewModel that is responsible for passing your custom customer attribute value to your phtml template.

Based on your information, I've written a full step-by-step including a Data patch for creating a new custom customer attribute, displaying and manipulating the custom customer attribute on the Customer Account Information page. Take a look at my code, you can display and manipulate your custom customer attributes on other pages.

Assume the Vendor name is TuVan and the module name is Customer.

Step 1: Create registration.php:
File path: app/code/TuVan/Customer/registration.php

<?php

use Magento\Framework\Component\ComponentRegistrar;

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

Step 2: Create module.xml:
File path: app/code/TuVan/Customer/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="TuVan_Customer">
        <sequence>
            <module name="Magento_Customer"/>
        </sequence>
    </module>
</config>

Step 3: Create AddFavoriteColorAttribute.php:
File path: app/code/TuVan/Customer/Setup/Patch/Data/AddFavoriteColorAttribute.php

<?php

namespace TuVan\Customer\Setup\Patch\Data;

use Magento\Customer\Api\CustomerMetadataInterface;
use Magento\Customer\Setup\CustomerSetupFactory;
use Magento\Framework\Setup\ModuleDataSetupInterface;
use Magento\Framework\Setup\Patch\DataPatchInterface;

class AddFavoriteColorAttribute implements DataPatchInterface
{
    /**
     * @var ModuleDataSetupInterface
     */
    private $moduleDataSetup;

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

    public function __construct(
        ModuleDataSetupInterface $moduleDataSetup,
        CustomerSetupFactory $customerSetupFactory
    ) {
        $this->moduleDataSetup = $moduleDataSetup;
        $this->customerSetupFactory = $customerSetupFactory;
    }

    /**
     * @inheritdoc
     */
    public function apply()
    {
        $customerSetup = $this->customerSetupFactory->create(['setup' => $this->moduleDataSetup]);
        $favoriteColorAttributeCode = 'favorite_color';

        $customerSetup->addAttribute(
            CustomerMetadataInterface::ENTITY_TYPE_CUSTOMER ,
            $favoriteColorAttributeCode, [
            'label' => 'Favorite Color',
            'type' => 'varchar',
            'input' => 'text',
            'required' => false,
            'visible' => true,
            'user_defined' => true,
            'position' => 999,
            'system' => false,
        ]);

        $customerSetup->addAttributeToSet(
            CustomerMetadataInterface::ENTITY_TYPE_CUSTOMER,
            CustomerMetadataInterface::ATTRIBUTE_SET_ID_CUSTOMER,
            null,
            $favoriteColorAttributeCode
        );

        $favoriteColorAttribute = $customerSetup->getEavConfig()->getAttribute(
            CustomerMetadataInterface::ENTITY_TYPE_CUSTOMER,
            $favoriteColorAttributeCode
        );
        $favoriteColorAttribute->addData([
            'used_in_forms' => [
                'customer_account_create',
                'customer_account_edit',
                'checkout_register',
                'adminhtml_customer',
                'adminhtml_checkout'
            ]
        ]);
        $favoriteColorAttribute->save();
    }

    public static function getDependencies()
    {
        return [];
    }

    public function getAliases()
    {
        return [];
    }
}

Step 4: Create customer_account_edit.xml:
File path: app/code/TuVan/Customer/view/frontend/layout/customer_account_edit.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>
        <referenceBlock name="customer_edit">
            <action method="setTemplate">
                <argument name="template" xsi:type="string">TuVan_Customer::form/edit.phtml</argument>
            </action>
            <block class="Magento\Framework\View\Element\Template" name="customer_favorite_color" template="TuVan_Customer::form/customer_account_edit_favorite_color.phtml">
                <arguments>
                    <argument name="view_model" xsi:type="object">TuVan\Customer\ViewModel\FavoriteColor</argument>
                </arguments>
            </block>
        </referenceBlock>
    </body>
</page>

Step 6: Create FavoriteColor.php:
File path: app/code/TuVan/Customer/ViewModel/FavoriteColor.php

<?php

namespace Magetu\Catalog\ViewModel;

use Magento\Customer\Api\CustomerRepositoryInterface;
use Magento\Customer\Model\Session;
use Magento\Framework\View\Element\Block\ArgumentInterface;

/**
 * Favorite Color view model
 */
class FavoriteColor implements ArgumentInterface
{
    /**
     * @var CustomerRepositoryInterface
     */
    private $customerRepository;

    /**
     * @var Session
     */
    private $customerSession;

    public function __construct(
        Session $customerSession,
        CustomerRepositoryInterface $customerRepository
    ) {
        $this->customerSession = $customerSession;
        $this->customerRepository = $customerRepository;
    }

    public function getFavoriteColor()
    {
        $customerId = $this->customerSession->getCustomerId();
        $customer = $this->customerRepository->getById($customerId);

        return $customer->getCustomAttribute('favorite_color')
            ? $customer->getCustomAttribute('favorite_color')->getValue() : '';
    }
}

Step 7: Create customer_account_edit_additional_info.phtml:
File path: app/code/TuVan/Customer/view/frontend/templates/form/customer_account_edit_favorite_color.phtml

<?php
/** @var \Magento\Framework\View\Element\Template $block */
/** @var \Magento\Framework\Escaper $escaper */
/** @var \Magetu\Catalog\ViewModel\FavoriteColor $viewModel */
$viewModel = $block->getViewModel();
?>
<div class="field favorite-color">
    <label for="favorite_color" class="label">
        <span>
            <?= $escaper->escapeHtml(__('Favorite Color')) ?>
        </span>
    </label>
    <div class="control">
        <?php
        $validationClass = $escaper->escapeHtmlAttr(
            $this->helper(\Magento\Customer\Helper\Address::class)
                ->getAttributeValidationClass('favorite_color')
        )
        ?>
        <input type="text"
               name="favorite_color"
               id="favorite_color"
               value="<?= $escaper->escapeHtmlAttr($viewModel->getFavoriteColor()) ?>"
               title="<?= $escaper->escapeHtmlAttr(__('Favorite Color')) ?>"
               class="input-text <?= $validationClass ?: '' ?>"
        >
    </div>
</div>

Step 8: Install the module: bin/magento setup:upgrade

Step 9: Compile code: bin/magento setup:di:compile

Step 10: Deploy static content: bin/magento setup:static-content:deploy -f

You are done.


Btw, I have some recommendations for you:

  1. I see you have a duplicate type attribute for input element. I recommend using a PhpStorm/VisualStudio/NetBeans/...IDE to work with Magento 2, they are professional IDEs that help you a lot when developing Magento or large PHP projects (of course, they also support highlight code and errors, so you can detect some errors like duplicate HTML attributes...).

If you use PhpStorm, Magento has Magento PhpStorm plugin (free) for PhpStorm, which is very helpful for Magento Developer to develop Magento 2: https://plugins.jetbrains.com/plugin/8024-magento-phpstorm 2.

  1. In PHTML templates, we should escape content whenever possible.
    Using $escaper->escape{suffix}() for that instead of $block->escape{suffix}() which is deprecated to prevent XSS attack.
    For instance: use $escaper->escapeHtml() for that instead of $block->escapeHtml().
    https://developer.adobe.com/commerce/php/development/security/cross-site-scripting/#phtml-templates
6
  • @dotancohen As you already add favorite_color custom customer attribute into your database, you have to remove it and re-run upgrade script. Let me know if you need help with that, I'll tell you how.
    – Tu Van
    Commented Dec 27, 2022 at 17:50
  • Thank you! I am embarrassed to say that I posted the incorrect code in the upgrade() method, on account of posting simplified code without e.g. version checks. I have updated the upgrade() method in the question to the proper code. Thank you.
    – dotancohen
    Commented Dec 28, 2022 at 6:04
  • 1
    @dotancohen I've updated my answer with more detail and shared something with you.
    – Tu Van
    Commented Dec 30, 2022 at 8:53
  • 1
    Amazing, thank you. You are correct, though I do use PhpStorm I often just create some files in VIM out of habit. This answer format is perfect for learning, you are a teacher and I enjoy reading your answers also for other people's question. Have a great week.
    – dotancohen
    Commented Jan 1, 2023 at 12:13
  • @dotancohen Thanks for your kind words, it gives me more motivation to share/help others. I've heard a few people talk about it, and hope I can hear more. I've heard you say you learned a lot from me in the previous post, so I know you would like to learn more about Magento 2. In most of my answers, before sharing my answer, I try to apply code, run it in a clean Magento instance with sample data, and test, then write the step-by-step instruction to allow everyone at all levels able to get it to work without asking for more assistance.
    – Tu Van
    Commented Jan 1, 2023 at 14:22

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.