CartThrob 9 documentation for ExpressionEngine commerce teams Visit CartThrob.com
CartThrob.com

Update Cart Form (tag pair)

update_cart_form updates existing cart rows, removes rows, and can save customer/session cart data (customer fields, shipping option, and custom data) in the same submission.

A video tutorial on this tag is available..

See also:

Row ID Indexing

Update fields for cart items must be keyed by the cart row ID.

Use {row_id} from cart_items_info:

<input type="text" name="quantity[{row_id}]" value="{quantity}">
<input type="checkbox" name="delete[{row_id}]">
<input type="text" name="item_options[{row_id}][notes]" value="{item_options:notes}">

For package sub-items, use a parent_row_id:sub_row_id index for updatable sub-item fields:

<input type="text" name="quantity[{row_id}:{sub:row_id}]" value="{sub:quantity}">
<input type="text" name="item_options[{row_id}:{sub:row_id}][size]" value="{sub:item_options:size}">

Parameters

Tag-level form data for update_cart_form includes return and secure_return.

Additional form behavior (validation, inline errors, required/rules, action overrides, etc.) comes from Global Form Parameters.

Commonly used with update_cart_form:

  • return
  • secure_return
  • error_handling
  • show_errors
  • required
  • rules:*
  • action
  • secure_action
  • id
  • class
  • name
  • onsubmit
  • logged_out_redirect

What this form may change

Posted item fields that apply by default:

  • quantity[{row_id}]
  • delete[{row_id}]
  • item_options[{row_id}][…]

Posted cart / session fields that apply by default (no extra parameter):

  • coupon_code
  • shipping_option
  • shipping[key] (saved shipping info, not an item amount)
  • customer fields
  • custom_data[key]
  • clear_cart

Posted item fields that apply only if you opt in (rare):

Leave those three parameters off on a normal cart. Quantity, options, and remove are enough. A price, shipping amount, or weight stored at add-to-cart is kept; omitting the parameters does not clear it. A posted price[{row_id}] without allow_user_price="yes" is ignored.

Turn them on only when this cart page is supposed to change those amounts. The usual case is a donation already in the cart: the donor should be able to change the amount. Most stores never need that.

Posted item fields that never apply here, even if present:

  • no_tax / tax_exempt
  • no_shipping / shipping_exempt

Those stay on the item from add_to_cart_form or the product entry.

allow_user_price

Rare. Allows posted price[{row_id}] to update that cart item’s price. Same idea as add_to_cart_form allow_user_price: it changes the stored item price. It is not checkout_form allow_user_price, which replaces the payable order total without repricing rows.

Use this when the cart should let someone change a donation amount (or another on-the-fly price). Do not enable it on a normal product cart.

allow_user_price="yes"

<input type="text" name="price[{row_id}]" value="{item_price:numeric}">

The browser controls this value. Enforce donation minimums, maximums, or other rules on the server when required.

allow_user_shipping

Rare. Allows posted shipping[{row_id}] to update that item’s shipping amount. Leave this off unless the cart is supposed to change item shipping. This is not shipping_option or shipping[key]; those still work without this parameter.

allow_user_shipping="yes"

<input type="text" name="shipping[{row_id}]" value="{item_shipping}">

allow_user_weight

Rare. Allows posted weight[{row_id}] to update that item’s weight. Leave this off unless the cart is supposed to change item weight.

allow_user_weight="yes"

<input type="text" name="weight[{row_id}]" value="{item_weight}">

Advanced: encoded subscription payloads are accepted and cleaned during update processing (subscription, subscription_allow_modification, and subscription_* values such as subscription_plan_id, subscription_price, subscription_interval_units, etc.).

Variables

You may use Global Tag Variables.

update_cart_form parses globalVariables(true), so form/error variables are available when using inline error handling (for example {if errors_exist}, {errors}, {error:field}).

Use custom_data:* variables in tag content to repopulate custom data inputs.

Form Fields

clear_cart

If present, clears all cart items in this submission.

<input type="submit" name="clear_cart" value="Clear Cart">

quantity[{row_id}]

Updates item quantity for that row.

<input type="text" name="quantity[{row_id}]" value="{quantity}">

Setting quantity to 0 removes the item.

delete[{row_id}]

Marks a row for removal. Any value works (checkbox is typical).

<input type="checkbox" name="delete[{row_id}]" value="yes">

item_options[{row_id}][field_name]

Updates item option/custom option data for a row.

<input type="text" name="item_options[{row_id}][notes]" value="{item_options:notes}">

price[{row_id}]

Updates that item’s price. Ignored unless allow_user_price="yes" is set on the tag. Most carts should not include this field.

<input type="text" name="price[{row_id}]" value="{item_price:numeric}">

shipping[{row_id}]

Updates that item’s shipping amount. Ignored unless allow_user_shipping="yes" is set on the tag. Rare; most carts should not include this field.

<input type="text" name="shipping[{row_id}]" value="{item_shipping}">

This is not shipping[key] (cart shipping info).

weight[{row_id}]

Updates that item’s weight. Ignored unless allow_user_weight="yes" is set on the tag. Rare; most carts should not include this field.

<input type="text" name="weight[{row_id}]" value="{item_weight}">

coupon_code

Applies a coupon code after item updates are processed.

<input type="text" name="coupon_code" value="">

shipping_option

Updates the cart’s selected shipping option.

<select name="shipping_option">
    {exp:cartthrob:get_shipping_options}
        <option value="{option_value}"{selected}>{option_name}</option>
    {/exp:cartthrob:get_shipping_options}
</select>

shipping[key]

Updates cart shipping info values saved through save_customer_info. This does not require allow_user_shipping. That parameter only gates per-item shipping[{row_id}].

Examples:

<input type="hidden" name="shipping[method]" value="ground">
<input type="hidden" name="shipping[eta]" value="5_days">

use_billing_info

When truthy, shipping customer fields are copied from billing fields during customer-info save processing.

<input type="checkbox" name="use_billing_info" value="1">

Customer fields

update_cart_form calls save_customer_info, so posted customer fields are saved in session/cart customer info.

Examples:

<input type="text" name="first_name" value="{customer_first_name}">
<input type="text" name="email_address" value="{customer_email_address}">
<input type="text" name="shipping_first_name" value="{customer_shipping_first_name}">
<input type="text" name="shipping_zip" value="{customer_shipping_zip}">

custom_data[key]

Saves cart custom data values.

<input type="text" name="custom_data[gift_message]" value="{custom_data:gift_message}">

Behavior and Constraints

Action flow:

  1. Validate form settings/rules.
  2. On validation failure, action completes through form builder for inline handling (clear_cart is explicitly preserved).
  3. Save customer info and related posted customer/shipping/custom data.
  4. If clear_cart is present, clear cart items and save cart.
  5. Otherwise, update/remove item rows based on posted row-indexed fields.
  6. If coupon_code is non-empty, apply coupon.
  7. Run cart inventory checks.
  8. Complete action with success/error redirect behavior.
  9. Extension hooks run at start/end:
    • cartthrob_update_cart_start
    • cartthrob_update_cart_end

Important notes:

  • clear_cart clears items only (it does not clear customer info/custom data).
  • delete[{row_id}] internally forces that row quantity to 0.
  • Quantity 0 removes the item row.
  • Only existing cart row IDs are updated.
  • Package sub-item updates use parent_row_id:sub_row_id keys.
  • See What this form may change for the default vs opt-in vs never-accepted item fields.

Examples

Update Quantities and Delete Rows

{exp:cartthrob:cart_items_info}
    {if first_row}
        {exp:cartthrob:update_cart_form return="store/view_cart"}
    {/if}

    <p>{title}</p>
    <input type="text" name="quantity[{row_id}]" value="{quantity}" size="2">
    <label>
        <input type="checkbox" name="delete[{row_id}]" value="yes">
        Remove this item
    </label>

    {if last_row}
        <input type="submit" value="Update Cart">
        {/exp:cartthrob:update_cart_form}
    {/if}
{/exp:cartthrob:cart_items_info}

Change a donation amount (rare)

Most carts omit allow_user_price. Use it when this page should let someone change a donation (or other on-the-fly price) already in the cart. Without the parameter, a posted price[{row_id}] is ignored and the amount from add-to-cart is kept.

{exp:cartthrob:cart_items_info}
    {if first_row}
        {exp:cartthrob:update_cart_form
            allow_user_price="yes"
            return="store/view_cart"}
    {/if}

    <p>{title}</p>
    <input type="text" name="quantity[{row_id}]" value="{quantity}" size="2">
    <label>Amount</label>
    <input type="text" name="price[{row_id}]" value="{item_price:numeric}">

    {if last_row}
        <input type="submit" value="Update Cart">
        {/exp:cartthrob:update_cart_form}
    {/if}
{/exp:cartthrob:cart_items_info}

Update Cart + Shipping/Customer Data + Coupon

{exp:cartthrob:update_cart_form return="store/checkout" error_handling="inline"}
    {if errors_exist}
        <p>Please fix the highlighted errors.</p>
    {/if}

    {exp:cartthrob:customer_info}
        <input type="text" name="shipping_first_name" value="{customer_shipping_first_name}">
        <input type="text" name="shipping_last_name" value="{customer_shipping_last_name}">
        <input type="text" name="email_address" value="{customer_email_address}">
        <input type="text" name="shipping_zip" value="{customer_shipping_zip}">
    {/exp:cartthrob:customer_info}

    {exp:cartthrob:get_shipping_options}
        <label>
            <input type="radio" name="shipping_option" value="{option_value}"{selected}>
            {option_name}
        </label>
    {/exp:cartthrob:get_shipping_options}

    <input type="text" name="coupon_code" value="" placeholder="Coupon code">
    <input type="submit" value="Update Cart and Continue">
{/exp:cartthrob:update_cart_form}

Shipping Array + Use Billing Info

{exp:cartthrob:update_cart_form return="store/checkout"}
    <label>
        <input type="checkbox" name="use_billing_info" value="1">
        Use billing address for shipping
    </label>

    <input type="hidden" name="shipping[method]" value="ground">
    <input type="hidden" name="shipping[eta]" value="5_days">

    <input type="submit" value="Save Shipping Info">
{/exp:cartthrob:update_cart_form}