Skip to main content

Woo Recipes

These recipes use scenario and demo-store structures that exist in the repo.

Product Archive Card

Backed by product_archive_simple_add and TestWooProductList.

Use a product loop and bind each card with {item.*}:

Product archive purchase card
{#loop products as item}
<article class="product-card">
<OmeWooAddToCartForm product='{{"product_id":"{item.id}","product_type":"{item.omewoo.product.type}"}}'>
{#slot default}
<OmeWooAddToCartButton behavior='{{"mode":"counter","trigger":"form_submit"}}' />
{/slot}
</OmeWooAddToCartForm>
</article>
{/loop}

Why it works: the form owns product ID/type and form submission; the button is a submit control inside the form. The E2E archive scenario submits the form and verifies CartCount updates.

Single Product Quantity

Backed by product_single_simple_add.

Use {this.*} on a single product template and set button quantity bounds:

Single product form with quantity bounds
<OmeWooAddToCartForm product='{{"product_id":"{this.id}","product_type":"{this.omewoo.product.type}"}}'>
{#slot default}
<OmeWooAddToCartButton
behavior='{{"mode":"counter","trigger":"form_submit"}}'
quantity='{{"min":"1","max":"3","default":"2"}}'
/>
{/slot}
</OmeWooAddToCartForm>

E2E fills 9, dispatches change, and verifies the input clamps to 3 before the cart count updates.

Variable Product Selector

Backed by variable_product_requires_variation, variation_selector_button_radio, and the demo single-product template.

Loop over product attributes and bind each AttributeSelector to the current attribute object:

Variation attribute selectors inside a purchase form
<OmeWooAddToCartForm product='{{"product_id":"{this.id}","product_type":"{this.omewoo.product.type}"}}'>
{#slot default}
{#loop this.omewoo.attributes as attribute}
<OmeWooAttributeSelector
target='{{"attribute":{attribute}}}'
ui='{{"mode":"radio","aria_label":"Choose {attribute.label}"}}'
/>
{/loop}
<OmeWooAddToCartButton behavior='{{"mode":"counter","trigger":"form_submit"}}' />
{/slot}
</OmeWooAddToCartForm>

Why it works: the selector writes selected variation attribute state into the purchase form. The form blocks submit until a required variation option is selected, and unavailable options do not select.

Cart Rows and Empty State

Backed by cart_items_component_preview_contract, cart_page_update_and_remove, and cart_totals_and_empty_slot.

Place cart item atoms inside the CartItems default slot and empty content inside the empty slot:

Cart item rows with empty fallback
<OmeWooCartItems>
{#slot default}
<OmeWooCartItemImage />
<OmeWooCartItemTitle />
<OmeWooCartItemQuantity />
<OmeWooCartItemRemove />
{/slot}
{#slot empty}
<p>Your cart is empty.</p>
{/slot}
</OmeWooCartItems>

E2E verifies row count, server-hydrated atom text, quantity updates, removal, totals refresh, and final empty state.

Coupons

Backed by cart_coupons.

Use CouponForm to apply codes, CouponAppliedList to render current coupons, and CouponRemoveButton inside the coupon row:

Coupon apply and remove
<OmeWooCouponForm />

<OmeWooCouponAppliedList>
{#slot default}
<OmeWooCouponRemoveButton />
{/slot}
</OmeWooCouponAppliedList>

E2E applies SAVE10, verifies discount totals and coupon rows, then removes the coupon and verifies totals return.

Shipping Methods

Backed by shipping_selector, shipping_selector_button_radio, shipping_selector_select, and shipping_selector_select_content_props.

Use ShippingMethodSelector wherever cart shipping selection should be available:

Shipping method selector in button-radio mode
<OmeWooShippingMethodSelector
ui='{{"mode":"button-radio","aria_label":"Choose a shipping method"}}'
content='{{"show_price":true,"price_separator":" - "}}'
/>

The selector uses package-aware rate values. E2E verifies button-radio and select modes, hiding when no shipping is needed, and total/order summary refresh after selecting free shipping.

Checkout Success

Backed by checkout_success and TestCheckoutDemo.

Use a provider, a form, address forms, selectors, terms, notices, and place order:

Checkout provider and form shell
<OmeWooCheckoutProvider>
{#slot default}
<OmeWooCheckoutForm>
{#slot default}
<OmeWooBillingAddressForm />
<OmeWooShippingAddressForm />
<OmeWooPaymentMethodSelector />
<OmeWooTermsCheckbox />
<OmeWooCheckoutNotices />
<OmeWooPlaceOrderButton />
{/slot}
</OmeWooCheckoutForm>
{/slot}
</OmeWooCheckoutProvider>

E2E fills the required billing fields, selects a payment method, clicks place order, and waits for an order-received or order-pay URL.

Native Hook Compatibility

Backed by lifecycle_add_to_cart, shipping_selector in pricing mode, and lifecycle_checkout.

Use the same components as normal. The important point is that Store API requests still run Woo hooks:

  • Add-to-cart validation can block the Etch form and render a Woo notice.
  • Add-to-cart hooks can inject cart item data.
  • Pricing hooks can change totals rendered by cart and order summary components.
  • Checkout hooks can update Store API orders and payment context.