How Woo Components Work
Woo components have two cooperating layers:
- PHP component markup renders the authored Etch block tree, data attributes, slots, preview branches, and server-known dynamic data.
- The Woo runtime binds those data attributes, reads Store API state, mutates Woo through Store API endpoints, and updates the same live DOM.
Boot Flow
Woo::maybe_boot() registers the Woo service when WooCommerce is available. The service is triggered by any Woo component key listed in Woo.php, and it localizes:
| Localized key | Runtime use |
|---|---|
storeApiBase | Base URL for /wc/store/v1 requests. |
nonce | Store API nonce header. |
checkoutUrl | Fallback redirect target for BuyNowButton. |
isAvailable and diagnostics | Runtime availability state. |
paymentMethods | Simple enabled payment methods for PaymentMethodSelector. |
checkoutFields | Woo checkout field rules, countries, states, locale overrides, and defaults. |
The browser service creates one WooCartStore and one WooCheckoutStore. Cart components subscribe to the cart store. Checkout components subscribe to the checkout store only when checkout UI is present.
SSR and Runtime Updates
The Woo line follows this rule:
| Surface | First visible state |
|---|---|
| Product providers and purchase forms | Authored server markup with product props and optional variation data. Product Provider begins at base-product state. |
| Cart items and totals | Server dynamic sources when the block tree references cart data, then runtime refresh. |
| Shipping and payment selectors | Server rows when dynamic sources are available, then runtime normalization and selection binding. |
| Checkout fields | Server-authored fields, then runtime applies Woo field schema and country/state logic. |
| Notices | Runtime feedback regions. |
Server markup is not thrown away. The runtime updates text, input values, row state, and cloned rows in place. Templates remain inert blueprints for rows that need to be cloned after a Store API response.
Store API Requests
The cart store sends every mutation through one FIFO coordinator, then refreshes subscribers from the confirmed Store API response:
| Action | Store API endpoint |
|---|---|
| Add item | POST /cart/add-item |
| Update quantity | POST /cart/update-item |
| Remove item | POST /cart/remove-item |
| Apply coupon | POST /cart/apply-coupon |
| Remove coupon | DELETE /cart/coupons?code=... |
| Select shipping | POST /cart/select-shipping-rate |
Shared cart state is never an optimistic draft. It is always the latest cart confirmed by Woo. A quantity input may temporarily show the shopper's local draft while a request is debouncing or queued, but cart rows, counts, totals, coupons, and shipping state continue to read the last confirmed response.
Quantity changes use absolute targets. A short internal 250 ms trailing debounce replaces an unstarted target for the same cart-line key, and at most one newer same-line target waits while a request is in flight. After every response, the coordinator commits that response first, then checks whether the newer target is already satisfied before sending another request. Removing an exact line cancels its unstarted quantity target. The debounce is an internal runtime guarantee; it is not a component prop or public configuration setting.
Operations for different lines and actions keep deterministic FIFO order. Per-line debounce completes before quantity work enters that lane, so a ready unrelated action does not wait behind a draft timer. A rejected operation does not poison the lane, so the next valid cart action can continue. An authoritative conflict cancels the remaining quantity intent for that exact line instead of retrying it automatically.
Mutation feedback hooks
Owned controls expose the detailed local phase in data-ome-woo-mutation-phase:
| Phase | Meaning |
|---|---|
idle | The control has no active local intent. |
debouncing | A quantity draft is waiting for the internal trailing window. |
queued | The intent is waiting behind earlier cart work. |
pending | Its Store API request is in flight. |
success | The final meaningful target was confirmed. This state returns to idle after brief feedback. |
error | The final meaningful intent failed; Cart Notices contains the actionable message. |
aria-busy is true for debouncing, queued, and pending. Released data-ome-state hooks remain compatible: those three phases map to loading, while success, error, and idle keep their existing values. Use semantic Woo events for integrations; use these data hooks only for local styling.
The checkout store also serializes requests:
| Action | Store API endpoint |
|---|---|
| Load checkout | GET /checkout |
| Persist fields | PUT /checkout?__experimental_calc_totals=true |
| Place order | POST /checkout |
Component Binding Order
WooRuntime.boot() binds Product Providers before their forms and selectors, then settles each Provider after initial selector synchronization. Initialization therefore publishes only the final semantic selection state. The runtime also binds display components, action components, checkout components, and selectors. This order matters because some render callbacks re-bind child actions:
| Parent render | Follow-up binding |
|---|---|
CartItems row render | Binds item quantity inputs and remove buttons in the rendered rows. |
CouponAppliedList row render | Binds coupon remove buttons in the rendered rows. |
OrderSummary render | Binds read-only summary rows and any row-level actions that are present. |
Composition Rules
| Component | Needs |
|---|---|
ProductProvider | A complete {this.omewoo} or {item.omewoo} product object. It renders a structural container with structure.tag and styling.class, provides derived state, and does not own purchase setters. |
AddToCartButton with trigger: standalone | A direct product_id prop or a scoped product quantity input. It is ignored when placed inside AddToCartForm; the form owns submission there. |
AddToCartButton with trigger: form_submit | A parent AddToCartForm; it renders as the form submit control. |
BuyNowButton | A parent AddToCartForm; it serializes the form then redirects. |
AttributeSelector | A parent purchase form and a bound props.target.attribute object. |
| Cart item atoms | A CartItems row or OrderSummary product row. |
CouponRemoveButton | A CouponAppliedList row with a coupon code. |
PlaceOrderButton | A parent checkout form scope. |
Events
The runtime dispatches bubbling Woo custom events for Provider variation selection, cart boot, add-to-cart, cart item mutations, checkout boot, and checkout submit lifecycle. Read Woo Custom Events for the supported event names, dispatch targets, and detail payload shapes.