Implement Phase 4 & 5: cart and checkout templates (Bootstrap 5, HPOS)
Phase 4 - Cart (9 templates):
- cart: 8+4 column layout, table-responsive items, coupon input-group
- cart-empty: centered empty state with cart-x icon
- cart-item-data: inline dl for variation details
- cart-totals: card with list-group-flush rows, sticky sidebar
- cart-shipping: form-check radio per shipping method
- cross-sells: product loop grid section
- mini-cart: offcanvas-compatible item list with remove buttons
- proceed-to-checkout-button: btn-primary btn-lg w-100
- shipping-calculator: collapsible form with form-select/form-control
Phase 5 - Checkout (12 templates):
- form-checkout: 7+5 column layout, sticky order review sidebar
- form-billing: card with field wrapper, optional account creation
- form-shipping: card with ship-to-different-address collapse toggle
- form-coupon: collapsible input-group with alert-info toggle
- form-login: collapsible login reusing global/form-login.html.twig
- review-order: card with table-sm, tfoot subtotal/shipping/total
- payment: list-group of payment gateways with radio selection
- payment-method: form-check with description collapse
- terms: form-check checkbox with T&C link
- thankyou: HPOS compatible, alert-success + order details list-group
- order-received: confirmation message
- cart-errors: alert-danger with return-to-cart button
All order data accessed via WC_Order methods (HPOS compatible).
CSS additions: cart thumbnail sizing, checkout form field overrides,
payment box transitions, dark mode focus states.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-28 10:33:49 +01:00
|
|
|
{#
|
|
|
|
|
# Cart Page (Bootstrap 5 Override)
|
|
|
|
|
#
|
|
|
|
|
# Main cart page with items table and totals sidebar.
|
|
|
|
|
# Layout: col-lg-8 (items) + col-lg-4 (totals).
|
|
|
|
|
#
|
|
|
|
|
# Expected context:
|
|
|
|
|
# cart_items - Array from WC()->cart->get_cart(), each with:
|
|
|
|
|
# .key - Cart item key
|
|
|
|
|
# .product - WC_Product object
|
|
|
|
|
# .product_id - Product ID
|
|
|
|
|
# .product_name - Filtered product name
|
|
|
|
|
# .permalink - Product URL
|
|
|
|
|
# .quantity - Quantity
|
|
|
|
|
# .subtotal - Line subtotal HTML
|
|
|
|
|
# .price - Unit price HTML
|
|
|
|
|
# .thumbnail - Product thumbnail HTML
|
|
|
|
|
# .item_data_html - Variation data HTML
|
|
|
|
|
# .remove_url - Remove item URL
|
|
|
|
|
# .visible - Whether item is visible
|
|
|
|
|
# .css_class - Item CSS class
|
|
|
|
|
#
|
|
|
|
|
# WooCommerce PHP equivalent: cart/cart.php
|
|
|
|
|
#
|
|
|
|
|
# @package WcBootstrap
|
|
|
|
|
# @since 0.1.0
|
|
|
|
|
#}
|
|
|
|
|
|
|
|
|
|
{{ do_action('woocommerce_before_cart') }}
|
|
|
|
|
|
|
|
|
|
<div class="row g-4">
|
|
|
|
|
{# Cart items table #}
|
|
|
|
|
<div class="col-lg-8">
|
|
|
|
|
<form class="woocommerce-cart-form" action="{{ wc_get_cart_url()|esc_url }}" method="post">
|
|
|
|
|
{{ do_action('woocommerce_before_cart_table') }}
|
|
|
|
|
|
|
|
|
|
<div class="table-responsive">
|
|
|
|
|
<table class="table align-middle shop_table shop_table_responsive cart woocommerce-cart-form__contents">
|
2026-02-28 22:13:31 +01:00
|
|
|
<thead>
|
Implement Phase 4 & 5: cart and checkout templates (Bootstrap 5, HPOS)
Phase 4 - Cart (9 templates):
- cart: 8+4 column layout, table-responsive items, coupon input-group
- cart-empty: centered empty state with cart-x icon
- cart-item-data: inline dl for variation details
- cart-totals: card with list-group-flush rows, sticky sidebar
- cart-shipping: form-check radio per shipping method
- cross-sells: product loop grid section
- mini-cart: offcanvas-compatible item list with remove buttons
- proceed-to-checkout-button: btn-primary btn-lg w-100
- shipping-calculator: collapsible form with form-select/form-control
Phase 5 - Checkout (12 templates):
- form-checkout: 7+5 column layout, sticky order review sidebar
- form-billing: card with field wrapper, optional account creation
- form-shipping: card with ship-to-different-address collapse toggle
- form-coupon: collapsible input-group with alert-info toggle
- form-login: collapsible login reusing global/form-login.html.twig
- review-order: card with table-sm, tfoot subtotal/shipping/total
- payment: list-group of payment gateways with radio selection
- payment-method: form-check with description collapse
- terms: form-check checkbox with T&C link
- thankyou: HPOS compatible, alert-success + order details list-group
- order-received: confirmation message
- cart-errors: alert-danger with return-to-cart button
All order data accessed via WC_Order methods (HPOS compatible).
CSS additions: cart thumbnail sizing, checkout form field overrides,
payment box transitions, dark mode focus states.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-28 10:33:49 +01:00
|
|
|
<tr>
|
|
|
|
|
<th class="product-thumbnail" scope="col" style="width: 80px;">
|
|
|
|
|
<span class="visually-hidden">{{ __('Thumbnail') }}</span>
|
|
|
|
|
</th>
|
|
|
|
|
<th class="product-name" scope="col">{{ __('Product') }}</th>
|
|
|
|
|
<th class="product-price" scope="col">{{ __('Price') }}</th>
|
|
|
|
|
<th class="product-quantity" scope="col" style="width: 160px;">{{ __('Quantity') }}</th>
|
|
|
|
|
<th class="product-subtotal" scope="col">{{ __('Subtotal') }}</th>
|
|
|
|
|
<th class="product-remove" scope="col" style="width: 50px;">
|
|
|
|
|
<span class="visually-hidden">{{ __('Remove') }}</span>
|
|
|
|
|
</th>
|
|
|
|
|
</tr>
|
|
|
|
|
</thead>
|
|
|
|
|
<tbody>
|
|
|
|
|
{{ do_action('woocommerce_before_cart_contents') }}
|
|
|
|
|
|
|
|
|
|
{% if cart_items is defined %}
|
|
|
|
|
{% for item in cart_items %}
|
|
|
|
|
{% if item.visible is not defined or item.visible %}
|
|
|
|
|
<tr class="woocommerce-cart-form__cart-item {{ item.css_class|default('') }}">
|
|
|
|
|
<td class="product-thumbnail">
|
|
|
|
|
{% if item.permalink %}
|
|
|
|
|
<a href="{{ item.permalink|esc_url }}">{{ item.thumbnail|raw }}</a>
|
|
|
|
|
{% else %}
|
|
|
|
|
{{ item.thumbnail|raw }}
|
|
|
|
|
{% endif %}
|
|
|
|
|
</td>
|
|
|
|
|
|
|
|
|
|
<td class="product-name" data-title="{{ __('Product') }}">
|
|
|
|
|
{% if item.permalink %}
|
|
|
|
|
<a href="{{ item.permalink|esc_url }}" class="text-decoration-none">
|
|
|
|
|
{{ item.product_name|esc_html }}
|
|
|
|
|
</a>
|
|
|
|
|
{% else %}
|
|
|
|
|
{{ item.product_name|esc_html }}
|
|
|
|
|
{% endif %}
|
|
|
|
|
{{ item.item_data_html|default('')|raw }}
|
|
|
|
|
</td>
|
|
|
|
|
|
|
|
|
|
<td class="product-price" data-title="{{ __('Price') }}">
|
|
|
|
|
{{ item.price|raw }}
|
|
|
|
|
</td>
|
|
|
|
|
|
|
|
|
|
<td class="product-quantity" data-title="{{ __('Quantity') }}">
|
|
|
|
|
{% include 'global/quantity-input.html.twig' with {
|
|
|
|
|
input_id: 'quantity_' ~ item.key,
|
|
|
|
|
input_name: 'cart[' ~ item.key ~ '][qty]',
|
|
|
|
|
input_value: item.quantity,
|
|
|
|
|
min_value: 0,
|
|
|
|
|
max_value: item.product.get_max_purchase_quantity()|default(0),
|
|
|
|
|
step: 1,
|
|
|
|
|
placeholder: '',
|
|
|
|
|
inputmode: 'numeric',
|
|
|
|
|
classes: 'qty',
|
|
|
|
|
readonly: false,
|
|
|
|
|
type: 'number',
|
|
|
|
|
args: { product_name: item.product_name }
|
|
|
|
|
} %}
|
|
|
|
|
</td>
|
|
|
|
|
|
|
|
|
|
<td class="product-subtotal" data-title="{{ __('Subtotal') }}">
|
|
|
|
|
{{ item.subtotal|raw }}
|
|
|
|
|
</td>
|
|
|
|
|
|
|
|
|
|
<td class="product-remove">
|
|
|
|
|
<a href="{{ item.remove_url|esc_url }}"
|
|
|
|
|
class="btn btn-sm btn-outline-danger remove"
|
|
|
|
|
aria-label="{{ __('Remove this item') }}"
|
|
|
|
|
data-product_id="{{ item.product_id }}"
|
|
|
|
|
data-product_sku="{{ item.product.get_sku()|default('')|esc_attr }}">
|
|
|
|
|
<i class="bi bi-x-lg" aria-hidden="true"></i>
|
|
|
|
|
</a>
|
|
|
|
|
</td>
|
|
|
|
|
</tr>
|
|
|
|
|
{% endif %}
|
|
|
|
|
{% endfor %}
|
|
|
|
|
{% endif %}
|
|
|
|
|
|
|
|
|
|
{{ do_action('woocommerce_cart_contents') }}
|
|
|
|
|
|
|
|
|
|
<tr>
|
|
|
|
|
<td colspan="6" class="actions">
|
|
|
|
|
<div class="d-flex justify-content-between align-items-center flex-wrap gap-2">
|
|
|
|
|
{% if wc_coupons_enabled() %}
|
|
|
|
|
<div class="coupon input-group" style="max-width: 350px;">
|
|
|
|
|
<label class="visually-hidden" for="coupon_code">{{ __('Coupon:') }}</label>
|
|
|
|
|
<input type="text"
|
|
|
|
|
name="coupon_code"
|
|
|
|
|
class="form-control"
|
|
|
|
|
id="coupon_code"
|
|
|
|
|
placeholder="{{ __('Coupon code') }}" />
|
|
|
|
|
<button type="submit"
|
|
|
|
|
class="btn btn-outline-secondary"
|
|
|
|
|
name="apply_coupon"
|
|
|
|
|
value="{{ __('Apply coupon') }}">
|
|
|
|
|
{{ __('Apply coupon') }}
|
|
|
|
|
</button>
|
|
|
|
|
{{ do_action('woocommerce_cart_coupon') }}
|
|
|
|
|
</div>
|
|
|
|
|
{% endif %}
|
|
|
|
|
|
|
|
|
|
<button type="submit"
|
|
|
|
|
class="btn btn-outline-primary"
|
|
|
|
|
name="update_cart"
|
|
|
|
|
value="{{ __('Update cart') }}">
|
|
|
|
|
{{ __('Update cart') }}
|
|
|
|
|
</button>
|
|
|
|
|
|
|
|
|
|
{{ do_action('woocommerce_cart_actions') }}
|
|
|
|
|
{{ wp_nonce_field('woocommerce-cart', 'woocommerce-cart-nonce') }}
|
|
|
|
|
</div>
|
|
|
|
|
</td>
|
|
|
|
|
</tr>
|
|
|
|
|
|
|
|
|
|
{{ do_action('woocommerce_after_cart_contents') }}
|
|
|
|
|
</tbody>
|
|
|
|
|
</table>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
{{ do_action('woocommerce_after_cart_table') }}
|
|
|
|
|
</form>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
{# Cart totals sidebar #}
|
|
|
|
|
<div class="col-lg-4">
|
|
|
|
|
<div class="cart-collaterals">
|
|
|
|
|
{{ do_action('woocommerce_cart_collaterals') }}
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
{{ do_action('woocommerce_after_cart') }}
|