How to remove postcode field from Magento2 checkout

In order to accomplish the postcode removal we need to:
- Remove it from checkout form
- Disable the postcode validators
1. Remove it from checkout form: Alter the postcode eav attribute (set is_user_defined to 1)
The postcode field is created by the vendor/magento/module-checkout/Block/Checkout/LayoutProcessor.php block using the customer_address and customer_register_address EAV attributes. If we set the postcode EAV attribute property is_user_defined to 1, then it won’t be included into the jsLayout json object based on which the checkout form is generated.
Let’s begin: the first step is to create a new module with a setup data resource which will change this attribute, let’s call it Bb_RemovePostcode.
a) Create the app/code/Bb/RemovePostcode/etc/module.xml:
1 2 3 4 5 6 7 8 9 10 |
<?xml version="1.0"?> <config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="module.xsd"> <module name="Bb_RemovePostcode" setup_version="1.0.0"> <sequence> <module name="Magento_Quote"/> <module name="Magento_Customer"/> <module name="Magento_Checkout"/> </sequence> </module> </config> |
b) Create the app/code/Bb/RemovePostcode/registration.php :
1 2 3 4 5 6 |
<?php \Magento\Framework\Component\ComponentRegistrar::register( \Magento\Framework\Component\ComponentRegistrar::MODULE, 'Bb_RemovePostcode', __DIR__ ); |
c) Create the app/code/Bb/RemovePostcode/Setup/InstallData.php setup file:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 |
<?php namespace Bb\RemovePostcode\Setup; use Magento\Customer\Setup\CustomerSetupFactory; use Magento\Framework\Setup\InstallDataInterface; use Magento\Framework\Setup\ModuleContextInterface; use Magento\Framework\Setup\ModuleDataSetupInterface; class InstallData implements InstallDataInterface { /** * Customer setup factory * * @var CustomerSetupFactory */ private $customerSetupFactory; /** * @param CustomerSetupFactory $customerSetupFactory */ public function __construct( CustomerSetupFactory $customerSetupFactory ) { $this->customerSetupFactory = $customerSetupFactory; } public function install(ModuleDataSetupInterface $setup, ModuleContextInterface $context) { /** @var CustomerSetup $customerSetup */ $customerSetup = $this->customerSetupFactory->create(['setup' => $setup]); $setup->startSetup(); $attribute = $customerSetup->getEavConfig()->getAttribute('customer_address', 'postcode'); $attribute->setIsUserDefined(1)->save(); $attribute->save(); } } |
Let’s activate the module by running on the cli on the root magento2 folder the following command: php bin/magento module:enable Fsu_RemovePostcode
You should see a green message.
And then: php bin/magento setup:upgrade
You should see a green message.
At this moment you should be able to see that the postcode checkout field was removed from the shipping address form.
You’ll be unable to complete an order because some postcode validators are still enabled. Let’s disable them.
2. Disabling the postcode validators
a) first validator you’ll find on the customer address repository object,
vendor\magento\module-customer\Model\ResourceModel\AddressRepository.php:284 and for disabling it we need to overwrite this class.
– let’s create the di.xml file under etc/ folder:
app/code/Bb/RemovePostcode/etc/di.xml :
1 2 3 4 5 6 7 |
<?xml version="1.0"?> <config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd"> <preference for="Magento\Customer\Api\AddressRepositoryInterface" type="Bb\RemovePostcode\Model\ResourceModel\AddressRepository" /> </config> |
– and the app/code/Bb/RemovePostcode/Model/ResourceModel/AddressRepository.php class file with the contents:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 |
<?php namespace Bb\RemovePostcode\Model\ResourceModel; class AddressRepository extends \Magento\Customer\Model\ResourceModel\AddressRepository { public function save(\Magento\Customer\Api\Data\AddressInterface $address) { $addressModel = null; $customerModel = $this->customerRegistry->retrieve($address->getCustomerId()); if ($address->getId()) { $addressModel = $this->addressRegistry->retrieve($address->getId()); } if ($addressModel === null) { $addressModel = $this->addressFactory->create(); $addressModel->updateData($address); $addressModel->setCustomer($customerModel); } else { $addressModel->updateData($address); } $inputException = $this->_validate($addressModel); if ($inputException->wasErrorAdded()) { throw $inputException; } $addressModel->save(); $address->setId($addressModel->getId()); // Clean up the customer registry since the Address save has a // side effect on customer : \Magento\Customer\Model\ResourceModel\Address::_afterSave $this->customerRegistry->remove($address->getCustomerId()); $this->addressRegistry->push($addressModel); $customerModel->getAddressesCollection()->clear(); return $addressModel->getDataModel(); } protected function _validate(\Magento\Customer\Model\Address $customerAddressModel) { $exception = new \Magento\Framework\Exception\InputException(); if ($customerAddressModel->getShouldIgnoreValidation()) { return $exception; } if (!\Zend_Validate::is($customerAddressModel->getFirstname(), 'NotEmpty')) { $exception->addError(__('%fieldName is a required field.', ['fieldName' => 'firstname'])); } if (!\Zend_Validate::is($customerAddressModel->getLastname(), 'NotEmpty')) { $exception->addError(__('%fieldName is a required field.', ['fieldName' => 'lastname'])); } if (!\Zend_Validate::is($customerAddressModel->getStreetLine(1), 'NotEmpty')) { $exception->addError(__('%fieldName is a required field.', ['fieldName' => 'street'])); } if (!\Zend_Validate::is($customerAddressModel->getCity(), 'NotEmpty')) { $exception->addError(__('%fieldName is a required field.', ['fieldName' => 'city'])); } if (!\Zend_Validate::is($customerAddressModel->getTelephone(), 'NotEmpty')) { $exception->addError(__('%fieldName is a required field.', ['fieldName' => 'telephone'])); } $havingOptionalZip = $this->directoryData->getCountriesWithOptionalZip(); if (!in_array($customerAddressModel->getCountryId(), $havingOptionalZip) && !\Zend_Validate::is($customerAddressModel->getPostcode(), 'NotEmpty') ) { //$exception->addError(__('%fieldName is a required field.', ['fieldName' => 'postcode'])); } if (!\Zend_Validate::is($customerAddressModel->getCountryId(), 'NotEmpty')) { $exception->addError(__('%fieldName is a required field.', ['fieldName' => 'countryId'])); } if ($this->directoryData->isRegionRequired($customerAddressModel->getCountryId())) { $regionCollection = $customerAddressModel->getCountryModel()->getRegionCollection(); if (!$regionCollection->count() && empty($customerAddressModel->getRegion())) { $exception->addError(__('%fieldName is a required field.', ['fieldName' => 'region'])); } elseif ( $regionCollection->count() && !in_array( $customerAddressModel->getRegionId(), array_column($regionCollection->getData(), 'region_id') ) ) { $exception->addError(__('%fieldName is a required field.', ['fieldName' => 'regionId'])); } } return $exception; } } |
We can see here that we extended both save() and _validate() methods in order to remove the postcode validator.
b) Another validator the we need to remove is located under the
Magento\Customer\Model\Address\Validator\Postcode class. Let’s overwrite isValid method with the help of a Plugin:
– open the di.xml file created at previous step and let’s add the following node:
1 2 3 |
<type name="Magento\Customer\Model\Address\Validator\Postcode"> <plugin name="Bb_RemovePostcode::customerAddressPostcodeValidator" type="Bb\RemovePostcode\Plugin\Customer\Address\PostcodeValidator" /> </type> |
– now let’s create the Plugin class, specified in the type attribute above Bb\RemovePostcode\Plugin\Customer\Address\PostcodeValidator :
1 2 3 4 5 6 7 8 9 10 11 12 |
<?php namespace Bb\RemovePostcode\Plugin\Customer\Address; class PostcodeValidator { public function afterIsValid($subject) { return true; } } |
It’s a very simple plugin that overwrites the returned value to boolean true no matter what the previous value was. So now this validator will return true no matter what.
c) Similar to the previous approach we need o extend the
Magento\Customer\Model\Attribute\Data\Postcode ‘s validate() method. We will do it via another Plugin:
– open the di.xml file created at previous step and let’s add the following node:
1 2 3 |
<type name="Magento\Customer\Model\Attribute\Data\Postcode"> <plugin name="Bb_RemovePostcode::customerAddressPostcodeValidatorValue" type="Bb\RemovePostcode\Plugin\Customer\Address\PostcodeValidatorValue" /> </type> |
– create the class here: Bb\RemovePostcode\Plugin\Customer\Address\PostcodeValidatorValue :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
<?php namespace Bb\RemovePostcode\Plugin\Customer\Address; class PostcodeValidatorAddress { public function afterValidate($subject, $result) { if(count($result) == 1){ if(!\Zend_Validate::is($subject->getPostcode(),'NotEmpty')){ return true; } } } } |
The overwritten validate() method has many other validators for the Customer Address. This method we added after it’s execution via the Plugin’s afterMethod feature it’s checking if the validate() method returns just one error and if that’s error cause is the empty postcode field. If so then ignore this and return true.
d) The last one, also similar to the previous validator is located on
Magento\Customer\Model\Address\AbstractAddress class, validateValue() method. We will extend it’s behaviour it via another Plugin:
– open the di.xml file created at previous step and let’s add the following node:
1 2 3 |
<type name="Magento\Customer\Model\Address\AbstractAddress"> <plugin name="Bb_RemovePostcode::customerAddressPostcodeValidatorAddress" type="Bb\RemovePostcode\Plugin\Customer\Address\PostcodeValidatorAddress" /> </type> |
– and let’s create the Bb\RemovePostcode\Plugin\Customer\Address\PostcodeValidatorAddress class:
1 2 3 4 5 6 7 8 9 10 11 12 |
<?php namespace Bb\RemovePostcode\Plugin\Customer\Address; class PostcodeValidatorValue { public function afterValidateValue($subject) { return true; } } |
Pretty self explanatory, returns no error regardless the previous validating result.
At this point you should be able to place a new order successfully, without the postcode field.
Let me know in the comments if it worked.
Cheers.