A checkout needs phone numbers in one consistent shape. Customers type them with country codes, with spaces, with dashes, sometimes with a leading plus. We added a normalisation step alongside the existing validation, tested it, and watched it do nothing at all.
Validation itself worked correctly — badly formed numbers were rejected with a clear message. But every order that went through still stored exactly what the customer typed, untouched.
The hook runs against a copy
WooCommerce assembles the submitted checkout data into an array before it runs the validation hook, and then builds the order from its own copy of that data a few lines later. Anything written into the array handed to the validation hook is discarded. The hook is there so you can reject a submission, not so you can rewrite one.
This is an easy mistake to make and a hard one to notice, because nothing errors. The code runs, the function returns, the values look right inside the hook. Only the saved order disagrees.
Reject in one place, clean in another
The fix was to split the two jobs. Validation stayed where it was, because that is genuinely the only place that can stop a submission. Normalisation moved to the point where WooCommerce hands over the order object it is about to save — a real object, whose setters actually persist.
And the client-side check is not the rule
There is also a JavaScript check on the same field, and it stays, because instant feedback while typing is worth having. It is not the rule though. Disabled scripts, an unusual browser or a direct form post all bypass it. The server-side check is the rule; the client-side one is a courtesy.
Key takeaways
- A hook firing at the right moment is not necessarily a hook writing to the right object.
- Validation hooks exist to block submissions; mutate on the object being saved instead.
- Silent no-ops are the expensive kind of bug — nothing fails, so nothing draws attention.
- Verify a data fix by reading the stored record, not by inspecting variables inside the hook.
Related reading: validating mobile numbers at checkout, a checkout without email addresses.
Running into a similar limitation in your own WooCommerce or WordPress store? Let’s Talk — ArtinTech Solution builds exactly this kind of custom store tooling.