You've already forked wc-bootstrap
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>
This commit is contained in:
42
PLAN.md
42
PLAN.md
@@ -573,30 +573,30 @@ Track completion per file. Mark with `[x]` when done.
|
||||
|
||||
### Phase 4 -- Cart
|
||||
|
||||
- [ ] `cart/cart.html.twig`
|
||||
- [ ] `cart/cart-empty.html.twig`
|
||||
- [ ] `cart/cart-item-data.html.twig`
|
||||
- [ ] `cart/cart-totals.html.twig`
|
||||
- [ ] `cart/cart-shipping.html.twig`
|
||||
- [ ] `cart/cross-sells.html.twig`
|
||||
- [ ] `cart/mini-cart.html.twig`
|
||||
- [ ] `cart/proceed-to-checkout-button.html.twig`
|
||||
- [ ] `cart/shipping-calculator.html.twig`
|
||||
- [x] `cart/cart.html.twig`
|
||||
- [x] `cart/cart-empty.html.twig`
|
||||
- [x] `cart/cart-item-data.html.twig`
|
||||
- [x] `cart/cart-totals.html.twig`
|
||||
- [x] `cart/cart-shipping.html.twig`
|
||||
- [x] `cart/cross-sells.html.twig`
|
||||
- [x] `cart/mini-cart.html.twig`
|
||||
- [x] `cart/proceed-to-checkout-button.html.twig`
|
||||
- [x] `cart/shipping-calculator.html.twig`
|
||||
|
||||
### Phase 5 -- Checkout
|
||||
|
||||
- [ ] `checkout/form-checkout.html.twig`
|
||||
- [ ] `checkout/form-billing.html.twig`
|
||||
- [ ] `checkout/form-shipping.html.twig`
|
||||
- [ ] `checkout/form-coupon.html.twig`
|
||||
- [ ] `checkout/form-login.html.twig`
|
||||
- [ ] `checkout/review-order.html.twig`
|
||||
- [ ] `checkout/payment.html.twig`
|
||||
- [ ] `checkout/payment-method.html.twig`
|
||||
- [ ] `checkout/terms.html.twig`
|
||||
- [ ] `checkout/thankyou.html.twig`
|
||||
- [ ] `checkout/order-received.html.twig`
|
||||
- [ ] `checkout/cart-errors.html.twig`
|
||||
- [x] `checkout/form-checkout.html.twig`
|
||||
- [x] `checkout/form-billing.html.twig`
|
||||
- [x] `checkout/form-shipping.html.twig`
|
||||
- [x] `checkout/form-coupon.html.twig`
|
||||
- [x] `checkout/form-login.html.twig`
|
||||
- [x] `checkout/review-order.html.twig`
|
||||
- [x] `checkout/payment.html.twig`
|
||||
- [x] `checkout/payment-method.html.twig`
|
||||
- [x] `checkout/terms.html.twig`
|
||||
- [x] `checkout/thankyou.html.twig`
|
||||
- [x] `checkout/order-received.html.twig`
|
||||
- [x] `checkout/cart-errors.html.twig`
|
||||
|
||||
### Phase 6 -- My Account
|
||||
|
||||
|
||||
@@ -187,6 +187,56 @@
|
||||
display: contents;
|
||||
}
|
||||
|
||||
/* ==========================================================================
|
||||
Cart Table
|
||||
Responsive cart item layout and thumbnail sizing.
|
||||
========================================================================== */
|
||||
|
||||
.woocommerce-cart-form .product-thumbnail img {
|
||||
width: 60px;
|
||||
height: 60px;
|
||||
object-fit: cover;
|
||||
border-radius: var(--bs-border-radius);
|
||||
}
|
||||
|
||||
/* ==========================================================================
|
||||
Checkout
|
||||
Sticky order review sidebar and payment method toggle.
|
||||
========================================================================== */
|
||||
|
||||
.payment_box {
|
||||
transition: all 0.2s ease;
|
||||
}
|
||||
|
||||
.woocommerce-checkout .form-row label {
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
/* Override WooCommerce form fields to use Bootstrap styles */
|
||||
.woocommerce-checkout .form-row input.input-text,
|
||||
.woocommerce-checkout .form-row textarea,
|
||||
.woocommerce-checkout .form-row select {
|
||||
display: block;
|
||||
width: 100%;
|
||||
padding: 0.375rem 0.75rem;
|
||||
font-size: 1rem;
|
||||
font-weight: 400;
|
||||
line-height: 1.5;
|
||||
color: var(--bs-body-color);
|
||||
background-color: var(--bs-body-bg);
|
||||
border: var(--bs-border-width) solid var(--bs-border-color);
|
||||
border-radius: var(--bs-border-radius);
|
||||
transition: border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out;
|
||||
}
|
||||
|
||||
.woocommerce-checkout .form-row input.input-text:focus,
|
||||
.woocommerce-checkout .form-row textarea:focus,
|
||||
.woocommerce-checkout .form-row select:focus {
|
||||
border-color: #86b7fe;
|
||||
outline: 0;
|
||||
box-shadow: 0 0 0 0.25rem rgba(13, 110, 253, 0.25);
|
||||
}
|
||||
|
||||
/* ==========================================================================
|
||||
Dark Mode Overrides
|
||||
Fix any plugin elements that don't adapt to Bootstrap's dark mode.
|
||||
@@ -194,7 +244,14 @@
|
||||
|
||||
/* Bootstrap 5 dark mode uses data-bs-theme="dark" attribute on <html> */
|
||||
[data-bs-theme="dark"] {
|
||||
/* Example overrides for dark mode compatibility */
|
||||
/* Checkout form focus color for dark mode */
|
||||
}
|
||||
|
||||
[data-bs-theme="dark"] .woocommerce-checkout .form-row input.input-text:focus,
|
||||
[data-bs-theme="dark"] .woocommerce-checkout .form-row textarea:focus,
|
||||
[data-bs-theme="dark"] .woocommerce-checkout .form-row select:focus {
|
||||
border-color: #6ea8fe;
|
||||
box-shadow: 0 0 0 0.25rem rgba(13, 110, 253, 0.25);
|
||||
}
|
||||
|
||||
/* ==========================================================================
|
||||
|
||||
23
templates/cart/cart-empty.html.twig
Normal file
23
templates/cart/cart-empty.html.twig
Normal file
@@ -0,0 +1,23 @@
|
||||
{#
|
||||
# Empty Cart (Bootstrap 5 Override)
|
||||
#
|
||||
# Displayed when the cart has no items.
|
||||
#
|
||||
# WooCommerce PHP equivalent: cart/cart-empty.php
|
||||
#
|
||||
# @package WcBootstrap
|
||||
# @since 0.1.0
|
||||
#}
|
||||
|
||||
{{ do_action('woocommerce_cart_is_empty') }}
|
||||
|
||||
<div class="text-center py-5">
|
||||
<i class="bi bi-cart-x display-1 text-body-secondary mb-4" aria-hidden="true"></i>
|
||||
<p class="lead text-body-secondary mb-4">{{ __('Your cart is currently empty.') }}</p>
|
||||
|
||||
{% if wc_get_page_id('shop') > 0 %}
|
||||
<a class="btn btn-primary btn-lg" href="{{ wc_get_page_permalink('shop')|esc_url }}">
|
||||
{{ __('Return to shop') }}
|
||||
</a>
|
||||
{% endif %}
|
||||
</div>
|
||||
24
templates/cart/cart-item-data.html.twig
Normal file
24
templates/cart/cart-item-data.html.twig
Normal file
@@ -0,0 +1,24 @@
|
||||
{#
|
||||
# Cart Item Data / Variation Details (Bootstrap 5 Override)
|
||||
#
|
||||
# Renders variation/custom data for a cart item.
|
||||
#
|
||||
# Expected context:
|
||||
# item_data - Array of variation data, each with:
|
||||
# .key - Attribute label
|
||||
# .value - Attribute value (HTML)
|
||||
#
|
||||
# WooCommerce PHP equivalent: cart/cart-item-data.php
|
||||
#
|
||||
# @package WcBootstrap
|
||||
# @since 0.1.0
|
||||
#}
|
||||
|
||||
{% if item_data is defined and item_data|length > 0 %}
|
||||
<dl class="variation small text-body-secondary mb-0 mt-1">
|
||||
{% for data in item_data %}
|
||||
<dt class="d-inline">{{ data.key|raw }}:</dt>
|
||||
<dd class="d-inline me-2">{{ data.value|raw }}</dd>
|
||||
{% endfor %}
|
||||
</dl>
|
||||
{% endif %}
|
||||
69
templates/cart/cart-shipping.html.twig
Normal file
69
templates/cart/cart-shipping.html.twig
Normal file
@@ -0,0 +1,69 @@
|
||||
{#
|
||||
# Cart Shipping Methods (Bootstrap 5 Override)
|
||||
#
|
||||
# Renders available shipping methods as Bootstrap form-check radios.
|
||||
#
|
||||
# Expected context:
|
||||
# available_methods - Array of shipping method objects
|
||||
# chosen_method - Currently chosen method ID
|
||||
# formatted_destination - Formatted shipping address
|
||||
# has_calculated_shipping - Whether shipping has been calculated
|
||||
# show_shipping_calculator - Whether to show the calculator
|
||||
# package_name - Package name/label
|
||||
# index - Package index
|
||||
#
|
||||
# WooCommerce PHP equivalent: cart/cart-shipping.php
|
||||
#
|
||||
# @package WcBootstrap
|
||||
# @since 0.1.0
|
||||
#}
|
||||
|
||||
<div class="woocommerce-shipping-totals shipping">
|
||||
<strong class="d-block mb-2">{{ package_name|default(__('Shipping'))|esc_html }}</strong>
|
||||
|
||||
{% if available_methods is defined and available_methods|length > 0 %}
|
||||
<ul id="shipping_method_{{ index|default(0) }}" class="list-unstyled mb-2">
|
||||
{% for method_id, method in available_methods %}
|
||||
<li class="form-check">
|
||||
{% if available_methods|length > 1 %}
|
||||
<input type="radio"
|
||||
name="shipping_method[{{ index|default(0) }}]"
|
||||
id="shipping_method_{{ index|default(0) }}_{{ method_id|esc_attr }}"
|
||||
value="{{ method_id|esc_attr }}"
|
||||
class="form-check-input shipping_method"
|
||||
data-index="{{ index|default(0) }}"
|
||||
{% if method_id == chosen_method %}checked{% endif %} />
|
||||
{% else %}
|
||||
<input type="hidden"
|
||||
name="shipping_method[{{ index|default(0) }}]"
|
||||
value="{{ method_id|esc_attr }}"
|
||||
class="shipping_method"
|
||||
data-index="{{ index|default(0) }}" />
|
||||
{% endif %}
|
||||
<label class="form-check-label" for="shipping_method_{{ index|default(0) }}_{{ method_id|esc_attr }}">
|
||||
{{ method.get_label()|raw }}
|
||||
</label>
|
||||
{{ do_action('woocommerce_after_shipping_rate', method, index|default(0)) }}
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
|
||||
{% if formatted_destination is defined and formatted_destination %}
|
||||
<p class="woocommerce-shipping-destination small text-body-secondary mb-0">
|
||||
{{ formatted_destination|raw }}
|
||||
</p>
|
||||
{% endif %}
|
||||
{% elseif not has_calculated_shipping|default(false) %}
|
||||
<p class="text-body-secondary small mb-0">
|
||||
{{ __('Shipping costs are calculated during checkout.') }}
|
||||
</p>
|
||||
{% else %}
|
||||
<p class="text-body-secondary small mb-0">
|
||||
{{ __('No shipping options were found.') }}
|
||||
</p>
|
||||
{% endif %}
|
||||
|
||||
{% if show_shipping_calculator|default(false) %}
|
||||
{% include 'cart/shipping-calculator.html.twig' %}
|
||||
{% endif %}
|
||||
</div>
|
||||
82
templates/cart/cart-totals.html.twig
Normal file
82
templates/cart/cart-totals.html.twig
Normal file
@@ -0,0 +1,82 @@
|
||||
{#
|
||||
# Cart Totals (Bootstrap 5 Override)
|
||||
#
|
||||
# Renders the cart totals as a Bootstrap card with list-group rows.
|
||||
#
|
||||
# Expected context:
|
||||
# cart - WC()->cart object (subtotal, fees, coupons, shipping, total)
|
||||
# cart_subtotal - Pre-rendered subtotal HTML
|
||||
# cart_total - Pre-rendered total HTML
|
||||
# coupons - Array of applied coupon objects
|
||||
# fees - Array of fee objects
|
||||
#
|
||||
# WooCommerce PHP equivalent: cart/cart-totals.php
|
||||
#
|
||||
# @package WcBootstrap
|
||||
# @since 0.1.0
|
||||
#}
|
||||
|
||||
<div class="cart_totals">
|
||||
{{ do_action('woocommerce_before_cart_totals') }}
|
||||
|
||||
<div class="card shadow-sm">
|
||||
<div class="card-header">
|
||||
<h2 class="h5 mb-0">{{ __('Cart totals') }}</h2>
|
||||
</div>
|
||||
|
||||
<ul class="list-group list-group-flush">
|
||||
{# Subtotal #}
|
||||
<li class="list-group-item d-flex justify-content-between">
|
||||
<span>{{ __('Subtotal') }}</span>
|
||||
<span>{{ cart_subtotal|default(cart.get_cart_subtotal())|raw }}</span>
|
||||
</li>
|
||||
|
||||
{# Coupons #}
|
||||
{% if coupons is defined %}
|
||||
{% for coupon in coupons %}
|
||||
<li class="list-group-item d-flex justify-content-between">
|
||||
<span>{{ __('Coupon:') }} {{ coupon.code|esc_html }}</span>
|
||||
<span>{{ coupon.discount_html|raw }}</span>
|
||||
</li>
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
|
||||
{# Shipping #}
|
||||
{{ do_action('woocommerce_cart_totals_before_shipping') }}
|
||||
|
||||
{% if wc_shipping_enabled() is defined and wc_shipping_enabled() %}
|
||||
<li class="list-group-item cart-shipping">
|
||||
{{ do_action('woocommerce_cart_totals_shipping') }}
|
||||
</li>
|
||||
{% endif %}
|
||||
|
||||
{{ do_action('woocommerce_cart_totals_after_shipping') }}
|
||||
|
||||
{# Fees #}
|
||||
{% if fees is defined %}
|
||||
{% for fee in fees %}
|
||||
<li class="list-group-item d-flex justify-content-between">
|
||||
<span>{{ fee.name|esc_html }}</span>
|
||||
<span>{{ fee.total_html|raw }}</span>
|
||||
</li>
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
|
||||
{{ do_action('woocommerce_cart_totals_before_order_total') }}
|
||||
|
||||
{# Order total #}
|
||||
<li class="list-group-item d-flex justify-content-between fw-bold fs-5">
|
||||
<span>{{ __('Total') }}</span>
|
||||
<span>{{ cart_total|default(cart.get_total())|raw }}</span>
|
||||
</li>
|
||||
|
||||
{{ do_action('woocommerce_cart_totals_after_order_total') }}
|
||||
</ul>
|
||||
|
||||
<div class="card-body">
|
||||
{{ do_action('woocommerce_proceed_to_checkout') }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{ do_action('woocommerce_after_cart_totals') }}
|
||||
</div>
|
||||
171
templates/cart/cart.html.twig
Normal file
171
templates/cart/cart.html.twig
Normal file
@@ -0,0 +1,171 @@
|
||||
{#
|
||||
# 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">
|
||||
<thead class="table-light">
|
||||
<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') }}
|
||||
32
templates/cart/cross-sells.html.twig
Normal file
32
templates/cart/cross-sells.html.twig
Normal file
@@ -0,0 +1,32 @@
|
||||
{#
|
||||
# Cross-sell Products (Bootstrap 5 Override)
|
||||
#
|
||||
# Renders cross-sell product recommendations below the cart.
|
||||
#
|
||||
# Expected context:
|
||||
# cross_sells - Array of WC_Product objects
|
||||
# columns - Number of columns
|
||||
# heading - Section heading (filtered)
|
||||
#
|
||||
# WooCommerce PHP equivalent: cart/cross-sells.php
|
||||
#
|
||||
# @package WcBootstrap
|
||||
# @since 0.1.0
|
||||
#}
|
||||
|
||||
{% if cross_sells is defined and cross_sells|length > 0 %}
|
||||
<section class="cross-sells mt-5">
|
||||
{% set heading = heading|default(__('You may be interested in…')) %}
|
||||
{% if heading %}
|
||||
<h2 class="h4 mb-4">{{ heading }}</h2>
|
||||
{% endif %}
|
||||
|
||||
{{ woocommerce_product_loop_start() }}
|
||||
|
||||
{% for product in cross_sells %}
|
||||
{% include 'content-product.html.twig' with { product: product } %}
|
||||
{% endfor %}
|
||||
|
||||
{{ woocommerce_product_loop_end() }}
|
||||
</section>
|
||||
{% endif %}
|
||||
87
templates/cart/mini-cart.html.twig
Normal file
87
templates/cart/mini-cart.html.twig
Normal file
@@ -0,0 +1,87 @@
|
||||
{#
|
||||
# Mini Cart / Cart Widget (Bootstrap 5 Override)
|
||||
#
|
||||
# Renders the mini cart as an offcanvas slide-in panel.
|
||||
#
|
||||
# Expected context:
|
||||
# cart_items - Array from WC()->cart->get_cart()
|
||||
# cart_is_empty - Whether cart is empty
|
||||
# cart_subtotal - Cart subtotal HTML
|
||||
# args - Widget arguments (list_class)
|
||||
#
|
||||
# WooCommerce PHP equivalent: cart/mini-cart.php
|
||||
#
|
||||
# @package WcBootstrap
|
||||
# @since 0.1.0
|
||||
#}
|
||||
|
||||
{{ do_action('woocommerce_before_mini_cart') }}
|
||||
|
||||
{% if not cart_is_empty|default(true) %}
|
||||
<ul class="woocommerce-mini-cart list-unstyled {{ args.list_class|default('') }}">
|
||||
{{ do_action('woocommerce_before_mini_cart_contents') }}
|
||||
|
||||
{% if cart_items is defined %}
|
||||
{% for item in cart_items %}
|
||||
<li class="woocommerce-mini-cart-item d-flex gap-3 py-2 border-bottom {{ item.css_class|default('') }}">
|
||||
{# Remove link #}
|
||||
<a href="{{ item.remove_url|esc_url }}"
|
||||
class="remove remove_from_cart_button text-danger"
|
||||
aria-label="{{ __('Remove this item') }}"
|
||||
data-product_id="{{ item.product_id }}"
|
||||
data-cart_item_key="{{ item.key }}">
|
||||
<i class="bi bi-x" aria-hidden="true"></i>
|
||||
</a>
|
||||
|
||||
{# Thumbnail #}
|
||||
{% if item.permalink %}
|
||||
<a href="{{ item.permalink|esc_url }}" class="flex-shrink-0" style="width: 50px;">
|
||||
{{ item.thumbnail|raw }}
|
||||
</a>
|
||||
{% endif %}
|
||||
|
||||
{# Product info #}
|
||||
<div class="flex-grow-1">
|
||||
{% if item.permalink %}
|
||||
<a href="{{ item.permalink|esc_url }}" class="text-decoration-none d-block small fw-semibold">
|
||||
{{ item.product_name }}
|
||||
</a>
|
||||
{% else %}
|
||||
<span class="d-block small fw-semibold">{{ item.product_name }}</span>
|
||||
{% endif %}
|
||||
|
||||
{{ item.item_data_html|default('')|raw }}
|
||||
|
||||
<span class="quantity small text-body-secondary">
|
||||
{{ item.quantity }} × {{ item.price|raw }}
|
||||
</span>
|
||||
</div>
|
||||
</li>
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
|
||||
{{ do_action('woocommerce_mini_cart_contents') }}
|
||||
</ul>
|
||||
|
||||
<div class="woocommerce-mini-cart__total border-top pt-3 mt-2">
|
||||
{{ do_action('woocommerce_widget_shopping_cart_total') }}
|
||||
<p class="total d-flex justify-content-between fw-bold mb-3">
|
||||
<span>{{ __('Subtotal:') }}</span>
|
||||
<span>{{ cart_subtotal|raw }}</span>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{{ do_action('woocommerce_widget_shopping_cart_before_buttons') }}
|
||||
|
||||
<div class="woocommerce-mini-cart__buttons d-grid gap-2">
|
||||
{{ do_action('woocommerce_widget_shopping_cart_buttons') }}
|
||||
</div>
|
||||
|
||||
{{ do_action('woocommerce_widget_shopping_cart_after_buttons') }}
|
||||
{% else %}
|
||||
<p class="woocommerce-mini-cart__empty-message text-body-secondary text-center py-3">
|
||||
{{ __('No products in the cart.') }}
|
||||
</p>
|
||||
{% endif %}
|
||||
|
||||
{{ do_action('woocommerce_after_mini_cart') }}
|
||||
12
templates/cart/proceed-to-checkout-button.html.twig
Normal file
12
templates/cart/proceed-to-checkout-button.html.twig
Normal file
@@ -0,0 +1,12 @@
|
||||
{#
|
||||
# Proceed to Checkout Button (Bootstrap 5 Override)
|
||||
#
|
||||
# WooCommerce PHP equivalent: cart/proceed-to-checkout-button.php
|
||||
#
|
||||
# @package WcBootstrap
|
||||
# @since 0.1.0
|
||||
#}
|
||||
|
||||
<a href="{{ wc_get_checkout_url()|esc_url }}" class="btn btn-primary btn-lg w-100 checkout-button">
|
||||
{{ __('Proceed to checkout') }}
|
||||
</a>
|
||||
109
templates/cart/shipping-calculator.html.twig
Normal file
109
templates/cart/shipping-calculator.html.twig
Normal file
@@ -0,0 +1,109 @@
|
||||
{#
|
||||
# Shipping Calculator (Bootstrap 5 Override)
|
||||
#
|
||||
# Collapsible form to estimate shipping costs.
|
||||
#
|
||||
# Expected context:
|
||||
# button_text - Submit button text
|
||||
# customer_country - Selected country code
|
||||
# customer_state - Selected state code
|
||||
# customer_city - City value
|
||||
# customer_postcode - Postcode value
|
||||
# countries - Array of country options
|
||||
# states - Array of state options for selected country
|
||||
# show_country - Whether to show country field
|
||||
# show_state - Whether to show state field
|
||||
# show_city - Whether to show city field
|
||||
# show_postcode - Whether to show postcode field
|
||||
#
|
||||
# WooCommerce PHP equivalent: cart/shipping-calculator.php
|
||||
#
|
||||
# @package WcBootstrap
|
||||
# @since 0.1.0
|
||||
#}
|
||||
|
||||
{{ do_action('woocommerce_before_shipping_calculator') }}
|
||||
|
||||
<form class="woocommerce-shipping-calculator mt-3" action="{{ wc_get_cart_url()|esc_url }}" method="post">
|
||||
<a href="#shippingCalcForm"
|
||||
class="btn btn-sm btn-outline-secondary"
|
||||
data-bs-toggle="collapse"
|
||||
role="button"
|
||||
aria-expanded="false"
|
||||
aria-controls="shippingCalcForm">
|
||||
{{ __('Calculate shipping') }}
|
||||
</a>
|
||||
|
||||
<div class="collapse mt-3" id="shippingCalcForm">
|
||||
{% if show_country|default(true) %}
|
||||
<div class="mb-3">
|
||||
<label for="calc_shipping_country" class="form-label">{{ __('Country / region') }}</label>
|
||||
<select name="calc_shipping_country" id="calc_shipping_country" class="form-select country_to_state">
|
||||
<option value="default">{{ __('Select a country / region…') }}</option>
|
||||
{% if countries is defined %}
|
||||
{% for code, name in countries %}
|
||||
<option value="{{ code|esc_attr }}"{% if code == customer_country %} selected{% endif %}>
|
||||
{{ name|esc_html }}
|
||||
</option>
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
</select>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% if show_state|default(true) %}
|
||||
<div class="mb-3">
|
||||
<label for="calc_shipping_state" class="form-label">{{ __('State / county') }}</label>
|
||||
{% if states is defined and states|length > 0 %}
|
||||
<select name="calc_shipping_state" id="calc_shipping_state" class="form-select">
|
||||
<option value="">{{ __('Select an option…') }}</option>
|
||||
{% for code, name in states %}
|
||||
<option value="{{ code|esc_attr }}"{% if code == customer_state %} selected{% endif %}>
|
||||
{{ name|esc_html }}
|
||||
</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
{% else %}
|
||||
<input type="text"
|
||||
class="form-control"
|
||||
name="calc_shipping_state"
|
||||
id="calc_shipping_state"
|
||||
placeholder="{{ __('State / county') }}"
|
||||
value="{{ customer_state|default('')|esc_attr }}" />
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% if show_city|default(false) %}
|
||||
<div class="mb-3">
|
||||
<label for="calc_shipping_city" class="form-label">{{ __('City') }}</label>
|
||||
<input type="text"
|
||||
class="form-control"
|
||||
name="calc_shipping_city"
|
||||
id="calc_shipping_city"
|
||||
placeholder="{{ __('City') }}"
|
||||
value="{{ customer_city|default('')|esc_attr }}" />
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% if show_postcode|default(true) %}
|
||||
<div class="mb-3">
|
||||
<label for="calc_shipping_postcode" class="form-label">{{ __('Postcode / ZIP') }}</label>
|
||||
<input type="text"
|
||||
class="form-control"
|
||||
name="calc_shipping_postcode"
|
||||
id="calc_shipping_postcode"
|
||||
placeholder="{{ __('Postcode / ZIP') }}"
|
||||
value="{{ customer_postcode|default('')|esc_attr }}" />
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<button type="submit" name="calc_shipping" value="1" class="btn btn-outline-primary">
|
||||
{{ button_text|default(__('Update')) }}
|
||||
</button>
|
||||
|
||||
{{ wp_nonce_field('woocommerce-shipping-calculator', 'woocommerce-shipping-calculator-nonce') }}
|
||||
</div>
|
||||
</form>
|
||||
|
||||
{{ do_action('woocommerce_after_shipping_calculator') }}
|
||||
24
templates/checkout/cart-errors.html.twig
Normal file
24
templates/checkout/cart-errors.html.twig
Normal file
@@ -0,0 +1,24 @@
|
||||
{#
|
||||
# Cart Errors on Checkout (Bootstrap 5 Override)
|
||||
#
|
||||
# Displayed when checkout cannot proceed due to cart validation errors.
|
||||
#
|
||||
# WooCommerce PHP equivalent: checkout/cart-errors.php
|
||||
#
|
||||
# @package WcBootstrap
|
||||
# @since 0.1.0
|
||||
#}
|
||||
|
||||
{{ do_action('woocommerce_cart_has_errors') }}
|
||||
|
||||
<div class="alert alert-danger mb-4" role="alert">
|
||||
<i class="bi bi-exclamation-triangle me-2" aria-hidden="true"></i>
|
||||
{{ __('There are some issues with the items in your cart. Please go back to your cart and resolve these issues before checking out.') }}
|
||||
</div>
|
||||
|
||||
<p>
|
||||
<a href="{{ wc_get_cart_url()|esc_url }}" class="btn btn-outline-primary">
|
||||
<i class="bi bi-arrow-left me-1" aria-hidden="true"></i>
|
||||
{{ __('Return to cart') }}
|
||||
</a>
|
||||
</p>
|
||||
66
templates/checkout/form-billing.html.twig
Normal file
66
templates/checkout/form-billing.html.twig
Normal file
@@ -0,0 +1,66 @@
|
||||
{#
|
||||
# Billing Form (Bootstrap 5 Override)
|
||||
#
|
||||
# Renders billing address fields within a Bootstrap card.
|
||||
#
|
||||
# Expected context:
|
||||
# checkout - WC_Checkout object with:
|
||||
# .get_checkout_fields('billing') - Array of billing field configs
|
||||
#
|
||||
# WooCommerce PHP equivalent: checkout/form-billing.php
|
||||
#
|
||||
# @package WcBootstrap
|
||||
# @since 0.1.0
|
||||
#}
|
||||
|
||||
<div class="woocommerce-billing-fields">
|
||||
<div class="card shadow-sm mb-4">
|
||||
<div class="card-header">
|
||||
<h3 class="h5 mb-0">{{ __('Billing details') }}</h3>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
{{ do_action('woocommerce_before_checkout_billing_form', checkout) }}
|
||||
|
||||
<div class="woocommerce-billing-fields__field-wrapper row g-3">
|
||||
{% if billing_fields is defined %}
|
||||
{% for key, field in billing_fields %}
|
||||
{{ woocommerce_form_field(key, field, checkout.get_value(key)) }}
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
{{ do_action('woocommerce_after_checkout_billing_form', checkout) }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{# Account creation fields (for guest checkout) #}
|
||||
{% if checkout.is_registration_enabled() is defined and checkout.is_registration_enabled() and not is_user_logged_in() %}
|
||||
{% if checkout.is_registration_required() is not defined or not checkout.is_registration_required() %}
|
||||
<div class="woocommerce-account-fields mb-4">
|
||||
<div class="form-check mb-3">
|
||||
<input class="form-check-input"
|
||||
type="checkbox"
|
||||
name="createaccount"
|
||||
id="createaccount"
|
||||
value="1"
|
||||
{{ checkout.get_value('createaccount') ? 'checked' : '' }} />
|
||||
<label class="form-check-label" for="createaccount">
|
||||
{{ __('Create an account?') }}
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{{ do_action('woocommerce_before_checkout_registration_form', checkout) }}
|
||||
|
||||
<div class="create-account collapse{% if checkout.get_value('createaccount') %} show{% endif %}">
|
||||
{% if account_fields is defined %}
|
||||
{% for key, field in account_fields %}
|
||||
{{ woocommerce_form_field(key, field, checkout.get_value(key)) }}
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
{{ do_action('woocommerce_after_checkout_registration_form', checkout) }}
|
||||
{% endif %}
|
||||
</div>
|
||||
52
templates/checkout/form-checkout.html.twig
Normal file
52
templates/checkout/form-checkout.html.twig
Normal file
@@ -0,0 +1,52 @@
|
||||
{#
|
||||
# Checkout Form (Bootstrap 5 Override)
|
||||
#
|
||||
# Main checkout page: 7+5 column layout (customer details + order review).
|
||||
#
|
||||
# Expected context:
|
||||
# checkout - WC_Checkout object
|
||||
#
|
||||
# WooCommerce PHP equivalent: checkout/form-checkout.php
|
||||
#
|
||||
# @package WcBootstrap
|
||||
# @since 0.1.0
|
||||
#}
|
||||
|
||||
{{ do_action('woocommerce_before_checkout_form', checkout) }}
|
||||
|
||||
<form name="checkout" method="post" class="checkout woocommerce-checkout"
|
||||
action="{{ wc_get_checkout_url()|esc_url }}" enctype="multipart/form-data">
|
||||
|
||||
<div class="row g-4">
|
||||
{# Customer details #}
|
||||
<div class="col-lg-7">
|
||||
{{ do_action('woocommerce_checkout_before_customer_details') }}
|
||||
|
||||
<div id="customer_details">
|
||||
{{ do_action('woocommerce_checkout_billing') }}
|
||||
{{ do_action('woocommerce_checkout_shipping') }}
|
||||
</div>
|
||||
|
||||
{{ do_action('woocommerce_checkout_after_customer_details') }}
|
||||
</div>
|
||||
|
||||
{# Order review sidebar #}
|
||||
<div class="col-lg-5">
|
||||
<div class="position-sticky" style="top: 1rem;">
|
||||
{{ do_action('woocommerce_checkout_before_order_review_heading') }}
|
||||
|
||||
<h3 class="h5 mb-3" id="order_review_heading">{{ __('Your order') }}</h3>
|
||||
|
||||
{{ do_action('woocommerce_checkout_before_order_review') }}
|
||||
|
||||
<div id="order_review" class="woocommerce-checkout-review-order">
|
||||
{{ do_action('woocommerce_checkout_order_review') }}
|
||||
</div>
|
||||
|
||||
{{ do_action('woocommerce_checkout_after_order_review') }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
{{ do_action('woocommerce_after_checkout_form', checkout) }}
|
||||
45
templates/checkout/form-coupon.html.twig
Normal file
45
templates/checkout/form-coupon.html.twig
Normal file
@@ -0,0 +1,45 @@
|
||||
{#
|
||||
# Checkout Coupon Form (Bootstrap 5 Override)
|
||||
#
|
||||
# Collapsible coupon code input on the checkout page.
|
||||
#
|
||||
# WooCommerce PHP equivalent: checkout/form-coupon.php
|
||||
#
|
||||
# @package WcBootstrap
|
||||
# @since 0.1.0
|
||||
#}
|
||||
|
||||
{% if wc_coupons_enabled() %}
|
||||
<div class="woocommerce-form-coupon-toggle mb-4">
|
||||
<div class="alert alert-info d-flex align-items-center" role="status">
|
||||
<i class="bi bi-tag me-2" aria-hidden="true"></i>
|
||||
{{ __('Have a coupon?') }}
|
||||
<a href="#checkoutCoupon"
|
||||
class="ms-1 alert-link"
|
||||
data-bs-toggle="collapse"
|
||||
role="button"
|
||||
aria-expanded="false"
|
||||
aria-controls="checkoutCoupon">
|
||||
{{ __('Click here to enter your code') }}
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="collapse mb-4" id="checkoutCoupon">
|
||||
<form class="checkout_coupon woocommerce-form-coupon" method="post">
|
||||
<div class="input-group">
|
||||
<input type="text"
|
||||
name="coupon_code"
|
||||
class="form-control"
|
||||
id="coupon_code_checkout"
|
||||
placeholder="{{ __('Coupon code') }}" />
|
||||
<button type="submit"
|
||||
class="btn btn-outline-secondary"
|
||||
name="apply_coupon"
|
||||
value="{{ __('Apply coupon') }}">
|
||||
{{ __('Apply coupon') }}
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
{% endif %}
|
||||
35
templates/checkout/form-login.html.twig
Normal file
35
templates/checkout/form-login.html.twig
Normal file
@@ -0,0 +1,35 @@
|
||||
{#
|
||||
# Checkout Login Form (Bootstrap 5 Override)
|
||||
#
|
||||
# Collapsible login prompt at the top of the checkout page.
|
||||
#
|
||||
# WooCommerce PHP equivalent: checkout/form-login.php
|
||||
#
|
||||
# @package WcBootstrap
|
||||
# @since 0.1.0
|
||||
#}
|
||||
|
||||
{% if is_user_logged_in() is defined and not is_user_logged_in() %}
|
||||
<div class="woocommerce-form-login-toggle mb-4">
|
||||
<div class="alert alert-info d-flex align-items-center" role="status">
|
||||
<i class="bi bi-person me-2" aria-hidden="true"></i>
|
||||
{{ __('Returning customer?') }}
|
||||
<a href="#checkoutLogin"
|
||||
class="ms-1 alert-link"
|
||||
data-bs-toggle="collapse"
|
||||
role="button"
|
||||
aria-expanded="false"
|
||||
aria-controls="checkoutLogin">
|
||||
{{ __('Click here to login') }}
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="collapse mb-4" id="checkoutLogin">
|
||||
{% include 'global/form-login.html.twig' with {
|
||||
message: __('If you have shopped with us before, please enter your details below. If you are a new customer, please proceed to the Billing section.'),
|
||||
redirect: wc_get_checkout_url(),
|
||||
hidden: false
|
||||
} %}
|
||||
</div>
|
||||
{% endif %}
|
||||
69
templates/checkout/form-shipping.html.twig
Normal file
69
templates/checkout/form-shipping.html.twig
Normal file
@@ -0,0 +1,69 @@
|
||||
{#
|
||||
# Shipping Form (Bootstrap 5 Override)
|
||||
#
|
||||
# Renders shipping address fields with "ship to different address" toggle.
|
||||
#
|
||||
# Expected context:
|
||||
# checkout - WC_Checkout object
|
||||
# shipping_fields - Array of shipping field configs
|
||||
# order_fields - Array of order note fields
|
||||
#
|
||||
# WooCommerce PHP equivalent: checkout/form-shipping.php
|
||||
#
|
||||
# @package WcBootstrap
|
||||
# @since 0.1.0
|
||||
#}
|
||||
|
||||
<div class="woocommerce-shipping-fields">
|
||||
<div class="card shadow-sm mb-4">
|
||||
<div class="card-header">
|
||||
<div class="form-check mb-0">
|
||||
<input class="form-check-input"
|
||||
type="checkbox"
|
||||
name="ship_to_different_address"
|
||||
id="ship-to-different-address-checkbox"
|
||||
value="1"
|
||||
{{ ship_to_different_address|default(false) ? 'checked' : '' }} />
|
||||
<label class="form-check-label h5 mb-0" for="ship-to-different-address-checkbox">
|
||||
{{ __('Ship to a different address?') }}
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card-body shipping_address collapse{% if ship_to_different_address|default(false) %} show{% endif %}">
|
||||
{{ do_action('woocommerce_before_checkout_shipping_form', checkout) }}
|
||||
|
||||
<div class="woocommerce-shipping-fields__field-wrapper row g-3">
|
||||
{% if shipping_fields is defined %}
|
||||
{% for key, field in shipping_fields %}
|
||||
{{ woocommerce_form_field(key, field, checkout.get_value(key)) }}
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
{{ do_action('woocommerce_after_checkout_shipping_form', checkout) }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{# Order notes #}
|
||||
<div class="woocommerce-additional-fields mb-4">
|
||||
{{ do_action('woocommerce_before_order_notes', checkout) }}
|
||||
|
||||
{% if order_fields is defined and order_fields|length > 0 %}
|
||||
<div class="card shadow-sm">
|
||||
<div class="card-header">
|
||||
<h3 class="h5 mb-0">{{ __('Additional information') }}</h3>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="woocommerce-additional-fields__field-wrapper">
|
||||
{% for key, field in order_fields %}
|
||||
{{ woocommerce_form_field(key, field, checkout.get_value(key)) }}
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{{ do_action('woocommerce_after_order_notes', checkout) }}
|
||||
</div>
|
||||
18
templates/checkout/order-received.html.twig
Normal file
18
templates/checkout/order-received.html.twig
Normal file
@@ -0,0 +1,18 @@
|
||||
{#
|
||||
# Order Received Message (Bootstrap 5 Override)
|
||||
#
|
||||
# Short confirmation text displayed on the thank-you page.
|
||||
# HPOS compatible: no $post global, uses WC_Order methods only.
|
||||
#
|
||||
# Expected context:
|
||||
# order - WC_Order object (optional)
|
||||
#
|
||||
# WooCommerce PHP equivalent: checkout/order-received.php
|
||||
#
|
||||
# @package WcBootstrap
|
||||
# @since 0.1.0
|
||||
#}
|
||||
|
||||
<p class="woocommerce-notice woocommerce-notice--success woocommerce-thankyou-order-received mb-0">
|
||||
{{ __('Thank you. Your order has been received.') }}
|
||||
</p>
|
||||
46
templates/checkout/payment-method.html.twig
Normal file
46
templates/checkout/payment-method.html.twig
Normal file
@@ -0,0 +1,46 @@
|
||||
{#
|
||||
# Single Payment Method (Bootstrap 5 Override)
|
||||
#
|
||||
# Renders a payment gateway as a list-group-item with radio and description.
|
||||
#
|
||||
# Expected context:
|
||||
# gateway - WC_Payment_Gateway object with:
|
||||
# .id - Gateway ID
|
||||
# .get_title() - Gateway title
|
||||
# .get_icon() - Gateway icon HTML
|
||||
# .has_fields() - Whether gateway has inline fields
|
||||
# .get_description() - Gateway description
|
||||
# .chosen - Whether this is the selected gateway
|
||||
# .payment_fields() - Renders inline payment fields
|
||||
#
|
||||
# WooCommerce PHP equivalent: checkout/payment-method.php
|
||||
#
|
||||
# @package WcBootstrap
|
||||
# @since 0.1.0
|
||||
#}
|
||||
|
||||
<li class="wc_payment_method payment_method_{{ gateway.id|esc_attr }} list-group-item">
|
||||
<div class="form-check">
|
||||
<input type="radio"
|
||||
class="form-check-input input-radio"
|
||||
name="payment_method"
|
||||
id="payment_method_{{ gateway.id|esc_attr }}"
|
||||
value="{{ gateway.id|esc_attr }}"
|
||||
data-order_button_text="{{ gateway.order_button_text|default('')|esc_attr }}"
|
||||
{% if gateway.chosen is defined and gateway.chosen %}checked{% endif %} />
|
||||
|
||||
<label class="form-check-label d-flex align-items-center gap-2" for="payment_method_{{ gateway.id|esc_attr }}">
|
||||
<span>{{ gateway.get_title()|esc_html }}</span>
|
||||
{{ gateway.get_icon()|raw }}
|
||||
</label>
|
||||
</div>
|
||||
|
||||
{% if gateway.has_fields() or gateway.get_description() %}
|
||||
<div class="payment_box payment_method_{{ gateway.id|esc_attr }} mt-2 ps-4{% if not gateway.chosen|default(false) %} d-none{% endif %}">
|
||||
{% if gateway.get_description() %}
|
||||
<p class="small text-body-secondary mb-2">{{ gateway.get_description()|wp_kses_post }}</p>
|
||||
{% endif %}
|
||||
{{ gateway.payment_fields() }}
|
||||
</div>
|
||||
{% endif %}
|
||||
</li>
|
||||
54
templates/checkout/payment.html.twig
Normal file
54
templates/checkout/payment.html.twig
Normal file
@@ -0,0 +1,54 @@
|
||||
{#
|
||||
# Payment Methods & Place Order (Bootstrap 5 Override)
|
||||
#
|
||||
# Renders payment gateway selection and the place order button.
|
||||
#
|
||||
# Expected context:
|
||||
# available_gateways - Array of WC_Payment_Gateway objects
|
||||
# order_button_text - Place order button label
|
||||
#
|
||||
# WooCommerce PHP equivalent: checkout/payment.php
|
||||
#
|
||||
# @package WcBootstrap
|
||||
# @since 0.1.0
|
||||
#}
|
||||
|
||||
<div id="payment" class="woocommerce-checkout-payment mt-4">
|
||||
{{ do_action('woocommerce_review_order_before_payment') }}
|
||||
|
||||
{% if available_gateways is defined and available_gateways|length > 0 %}
|
||||
<div class="card shadow-sm mb-3">
|
||||
<div class="card-header">
|
||||
<h4 class="h6 mb-0">{{ __('Payment method') }}</h4>
|
||||
</div>
|
||||
<ul class="wc_payment_methods payment_methods list-group list-group-flush">
|
||||
{% for gateway_id, gateway in available_gateways %}
|
||||
{% include 'checkout/payment-method.html.twig' with { gateway: gateway } %}
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</div>
|
||||
{% else %}
|
||||
<div class="alert alert-warning mb-3" role="alert">
|
||||
{{ __('Sorry, it seems that there are no available payment methods. Please contact us if you require assistance or wish to make alternate arrangements.') }}
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<div class="place-order">
|
||||
{{ do_action('woocommerce_review_order_before_submit') }}
|
||||
|
||||
{{ wp_nonce_field('woocommerce-process_checkout', 'woocommerce-process-checkout-nonce') }}
|
||||
|
||||
<button type="submit"
|
||||
class="btn btn-primary btn-lg w-100"
|
||||
name="woocommerce_checkout_place_order"
|
||||
id="place_order"
|
||||
value="{{ order_button_text|default(__('Place order')) }}"
|
||||
data-value="{{ order_button_text|default(__('Place order')) }}">
|
||||
{{ order_button_text|default(__('Place order')) }}
|
||||
</button>
|
||||
|
||||
{{ do_action('woocommerce_review_order_after_submit') }}
|
||||
</div>
|
||||
|
||||
{{ do_action('woocommerce_review_order_after_payment') }}
|
||||
</div>
|
||||
91
templates/checkout/review-order.html.twig
Normal file
91
templates/checkout/review-order.html.twig
Normal file
@@ -0,0 +1,91 @@
|
||||
{#
|
||||
# Order Review Table (Bootstrap 5 Override)
|
||||
#
|
||||
# Renders the order summary table during checkout.
|
||||
#
|
||||
# Expected context:
|
||||
# cart_items - Array of cart items for review
|
||||
# cart_subtotal - Subtotal HTML
|
||||
# cart_total - Total HTML
|
||||
# coupons - Applied coupons
|
||||
# fees - Fees
|
||||
#
|
||||
# WooCommerce PHP equivalent: checkout/review-order.php
|
||||
#
|
||||
# @package WcBootstrap
|
||||
# @since 0.1.0
|
||||
#}
|
||||
|
||||
<div class="card shadow-sm woocommerce-checkout-review-order-table">
|
||||
<div class="card-body p-0">
|
||||
<table class="table table-sm mb-0 shop_table woocommerce-checkout-review-order-table">
|
||||
<thead class="table-light">
|
||||
<tr>
|
||||
<th class="product-name" scope="col">{{ __('Product') }}</th>
|
||||
<th class="product-total text-end" scope="col">{{ __('Subtotal') }}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{{ do_action('woocommerce_review_order_before_cart_contents') }}
|
||||
|
||||
{% if cart_items is defined %}
|
||||
{% for item in cart_items %}
|
||||
<tr class="cart_item">
|
||||
<td class="product-name">
|
||||
{{ item.product_name|esc_html }}
|
||||
<strong class="product-quantity text-body-secondary">× {{ item.quantity }}</strong>
|
||||
{{ item.item_data_html|default('')|raw }}
|
||||
</td>
|
||||
<td class="product-total text-end">
|
||||
{{ item.subtotal|raw }}
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
|
||||
{{ do_action('woocommerce_review_order_after_cart_contents') }}
|
||||
</tbody>
|
||||
<tfoot>
|
||||
<tr class="cart-subtotal">
|
||||
<th scope="row">{{ __('Subtotal') }}</th>
|
||||
<td class="text-end">{{ cart_subtotal|raw }}</td>
|
||||
</tr>
|
||||
|
||||
{% if coupons is defined %}
|
||||
{% for coupon in coupons %}
|
||||
<tr class="cart-discount coupon-{{ coupon.code|esc_attr }}">
|
||||
<th scope="row">{{ __('Coupon:') }} {{ coupon.code|esc_html }}</th>
|
||||
<td class="text-end">{{ coupon.discount_html|raw }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
|
||||
{{ do_action('woocommerce_review_order_before_shipping') }}
|
||||
|
||||
{% if wc_shipping_enabled() is defined and wc_shipping_enabled() %}
|
||||
{{ do_action('woocommerce_review_order_shipping') }}
|
||||
{% endif %}
|
||||
|
||||
{{ do_action('woocommerce_review_order_after_shipping') }}
|
||||
|
||||
{% if fees is defined %}
|
||||
{% for fee in fees %}
|
||||
<tr class="fee">
|
||||
<th scope="row">{{ fee.name|esc_html }}</th>
|
||||
<td class="text-end">{{ fee.total_html|raw }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
|
||||
{{ do_action('woocommerce_review_order_before_order_total') }}
|
||||
|
||||
<tr class="order-total">
|
||||
<th scope="row" class="fw-bold">{{ __('Total') }}</th>
|
||||
<td class="text-end fw-bold fs-5">{{ cart_total|raw }}</td>
|
||||
</tr>
|
||||
|
||||
{{ do_action('woocommerce_review_order_after_order_total') }}
|
||||
</tfoot>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
32
templates/checkout/terms.html.twig
Normal file
32
templates/checkout/terms.html.twig
Normal file
@@ -0,0 +1,32 @@
|
||||
{#
|
||||
# Terms & Conditions Checkbox (Bootstrap 5 Override)
|
||||
#
|
||||
# WooCommerce PHP equivalent: checkout/terms.php
|
||||
#
|
||||
# @package WcBootstrap
|
||||
# @since 0.1.0
|
||||
#}
|
||||
|
||||
{{ do_action('woocommerce_checkout_before_terms_and_conditions') }}
|
||||
|
||||
{% if wc_terms_and_conditions_checkbox_enabled() is defined and wc_terms_and_conditions_checkbox_enabled() %}
|
||||
<div class="woocommerce-terms-and-conditions-wrapper mb-3">
|
||||
{{ do_action('woocommerce_checkout_terms_and_conditions') }}
|
||||
|
||||
<div class="form-check">
|
||||
<input type="checkbox"
|
||||
class="form-check-input woocommerce-form__input-checkbox"
|
||||
name="terms"
|
||||
id="terms"
|
||||
{% if terms_checked is defined and terms_checked %}checked{% endif %}
|
||||
required
|
||||
aria-required="true" />
|
||||
<label class="form-check-label woocommerce-form__label-for-checkbox" for="terms">
|
||||
{{ wc_terms_and_conditions_checkbox_text()|raw }}
|
||||
</label>
|
||||
<input type="hidden" name="terms-field" value="1" />
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{{ do_action('woocommerce_checkout_after_terms_and_conditions') }}
|
||||
75
templates/checkout/thankyou.html.twig
Normal file
75
templates/checkout/thankyou.html.twig
Normal file
@@ -0,0 +1,75 @@
|
||||
{#
|
||||
# Thank You / Order Confirmation (Bootstrap 5 Override)
|
||||
#
|
||||
# HPOS compatible: uses WC_Order object methods only, no $post global.
|
||||
#
|
||||
# Expected context:
|
||||
# order - WC_Order object (or null on failure)
|
||||
#
|
||||
# WooCommerce PHP equivalent: checkout/thankyou.php
|
||||
#
|
||||
# @package WcBootstrap
|
||||
# @since 0.1.0
|
||||
#}
|
||||
|
||||
{{ do_action('woocommerce_before_thankyou') }}
|
||||
|
||||
{% if order is defined and order %}
|
||||
{% if order.has_status('failed') %}
|
||||
<div class="alert alert-danger mb-4" role="alert">
|
||||
<p class="mb-0">
|
||||
{{ __('Unfortunately your order cannot be processed as the originating bank/merchant has declined your transaction. Please attempt your purchase again.') }}
|
||||
</p>
|
||||
</div>
|
||||
<p>
|
||||
<a href="{{ order.get_checkout_payment_url()|esc_url }}" class="btn btn-outline-primary">
|
||||
{{ __('Pay') }}
|
||||
</a>
|
||||
</p>
|
||||
{% else %}
|
||||
<div class="alert alert-success mb-4" role="alert">
|
||||
<i class="bi bi-check-circle me-2" aria-hidden="true"></i>
|
||||
{% include 'checkout/order-received.html.twig' with { order: order } %}
|
||||
</div>
|
||||
|
||||
<div class="card shadow-sm mb-4">
|
||||
<div class="card-header">
|
||||
<h2 class="h5 mb-0">{{ __('Order details') }}</h2>
|
||||
</div>
|
||||
<ul class="list-group list-group-flush">
|
||||
<li class="list-group-item d-flex justify-content-between">
|
||||
<span class="text-body-secondary">{{ __('Order number:') }}</span>
|
||||
<strong>{{ order.get_order_number() }}</strong>
|
||||
</li>
|
||||
<li class="list-group-item d-flex justify-content-between">
|
||||
<span class="text-body-secondary">{{ __('Date:') }}</span>
|
||||
<strong>{{ order.get_date_created().date_i18n(wc_date_format()) }}</strong>
|
||||
</li>
|
||||
{% if order.get_billing_email() %}
|
||||
<li class="list-group-item d-flex justify-content-between">
|
||||
<span class="text-body-secondary">{{ __('Email:') }}</span>
|
||||
<strong>{{ order.get_billing_email()|esc_html }}</strong>
|
||||
</li>
|
||||
{% endif %}
|
||||
<li class="list-group-item d-flex justify-content-between">
|
||||
<span class="text-body-secondary">{{ __('Total:') }}</span>
|
||||
<strong>{{ order.get_formatted_order_total()|raw }}</strong>
|
||||
</li>
|
||||
{% if order.get_payment_method_title() %}
|
||||
<li class="list-group-item d-flex justify-content-between">
|
||||
<span class="text-body-secondary">{{ __('Payment method:') }}</span>
|
||||
<strong>{{ order.get_payment_method_title()|esc_html }}</strong>
|
||||
</li>
|
||||
{% endif %}
|
||||
</ul>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{{ do_action('woocommerce_thankyou_' ~ order.get_payment_method(), order.get_id()) }}
|
||||
{{ do_action('woocommerce_thankyou', order.get_id()) }}
|
||||
{% else %}
|
||||
<div class="alert alert-success mb-4" role="alert">
|
||||
<i class="bi bi-check-circle me-2" aria-hidden="true"></i>
|
||||
{% include 'checkout/order-received.html.twig' %}
|
||||
</div>
|
||||
{% endif %}
|
||||
Reference in New Issue
Block a user