# Product Archive Flow

> How the Woo product archive demo connects product loops, dynamic product data, purchase forms, cart count, and notices.

<!-- Sources: src/Testing/E2E/Woo/WooDemoStoreBuilder.php; src/Testing/E2E/Woo/WooDemoStoreAssets.php; src/Testing/E2E/Woo/WooScenarioProvider.php; src/Patterns/Testing/TestWooProductList/TestWooProductList.php; src/Patterns/Testing/TestWooProductList/TestWooProductList.css; src/Woo/ProductDynamicData.php; src/Components/Woo/AddToCartForm/AddToCartForm.php; src/Components/Woo/AddToCartButton/AddToCartButton.php; src/Components/Woo/AttributeSelector/AttributeSelector.php; src/Components/Woo/BuyNowButton/BuyNowButton.php; src/Components/Woo/CartCount/CartCount.php; src/Components/Woo/CartNotices/CartNotices.php; client/src/domains/woo/components/add-to-cart-form.ts; client/src/domains/woo/components/add-to-cart-button.ts; tests/e2e/components/woo/behavior.spec.ts -->

# Product Archive Flow

The product archive flow is the canonical product-list purchase example. `WooDemoStoreBuilder` registers an archive template from `TestWooProductList` and a product loop preset that queries seeded demo products.

## Flow Structure

```text
Archive template
  CartCount
  CartNotices
  Product loop over product posts
    Product image from item.omewoo.media
    Product title and price
    AddToCartForm
      AttributeSelector loop over item.omewoo.attributes
      AddToCartButton
      BuyNowButton
    Simple-product quick AddToCartButton
```

The archive uses `{item.*}` because each card is inside a loop item. Product-level Woo dynamic data is available as `{item.omewoo.*}`.

## Product Loop Data

The demo loop preset is a normal `WP_Query` loop for `product` posts. It is scoped to the demo product marker meta used by `WooDemoStoreProductSeeder`, then sorted by menu order and title.

Inside each product card:

| Binding | Meaning |
| --- | --- |
| `{item.id}` | Current product ID. |
| `{item.title}` | Current product title. |
| `{item.omewoo.media.image.url}` | Product image URL. |
| `{item.omewoo.media.image.alt}` | Product image alt text. |
| `{item.omewoo.price.text}` | Formatted product price text. |
| `{item.omewoo.product.type}` | Product type used by purchase controls. |
| `{item.omewoo.attributes}` | Variable-product attribute objects for selector loops. |

## Purchase Behavior

The form path is used for the full purchase area. `AddToCartForm` receives the current product ID and product type, then `AddToCartButton` uses `trigger=form_submit` so the form owns the Store API payload. `BuyNowButton` is also inside the form and redirects after the add succeeds.

The same archive pattern also includes a simple-product quick add button outside the form. That button is guarded by a condition on `item.omewoo.product.type === simple`, so it can send a standalone add request with only the current product ID and quantity.

## Variation Selectors

Variable product selectors come from a nested loop over `item.omewoo.attributes`. Each loop item is passed to `AttributeSelector` through the `target.attribute` expression. The archive pattern uses select mode and lets the runtime synchronize selected attribute values back to the parent `AddToCartForm`.

If the user submits a variable product before selecting a required variation, the form stays invalid and the cart is not changed. E2E covers that behavior separately in `variable_product_requires_variation`.

## Cart State On The Archive

`CartCount` is placed above the product loop so successful add-to-cart actions from any card update one shared count. `CartNotices` is also outside the product cards, which gives the archive one live region for errors and success messages.

This pairing matters because product cards can be repeated many times, but cart state is global for the page.

## E2E Coverage

| Scenario | Verified behavior |
| --- | --- |
| `product_archive_simple_add` | Submitting a product-card form updates the cart count. |
| `cart_count_add_to_cart` | A standalone add button updates count and button state. |
| `add_to_cart_button_inside_form` | Runtime does not accidentally bind a standalone trigger inside a form. |
| `variable_product_requires_variation` | Required variation selection blocks submit until valid. |
| `buy_now_redirect` | Buy-now adds to cart and redirects to checkout. |
| `out_of_stock_product_disabled` | Unavailable product state disables purchase controls. |
