Making your WooCommerce catalog agent-readable (AEO)
How to make WooCommerce product pages agent-readable: complete attributes, correct Product JSON-LD, and server-rendered content AI agents can parse.

Once your product data is enriched — attributes filled in, identifiers assigned, use-cases written — the question is whether that data ever reaches the page in a form a shopping agent, or a search crawler, can actually read. WooCommerce gives you most of the plumbing natively: global attributes, a built-in structured data block, and server-rendered templates. This guide covers configuring that plumbing correctly, where the defaults fall short, and how to check your work.
Step 1: Put attributes where WooCommerce (and agents) expect them
WooCommerce distinguishes between two kinds of attributes, and the distinction matters for AI-readability:
- Global attributes are created once under Products → Attributes, then assigned to any product. They support consistent term slugs (e.g.,
pa_material), which lets an agent, or your own search, reliably compare "material" across your whole catalog. - Custom (local) attributes are typed directly into a single product's Attributes tab and aren't reusable elsewhere.
For either type, two checkboxes decide whether an attribute is actually machine-visible:
- "Visible on the product page" — if unchecked, the attribute exists in your admin and database but never renders into the page's HTML at all. It is invisible to crawlers, agents, and shoppers alike.
- "Used for variations" — relevant for variable products; variation-level values (e.g., a size/color combination's price and stock) should still resolve to real, non-AJAX-gated data in the page's variation JSON so an agent isn't stuck guessing.
Checked, visible attributes populate WooCommerce's Additional Information tab automatically — a real, semantic HTML table rendered in the same server response as the rest of the page. WooCommerce's product tabs are CSS-hidden panels, not lazy-loaded content, so this table is present in the raw HTML an agent fetches, not just in what a browser later renders.
While you're in the product editor, also fill in the native GTIN, UPC, EAN, or ISBN field (added to WooCommerce core in version 9.2, on the Inventory tab of Product data). It's the cleanest way to give agents — and Google — a stable product identifier, and, as covered next, WooCommerce pulls it straight into structured data for you.
(WooCommerce: Managing Product Categories, Tags and Attributes; WooCommerce GTIN field, added in 9.2)
Step 2: Get Product JSON-LD right — including what's missing by default
WooCommerce automatically emits schema.org/Product JSON-LD on every product page, generated by the WC_Structured_Data class and output on the wp_footer hook — part of the initial server response, not injected later by JavaScript. Out of the box it includes name, url, description, image, sku, gtin (if you've set the native field above), an offers block with price, priceCurrency, and availability, plus aggregateRating and up to five recent review entries when reviews are enabled and populated.
What it does not include by default:
brand— since WooCommerce 9.6 (January 2025), Brands is a native core feature (Products → Brands, a built-inproduct_brandtaxonomy) rather than a separate extension. Populating it still isn't enough on its own:brandisn't one of the propertiesWC_Structured_Datamaps by default, so it won't show up in the JSON-LD until you add it via the filter below.mpn— no core field; only relevant if you track manufacturer part numbers as custom meta.- Anything from custom fields or a PIM-fed attribute that isn't one of the properties
WC_Structured_Dataalready maps.
Extend the block with the woocommerce_structured_data_product filter rather than replacing WooCommerce's output — this keeps price, availability, and review data in sync with core as WooCommerce updates it:
add_filter( 'woocommerce_structured_data_product', function( $markup, $product ) {
// Pull brand from WooCommerce's built-in product_brand taxonomy (Products → Brands, core since 9.6).
$brand_terms = wc_get_product_terms( $product->get_id(), 'product_brand', array( 'fields' => 'names' ) );
if ( ! empty( $brand_terms ) ) {
$markup['brand'] = array(
'@type' => 'Brand',
'name' => $brand_terms[0],
);
}
// Pull an MPN if you're storing one as product meta.
$mpn = $product->get_meta( '_mpn', true );
if ( $mpn ) {
$markup['mpn'] = $mpn;
}
return $markup;
}, 10, 2 );
For AI shopping agents and Google's merchant listing eligibility, brand and a gtin/mpn pair turn a generic snippet into something an agent can match against its own product knowledge and compare across retailers — treat them as required, not optional, alongside price, priceCurrency, and availability.
(Google: How to add merchant listing structured data; WooCommerce Structured Data wiki; WooCommerce 9.6: Brands enabled by default in core)
Step 3: Confirm the content is actually server-rendered
The default WooCommerce theme stack — classic PHP templates or a block theme's Product block templates — renders the product title, description, attributes table, and JSON-LD in the initial HTML response. That's the easy case. Two setups quietly break it:
- Headless/decoupled front ends built on the WooCommerce Store API or GraphQL with a React/Next.js front end. If that front end is client-side rendered (CSR) only, the HTML an agent or crawler first fetches is a near-empty shell — product content only exists after JavaScript executes, which many AI crawlers and shopping agents don't do reliably. Going headless means you need server-side rendering or static generation for product routes specifically, not just for the shell.
- Custom tabs or specs loaded via AJAX after page load (common with some page builders). If a fact only appears after an XHR call fires, treat it as invisible to anything that doesn't run a full browser.
What an AI agent can and cannot extract
Can extract, when the setup above is in place:
- Price, currency, and stock status from the
offersblock in JSON-LD. - SKU/GTIN/brand for identifier matching against other retailers or a manufacturer catalog.
- Attribute name/value pairs from the server-rendered Additional Information table.
- Plain-language answers to buyer questions when written into the visible description or a real FAQ block, not buried in a downloadable spec sheet.
Cannot extract, even with a good PIM behind the scenes:
- Attributes left unchecked for "Visible on the product page" — correct in the database, absent from the page.
- Brand/MPN if your brand taxonomy isn't hooked into
woocommerce_structured_data_product— visible to a human reading the page, missing from the machine-readable layer. - Any content that only renders after client-side JavaScript runs, on a headless storefront without SSR.
- Facts that exist only in a PDF, an image of a spec table, or a chat-widget answer — none of that is parseable text on the page itself.
How to validate
- View-source vs. rendered DOM: run
curl -s https://yourstore.com/product/example-widget/ | grep -A 40 'application/ld+json'and compare it to DevTools' rendered DOM. If JSON-LD or the attribute table shows up in DevTools but not in thecurloutput, it's added by client-side JavaScript and most agents won't see it. - Rich Results Test (search.google.com/test/rich-results) to confirm the JSON-LD parses and check which rich result types it's eligible for.
- Schema Markup Validator (validator.schema.org) for a stricter schema.org-spec check independent of Google's eligibility rules.
- Spot-check a few product URLs with
curlforgtin,brand, andoffers.availability— the fields most likely to be missing even when the rest of the JSON-LD looks fine.
Verified as of July 2026 against WooCommerce core documentation, the WooCommerce Structured Data source, and Google Search Central's merchant listing guidance; menu paths assume a recent WooCommerce core version and may shift with page-builder or block-theme customizations.
This exercise only pays off if the attributes and identifiers going into these fields are complete and current — the half of the problem Anglera is built for. Anglera continuously enriches your product data (attributes, specs, identifiers, use-cases) directly in your PIM or product source, so the GTIN field, attribute table, and JSON-LD extension above have accurate, complete data to render in the first place.
