silvershop-suite / address-formats
Per-country address field rules for SilverShop: labels, required fields, postcode validation and formatting. Fixes per-country checkout and provides a reusable address formatter.
Package info
github.com/silvershop-suite/silvershop-address-formats
Type:silverstripe-vendormodule
pkg:composer/silvershop-suite/address-formats
Requires
- php: ^8.3
- silvershop/core: ^6
- silverstripe/framework: ^6.0
Requires (Dev)
- commerceguys/addressing: ^2.0
- phpunit/phpunit: ^11.0
- silverstripe/sqlite3: ^4
- squizlabs/php_codesniffer: ^3.7
Suggests
- commerceguys/addressing: Global country coverage via the Google libaddressinput dataset — enable with AddressFormatRegistry.rule_provider: addressing.
Provides
None
Conflicts
None
Replaces
None
README
Per-country address field rules for SilverShop — labels,
required/hidden fields, postcode patterns and a reusable address formatter — plus a fix for the hardcoded
State-required checkout blocker.
Out of the box silvershop's customer Address requires State for every country, so NL / BE / DE / GB
customers can't complete checkout. This module makes address rules per-country and config-driven, with a
safe default that keeps existing behaviour where no country rule applies.
What it adds
AddressFormatRegistry+AddressFormat— per-ISO-country rules merged over adefaultentry, so a country only declares what differs: fieldlabels(Postcode / ZIP / PLZ, State → Province / County),required,hidden(e.g. no State for NL),postcode_regex, and a displayformat.CustomerAddressExtensiononSilverShop\Model\Address— relabels/hides fields per country (updateFormFields) and sets the per-country required fields (updateRequiredFields), fixing the State-required checkout blocker.AddressFormatter— renders address-like data to a one-line or multi-line address for a country. Reused by store-profile, shipping labels and invoicing.- Live country switching (default on) — the front-end form re-labels, shows/hides and re-requires fields as the customer changes Country, with a no-JS baseline. Overridable template + JS (see below).
- Postcode validation + normalisation — the per-country
postcode_regexis enforced on the model and exposed as an HTML5pattern, and postcodes are normalised on save (e.g. NL1234ab→1234 AB, GB/CA upper-cased). - House-number split (opt-in per country, e.g. NL/DE) — a separate
HouseNumberfield on the customer address, composed back into the address string for display. Off by default; nullable column. - Global coverage (optional) — install
commerceguys/addressingand setrule_provider: addressingto source rules for every country from the Google libaddressinput dataset; your YAML entries still override it. - Ships rules for ~23 countries (NL, BE, DE, FR, GB, US, NZ, AU, AT, CH, CZ, DK, ES, FI, IE, IT, LU, NO, PL, PT,
SE, CA, JP) + a
default; add or override any country in YAML.
Live country switching
With live_country_switching on (default), the address form keeps every field in the DOM and ships a small script
that adapts it client-side on Country change: it toggles a addressformat-hidden class on the holder, swaps labels,
updates required/aria-required, and sets the postcode pattern. It reads a per-country rules JSON and dispatches
an addressformat:changed event. Everything is overridable:
- Override the template
SilverShop/AddressFormats/Includes/AddressFormatScript.ssin your theme/project. - Fields are tagged
data-addressformat-field="Address|AddressLine2|City|State|PostalCode"— style/script against that. - Turn it off (revert to server-side field removal, no client switching):
SilverShop\AddressFormats\AddressFormatRegistry: live_country_switching: false
Installation
composer require silvershop-suite/address-formats
Then run dev/build.
Adding or overriding a country
Rules live under AddressFormatRegistry.formats, keyed by ISO-3166-1 alpha-2 code. Each entry is merged over
default, so you only set what changes:
SilverShop\AddressFormats\AddressFormatRegistry: formats: IE: required: ['Address', 'City'] hidden: ['State'] labels: PostalCode: 'Eircode' postcode_regex: ''
Global coverage (libaddressinput)
The bundled YAML covers ~23 countries. For every country, install
commerceguys/addressing (the Google libaddressinput dataset) and
switch the provider:
composer require commerceguys/addressing
SilverShop\AddressFormats\AddressFormatRegistry: rule_provider: addressing
Required/hidden fields, field labels, postcode pattern and line order then come from the dataset for any country,
with your formats YAML layered on top as per-country overrides (so NL/DE keep their house-number split, custom
labels, etc.). Without the library, or with rule_provider: config (the default), only the bundled YAML is used.
House-number split
Countries configured with house_number: true (ships for NL and DE) get a separate HouseNumber input
beside the street, and the number is composed back into the single-line address (via updateToString) so stored and
displayed addresses stay whole. It adds a nullable HouseNumber column to the customer Address — run dev/build
after enabling. Off for every other country; existing data is untouched (the street stays in Address). Enable it for
another country in YAML:
SilverShop\AddressFormats\AddressFormatRegistry: formats: AT: house_number: true required: ['Address', 'HouseNumber', 'PostalCode', 'City'] labels: {Address: 'Straße', HouseNumber: 'Hausnr.'} format: ['{Address} {HouseNumber}', '{PostalCode} {City}', '{Country}']
Postcode rules
Each country may set a postcode_regex (enforced on the model + surfaced as an HTML5 pattern) and an optional
postcode_transform applied on save — upper, nl (1234ab → 1234 AB) or ca (m5h2n2 → M5H 2N2). An empty
regex skips validation; presence is governed by required.
Status
v1.3 — per-country labels / required / hidden / formatter + the checkout blocker fix, live country switching,
postcode validation + normalisation (~23 bundled countries), opt-in house-number split (NL/DE), and an optional
libaddressinput provider for global coverage. i18n: the per-country field labels are
configuration data (not translatable); the only UI string is the postcode validation message, shipped in en + nl +
de + fr + es + it. Planned: HouseNumber split (NL/DE) and a pluggable libaddressinput provider for full global
coverage — see PLAN-address-formats-v1.1.md in the consuming
project for the roadmap.
Licence
BSD-3-Clause.
Credits
Built and maintained by Remy Vaartjes (remy@xd.nl) — part of the SilverShop-Suite.