Two failures that were not where they appeared
The problem
A checkout rejecting orders for a missing name that was plainly filled in, and a point of sale offering staff outlets that had been switched off. Both were reported as faults in the component the user was looking at, and neither was.
The most expensive hours in debugging go on faults that are reported accurately and located wrongly. Both of these were exactly that.
The checkout that insisted on a name it had been given
Checkout refused to complete, reporting a required name field, with every field on screen visibly filled in. The obvious suspects were all wrong: duplicated fields in the markup, a stale same-as-shipping flag, a skipped step in the multi-step layout, a content security policy blocking a script.
The cause was a small custom plugin that adds fields to the registration form. It validated the unprefixed field names that registration posts — and it did so through a filter that also fires when checkout creates a customer account, where the same fields arrive under prefixed names. So the check looked for fields that could not exist in that context and correctly reported them missing.
The fix is to establish which form is actually being submitted, using a hidden marker with a nonce as a fallback, and only validate when it is the one the code was written for. The general lesson is worth keeping: a hook named after one workflow is not scoped to it, and the second caller is usually discovered in production.
The till that offered outlets nobody could use
Outlets switched off in the administration screens kept appearing in the point of sale selector. Two things made this awkward. The till is served from a custom endpoint rather than a page, so the usual way of asking which page you are on returns nothing useful — detection has to key off whether the relevant script is queued instead.
And the outlet data is handed to a JavaScript application through a localised object. A script in the footer runs long after that application has read the object and built its interface, so filtering there changes nothing visible. The data has to be corrected in the moment between the object being printed and the application loading, by injecting immediately ahead of the script tag itself. A watcher on the resulting markup stays in place as a safety net.
The common thread
In both cases the component that reported the fault was behaving correctly. What was wrong was an assumption about when code runs and what else calls it — which is not visible in either component on its own, and is why reading the two files that look relevant is rarely enough.
The outcome
Both traced to code running in a context nobody had considered, and fixed at the cause rather than patched at the symptom.
