---
title: "AI Shopping Agents and WooCommerce: Making Product Pages Readable"
description: "Get WooCommerce ready for AI shopping agents: what your product schema really says, Markdown pages with prices, the Store API and a validated ChatGPT feed."
url: "https://skybootstrap.com/ai-shopping-agents-woocommerce/"
canonical_url: "https://skybootstrap.com/ai-shopping-agents-woocommerce/"
date: "2026-10-29T01:00:00+06:00"
modified: "2026-10-28T14:33:01+06:00"
author: Skybootstrap Team
type: article
site: SkyBootstrap
language: en-US
---

# AI Shopping Agents and WooCommerce: Making Product Pages Readable

AI shopping agents on WooCommerce stores can only recommend what they can read, and some of what a store outputs can be wrong or missing. On our test store, an SEO plugin on its default settings replaced WooCommerce’s product markup and dropped the brand and the regular price. Our Markdown product pages had no price at all.

This guide covers the four places agents get product data from on WooCommerce and the results of testing each one on a WooCommerce 11.2.1 store. It ends with the fixes, including code for Markdown product facts and a ChatGPT product feed.

## What AI shopping agents read on WooCommerce

An AI shopping agent can get product data from four places on a WooCommerce store: structured data in the page, the page itself, the public Store API, and a feed you send. An AI shopping agent is a tool that researches or buys products for a person, such as ChatGPT’s shopping features.

- Structured data: the JSON-LD block in each product page that states the name, price, stock, and brand in a fixed format.
- The page: HTML for most visitors, or Markdown if your site serves it to agents that ask for it.
- The Store API: WooCommerce’s public product JSON at `/wp-json/wc/store/v1/products`.
- A product feed: a file of your products that you submit to a platform such as OpenAI’s merchant program.

Apart from feeds you submit, no AI company documents which of these its shopping features read, so keep all four accurate. The first three exist on your store today, whether you’ve checked them or not. Crawlers have to be let in too: OAI-SearchBot is the crawler OpenAI uses to show websites in ChatGPT’s search features, so don’t block it in robots.txt.

## Check what your product schema really says

Open a product page and read its JSON-LD: on our test store, Rank Math’s default settings replaced WooCommerce’s product markup and dropped the brand, the regular price and the clean product name. Product structured data is the machine-readable summary of a product, written in schema.org’s Product format inside a `<script type="application/ld+json` tag.

We set up three products with a brand, SKU, GTIN and stock, put one on sale and gave one two test reviews. Then we compared the markup from Rank Math 1.0.280 on its default product settings (AIOSEO 5.0.3 was active too) against WooCommerce with both SEO plugins switched off:

| Field | WooCommerce alone | With Rank Math active |
| --- | --- | --- |
| Product name | “Summit 45L Hiking Pack” | “Summit 45L Hiking Pack – LLMs Lab” (site name added) |
| Brand | Northfield Gear | Missing |
| Price on sale | 129.00 plus the 149.00 list price | 129.00 only |
| Availability, SKU, GTIN (and rating, on our reviewed product) | Present | Present |
| Seller | Organization | Follows Rank Math’s “Person or Company” setting (Person on our test site) |

![Side-by-side JSON-LD for the same WooCommerce product: WooCommerce alone includes a brand and a 149.00 list price; with Rank Math's default settings the name gains ' - LLMs Lab' and the brand and list price are gone](https://skybootstrap.com/wp-content/uploads/2026/10/ai-shopping-agents-woocommerce-schema-compare.webp "The Product markup each setup printed for the same on-sale product on our test store.")

AIOSEO printed no Product markup of its own, and we didn’t test Rank Math with AIOSEO switched off. Two of Rank Math’s gaps are settings, which we confirmed on the test store:

- Brand: go to **Rank Math → General Settings → WooCommerce → Brand** and pick the Brands taxonomy. The brand then appeared in the markup.
- Name: the product name in the markup comes from the product’s SEO title, which by default adds your site name. Setting **Titles & Meta → Products → Single Product Title** to `%title%` gave a clean name. Check your page title afterwards, because the same setting shapes it.

We found no setting that adds the regular price back while a product is on sale. Your plugin and settings may behave differently, so check your own output:

1. Open a product page, view the source and search for `"@type":"Product"` (or paste the URL into Google’s Rich Results Test).
2. Count the Product blocks. One is right; two that disagree is worse than one, because an agent can’t tell which one is right.
3. Check that the name matches the product, the brand is there, and the price and availability match the page.
4. Check the GTIN, the barcode number (EAN, UPC or ISBN) stored in WooCommerce’s GTIN field. WooCommerce only checks its length, not its check digit, so a typo can pass straight into your markup.

## Put price and stock in your Markdown product pages

If you serve Markdown to agents, add the product facts: our Markdown product pages had the description but no price, stock, SKU or brand until we added a small add-on. Markdown tools that convert the post content, like the one we tested, only see the description on a product page. A plugin built for stores adds the facts without code, and ours does (details below). The add-on is for any other setup.

We tested the small plugin from [our Markdown serving tutorial](https://skybootstrap.com/serve-markdown-to-ai-agents/). The product’s Markdown came to 76 tokens against 33,082 for the HTML page, but it said nothing about what the product costs or whether it’s in stock. This add-on puts a list of facts at the top. Save it as `wp-content/mu-plugins/woo-markdown-facts.php` (create the mu-plugins folder with your host’s file manager if it isn’t there). It works with that plugin’s Accept-header, `.md` and `?format=md` routes and leaves the HTML page alone:

```
<?php
/**
 * Plugin Name: Woo Markdown Product Facts
 * Description: Adds price, stock, SKU, GTIN, brand and rating to the Markdown version of WooCommerce product pages.
 * Works with the Markdown plugin from our serving guide (it reads the same "wants Markdown" check). Needs WooCommerce 9.1 or later.
 */
add_filter( 'the_content', function ( $content ) {
$wants_md = ! empty( $GLOBALS['smd_force'] ) || ( function_exists( 'smd_wants_markdown' ) && smd_wants_markdown() );
if ( ! $wants_md || ! function_exists( 'wc_get_product' ) || ! is_singular( 'product' ) ) {
return $content;
}
$product = wc_get_product( get_the_ID() );
if ( ! $product ) {
return $content;
}
$currency = get_woocommerce_currency();
$money = function ( $amount ) use ( $currency ) {
return wc_format_decimal( $amount, wc_get_price_decimals() ) . ' ' . $currency;
};
// Prices as the shop shows them (with or without tax); variable products show their lowest price.
$variable = $product->is_type( 'variable' );
$price = $variable ? $product->get_variation_price( 'min', true ) : wc_get_price_to_display( $product );
$stock = array( 'instock' => 'In stock', 'outofstock' => 'Out of stock', 'onbackorder' => 'On backorder' );
$brands = wp_get_post_terms( $product->get_id(), 'product_brand', array( 'fields' => 'names' ) );
$facts = array(
'Price' => '' !== $product->get_price() ? ( $variable ? 'from ' : '' ) . $money( $price ) : '',
'Regular price' => ! $variable && $product->is_on_sale() ? $money( wc_get_price_to_display( $product, array( 'price' => $product->get_regular_price() ) ) ) : '',
'Availability' => isset( $stock[ $product->get_stock_status() ] ) ? $stock[ $product->get_stock_status() ] : '',
'SKU' => $product->get_sku(),
'GTIN' => $product->get_global_unique_id(),
'Brand' => is_wp_error( $brands ) ? '' : implode( ', ', $brands ),
'Rating' => $product->get_review_count() ? $product->get_average_rating() . ' out of 5 (' . $product->get_review_count() . ' reviews)' : '',
'Buy' => get_permalink( $product->get_id() ),
);
$list = '';
foreach ( array_filter( $facts ) as $label => $value ) {
$list .= '<li><strong>' . esc_html( $label ) . ':</strong> ' . esc_html( $value ) . '</li>';
}
return '<ul>' . $list . '</ul>' . $content;
}, 5 );
```

With it in place, the same product’s Markdown starts with its price, regular price, availability, SKU, GTIN, brand and a link to buy. It still cost only 105 to 197 tokens per product. If you use a Markdown plugin instead, open one product’s Markdown version and check it shows the price and stock before you rely on it. Our own [Skyboot AI Markdown](https://skybootstrap.com/skyboot-ai-markdown/), for example, lists price, sale and regular price, stock, SKU, GTIN and brand on product pages according to [its e-commerce documentation](https://skybootstrap.com/docs/skyboot-ai-markdown/ecommerce/), which doesn’t mention a buy link. In its llms.txt, each product line starts with price and availability, and product categories are listed with product counts. Hidden products and the cart, checkout and account pages stay out. Whatever you use, the add-on above shows the fields to look for.

## Know what the Store API already shares

WooCommerce’s Store API already gives anyone, without a login, your products’ names, prices, stock and ratings as JSON, so keep that data as accurate as the page. The Store API is the public interface WooCommerce’s own block-based cart and checkout use.

On our test store, `/wp-json/wc/store/v1/products` answered without a login. It returned each product’s name, SKU, price, stock status, brand, images, categories and rating. The admin REST API at `/wp-json/wc/v3/products` refused the same request. Three details matter if a tool reads it:

- Prices come in the currency’s smallest unit: our 119.00 USD product appeared as `11900`, with `currency_minor_unit: 2` beside it.
- There’s no GTIN field, so anything that matches products by barcode needs your structured data or a feed.
- Out-of-stock products are listed too, marked `is_in_stock: false`, so an agent reading the API sees the same stock picture as a shopper on the page.

You don’t need to do anything to the Store API. Just know that whatever you put in WooCommerce is already public in machine-readable form.

## Build a product feed for ChatGPT shopping

Export your products in OpenAI’s feed format with nine required fields, check prices, stock values and GTINs against the spec, then apply as a merchant; we built and validated one from WooCommerce. A product feed is a file listing your products in a fixed format, refreshed as prices and stock change.

[OpenAI’s feed specification](https://developers.openai.com/commerce/specs/feed) requires `item_id`, `title`, `description`, `url`, `brand`, `seller_name`, `image_url`, `availability` and `price`. Prices are written as `79.99 USD`, availability as `in_stock` or `out_of_stock` (among a few others), and an optional GTIN must have a valid check digit. Here’s where each required field comes from in WooCommerce:

| Feed field | WooCommerce source |
| --- | --- |
| `item_id` | SKU, or the product ID if there’s no SKU |
| `title`, `description`, `url`, `image_url` | Product name, long or short description, permalink, featured image |
| `brand` | The product’s brand (WooCommerce Brands); the script falls back to your store name, which is only right for products you make |
| `seller_name` | Your site title |
| `availability` | Stock status |
| `price`, `sale_price` | Regular price, plus the sale price when the product is on sale |

This script builds a JSONL feed, one product per line, from your published simple products. It skips products with no regular price, image or description, and any GTIN that fails the check digit test:

```
<?php
// Build a product feed in OpenAI's JSONL format from WooCommerce simple products.
// Run from the site folder: wp eval-file openai-feed.php > feed.jsonl
if ( ! defined( 'WP_CLI' ) ) {
exit; // Runs only through WP-CLI, never as a web page.
}
$seller = html_entity_decode( get_bloginfo( 'name' ), ENT_QUOTES, 'UTF-8' );
$currency = get_woocommerce_currency();
$money = function ( $amount ) use ( $currency ) {
return number_format( (float) $amount, 2, '.', '' ) . ' ' . $currency;
};
// Plain text on one line: keeps the space between paragraphs, drops shortcodes and HTML entities.
$plain = function ( $html ) {
$text = wp_strip_all_tags( str_replace( '<', ' <', strip_shortcodes( $html ) ) );
return trim( preg_replace( '/\s+/u', ' ', html_entity_decode( $text, ENT_QUOTES, 'UTF-8' ) ) );
};
// OpenAI rejects GTINs with a wrong check digit, so test it before adding one.
$gtin_ok = function ( $gtin ) {
if ( ! preg_match( '/^(\d{8}|\d{12}|\d{13}|\d{14})$/D', $gtin ) ) {
return false;
}
$digits = array_reverse( str_split( $gtin ) );
$sum = 0;
foreach ( array_slice( $digits, 1 ) as $i => $d ) {
$sum += (int) $d * ( 0 === $i % 2 ? 3 : 1 );
}
return ( 10 - $sum % 10 ) % 10 === (int) $digits[0];
};
$stock = array( 'instock' => 'in_stock', 'outofstock' => 'out_of_stock', 'onbackorder' => 'backorder' );
$products = wc_get_products( array( 'status' => 'publish', 'type' => 'simple', 'visibility' => 'catalog', 'limit' => -1 ) );
foreach ( $products as $product ) {
$id = $product->get_sku() ? $product->get_sku() : (string) $product->get_id();
$description = $plain( $product->get_description() ? $product->get_description() : $product->get_short_description() );
$image = wp_get_attachment_url( $product->get_image_id() );
if ( '' === $product->get_regular_price() || ! $image || '' === $description ) {
fwrite( STDERR, "Skipped {$id}: it needs a regular price, a product image and a description\n" );
continue;
}
$brands = wp_get_post_terms( $product->get_id(), 'product_brand', array( 'fields' => 'names' ) );
$item = array(
'item_id' => $id,
'title' => mb_substr( $plain( $product->get_name() ), 0, 150 ),
'description' => mb_substr( $description, 0, 5000 ),
'url' => get_permalink( $product->get_id() ),
'brand' => ! is_wp_error( $brands ) && $brands ? $brands[0] : $seller,
'seller_name' => $seller,
'image_url' => $image,
'availability' => isset( $stock[ $product->get_stock_status() ] ) ? $stock[ $product->get_stock_status() ] : 'unknown',
'price' => $money( $product->get_regular_price() ),
);
if ( $product->is_on_sale() && '' !== $product->get_sale_price() ) {
$item['sale_price'] = $money( $product->get_sale_price() );
}
$gtin = preg_replace( '/\D/', '', $product->get_global_unique_id() );
if ( $gtin && $gtin_ok( $gtin ) ) {
$item['gtin'] = $gtin;
} elseif ( $gtin ) {
fwrite( STDERR, "Skipped invalid GTIN {$gtin} for {$id}\n" );
}
echo wp_json_encode( $item, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE ) . "\n";
}
```

Run it from your site folder with `wp eval-file openai-feed.php > feed.jsonl`. On our three test products, every line passed the spec’s rules for required fields, money format, availability values, sale price below the regular price and GTIN check digits. When we gave one product a wrong check digit, the script skipped that GTIN and printed a warning. It also handled a backordered product, a GTIN typed with dashes and a product with no image correctly.

No command line on your hosting plan? Your developer or host support can run it for you. Either way, keep the script outside your public web folder.

Variable products need one line per variation, which this script doesn’t cover. Run it on a schedule (a daily server cron job running the same command works), at least daily, so price and stock in the feed don’t drift from the store. A sale that ends in the store but not in the feed is the kind of mismatch an agent will pass straight to a buyer.

The feed alone doesn’t get you listed. Merchants apply at chatgpt.com/merchants, and direct onboarding is for approved partners. Alhena’s guide reports that feeds go up by SFTP or API, with a daily full update recommended. Checkout inside ChatGPT needs a separate integration plus links to your privacy policy and terms.

## Frequently Asked Questions

### What do AI shopping agents read on a WooCommerce store?

An agent can get product data from four places: structured data in the page, the page itself, WooCommerce’s public Store API and a product feed you send. These sources can disagree, so check that price, stock and brand match across all of them before you rely on any single one to describe your products.

### Does Rank Math change WooCommerce product schema?

On our test store, Rank Math’s default settings replaced WooCommerce’s own product markup, dropped the brand and the regular price, and added the site name to the product name. Open a product page and read its JSON-LD to see what your setup outputs, then adjust the SEO plugin’s schema settings if anything is missing.

### How do I get WooCommerce products into ChatGPT shopping?

Export your products in OpenAI’s product feed format, which has nine required fields, then check prices, stock values and GTINs against the spec before applying as a merchant. We built and validated one feed from WooCommerce. Refresh the feed whenever prices or stock change, so agents never quote an old price.

## What WooCommerce itself offers agents

WooCommerce 11.2.1 registers seven abilities for products and orders and has an MCP integration switched off by default. When Nexter summarised it in July 2026, agent checkout through Stripe and the Agentic Commerce Protocol was still waitlist-only.

The abilities let an AI tool, signed in as a store user, query, create, update and delete products, and query orders, add order notes and change order status. Five of the seven change data. WooCommerce first shipped this MCP integration in version 10.3, built on the WordPress Abilities API. Who can run abilities, and how to keep agents on a short leash, is covered in [our site owner’s guide to the Abilities API](https://skybootstrap.com/wordpress-abilities-api/).

On checkout, the Agentic Commerce Protocol (ACP) is an open standard from OpenAI for product feeds, checkout and payments. ChatGPT’s Instant Checkout was “currently available to approved partners”. Stripe’s Agentic Commerce Suite for WooCommerce was announced in December 2025, and [Nexter’s summary](https://nexterwp.com/blog/agentic-commerce-woocommerce/) says it will reach WooCommerce through the official Stripe extension, with a waitlist open. Clean product data is the part you can do now, whichever route arrives first.

Your checklist:

1. Check one product page’s schema for the right name, a brand, both prices and correct stock. If you run our plugin, its Citation Readiness score checks each product for a brand plus an SKU or GTIN, at least three attributes and at least three reviews ([product checks](https://skybootstrap.com/docs/skyboot-ai-markdown/citation-readiness/)). It reads the product data, not the schema, so still check the schema.
2. Fix GTINs that fail their check digit.
3. If you serve Markdown, make sure product pages include price and stock.
4. Let OAI-SearchBot crawl your store. Our plugin’s crawler access test requests your homepage as OAI-SearchBot and ChatGPT-User and reads your robots.txt, so a site-wide firewall or Cloudflare block shows up without a terminal ([crawler access test](https://skybootstrap.com/docs/skyboot-ai-markdown/ai-visibility/)). It tests from your own server, so a CDN rule that trusts verified crawler IPs can behave differently for the real bots.
5. Generate a feed and validate it, then apply as a merchant if ChatGPT shopping matters to you.
6. Keep WooCommerce updated, and decide who may use its product and order abilities before you turn on MCP.

For the wider picture of making WordPress readable by AI, start with [our llms.txt hub for WordPress](https://skybootstrap.com/llms-txt-wordpress/), and for help docs and knowledge bases see [our guide to AI-friendly documentation](https://skybootstrap.com/ai-friendly-documentation/).