WooCommerce products with conflicting GTINs

One product, two codes: the native WooCommerce field says one GTIN, an EAN plugin's field says another. Whatever reads the native field — structured data, exports, every feed plugin — tells one story; whatever reads the plugin tells a different one, and your channels get contradictory signals about what the product is. CatalogLift finds each product whose fields disagree, and shows you both codes side by side.

Sales-readiness Medium severity Fix in CatalogLift

Why two codes are worse than one

A conflicting GTIN is not a missing one — the store has too many answers, not too few. The native GTIN, UPC, EAN, or ISBN field holds one code, a plugin key like _alg_ean or _wc_gla_gtin holds another, and each reader picks whichever field it was built to read.

  • The feed and the page contradict each other. A feed built from the plugin's field submits one code while the product page's JSON-LD, built from the native field, carries the other. Google reads both. A code that disagrees with the page it came from is exactly the mismatch that gets an offer disapproved or matched to a product you don't sell.
  • Every channel gets its own version. Feed plugins and the CSV export read the native field; the EAN plugin renders its own on the product page and hands it to its own integrations. Two comparison sites can end up filing the same product under two different identities.
  • At least one code is wrong — silently. Both fields render, both look filled, nothing errors. One of the two codes points at the wrong product, or at nothing, and no report in WooCommerce will ever put the two values next to each other.
  • Every future fix inherits the doubt. A migration to the native field, an export for an agency, a marketplace onboarding — each one starts with the same unanswered question of which code to carry forward, multiplied by every conflicted product.

How to find conflicting GTINs manually

Both values live in postmeta, so the check is a self-join: one alias for the native _global_unique_id, one for the plugin's key. This WP-CLI query lists products where both fields hold a value and the values differ:

wp db query "SELECT p.ID, p.post_title,
       g.meta_value AS native_gtin, e.meta_value AS plugin_gtin
FROM wp_posts p
JOIN wp_postmeta g
  ON g.post_id = p.ID AND g.meta_key = '_global_unique_id'
LEFT JOIN wp_postmeta e
  ON e.post_id = p.ID AND e.meta_key = '_alg_ean'
WHERE p.post_type IN ('product', 'product_variation')
  AND p.post_status = 'publish'
  AND g.meta_value != ''
  AND e.meta_value != ''
  AND g.meta_value != e.meta_value
ORDER BY p.ID;"

Adjust the table prefix if yours isn't wp_, and swap _alg_ean for the key your stack writes — _wc_gla_gtin, fb_gtin, _wpm_gtin_code and the rest each need their own run.

The query finds the disagreements; it cannot settle them. SQL won't compute a GS1 checksum, so every row still needs both codes validated by hand, and the honest cases — where both codes are well-formed — need someone to check the physical product or the supplier sheet before either field is touched. And the comparison only covers the one key you joined on.

How CatalogLift finds it

Every scan reads the native field and the plugin fields of each product in the synced catalog — the same source-aware reading as the hidden-code check, so a configurable or serialized plugin key is read the way its plugin wrote it. A product where both a native and a plugin value exist and differ becomes a finding at medium severity, and the evidence shows both codes and where each one lives: the value, the source, the exact meta key. The disagreement stops being invisible; it is two named values side by side.

Then each code runs through deterministic validation — the GS1 mod-10 checksum, mod-11 for ISBN-10 — and the evidence marks which of the two values passed. When the plugin's code is the only one that passes, the proposal is pre-filled with it: writing it into the native field is the change that ends the disagreement. When the native code is the one that passes, nothing is pre-filled — the native field already carries the right value, and the plugin's field is corrected in the store, which CatalogLift never writes. When both codes pass, the proposal field is left empty on purpose: two valid codes are two claims about the world, and no checksum — and no AI, which never produces or picks a code here — can tell which one is on the box. You decide, inside CatalogLift, with both values in front of you; CatalogLift writes only what was decided to WooCommerce, and the next scan verifies the fields finally agree. The first scan costs nothing and needs no card.

Fair questions, straight answers.

How do two different GTINs end up on one product?

Layered history. The store kept codes in an EAN plugin for years, then WooCommerce 9.1 added the native field and new codes started landing there — by hand, by import, by a migration that half-ran. A supplier update rewrites one field and not the other, a CSV maps the wrong column, and from then on the product carries two codes that were each correct at some point.

Why does it matter which field wins?

Because different systems read different fields. WooCommerce's JSON-LD and CSV export read the native field; the plugin renders and feeds its own. When the two disagree, Google can receive one code in the feed and read another in the page's structured data — mismatched identifiers are the kind of data quality problem that gets an offer disapproved or matched to the wrong product, and every channel is quietly telling a different story.

How does CatalogLift decide which code is right?

It often can't, and it says so. Each code is run through deterministic validation — the GS1 mod-10 checksum, mod-11 for ISBN-10 — which is arithmetic, not judgment. When the plugin's code is the only one that passes, CatalogLift pre-fills the proposal with it, because writing it into the native field is the change that ends the disagreement. When the native code is the sound one, the native field already carries the right value — the plugin's field is what needs correcting, in the store, and CatalogLift never writes plugin data. And when both pass, the proposal field is left empty on purpose: two well-formed codes are two claims about the world, and only someone who can check the box or the supplier sheet knows which one is this product.

Can AI pick the code for me?

No AI touches this check. A GTIN is a fact assigned by GS1, and a model has no way to know which of two valid codes belongs to your product — it could only guess, fluently. The comparison and the checksums are deterministic; the decision between two valid codes is yours; and once you approve, CatalogLift writes exactly that code to WooCommerce and the next scan verifies the two fields agree.

See it on your own catalog.

Create a free account, connect your WooCommerce store and this check runs on your real products, along with the rest.

No card required. The free plan never writes to WooCommerce.