Welcome to the second article in the “Commerce 2.x Stories” series. This time we’re going to talk about addressing, and our efforts to improve the already good Commerce 1.x addressing implementation (addressfield).

By addressing we mean storing, manipulating and formatting postal addresses, meant to identify a precise recipient location for shipping or billing purposes.

On eCommerce sites in general, when going through checkout customers are often annoyed by US-centric address forms. When interviewed about cart abandonment, this topic comes up time and time again. However, localizing an address form takes more effort than deciding whether a label should read “Postal code” vs. “ZIP code”.

Address formats



Each country has a different address format that tells us:

Which fields are used in which order (Is there a state field? Does the zip code come before the city? After the state?)

Which fields are required

Which fields need to be uppercased for the actual mailing to facilitate automated sorting of mail

The labels for the administrative area (state, province, parish, etc.), and the postal code (Postal code or ZIP code)

Validation rules for postal codes, usually in the form of a regular expression.

In countries using a non-latin script (such as China, Taiwan, Korea), the order of fields varies based on the language/script used. Addresses written in latin script follow the minor-to-major order (start with the street, end with the country) while addresses written in the chinese script follow the major-to-minor order (start with the country, end with the street).

All this needs to be taken into account when generating and validating an address form. Selecting a different country requires re-rendering the address form using a different format.

The address format is usually described on the site of the national post office, but collecting the data still requires a lot of manual browsing, translation, and research.

Subdivisions

A country can have several levels of subdivisions that are used for addressing. In the United States that would be the state. In Brazil it would be the state and the municipality. In China it would be the province, the prefecture-level city, and the county.

A user friendly address form would provide dropdowns for these subdivisions, thus speeding up the data entry process and reducing mistakes. Of course, the hard part is gathering the data for every country, which is why most sites only do this for the United States and / or the local market.

The model

Once the form has been filled out and validated, the address data needs to be stored somewhere. Figuring out the right model with the right field names can be tricky, but that dilemma is solved by the OASIS xAL standard. Used by Google Maps for geocoding, it defines the standard fields such as:

Country

Administrative area (province / state / emirate / island)

Locality (city/municipality)

Dependent locality (district)

Postal code

Commerce 1.x

For the addressing needs of Commerce 1.x the addressfield module was created. It stores addresses using the xNAL standard, accommodates both name and address data, and provides per-country address forms.

The module made one mistake, the address formats are declared imperatively, not declaratively. This means that there’s no “address_format” table that stores information needed to format an address. Instead, adding support for a new country involves writing a new plugin, or modifying the default one (by adding if clauses that change the weights and visibility of form elements, etc). This proved to be cumbersome, and it slowed down the community efforts to fill-in the blanks and expand support for missing countries.

Furthermore, it provides no postal code validation or uppercasing rules.

It was a good first try, but we can do better.

commerceguys/addressing

Going back to the drawing board, we found Google's i18n Services Address Data Service.

Created to power Android’s address forms, It contains address formats for over 200 countries as well as subdivisions for 40 of them (including Brazil and China as mentioned in our examples above). Furthermore, the dataset is constantly being expanded and improved.

Having that amount of default data changes everything, allowing us to do something truly great. After receiving confirmation from Google that we can parse and commit their dataset into an MIT licensed library, we began creating a library that tries to finally solve the addressing problem for all PHP projects.

Meet commerceguys/addressing.

Features:

Address formats for 200 countries

Subdivisions (administrative areas, localities, dependent localities) for 40 countries

Subdivision translations for all of the parent country's (i.e Canada, Switzerland) official languages.

Validation (via Symfony Validator)

Form generation (via Symfony Form)

Postal formatting

<?php

use CommerceGuys \ Addressing \ Formatter \ PostalFormatter ;

use CommerceGuys \ Addressing \ Metadata \ AddressMetadataRepository ;



$repository = new AddressMetadataRepository ();



// Get the address format for Brazil.

$addressFormat = $repository -> getAddressFormat ( 'BR' );

// Get the subdivisions for Brazil.

$states = $repository -> getSubdivisions ( 'BR' );

foreach ( $states as $state ) {

$municipalities = $state -> getChildren ();

}



// Get the subdivisions for Canada, in French.

$states = $repository -> getSubdivisions ( 'CA' , 0 , 'fr' );

foreach ( $states as $state ) {

echo $state -> getName ();

}



$formatter = new PostalFormatter ( $repository );

// Format an address for sending from Switzerland, in French.

// If the address destination is not Switzerland, the country name will be

// appended in French, uppercase.

echo $formatter -> format ( $address , 'CH' , 'fr' );

?>

Commerce 2.x

Commerce 2.x will depend on Addressfield 2.x, which will pull in the commerceguys/addressing library, store the address formats and subdivisions as configuration entities, and use them to generate and validate Drupal forms.

We gain a much richer dataset and greatly improved support for countries such as China, Korea, Brazil, and others. Best of all, our efforts benefit the whole wider PHP community.