WooCommerce reports options twice, in two alphabets

A bug that only appeared on colour products: attribute terms are display labels, variations record slugs, and comparing the two directly fails silently.

The Add to cart button on a scooter stayed dead. The shopper had picked Royal Blue, the chip was highlighted, and the button refused to enable. Every weight-based product on a different store worked perfectly.

Two spellings of the same choice

WooCommerce’s Store API describes a variable product’s choices in two places. The attribute lists its terms as display labels:

{ "name": "Color", "terms": [{ "name": "Royal Blue" }] }

Each variation records the same choice as a slug:

{ "id": 166571, "attributes": [{ "name": "Color", "value": "royal-blue" }] }

We were matching the shopper’s pick against the variation values directly. “Royal Blue” is not “royal-blue”, so nothing ever matched, and the button had no variation id to send.

Why weights hid it

The other store sells by weight. Its terms are 500ml and 1000ml, and the slug of 500ml is 500ml. Identical in both alphabets. Every test passed, on every product, because no value in that catalogue contained a capital letter or a space.

That is the uncomfortable part. The tests were not weak; the data was. A bug can hide behind a catalogue that happens not to exercise it, and the only defence is a fixture that deliberately does. Ours now compares a label-against-slug pair alongside the identical-spelling case that always worked.

The fix

Normalise both sides before comparing:

const slug = (s) => (s || "").toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "");

Three lines, once the cause was known. Finding it took a colour catalogue.

While we were in there

A variable product cannot be added to a WooCommerce cart by its parent id at all. The Store API answers Missing attributes for variable product. Any integration that puts products in a cart needs the variation’s own id, and if yours has only ever been tested against simple products, it will fail the first time a customer picks a size.

This is the product those notes are about

The trace panel is the part worth looking at: every candidate, its score, and the line that decided which reached the shopper.