I want to try and stop Commerce 3 creating a new customer address if it’s a duplicate of an existing one.
As an example, a store selling digital products has a checkout form that simply asks for the customer’s country, no other address info is required. All we need is one select field for the country (pre-checked if we already have that info). We could add radio buttons to select any previously saved addresses as well as a field to select a (new) country. However, even if we do that, there’s still a chance the user opts to enter a new address and actually submits a duplicate.
I’ve created a plugin that catches a duplicate address and then tries to set the cart’s billingAddressId so a new address isn’t created. What I have so far though doesn’t work. It doesn’t successfully update the billingAddressId
. If I use Craft::$app->getElements()->saveElement($cart)
it results in a loop in this case.
How can I complete this to update the cart, or perhaps the post data in this case, with the matched billingAddressId
?
Event::on(Address::class, Address::EVENT_BEFORE_VALIDATE, function (Event $e) {
$sentCountryId = $e->sender->countryId;
$currentUser = Craft::$app->user;
$cart = craft\commerce\Plugin::getInstance()->getCarts()->getCart();
$addresses = $cart->customer->addresses;
$match = 0;
// Only check against saved addresses if currentUser has any
if ($currentUser and $addresses) {
// If true, loop saved address to check for a country match
foreach($addresses as $address) {
// Loop until a match is found
if ($match == 0) {
$savedCountryId = $address->countryId;
if ($sentCountryId == $savedCountryId) {
$match = $address->id;
}
}
};
// If there’s a match set the cart’s billingAddressId
// to stop a new address being created:
if ($match) {
$cart->billingAddressId = $match; // This doesn’t work on it’s own
// Craft::$app->getElements()->saveElement($cart); // Results in a loop
$e->handled = true;
}
}
});