Drupal Commerce Blog

What's happening in the world of Drupal Commerce.

Commerce 2.x Stories - Addressing

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.

Bojan Zivanovic
Posted: Sep 24, 2014

Comments

Walt Daniels on September 24, 2014

All CRMs also need many of the features of addressfield, and they frequently us Commerce, at least to take donations for non-profits. Some of them try to use addressfield but it is only part of the contact info that they typically collect. See AbleOrganizer for instance.

If not used then there is the potential for duplicate data where no one is sure which one is right.

----------
There is another issue that comes up in the US. Some zipcodes have several names, some of which are what people use when filling out forms, but are not officially recognized by USPS. They generally go through, as well as occasional beyond the pale extra effort. I once (in 1960-66) got mail addressed to me on Two Line Drive, Hyattsville,IN when my address was really Tulane Drive, Hyattsville. MD. (no zip provided). The key issue here is whether to fix the address or not from what the user supplied.