diff --git a/CHANGELOG.md b/CHANGELOG.md index 5cf2e89cce9..71e0801bd40 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ ## Unreleased - Fixed a bug where it wasn’t possible to override named transforms in GraphQL queries. ([#15572](https://github.com/craftcms/cms/issues/15572)) +- Fixed a bug where address subdivision fields could be incorrectly labelled and/or populated with the wrong options. ([#15551](https://github.com/craftcms/cms/issues/15551), [#15584](https://github.com/craftcms/cms/pull/15584)) - Fixed a bug where it wasn’t possible to remove nested entries in Matrix fields if the Min Entries setting had been reached. ([#15575](https://github.com/craftcms/cms/issues/15575)) - Fixed a bug where Matrix and Addresses fields weren’t displaying or validating unpublished drafts. ([#15536](https://github.com/craftcms/cms/issues/15536)) diff --git a/src/helpers/Cp.php b/src/helpers/Cp.php index b84779fead6..ba36dfecccd 100644 --- a/src/helpers/Cp.php +++ b/src/helpers/Cp.php @@ -7,6 +7,7 @@ namespace craft\helpers; +use CommerceGuys\Addressing\Subdivision\SubdivisionRepository as BaseSubdivisionRepository; use Craft; use craft\base\Actionable; use craft\base\Chippable; @@ -2088,6 +2089,8 @@ public static function addressFieldsHtml(Address $address): string $addressesService->getUsedSubdivisionFields($address->countryCode), )) + $requiredFields; + $parents = self::_getSubdivisionParents($address, $visibleFields); + return static::textFieldHtml([ 'status' => $address->getAttributeStatus('addressLine1'), @@ -2143,10 +2146,7 @@ public static function addressFieldsHtml(Address $address): string $belongsToCurrentUser ? 'address-level2' : 'off', isset($visibleFields['locality']), isset($requiredFields['locality']), - array_values(array_filter([ - $address->countryCode, - array_key_exists('administrativeArea', $visibleFields) ? $address->administrativeArea : false, - ], fn($v) => $v !== false)), + $parents['locality'], true, ) . self::_subdivisionField( @@ -2155,11 +2155,7 @@ public static function addressFieldsHtml(Address $address): string $belongsToCurrentUser ? 'address-level3' : 'off', isset($visibleFields['dependentLocality']), isset($requiredFields['dependentLocality']), - array_values(array_filter([ - $address->countryCode, - array_key_exists('administrativeArea', $visibleFields) ? $address->administrativeArea : false, - array_key_exists('locality', $visibleFields) ? $address->locality : false, - ], fn($v) => $v !== false)), + $parents['dependentLocality'], false, ) . static::textFieldHtml([ @@ -2197,6 +2193,49 @@ public static function addressFieldsHtml(Address $address): string ]); } + /** + * Get parents array that needs to be passed to the subdivision repository getList() method to get the list of subdivisions back. + * + * For the administrativeArea, the parent is always just the country code. + * + * For the locality: + * - it could be just the country code + * - for countries that don't use administrativeArea field; that's the case with Andorra + * - it could be the country code and the administrative area code + * - for countries that use both administrative areas and localities; e.g. Chile (Chile => Araucania > Carahue) + * - the administrative area can be passed as null too; + * this will be triggered for the United Kingdom (GB), where you can conditionally turn on administrativeArea; + * in the case of GB, not passing null as the second value would result + * in the administrativeAreas list being returned for the locality field (https://github.com/craftcms/cms/issues/15551); + * + * For the dependentLocality: + * - as above but taking locality into consideration too; e.g. China has all 3 levels of subdivisions and has lists for all 3 of them + * (China => Heilongjiang Sheng > Hegang Shi > Dongshan Qu) + * + * @param Address $address + * @param array $visibleFields + * @return array + */ + private static function _getSubdivisionParents(Address $address, array $visibleFields): array + { + $baseSubdivisionRepository = new BaseSubdivisionRepository(); + + $localityParents = [$address->countryCode]; + $administrativeAreas = $baseSubdivisionRepository->getList([$address->countryCode]); + + if (array_key_exists('administrativeArea', $visibleFields) || empty($administrativeAreas)) { + $localityParents[] = $address->administrativeArea; + } + + $dependentLocalityParents = $localityParents; + $localities = $baseSubdivisionRepository->getList($localityParents); + if (array_key_exists('locality', $visibleFields) || empty($localities)) { + $dependentLocalityParents[] = $address->locality; + } + + return ['locality' => $localityParents, 'dependentLocality' => $dependentLocalityParents]; + } + private static function _subdivisionField( Address $address, string $name,