# Data Context and Dynamic Sources

> Choose the right Woo data prefix for product loops, single product templates, cart rows, selectors, and checkout fields.

# Data Context and Dynamic Sources

Most Woo authoring issues come from using the right component in the wrong data context. Start with the prefix, then choose the component.

## Product Data: `item` vs `this`

Product data is exposed under `omewoo` when the current post is a Woo product.

| Where you are | Use this prefix | Example |
| --- | --- |
| Product archive or product loop | `{item.*}` | `{item.id}`, `{item.title}`, `{item.omewoo.price.text}` |
| Single product template | `{this.*}` | `{this.id}`, `{this.title}`, `{this.omewoo.price.text}` |

Use the same field names in both contexts. Only the prefix changes.

`ProductProvider` is the one component that receives the complete object directly: use `{item.omewoo}` inside a product loop and `{this.omewoo}` on a single product template. Do not rebuild a partial object for it.

<CodeExample title="Product archive card uses item" language="text">
{`{#loop products as item}
  Product title: {item.title}
  Product price: {item.omewoo.price.text}
  <OmeWooAddToCartForm product='{{"product_id":"{item.id}","product_type":"{item.omewoo.product.type}"}}'>
    {#slot default}
      <OmeWooAddToCartButton behavior='{{"mode":"counter","trigger":"form_submit"}}' />
    {/slot}
  </OmeWooAddToCartForm>
{/loop}`}
</CodeExample>

<CodeExample title="Single product template uses this" language="text">
{`Product title: {this.title}
Product price: {this.omewoo.price.text}
<OmeWooAddToCartForm product='{{"product_id":"{this.id}","product_type":"{this.omewoo.product.type}"}}'>
  {#slot default}
    <OmeWooAddToCartButton behavior='{{"mode":"counter","trigger":"form_submit"}}' />
  {/slot}
</OmeWooAddToCartForm>`}
</CodeExample>

## Common Product Fields

| Expression | Use |
| --- | --- |
| `{item.id}` or `{this.id}` | Product ID for `AddToCartForm.product.product_id`. |
| `{item.omewoo.product.type}` or `{this.omewoo.product.type}` | Product type for `AddToCartForm.product.product_type`. |
| `{item.omewoo.price.text}` or `{this.omewoo.price.text}` | Formatted price text. |
| `{item.omewoo.media.image.url}` or `{this.omewoo.media.image.url}` | Main product image URL. |
| `{item.omewoo.media.image.alt}` or `{this.omewoo.media.image.alt}` | Main product image alt text. |
| `{item.omewoo.media.gallery}` or `{this.omewoo.media.gallery}` | Ordered base media collection for `ProductMedia.media`. |
| `{item.omewoo.media.variationGalleries}` or `{this.omewoo.media.variationGalleries}` | Selector-aware variation galleries consumed through the nearest `ProductProvider`. |
| `{item.omewoo.attributes}` or `{this.omewoo.attributes}` | Variable-product attributes for `AttributeSelector`. |
| `{item.omewoo.variants}` or `{this.omewoo.variants}` | Variation catalogue for `AddToCartForm` variation resolution. |

Keep gallery-aware UI and purchase UI on separate data paths. Bind `omewoo.media.image.id` to a hero `ProductImage`, `omewoo.media.gallery` to `ProductMedia`, and pass the complete `omewoo` object to the nearest `ProductProvider` so it can resolve `media.variationGalleries`. Continue using `omewoo.variants` only for `AddToCartForm` variation resolution.

See [Woo Dynamic Data Tree](/woo/woo-dynamic-data-tree) for the full field-by-field reference.

## Product Provider Scope

`OmeWooProductProvider` stores the base product and derived variable-product selection state for its nearest descendants. It is a real structural DOM container and supports only simple and variable products. Use `structure.tag` to choose the root tag and `styling.class` to control its layout and presentation.

```etch
<OmeWooProductProvider product="{this.omewoo}">
  {#slot default}
    <OmeWooAddToCartForm>...</OmeWooAddToCartForm>
  {/slot}
</OmeWooProductProvider>
```

In a product loop, replace `this` with `item` and render one Provider per loop item. A nested Provider is an isolation boundary; descendants never read selection state from an outer Provider. The Provider exposes derived read-only state, while `AttributeSelector`, `VariationResetButton`, quantity, and cart mutation controls remain scoped to `AddToCartForm`.

`ProductImage` and `ProductMedia` also use the nearest Provider. Product Media selection changes the Provider's active image only; it does not change the current variation or submit anything. Both atoms preserve their authored server-rendered output when used without a valid Provider, with a development-only warning explaining how to enable synchronization.

Standalone `AddToCartForm` remains valid. It uses the same variation-selection controller internally and keeps its released DOM and submit contracts.

## Variation Post Context

When the queried post is Woo's native `product_variation`, `omewoo` describes that variation. Its `media.gallery` describes the current variation, while `media.variationGalleries`, `attributes`, and `variants` stay empty because selector maps belong to the parent variable product. Variation templates should use `parentProduct` for parent identity and `selectedAttributes` for displayable selected values.

| Expression | Use |
| --- | --- |
| `{this.omewoo.parentProduct}` | Parent product identity when the current post is a Woo variation. |
| `{this.omewoo.selectedAttributes}` | Displayable selected variation attributes. |
| `{this.omewoo.selectedAttributesMap}` | Normalized selected variation values keyed by Store API attribute key. |

## Cart Dynamic Sources

`CartItemsDynamicSource` registers four source keys when the block tree contains cart-aware components or expressions:

| Source | Shape |
| --- | --- |
| `cartItems` | Cart item rows with `key`, compatibility `productId`, additive exact `purchasableId`, title fields, attributes, quantity, additive `quantityLimits`, URL, price text, subtotal text, and image data. |
| `cartSummary` | `item_count`, `line_count`, and `state` where state is `has-items` or `empty`. |
| `cartTotals` | Released flat total fields plus the additive `cartAmount` lane for tax-aware shopper measures, nullable shipping state, and currency metadata. |
| `cartCoupons` | Applied coupon rows with `code`. |

The source registration is lazy. A page that does not render cart components does not register cart sources for that request.

For new total readouts, use `OmeWooCartAmount`. Its server-rendered source at `cartTotals.cartAmount` mirrors Store API minor-unit totals: split `total_items`/`total_items_tax`, `total_discount`/`total_discount_tax`, `total_fees`/`total_fees_tax`, nullable `total_shipping`/`total_shipping_tax`, direct `total_tax`, direct `total_price`, shipping calculation flags, normalized tax display, and currency metadata. The component keeps this server-rendered output until the Cart Store confirms hydration.

The existing flat `cartTotals` fields remain unchanged for the five released fixed total atoms. Those compatibility fields can expose a positive discount and missing-value-to-zero behavior, so they are not silently migrated into the shopper-tax-aware lane. See [Cart Totals](/woo/component-families/cart-totals) for the component choice and exact state rules.

## Cart Item Hydration

`CartItems` renders one authored row template. Server render and runtime both hydrate the row's atoms:

| Atom marker | Data field |
| --- | --- |
| `data-ome-woo-cart-item-field="image"` | Product image URL, srcset, and alt text with authored fallback. |
| `data-ome-woo-cart-item-field="title"` | Product title or composed variant title. |
| `data-ome-woo-cart-item-field="priceText"` | Unit price text. |
| `data-ome-woo-cart-item-field="subtotalText"` | Line subtotal text. |
| `data-ome-woo-cart-item-quantity` | Canonical quantity input value, exact cart item key, and Woo quantity limits. |
| `data-ome-woo-cart-item-quantity-stepper` | Opt-in decrease/value/increase presentation backed by the canonical exact-line input. |
| `data-ome-woo-cart-item-remove` | Remove button cart item key. |
| `data-ome-woo-cart-attribute-list` | Selected variation attributes cloned from the attribute template. |

This is why cart item atoms are meaningful only inside a cart item row or an order summary row.

`productId` keeps its released compatibility semantics unchanged. `purchasableId` is the explicit exact identity used for product-level cart matching: the variation ID for a variation line, otherwise the simple product ID. Existing consumers do not need to migrate, and standard lines may expose the same value in both fields. `ProductCartQuantity` uses the additive field conservatively and disables mutation when more than one line matches; it does not infer plugin-defined bundle, composite, add-on, or custom line identity.

## Selector Sources

`WooSelectorDynamicSource` registers selector rows while blocks render:

| Source | Used by |
| --- | --- |
| `shippingRates` | `ShippingMethodSelector` rows. |
| `paymentMethods` | `PaymentMethodSelector` rows and runtime config. |

Shipping rates use package-aware values. The row value is `{package_id}:{rate_id}`, while the hidden input keeps the raw Woo rate ID and package-specific input name. This lets Woo distinguish rates across packages.

Payment methods only include enabled simple gateways. Gateways with custom fields are skipped by `get_simple_payment_methods()`, because this selector renders simple radio/select choices rather than gateway-specific embedded forms.

## Checkout Field Schema

`CheckoutFieldSchema::build()` reads Woo countries, checkout fields, locale overrides, states, and store defaults. The runtime uses that schema to:

- Render country options.
- Switch state between select, text, and hidden modes.
- Apply Woo labels, required flags, hidden flags, field types, autocomplete, and priorities.
- Validate rendered fields before Store API submit.

Address forms still expose copy props, but `use_woo_defaults: true` keeps Woo's field copy as the default source.

## Dynamic Data Examples

Variable selector loop on a single product:

```etch
{#loop this.omewoo.attributes as attribute}
  <OmeWooAttributeSelector target='{{"attribute":{attribute}}}' />
{/loop}
```
The same selector loop inside a product archive card uses `item`:

```etch
{#loop item.omewoo.attributes as attribute}
  <OmeWooAttributeSelector target='{{"attribute":{attribute}}}' />
{/loop}
```
