=== WebToffee Universal Commerce Protocol Enabler for Woocommerce ===
Contributors: webtoffee
Tags: ucp, woocommerce, ai commerce, checkout, rest api
Requires at least: 6.0
Tested up to: 7.0
Requires PHP: 7.4
Stable tag: 1.0.0
WC requires at least: 7.0
WC tested up to: 10.9.1
License: GPLv2 or later
License URI: https://www.gnu.org/licenses/gpl-2.0.html

Make your WooCommerce store discoverable and purchasable by AI shopping agents through the Universal Commerce Protocol (UCP).

== Description ==

**WebToffee Universal Commerce Protocol Enabler for Woocommerce** integrates your store with the [Universal Commerce Protocol](https://ucp.dev) — the open standard that lets AI assistants (Google AI Mode, Gemini, ChatGPT, and others) discover, browse, and purchase from your store without custom builds for each platform.

Once activated, two things happen automatically:

1. **A discovery profile is published at `/.well-known/ucp`** — the standard entry point that AI platforms fetch to learn what your store supports.
2. **REST endpoints go live at `/wp-json/wt-ucp/v1/`** — implementing the five standard UCP capabilities.

= Capabilities =

**Checkout** (`dev.ucp.shopping.checkout`)
Create, update, and complete checkout sessions. An AI agent calls `POST /checkout-sessions` with a list of items and buyer details, updates it with shipping info via `PUT`, then finalises payment via `POST .../complete`. Sessions map directly to WooCommerce pending orders.

**Cart** (`dev.ucp.shopping.cart`)
Session-based basket building before a purchase is ready to commit. The agent creates a cart with `POST /carts`, then optionally hands it off to the human buyer via a `continue_url` that loads items into the WooCommerce frontend cart and redirects to the cart page.

**Order** (`dev.ucp.shopping.order`)
Lets agents check the status of any order using `GET /orders/{id}`, covering the full WooCommerce order lifecycle from pending to fulfilled.

**Catalog** (`dev.ucp.shopping.catalog`)
Product search via `GET /catalog/search` and individual item lookup via `GET /catalog/items/{id}`. Returns prices in minor currency units as required by the spec.

**Discount** (`dev.ucp.shopping.discount`)
Extends the Cart and/or Checkout capabilities with coupon code support. An agent submits `discounts.codes` inside any Cart or Checkout create/update request. The plugin validates each code against WooCommerce coupons, applies the discount, and returns the structured `discounts.applied` array alongside updated line-item and order-level totals. Coupons applied automatically by WooCommerce hooks are surfaced as `automatic: true` entries. Supports `percent`, `fixed_cart`, and `fixed_product` WooCommerce coupon types. Rejected codes are returned as typed `messages` entries (e.g. `discount_code_expired`, `discount_code_combination_disallowed`).

= Discount Behaviour =

* **Replacement semantics** — each Cart or Checkout PUT replaces the full set of applied codes. Send an empty `discounts.codes` array to clear all discounts.
* **Cart sessions** — discounts are computed entirely in PHP against `WC_Coupon` without requiring a live WooCommerce cart session. Per-line `items_discount` totals are injected into `line_items[].totals` and the cart-level `totals` array.
* **Checkout sessions** — discounts are applied directly to the WooCommerce order via `$order->apply_coupon()`. `$order->calculate_totals()` is called automatically; the response reflects WooCommerce's authoritative totals.
* **Total types** — line-item-level discounts appear as `items_discount` entries; order-level discounts appear as `discount` entries, matching the UCP spec distinction.
* **Automatic coupons** — coupons applied by a WooCommerce hook (not in the submitted codes) are returned in `discounts.applied` with `"automatic": true` and no `code` field.

= REST Endpoints =

| Method | Path | Capability |
|--------|------|------------|
| GET    | `/wp-json/wt-ucp/v1/catalog/search`                        | Catalog  |
| GET    | `/wp-json/wt-ucp/v1/catalog/items/{id}`                    | Catalog  |
| POST   | `/wp-json/wt-ucp/v1/carts`                                 | Cart     |
| GET    | `/wp-json/wt-ucp/v1/carts/{id}`                            | Cart     |
| PUT    | `/wp-json/wt-ucp/v1/carts/{id}`                            | Cart     |
| POST   | `/wp-json/wt-ucp/v1/checkout-sessions`                     | Checkout |
| GET    | `/wp-json/wt-ucp/v1/checkout-sessions/{id}`                | Checkout |
| PUT    | `/wp-json/wt-ucp/v1/checkout-sessions/{id}`                | Checkout |
| POST   | `/wp-json/wt-ucp/v1/checkout-sessions/{id}/complete`       | Checkout |
| POST   | `/wp-json/wt-ucp/v1/checkout-sessions/{id}/cancel`         | Checkout |
| GET    | `/wp-json/wt-ucp/v1/orders/{id}`                           | Order    |

Discount codes are submitted as `discounts.codes` inside the Cart and Checkout create/update request bodies — no separate endpoint is needed.

= Settings =

Go to **WooCommerce → UCP Enabler** to configure:

* **General** — UCP protocol version, API base endpoint (for proxied setups), profile cache TTL.
* **Capabilities** — Toggle individual capabilities on or off using the switch controls. The Discount toggle is only effective when Cart or Checkout (or both) are also enabled.
* **Payment Handler** — Configure a PSP tokenizer: token retrieval URL, public key, and accepted card brands.

= Payment Processing =

The plugin handles the UCP protocol layer and stores the payment token in WooCommerce order meta (`_ucp_payment_token`). The actual charge against your PSP is delegated via a WordPress filter, giving you full control:

`php
add_filter( 'wbte_ucp_enabler_process_payment', function( $result, $order, $instrument, $credential ) {
    // $credential['token'] is the PSP token sent by the agent.
    // Call your payment gateway SDK here.
    // On success: return null (or call $order->payment_complete($tx_id) first).
    // On failure: return a WP_Error.
    return null;
}, 10, 4 );
`

= Cart Handoff =

When an agent builds a cart for a human buyer to finish, the `continue_url` in the cart response is a one-time link that loads all items into the WooCommerce session and redirects to the WooCommerce cart page. The token is consumed on first use. Any discounts applied to the cart are preserved in the transient and will be visible in the response on subsequent GETs.

= Item ID Convention =

UCP uses a single string `item.id` to identify products. The plugin maps:
* `"123"` → WooCommerce product ID 123
* `"123-456"` → WooCommerce product 123, variation 456

The catalog endpoint returns variation IDs in `"{product_id}-{variation_id}"` format so agents can reference them directly. Override with the `wbte_ucp_enabler_resolve_item_id` filter for custom slug-based IDs.

= Extend the Profile =

`php
add_filter( 'wbte_ucp_enabler_profile', function( $profile, $settings ) {
    // Add signing_keys, custom extensions, etc.
    return $profile;
}, 10, 2 );
`

== External services ==

This plugin does not send any data to WebToffee or to any third party by itself. However, its entire purpose is to let external AI shopping agents (Google AI Mode, Gemini, ChatGPT, and others that implement the Universal Commerce Protocol) call your own store's REST API to browse your catalog and place orders — this section documents that data flow.

**Universal Commerce Protocol (ucp.dev) schema references.** The `/.well-known/ucp` profile and the plugin's REST responses embed several fixed URLs like `https://ucp.dev/{version}/schemas/shopping/checkout.json` and `https://ucp.dev/{version}/specification/overview`. These are static links to the public UCP specification/schema documentation, included so that any AI agent reading your profile knows which version of the protocol and JSON schema your store implements. Your server does not call these URLs at runtime and no store or customer data is ever sent to ucp.dev; the links are descriptive metadata only, and only the requesting agent (not this plugin) may choose to resolve them. ucp.dev is an open specification site (not a paid service) published under the Apache License 2.0.
Service: Universal Commerce Protocol specification (ucp.dev), an open standard maintained by the UCP Authors (Google, Shopify, and other industry partners) on GitHub.
Specification & source: https://github.com/Universal-Commerce-Protocol/ucp
License: https://github.com/Universal-Commerce-Protocol/ucp/blob/main/LICENSE

**Inbound requests from AI shopping agents.** Once activated, this plugin exposes REST endpoints (catalog, cart, checkout, order) under `/wp-json/wt-ucp/v1/`. Any AI platform or agent that supports UCP can call these endpoints directly to search your catalog, build a cart, and complete checkout — this is the plugin's core function, not an optional integration. Catalog search/lookup is open to any caller. Checkout-session and order operations beyond creation require the caller to present the session token issued at checkout creation (delivered via an `X-UCP-Session-Token` response header, and presented back as a standard `Authorization: Bearer <token>` header, per the UCP REST binding's own guidance on authenticating individual operations) — so an agent can only read or modify a session it created itself. No background or scheduled data transmission occurs; every exchange is a direct response to a request initiated by the agent. Which AI platforms can reach your store depends entirely on which agents or vendors you choose to make your `/.well-known/ucp` profile known to; this plugin does not register your store with, or transmit data to, any specific AI vendor on its own.

**Optional payment handler / tokenizer.** If you configure a Payment Handler under Settings, card/payment data is tokenized by the handler you choose to configure. Consult that provider's own terms of service and privacy policy, as it is not bundled with or endorsed by this plugin.

== Installation ==

1. Upload the `wt-ucp-enabler-for-woocommerce` folder to `/wp-content/plugins/`.
2. Activate through the **Plugins** screen in WordPress admin.
3. Go to **WooCommerce → UCP Enabler** to review settings.
4. Optionally enter your PSP tokenizer credentials under **Payment Handler**.
5. Verify your profile is live at `https://yourstore.com/.well-known/ucp`.

== Frequently Asked Questions ==

= Does this work with WooCommerce HPOS? =

Yes. The plugin declares full compatibility with WooCommerce High-Performance Order Storage (custom order tables).

= Which UCP spec version is implemented? =

Version `2026-04-08`. The version can be reviewed (and changed if needed) under **WooCommerce → UCP Enabler → General**.

= Can I disable individual capabilities? =

Yes. Go to **WooCommerce → UCP Enabler → Capabilities** and toggle each one independently. Disabled capabilities are removed from the profile and return 404 on their endpoints. The Discount capability also silently no-ops if both Cart and Checkout are disabled.

= Which WooCommerce coupon types are supported for discounts? =

`percent`, `fixed_cart`, and `fixed_product`. Other coupon types introduced by WooCommerce extensions are skipped gracefully — the code is returned as rejected with an appropriate message rather than throwing an error.

= The AI agent needs to charge a card — how does that work? =

Configure your PSP tokenizer under the **Payment Handler** tab. The agent acquires a payment token directly from your PSP, then submits it to `POST /checkout-sessions/{id}/complete`. Hook into `wbte_ucp_enabler_process_payment` to charge the token through your payment gateway.

= My store is behind a reverse proxy / CDN — what do I need to change? =

Update the **API Base Endpoint** field under **General** to the public-facing URL your proxy exposes. The profile will advertise that URL to agents while WordPress continues to serve the routes internally.

= How do agents authenticate to read or change a checkout session or order? =

`POST /checkout-sessions` and catalog search are open to any caller, matching the UCP spec's own guidance that businesses "MAY require authentication for some operations while leaving others open." Every other operation on a checkout session (`GET`, `PUT`, `.../complete`, `.../cancel`) and `GET /orders/{id}` requires the session token issued at creation time: it is returned in the `X-UCP-Session-Token` response header of the `POST /checkout-sessions` call, and must be sent back as a standard `Authorization: Bearer <token>` header — the mechanism the UCP HTTP/REST binding itself recommends — on every subsequent request for that session. This prevents one caller from reading or modifying another caller's checkout or order by guessing its id. Logged-in users with the `manage_woocommerce` capability (shop managers/admins) can always access these endpoints without a token.

== Screenshots ==

1. **WooCommerce → UCP Enabler — General** — protocol version, endpoint, and cache settings.
2. **Capabilities tab** — toggle each UCP capability on or off with a switch, including the new Discount capability.
3. **Payment Handler tab** — configure PSP tokenizer credentials and accepted card brands.
4. **/.well-known/ucp** — the live discovery profile served by the plugin, now including `dev.ucp.shopping.discount`.

== Changelog ==

= 1.0.0 =
* Initial release.
* Checkout capability: `POST /checkout-sessions`, `GET`, `PUT`, `POST .../complete`, `POST .../cancel`. Non-creation operations on a checkout session, and `GET /orders/{id}`, require the session token issued at creation, presented as a standard `Authorization: Bearer <token>` header per the UCP HTTP/REST binding's own guidance.
* Cart capability: session-based `POST /carts`, `GET /carts/{id}`, `PUT /carts/{id}` with `continue_url` handoff; cart id is a 128-bit CSPRNG value.
* Order capability: `GET /orders/{id}`.
* Catalog capability: `GET /catalog/search`, `GET /catalog/items/{id}`.
* Discount capability (`dev.ucp.shopping.discount`) extending Cart and/or Checkout: coupon validation and application, per-line `items_discount` totals, `items_discount` vs `discount` order-level total types, automatic coupon detection, typed rejection messages, replacement semantics on every PUT.
* Discovery profile at `/.well-known/ucp` with `Cache-Control` headers per UCP spec.
* PSP tokenizer payment handler support with `wbte_ucp_enabler_process_payment` filter.
* Toggle switch UI for capability settings; pill-button UI for card brand selection.
* WooCommerce HPOS (custom order tables) compatibility declared.
* WooCommerce → UCP Enabler submenu page with General / Capabilities / Payment Handler tabs.
* Settings link added to the Plugins list table.