WooCommerce Checkout (real, optional)
Built without a live WooCommerce install to test against. WooCommerce and WPGraphQL for WooCommerce aren't installed in this starter kit's own dev environment, so this flow was verified by build/typecheck only, not end-to-end against a real store. Treat your first real use as a verify-carefully situation — test a full purchase in a sandbox before relying on it in production.
Replaces the previous purely-mock /shop checkout ("Proceed to Checkout"
just showed a fake success message) with a real cart-to-order flow via
WooCommerce's own Store API — not a URL-parameter hack, this is
WooCommerce's officially-supported mechanism for headless/decoupled carts.
Why redirect to WooCommerce's own checkout, not a custom UI
Building custom payment UI in Next.js means either handling card data
directly (real PCI compliance scope) or embedding one specific gateway's
client SDK (locks the starter kit to that processor). Redirecting to
WooCommerce's own hosted /checkout/ page keeps payment UI and PCI scope
entirely on the WordPress/WooCommerce side — same reasoning already applied
to the Stripe Payment Link integration.
Setup
- Install WooCommerce and WPGraphQL for WooCommerce (WooGraphQL) on WordPress.
- Set
headlesscore_nextjs_url(wp-admin → Headless Core → Settings → Connection) to your Next.js frontend's URL —inc/woocommerce.phpreads this same option to configure Store API CORS. - That's it on the config side — no new env vars on the Next.js side;
the flow uses
NEXT_PUBLIC_WORDPRESS_URL(already required) and the tenant-resolved WordPress URL passed intoShopContainer.
How it works
/shopfetches products viagetHeadlessProducts()first; if empty, falls back togetShopProducts()(real WooCommerce via WooGraphQL).ShopContainerreceives anisWooCommerceflag —trueonly when the catalog actually came from WooCommerce (has awooCommerceId, WPGraphQL'sdatabaseId— not the opaqueidfield, which the WooCommerce Store API can't use).- Cart stays entirely client-side, unchanged.
- "Proceed to Checkout", when
isWooCommerceis true:GET {wordpressUrl}/wp-json/wc/store/v1/cart(credentials: "include") establishes/reads the WooCommerce session cookie and returns aNonceresponse header.POST {wordpressUrl}/wp-json/wc/store/v1/cart/add-itemonce per cart line, with theNonceheader andcredentials: "include".window.location.href = "{wordpressUrl}/checkout/"— the customer completes payment on WooCommerce's own checkout page, whatever gateway you've configured there.
- When
isWooCommerceisfalse(catalog came from theheadless_productCPT or mock data — no real WooCommerce store behind it), the button reads "Proceed to Checkout (Demo)" and keeps the original UI-only confirmation — there's no real order to place.
CORS (required)
The Store API calls above are cross-origin and credentialed (carry
cookies) — browsers block this by default. inc/woocommerce.php adds a
rest_pre_serve_request filter scoped only to routes under
/wc/store/ (not a blanket CORS loosening across the site), setting:
Access-Control-Allow-Origin: {headlesscore_nextjs_url}
Access-Control-Allow-Credentials: true
Access-Control-Expose-Headers: Nonce
Access-Control-Expose-Headers: Nonce matters specifically — without it,
cross-origin fetch() responses hide all but a small set of "simple"
headers from JavaScript, and the frontend can't read the Nonce it needs
for the add-item call.
Guarded by function_exists('WC'), so this filter is completely inert
when WooCommerce isn't installed (the default state of this starter kit).
Testing
# Confirm the cart endpoint responds and CORS headers are present
curl -i "https://your-wp-site.com/wp-json/wc/store/v1/cart" \
-H "Origin: https://your-nextjs-site.com"
Look for Access-Control-Allow-Origin in the response matching your
Next.js URL. Then test a full add-to-cart → checkout → payment flow with
a WooCommerce test/sandbox gateway before going live.
Deferred (not in v1)
- Custom/embedded checkout UI — deliberately out of scope, see rationale above.
- Cart persistence across devices/sessions — relies entirely on WooCommerce's own session cookie (same-browser only).
- Multi-tenant-aware WooCommerce — assumes one WooCommerce store, same single-seller assumption as the Stripe integration.