> ## Documentation Index
> Fetch the complete documentation index at: https://docs.elasticfunnels.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Cart

> Cart items, quantity controls, and data attributes for the template engine and cart plugin.

This page covers **cart** usage: **`cartItems`**, item properties, and **data attributes** for quantity and remove. For checkout-only topics (totals, form fields, coupon, payment), see [Checkout](/frontend-template-engine/checkout).

***

## Scope: `cartItems` / `items`

**`cartItems`** (or **`items`**) is an array of line items. The cart plugin fills it; UI updates are reactive when cart scope changes.

| Item property         | Type           | Description                                                     | In template                                 |
| --------------------- | -------------- | --------------------------------------------------------------- | ------------------------------------------- |
| **`code`**            | string         | Product/cart line code                                          | Use with qty/remove data attributes         |
| **`name`**            | string         | Product name                                                    | `[[ item.name ]]`                           |
| **`image`**           | string         | Product image URL                                               | `[[ item.image ]]`                          |
| **`quantity`**        | number         | Quantity                                                        | `[[ item.quantity ]]`                       |
| **`price`**           | string         | Unit price (formatted)                                          | `[[ item.price ]]` — do not use formatPrice |
| **`total`**           | string         | Line total (formatted)                                          | `[[ item.total ]]` — do not use formatPrice |
| **`retail_price`**    | string         | Original/retail price (formatted)                               | `[[ item.retail_price ]]`                   |
| **`discount_total`**  | string         | Per-line savings (formatted)                                    | `[[ item.discount_total ]]`                 |
| **`currency`**        | string         | Currency code                                                   | `[[ item.currency ]]`                       |
| **`is_subscription`** | boolean        | `true` when this is a subscription product                      | `[[ item.is_subscription ]]`                |
| **`subscription`**    | object \| null | Subscription details (see below) — `null` for one-time products | `[[ item.subscription.frequency ]]`         |
| **`bonuses`**         | array          | Bonus products included with this item (see below)              | `template-foreach` loop                     |
| **`courses`**         | array          | Courses linked to this product (see below)                      | `template-foreach` loop                     |

<Info>
  **`price`** and **`total`** are already formatted. Use **`[[ item.price ]]`** and **`[[ item.total ]]`** as-is. See [Functions](/frontend-template-engine/built-in-functions#price-display-table) for when to use **formatPrice**.

  `bonuses`, `courses`, `is_subscription`, and `subscription` are populated after a brief async fetch from the server when the cart loads. They are always present (empty array / `false` / `null`) so templates never error.
</Info>

***

## Subscription details (`item.subscription`)

When `item.is_subscription` is `true`, `item.subscription` contains billing cadence and trial settings:

| Property                | Type    | Description                                                       |
| ----------------------- | ------- | ----------------------------------------------------------------- |
| **`frequency`**         | number  | How often the subscription bills (e.g. `3`)                       |
| **`frequency_unit`**    | string  | Unit for the frequency: `"day"`, `"week"`, `"month"`, or `"year"` |
| **`trial_days`**        | number  | Free trial length in days (`0` = no trial)                        |
| **`first_charge_free`** | boolean | `true` when the first billing cycle is free                       |

Example — showing billing cadence next to the price:

```html theme={null}
<template-foreach data-each="item in cartItems">
  <span>[[ item.name ]]</span>
  <span>[[ item.price ]]</span>
  <template-if data-condition="item.is_subscription">
    <span>Every [[ item.subscription.frequency ]] [[ item.subscription.frequency_unit ]]</span>
  </template-if>
</template-foreach>
```

The same `is_subscription` and `subscription` fields are available on `checkout` scope for single-product checkout pages (e.g. `[[ checkout.is_subscription ]]`, `[[ checkout.subscription.frequency ]]`).

***

## Bonus products (`item.bonuses`)

Each cart item may include a **`bonuses`** array — products that are included free with that item (configured in the product catalog under Bonuses). Populated automatically from the `/api/cart-products` response after the cart loads.

Each element in `item.bonuses` has:

| Property             | Description                                               |
| -------------------- | --------------------------------------------------------- |
| **`code`**           | Bonus product code                                        |
| **`name`**           | Bonus product name                                        |
| **`image`**          | Bonus product image URL                                   |
| **`price`**          | Price (formatted) — typically `$0.00` for free bonuses    |
| **`retail_price`**   | Retail value (formatted) — useful for "valued at" display |
| **`original_price`** | Same as `retail_price`                                    |
| **`currency`**       | Currency code                                             |

Example:

```html theme={null}
<template-foreach data-each="item in cartItems">
  <div class="cart-line">
    <img src="[[ item.image ]]" alt="[[ item.name ]]" />
    <span>[[ item.name ]]</span>
    <span>[[ item.price ]]</span>
    <template-foreach data-each="bonus in item.bonuses">
      <div class="cart-bonus">
        <img src="[[ bonus.image ]]" alt="[[ bonus.name ]]" />
        <span>[[ bonus.name ]]</span>
        <span>FREE (valued at [[ bonus.retail_price ]])</span>
      </div>
    </template-foreach>
  </div>
</template-foreach>
```

`item.bonuses` is always an array — empty when the product has no bonuses configured.

***

## Courses (`item.courses`)

When a product has linked courses, they are available as `item.courses`. Populated automatically from the `/api/cart-products` response after the cart loads.

Each element in `item.courses` has:

| Property              | Description                                         |
| --------------------- | --------------------------------------------------- |
| **`id`**              | Course ID                                           |
| **`title`**           | Course title                                        |
| **`slug`**            | URL slug (used to link to the course page)          |
| **`description`**     | Short description                                   |
| **`cover`**           | Cover image URL                                     |
| **`instructor_name`** | Instructor name (if set)                            |
| **`status`**          | Publication status (`"published"`, `"draft"`, etc.) |

Example — listing included courses beneath a cart line:

```html theme={null}
<template-foreach data-each="item in cartItems">
  <span>[[ item.name ]]</span>
  <template-foreach data-each="course in item.courses">
    <div class="cart-course">
      <img src="[[ course.cover ]]" alt="[[ course.title ]]" />
      <span>[[ course.title ]]</span>
    </div>
  </template-foreach>
</template-foreach>
```

`item.courses` is always an array — empty when the product has no linked courses.

***

## Quantity and remove (data attributes)

Use these so the **cart plugin** handles +/- and remove without custom script:

| Attribute                         | Element                 | Purpose                                        |
| --------------------------------- | ----------------------- | ---------------------------------------------- |
| **`data-cart-qty-minus`**         | Button                  | Decrease quantity                              |
| **`data-cart-qty-plus`**          | Button                  | Increase quantity                              |
| **`data-cart-qty-remove`**        | Button/link             | Remove line (set qty to 0)                     |
| **`data-code="[[ item.code ]]"`** | Same element or parent  | So the plugin receives the actual product code |
| **`data-disable-when-one`**       | Minus button (optional) | Disable when `item.quantity <= 1`              |

Example:

```html theme={null}
<template-foreach data-each="item in cartItems">
  <div class="cart-line">
    <img alt="[[ item.name ]]" src="[[ item.image ]]" />
    <span>[[ item.name ]]</span>
    <button type="button" data-cart-qty-minus data-code="[[ item.code ]]" data-disable-when-one aria-label="Decrease">−</button>
    <span>[[ item.quantity ]]</span>
    <button type="button" data-cart-qty-plus data-code="[[ item.code ]]" aria-label="Increase">+</button>
    <span>[[ item.total ]]</span>
    <button type="button" data-cart-qty-remove data-code="[[ item.code ]]" aria-label="Remove">Remove</button>
  </div>
</template-foreach>
```

You can wrap the Remove button in **`<template-if data-condition="cartItems.length > 1">`** so it only shows when there is more than one item (use **`&gt;`** for `>` in **`data-condition`**).

For custom behavior, use **`@click`** with **`window.ef.addToCart(code, options?, quantity?)`**, **`window.ef.setCartQuantity(code, quantity)`**, or **`window.ef.removeFromCart(code, allowClear?)`** if the app exposes **`window.ef`**.

***

## Order bumps (on checkout)

On checkout pages, bump cards use these **data attributes** so the bump-products plugin can toggle and style:

| Attribute                                                               | Where                      | Purpose                                                  |
| ----------------------------------------------------------------------- | -------------------------- | -------------------------------------------------------- |
| **`data-bump-code="[[ bump.code ]]"`**                                  | Card/container             | Plugin adds `.selected` / `.bump-selected` when selected |
| **`data-bump-checkbox="[[ bump.code ]]"`**                              | Checkbox                   | Links checkbox to bump code                              |
| **`data-bump-toggle="[[ bump.code ]]"`**                                | Label or clickable wrapper | Click toggles the checkbox                               |
| **`name="bump"`** or **`name="bump[]"`**, **`value="[[ bump.code ]]"`** | Checkbox                   | Form submit and plugin read selected codes               |

For **scope** (**`checkout.bump_products`**, **`checkout.selectedBumpLines`**) and full **offer vs added** template pattern, see [Checkout — Order bumps](/frontend-template-engine/checkout#order-bumps).

***

## Summary

* Use **`cartItems`** and **`[[ item.* ]]`**; **`item.price`** and **`item.total`** are already formatted.
* **`item.is_subscription`** / **`item.subscription`** — billing cadence; also on `checkout` scope for single-product pages.
* **`item.bonuses`** — free bonus products linked to the item; always an array.
* **`item.courses`** — courses linked to the product; always an array.
* Use **data-cart-qty-minus/plus/remove** and **data-code** for qty and remove.
* Bumps: use **data-bump-**\* attributes; scope and patterns are in [Checkout](/frontend-template-engine/checkout).
