diff --git a/.gitignore b/.gitignore index b9d8a2c..559310b 100644 --- a/.gitignore +++ b/.gitignore @@ -34,3 +34,4 @@ releases/ # Docker runtime .env +KNOWN_BUGS.md diff --git a/CHANGELOG.md b/CHANGELOG.md index 47651a6..cd42f6f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,35 @@ All notable changes to this project will be documented in this file. +## [0.1.5] - 2026-03-01 + +### Fixed + +- **Empty page title on catalog pages** (`header.html.twig`): Replaced `page_title` context variable (never passed by WC) with direct `fn('woocommerce_page_title', false)` call +- **Missing breadcrumbs on catalog pages** (`archive-product.php`): Added `woocommerce_breadcrumb()` call before shop loop header +- **Missing product categories on catalog pages** (`content-product-cat.html.twig`): Renamed template from hyphen (`content-product-cat`) to underscore (`content-product_cat`) to match WC's `wc_get_template()` filename convention +- **Product grid 4 columns instead of 3** (`functions.php`, `loop-start.html.twig`): Changed default columns from 4 to 3 for better card proportions with sidebar +- **Double chevron on sort dropdown** (`wc-bootstrap.css`): Removed conflicting `appearance: auto` rule; set `appearance: none` to let Bootstrap's `form-select` class handle the dropdown arrow exclusively +- **Variable product add-to-cart button stays disabled** (`variable.html.twig`, `variation-add-to-cart-button.html.twig`): Added missing `data-product_id` and `data-product_variations` attributes to form; replaced HTML `disabled` attribute on button with CSS classes `disabled wc-variation-selection-needed` (WC JS only toggles CSS classes, never removes the HTML attribute) +- **Variable product select white background in dark mode** (`wc-bootstrap.css`): Increased dark mode override specificity to `(0,5,1)` to beat WC's `.woocommerce div.product form.cart .variations select` at `(0,4,3)` which uses `background` shorthand; also overrides `background-image` for Bootstrap's dark-mode-aware chevron SVG +- **Product gallery missing main image in thumbnail strip** (`product-image.html.twig`): Prepend main image ID to gallery IDs using `[post_thumbnail_id]|merge(gallery_image_ids)` with active state on first thumbnail; added `{% if thumb_url %}` guard to skip invalid attachment IDs +- **Related/upsells products show same product repeated** (`related.html.twig`, `up-sells.html.twig`): Added `wc_setup_product_data()` call before each product render and `wp_reset_postdata()` after loop to set global `$product` correctly for WC hooks +- **Grouped product add-to-cart button/pricing broken** (`grouped.html.twig`): Rewrote template to compute `quantites_required` and `show_add_to_cart_button` in loop (matching WC PHP logic); moved hidden `add-to-cart` input outside conditional; added `has_options()` and `is_sold_individually()` checks +- **Downloads page empty** (`downloads.html.twig`): Replaced fragile `fn('WC').customer.get_downloadable_products()` chain with direct `fn('wc_get_customer_available_downloads', get_current_user_id())` call + +### Added + +- **Product gallery JS** (`product-gallery.js`): Vanilla JS click handler for thumbnail-to-main-image swap with active state highlighting and gallery fade-in +- **`wc_setup_product_data()` Twig function** (`WooCommerceExtension.php`): Sets `$GLOBALS['product']` and calls `setup_postdata()` for correct product context in Twig loops +- **`wp_reset_postdata` Twig function** (`WooCommerceExtension.php`): Restores global post state after product loops +- **`sanitize_title` Twig filter** (`WooCommerceExtension.php`): Matches WC PHP's lowercase attribute name handling for variation form data attributes +- **Product thumbnails suppressor** (`product-thumbnails.html.twig`): Empty template override to prevent WC's default full-size gallery images rendering below custom thumbnail row + +### Changed + +- **Whitelisted functions** (`WooCommerceExtension.php`): Added `woocommerce_page_title` and `wc_get_customer_available_downloads` to `ALLOWED_FUNCTIONS` +- **Removed obsolete files**: Deleted `PLAN.md` and `SETUP.md` (superseded by CLAUDE.md) + ## [0.1.4] - 2026-03-01 ### Security diff --git a/CLAUDE.md b/CLAUDE.md index 406127c..4378911 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -237,6 +237,24 @@ Recurring bugs and non-obvious behaviours discovered across sessions. **Read thi - **WooCommerce float layout fights Bootstrap grid** -- `div.product div.images/summary` have `float:left/right; width:48%` in `woocommerce-layout.css`. Override with `float: none; width: 100%`. - **Bootstrap `g-*` gutters add negative top margin** -- `g-4` sets both `--bs-gutter-x` and `--bs-gutter-y`; the `.row` gets `margin-top: calc(-1 * var(--bs-gutter-y))` pulling it upward. Use `gx-*` for horizontal-only gutters when vertical gap isn't desired. +### WooCommerce Variation JS + +- **NEVER use HTML `disabled` attribute on the add-to-cart button.** WC's `add-to-cart-variation.js` only manages CSS classes (`disabled`, `wc-variation-selection-needed`) via jQuery `.addClass()`/`.removeClass()`. It never removes the HTML `disabled` attribute. The HTML attribute prevents click events from firing, making the button permanently unclickable. +- Use CSS classes `disabled wc-variation-selection-needed` instead. WC's `onAddToCart` handler checks `$button.is('.disabled')` (CSS class), not the HTML property. +- WC variation form requires `data-product_id` and `data-product_variations` on `
`. Without these, the JS doesn't initialize. +- Attribute select `name` and `data-attribute_name` must use `sanitize_title()` on the attribute name (lowercase, hyphens) to match the keys in the variation JSON data. + +### WooCommerce Variation Select CSS Specificity + +- WC's `.woocommerce div.product form.cart .variations select` at specificity `(0,4,3)` uses `background` shorthand — this resets BOTH `background-color` and `background-image`. A dark mode override must exceed `(0,4,3)` AND override `background-image` with `var(--bs-form-select-bg-img)` for Bootstrap's dark-mode-aware chevron SVG. +- Previous selector `[data-bs-theme="dark"] .variations .form-select` at `(0,3,0)` lost the specificity battle. + +### WooCommerce Gallery Data Integrity + +- `_product_image_gallery` post meta may contain IDs pointing to product variations or other non-attachment posts instead of image attachments. `wp_get_attachment_url()` returns empty/false for these. +- Always guard thumbnail rendering with `{% if thumb_url %}` after calling `wp_get_attachment_url(image_id)`. +- The main product image should be prepended to the gallery strip so users can switch back to it after viewing gallery images. + ### Double Heading Prevention - Parent theme (`wp-bootstrap`) conditionally skips its `

` when `post.title` is empty. @@ -327,10 +345,50 @@ The child theme inherits from `wp-bootstrap` via WordPress `Template: wp-bootstr ## Version History -Current version: **v0.1.4** +Current version: **v0.1.5** ## Session History +### 2026-03-01 — v0.1.5 Fix 10 Known Bugs + +**Scope:** Fixed all 10 bugs from KNOWN_BUGS.md — catalog page features (title, breadcrumbs, categories, filters, sort dropdown), single product fixes (variable form, gallery, related products, grouped products), and downloads page. + +**Files changed (17):** + +- `inc/Twig/WooCommerceExtension.php` — Added `woocommerce_page_title` and `wc_get_customer_available_downloads` to `ALLOWED_FUNCTIONS`; added `wc_setup_product_data()` method, `wp_reset_postdata` Twig function, and `sanitize_title` Twig filter +- `templates/single-product/add-to-cart/variable.html.twig` — Added `data-product_id` and `data-product_variations` attributes to form; applied `sanitize_title` filter on attribute names for variation matching +- `templates/single-product/add-to-cart/variation-add-to-cart-button.html.twig` — Removed HTML `disabled` attribute, replaced with CSS classes `disabled wc-variation-selection-needed` (WC JS only manages CSS classes, never the HTML attribute) +- `templates/single-product/product-image.html.twig` — Prepend main image to gallery thumbnail strip; added `{% if thumb_url %}` guard for invalid attachment IDs +- `templates/single-product/product-thumbnails.html.twig` — New empty override to suppress WC's default full-size gallery images +- `templates/single-product/related.html.twig` — Added `wc_setup_product_data()` before each product render + `wp_reset_postdata()` after loop +- `templates/single-product/up-sells.html.twig` — Same setup_postdata fix as related.html.twig +- `templates/single-product/add-to-cart/grouped.html.twig` — Rewrote to compute `quantites_required`/`show_add_to_cart_button` in loop (matching WC PHP); moved hidden input outside conditional; added `has_options()` and `is_sold_individually()` checks +- `templates/loop/header.html.twig` — Replaced `page_title` context variable with direct `fn('woocommerce_page_title', false)` call +- `woocommerce/archive-product.php` — Added `woocommerce_breadcrumb()` call before shop loop header +- `functions.php` — Changed loop columns from 4 to 3; added product gallery JS conditional enqueue +- `templates/loop/loop-start.html.twig` — Changed default columns from 4 to 3 +- `assets/css/wc-bootstrap.css` — Replaced duplicate ordering select rules with `appearance: none`; increased dark mode variation select specificity to `(0,5,1)` to beat WC's `(0,4,3)` background shorthand +- `templates/content-product-cat.html.twig` — Renamed to `content-product_cat.html.twig` (WC uses underscore) +- `assets/js/product-gallery.js` — New: thumbnail click-to-swap, gallery fade-in, active state highlighting +- `templates/myaccount/downloads.html.twig` — Replaced `fn('WC').customer.get_downloadable_products()` with direct `fn('wc_get_customer_available_downloads', get_current_user_id())` +- `style.css` — Version bump 0.1.4 → 0.1.5 + +**Key decisions:** + +- **`wc_setup_product_data()` over PHP bridge:** Adding a Twig function that sets `$GLOBALS['product']` + `setup_postdata()` is simpler and more maintainable than creating PHP bridge files for related/upsells rendering +- **`json_encode|esc_attr` over `wc_esc_json`:** Avoids adding a custom filter; `esc_attr` performs the same HTML entity encoding as `wc_esc_json` +- **3 columns default:** With sidebar taking `col-lg-3`, 3 product columns in `col-lg-9` gives better card proportions than 4 +- **Vanilla JS gallery:** Lightweight click-to-swap handler instead of WC's built-in flexslider/photoswipe (which requires specific PHP setup for `wp_get_attachment_image_src` data attributes) +- **CSS class `disabled` over HTML `disabled` attribute:** WC's `add-to-cart-variation.js` `onShow`/`onHide` only toggle CSS classes (`disabled`, `wc-variation-selection-needed`). The `onAddToCart` handler checks `.is('.disabled')`. Using the HTML `disabled` attribute prevents click events entirely and WC JS never removes it. +- **CSS specificity `(0,5,1)` for dark mode selects:** WC's `.woocommerce div.product form.cart .variations select` at `(0,4,3)` uses `background` shorthand which resets `background-color` and `background-image`. Must exceed this specificity AND override `background-image` for Bootstrap's dark-mode SVG chevron. + +**Key findings (WC variation JS):** + +- WC's `add-to-cart-variation.js` event flow: `onChange` → `check_variations` → `findMatchingVariations` → `found_variation` → `onFoundVariation` (300ms setTimeout) → `show_variation` → `onShow` (removes CSS class only) +- `onShow` calls `$button.removeClass('disabled wc-variation-selection-needed')` — never touches the HTML `disabled` attribute/property +- `onAddToCart` checks `$button.is('.disabled')` — CSS class, not HTML attribute +- Gallery `_product_image_gallery` meta may contain IDs of product variations or posts instead of image attachments — always guard with `{% if thumb_url %}` after `wp_get_attachment_url()` + ### 2026-03-01 — v0.1.4 Security Audit & Performance Fixes **Scope:** Cross-theme security audit (12 findings), all fixed. Covers fn() whitelist, notice data escaping, search query escaping, per-request context caching, shared render helper, and unused constant removal. diff --git a/PLAN.md b/PLAN.md deleted file mode 100644 index 7443a12..0000000 --- a/PLAN.md +++ /dev/null @@ -1,652 +0,0 @@ -# WooCommerce to Bootstrap 5 -- Template Conversion Plan - -This document outlines the full plan for converting WooCommerce's default templates into Bootstrap 5 themed Twig overrides within the `wc-bootstrap` child theme. - -## Scope - -**Source:** 233 WooCommerce PHP/HTML templates in `wp-content/plugins/woocommerce/templates/` -**Target:** Twig template overrides in `wp-content/themes/wc-bootstrap/templates/` -**Design system:** Bootstrap 5.3 (loaded via parent theme `wp-bootstrap`) - -The plugin is **read-only** -- we never modify WooCommerce source. All customisation happens through Twig template overrides via `TemplateOverride::prependPath()` and WordPress hooks in `functions.php`. - ---- - -## Existing Scaffold (v0.1.0) - -Already in place: - -| File | Purpose | -| ---- | ------- | -| `templates/base.html.twig` | Conditional wrapper (`_theme_wrapped` detection) | -| `templates/layouts/account.html.twig` | My Account layout shell | -| `templates/layouts/archive.html.twig` | Product archive / search layout | -| `templates/layouts/form.html.twig` | Centered form layout (card + shadow) | -| `templates/layouts/page.html.twig` | Generic content page | -| `templates/layouts/single.html.twig` | Detail page (8+4 grid) | -| `templates/components/card.html.twig` | Reusable product/post card | -| `templates/components/pagination.html.twig` | Bootstrap pagination nav | -| `inc/TemplateOverride.php` | Twig loader hook | -| `functions.php` | Style chain, render filter, wrapping signal | -| `assets/css/wc-bootstrap.css` | Button/alert/dark-mode overrides | - ---- - -## Conversion Phases - -### Phase 1 -- Global & Notices (Foundation) - -Templates that appear on every WooCommerce page. Must be done first because all other templates depend on them. - -#### 1.1 Global Templates - -| WooCommerce Template | Theme Override | Bootstrap 5 Mapping | -| -------------------- | -------------- | -------------------- | -| `global/wrapper-start.php` | `global/wrapper-start.html.twig` | `
` (or skip if `_theme_wrapped`) | -| `global/wrapper-end.php` | `global/wrapper-end.html.twig` | Closing `
` | -| `global/breadcrumb.php` | `global/breadcrumb.html.twig` | `nav[aria-label] > ol.breadcrumb > li.breadcrumb-item` | -| `global/sidebar.php` | `global/sidebar.html.twig` | `aside.col-lg-3` with `offcanvas-lg` for mobile | -| `global/quantity-input.php` | `global/quantity-input.html.twig` | `input-group` with `btn-outline-secondary` +/- buttons | -| `global/form-login.php` | `global/form-login.html.twig` | Extend `layouts/form.html.twig`, `form-control`, `form-label` | - -#### 1.2 Notice Templates - -| WooCommerce Template | Theme Override | Bootstrap 5 Mapping | -| -------------------- | -------------- | -------------------- | -| `notices/notice.php` | `notices/notice.html.twig` | `alert alert-info alert-dismissible fade show` | -| `notices/error.php` | `notices/error.html.twig` | `alert alert-danger alert-dismissible fade show` | -| `notices/success.php` | `notices/success.html.twig` | `alert alert-success alert-dismissible fade show` | - -**Notes:** - -- Notices must support multiple messages (WooCommerce passes arrays) -- Include `btn-close` with `data-bs-dismiss="alert"` -- Respect dark mode via Bootstrap's adaptive colour utilities - ---- - -### Phase 2 -- Product Archive & Shop Loop (Storefront) - -The shop page, category pages, and product grid. This is the main entry point for customers. - -#### 2.1 Archive Container - -| WooCommerce Template | Theme Override | Bootstrap 5 Mapping | -| -------------------- | -------------- | -------------------- | -| `archive-product.php` | `archive-product.html.twig` | Extend `layouts/archive.html.twig`; 3+9 grid (filter sidebar + products) | -| `content-product.php` | `content-product.html.twig` | Extend `components/card.html.twig`; product card in grid | -| `content-product-cat.php` | `content-product-cat.html.twig` | Category card with thumbnail | -| `product-searchform.php` | `product-searchform.html.twig` | `input-group` with `form-control` + `btn btn-outline-primary` | - -#### 2.2 Loop Components - -| WooCommerce Template | Theme Override | Bootstrap 5 Mapping | -| -------------------- | -------------- | -------------------- | -| `loop/loop-start.php` | `loop/loop-start.html.twig` | `
` | -| `loop/loop-end.php` | `loop/loop-end.html.twig` | `
` | -| `loop/header.php` | `loop/header.html.twig` | Flex row: result-count left, orderby right | -| `loop/result-count.php` | `loop/result-count.html.twig` | `

` | -| `loop/orderby.php` | `loop/orderby.html.twig` | `form-select form-select-sm` in flex container | -| `loop/pagination.php` | `loop/pagination.html.twig` | Delegate to `components/pagination.html.twig` | -| `loop/no-products-found.php` | `loop/no-products-found.html.twig` | `alert alert-info` with icon | -| `loop/add-to-cart.php` | `loop/add-to-cart.html.twig` | `btn btn-primary btn-sm w-100` | -| `loop/price.php` | `loop/price.html.twig` | `` (sale: `text-decoration-line-through text-body-secondary` + `text-danger`) | -| `loop/rating.php` | `loop/rating.html.twig` | Bootstrap Icons stars (`bi-star-fill`, `bi-star`) | -| `loop/sale-flash.php` | `loop/sale-flash.html.twig` | `badge bg-danger position-absolute top-0 start-0 m-2` | - ---- - -### Phase 3 -- Single Product Page - -The product detail page, including gallery, variations, tabs, and related products. - -#### 3.1 Product Layout - -| WooCommerce Template | Theme Override | Bootstrap 5 Mapping | -| -------------------- | -------------- | -------------------- | -| `single-product/product-image.php` | `single-product/product-image.html.twig` | Main image + thumbnail row; `img-fluid rounded`; lightbox via PhotoSwipe or Bootstrap modal | -| `single-product/title.php` | `single-product/title.html.twig` | `

` | -| `single-product/price.php` | `single-product/price.html.twig` | `fs-3 fw-bold`; sale styling as in loop | -| `single-product/short-description.php` | `single-product/short-description.html.twig` | `
` | -| `single-product/meta.php` | `single-product/meta.html.twig` | `
` with `col-sm-3`/`col-sm-9` pairs | -| `single-product/rating.php` | `single-product/rating.html.twig` | Stars + link to reviews tab | -| `single-product/stock.php` | `single-product/stock.html.twig` | `badge bg-success` (in stock) / `badge bg-danger` (out of stock) | -| `single-product/sale-flash.php` | `single-product/sale-flash.html.twig` | `badge bg-danger fs-6` | -| `single-product/share.php` | `single-product/share.html.twig` | `btn-group` with Bootstrap Icon buttons | -| `single-product/product-attributes.php` | `single-product/product-attributes.html.twig` | `table table-sm table-striped` | -| `single-product/related.php` | `single-product/related.html.twig` | Section heading + `row row-cols-2 row-cols-lg-4 g-4` of cards | -| `single-product/up-sells.php` | `single-product/up-sells.html.twig` | Same grid as related | - -#### 3.2 Add to Cart Forms - -| WooCommerce Template | Theme Override | Bootstrap 5 Mapping | -| -------------------- | -------------- | -------------------- | -| `single-product/add-to-cart/simple.php` | `single-product/add-to-cart/simple.html.twig` | `input-group` (quantity) + `btn btn-primary btn-lg` | -| `single-product/add-to-cart/variable.php` | `single-product/add-to-cart/variable.html.twig` | `form-select` per attribute + quantity + button | -| `single-product/add-to-cart/grouped.php` | `single-product/add-to-cart/grouped.html.twig` | `table table-borderless` with quantity inputs per item | -| `single-product/add-to-cart/external.php` | `single-product/add-to-cart/external.html.twig` | `btn btn-outline-primary btn-lg` with external link icon | -| `single-product/add-to-cart/variation.php` | `single-product/add-to-cart/variation.html.twig` | Variation data container (hidden, JS-driven) | -| `single-product/add-to-cart/variation-add-to-cart-button.php` | `single-product/add-to-cart/variation-add-to-cart-button.html.twig` | Same as simple but variation-aware | - -#### 3.3 Product Tabs - -| WooCommerce Template | Theme Override | Bootstrap 5 Mapping | -| -------------------- | -------------- | -------------------- | -| `single-product/tabs/tabs.php` | `single-product/tabs/tabs.html.twig` | `nav nav-tabs` + `tab-content` with `tab-pane fade` | -| `single-product/tabs/description.php` | `single-product/tabs/description.html.twig` | `tab-pane` with prose content | -| `single-product/tabs/additional-information.php` | `single-product/tabs/additional-information.html.twig` | `tab-pane` with attributes table | - ---- - -### Phase 4 -- Cart - -The cart page with item management, shipping calculator, and totals. - -| WooCommerce Template | Theme Override | Bootstrap 5 Mapping | -| -------------------- | -------------- | -------------------- | -| `cart/cart.php` | `cart/cart.html.twig` | `row`: `col-lg-8` (items table) + `col-lg-4` (totals sidebar) | -| `cart/cart-empty.php` | `cart/cart-empty.html.twig` | Centred `alert alert-info` + `btn btn-primary` to shop | -| `cart/cart-item-data.php` | `cart/cart-item-data.html.twig` | `
` | -| `cart/cart-totals.php` | `cart/cart-totals.html.twig` | `card` with `list-group list-group-flush` rows | -| `cart/cart-shipping.php` | `cart/cart-shipping.html.twig` | `form-check` radio buttons per shipping method | -| `cart/cross-sells.php` | `cart/cross-sells.html.twig` | Section below cart; `row row-cols-2 row-cols-md-4 g-3` of small cards | -| `cart/mini-cart.php` | `cart/mini-cart.html.twig` | `offcanvas offcanvas-end` slide-in panel | -| `cart/proceed-to-checkout-button.php` | `cart/proceed-to-checkout-button.html.twig` | `btn btn-primary btn-lg w-100` | -| `cart/shipping-calculator.php` | `cart/shipping-calculator.html.twig` | Collapsible form (`collapse`) with `form-select` for country/state | - -**Cart Table Structure:** - -```html -
- - - - - - - - - - - -
ProductPriceQuantitySubtotal
-
-``` - ---- - -### Phase 5 -- Checkout - -The checkout flow including billing/shipping forms, order review, and payment. - -| WooCommerce Template | Theme Override | Bootstrap 5 Mapping | -| -------------------- | -------------- | -------------------- | -| `checkout/form-checkout.php` | `checkout/form-checkout.html.twig` | `row`: `col-lg-7` (forms) + `col-lg-5` (order review, sticky) | -| `checkout/form-billing.php` | `checkout/form-billing.html.twig` | `card mb-4` with `form-control`, `form-label`, `form-select` fields | -| `checkout/form-shipping.php` | `checkout/form-shipping.html.twig` | Same card style; `form-check` for "ship to different address" toggle | -| `checkout/form-coupon.php` | `checkout/form-coupon.html.twig` | `input-group` inline: `form-control` + `btn btn-outline-secondary` | -| `checkout/form-login.php` | `checkout/form-login.html.twig` | Collapsible (`collapse`) login form above checkout | -| `checkout/review-order.php` | `checkout/review-order.html.twig` | `card` with `table table-sm` for items + `list-group` for totals | -| `checkout/payment.php` | `checkout/payment.html.twig` | `list-group` of `form-check` radio items per gateway; `btn btn-primary btn-lg w-100` place order | -| `checkout/payment-method.php` | `checkout/payment-method.html.twig` | `list-group-item` with radio + label + description collapse | -| `checkout/terms.php` | `checkout/terms.html.twig` | `form-check` checkbox with link to terms page | -| `checkout/thankyou.php` | `checkout/thankyou.html.twig` | `alert alert-success` + order details card | -| `checkout/order-received.php` | `checkout/order-received.html.twig` | Confirmation message with order summary | -| `checkout/cart-errors.php` | `checkout/cart-errors.html.twig` | `alert alert-danger` list | - ---- - -### Phase 6 -- My Account Dashboard - -The customer account area with orders, addresses, and account management. - -#### 6.1 Account Shell - -| WooCommerce Template | Theme Override | Bootstrap 5 Mapping | -| -------------------- | -------------- | -------------------- | -| `myaccount/my-account.php` | `myaccount/my-account.html.twig` | Extend `layouts/account.html.twig`; 3+9 grid (nav + content) | -| `myaccount/navigation.php` | `myaccount/navigation.html.twig` | `list-group` in sticky sidebar (desktop) / `nav nav-pills` (mobile) | -| `myaccount/dashboard.php` | `myaccount/dashboard.html.twig` | Welcome card + quick links as `row row-cols-1 row-cols-md-3 g-3` | - -#### 6.2 Orders - -| WooCommerce Template | Theme Override | Bootstrap 5 Mapping | -| -------------------- | -------------- | -------------------- | -| `myaccount/orders.php` | `myaccount/orders.html.twig` | `table-responsive` > `table table-hover` with status badges | -| `myaccount/view-order.php` | `myaccount/view-order.html.twig` | Order details card + address cards row | - -#### 6.3 Addresses & Account - -| WooCommerce Template | Theme Override | Bootstrap 5 Mapping | -| -------------------- | -------------- | -------------------- | -| `myaccount/my-address.php` | `myaccount/my-address.html.twig` | `row row-cols-1 row-cols-md-2 g-4`; billing + shipping cards | -| `myaccount/form-edit-address.php` | `myaccount/form-edit-address.html.twig` | `card` form with `form-control`, `form-select` | -| `myaccount/form-edit-account.php` | `myaccount/form-edit-account.html.twig` | `card` form for name, email, password change | -| `myaccount/downloads.php` | `myaccount/downloads.html.twig` | `table table-striped` with download links | -| `myaccount/payment-methods.php` | `myaccount/payment-methods.html.twig` | `list-group` of saved methods with delete button | -| `myaccount/form-add-payment-method.php` | `myaccount/form-add-payment-method.html.twig` | `card` form | - -#### 6.4 Authentication - -| WooCommerce Template | Theme Override | Bootstrap 5 Mapping | -| -------------------- | -------------- | -------------------- | -| `myaccount/form-login.php` | `myaccount/form-login.html.twig` | `row row-cols-1 row-cols-md-2 g-4`: login card + register card side-by-side | -| `myaccount/form-lost-password.php` | `myaccount/form-lost-password.html.twig` | Extend `layouts/form.html.twig`; centered card | -| `myaccount/form-reset-password.php` | `myaccount/form-reset-password.html.twig` | Extend `layouts/form.html.twig`; centered card | -| `myaccount/lost-password-confirmation.php` | `myaccount/lost-password-confirmation.html.twig` | `alert alert-success` | - ---- - -### Phase 7 -- Order Details - -Order display used on thank-you page, view-order, and emails. - -| WooCommerce Template | Theme Override | Bootstrap 5 Mapping | -| -------------------- | -------------- | -------------------- | -| `order/order-details.php` | `order/order-details.html.twig` | `card` > `table-responsive` > `table` | -| `order/order-details-item.php` | `order/order-details-item.html.twig` | `` with product image thumbnail, name, quantity, price | -| `order/order-details-customer.php` | `order/order-details-customer.html.twig` | `row row-cols-1 row-cols-md-2`: billing + shipping address cards | -| `order/form-tracking.php` | `order/form-tracking.html.twig` | Extend `layouts/form.html.twig`; order ID + email fields | -| `order/order-again.php` | `order/order-again.html.twig` | `btn btn-outline-primary` | - ---- - -### Phase 8 -- Email Templates - -Email templates require special treatment: no external CSS, no Bootstrap JS, inline styles only. - -**Strategy:** Use Bootstrap's colour palette as CSS custom properties mapped to inline styles. Prefix all classes with `wc-email-` to avoid email client conflicts (per architecture decision in CLAUDE.md). - -#### 8.1 Email Shell - -| WooCommerce Template | Theme Override | Purpose | -| -------------------- | -------------- | ------- | -| `emails/email-header.php` | `emails/email-header.html.twig` | Table-based header with logo, store name | -| `emails/email-footer.php` | `emails/email-footer.html.twig` | Table-based footer with store info | -| `emails/email-styles.php` | `emails/email-styles.html.twig` | Inline CSS aligned to Bootstrap colour palette | - -#### 8.2 Email Content Components - -| WooCommerce Template | Theme Override | Purpose | -| -------------------- | -------------- | ------- | -| `emails/email-order-details.php` | `emails/email-order-details.html.twig` | Order items table | -| `emails/email-order-items.php` | `emails/email-order-items.html.twig` | Single order item row | -| `emails/email-customer-details.php` | `emails/email-customer-details.html.twig` | Customer info section | -| `emails/email-addresses.php` | `emails/email-addresses.html.twig` | Billing + shipping addresses | -| `emails/email-downloads.php` | `emails/email-downloads.html.twig` | Downloads table | - -#### 8.3 Transactional Emails (Priority Order) - -High-traffic emails first: - -1. `emails/customer-processing-order.php` -- Order confirmation -2. `emails/customer-completed-order.php` -- Order shipped/complete -3. `emails/customer-on-hold-order.php` -- Awaiting payment -4. `emails/customer-new-account.php` -- Welcome email -5. `emails/customer-reset-password.php` -- Password reset -6. `emails/customer-invoice.php` -- Invoice/receipt -7. `emails/customer-note.php` -- Order note -8. `emails/customer-refunded-order.php` -- Refund notification -9. `emails/customer-cancelled-order.php` -- Cancellation -10. `emails/customer-failed-order.php` -- Payment failure - -Admin emails: - -11. `emails/admin-new-order.php` -- New order notification -12. `emails/admin-cancelled-order.php` -- Cancellation alert -13. `emails/admin-failed-order.php` -- Payment failure alert - -#### 8.4 Plain Text Emails - -The `emails/plain/` directory contains plain-text variants. These need minimal conversion -- mainly ensuring consistent formatting and branding text. Lower priority; can be done as a batch after HTML emails. - ---- - -### Phase 9 -- Supplementary Templates - -Lower-traffic pages and edge cases. - -#### 9.1 Brands - -| WooCommerce Template | Theme Override | Bootstrap 5 Mapping | -| -------------------- | -------------- | -------------------- | -| `brands/brand-description.php` | `brands/brand-description.html.twig` | `
` with prose | -| `brands/taxonomy-product_brand.php` | `brands/taxonomy-product_brand.html.twig` | Extend `layouts/archive.html.twig` | -| `brands/shortcodes/brands-a-z.php` | `brands/shortcodes/brands-a-z.html.twig` | Letter nav + `row` grid of brand cards | -| `brands/shortcodes/single-brand.php` | `brands/shortcodes/single-brand.html.twig` | Brand card | - -#### 9.2 Auth (OAuth) - -| WooCommerce Template | Theme Override | Bootstrap 5 Mapping | -| -------------------- | -------------- | -------------------- | -| `auth/form-login.php` | `auth/form-login.html.twig` | Extend `layouts/form.html.twig` | -| `auth/form-grant-access.php` | `auth/form-grant-access.html.twig` | `card` with scope list + approve/deny buttons | - -#### 9.3 Back-in-Stock - -| WooCommerce Template | Theme Override | Bootstrap 5 Mapping | -| -------------------- | -------------- | -------------------- | -| `single-product/back-in-stock-form.php` | `single-product/back-in-stock-form.html.twig` | `card card-body` with email `input-group` | - ---- - -## CSS Strategy - -### File: `assets/css/wc-bootstrap.css` - -Additions needed per phase: - -| Phase | CSS Additions | -| ----- | ------------- | -| 1 | Quantity input-group sizing; notice icon spacing | -| 2 | Product card hover lift effect; sale badge positioning; star rating colours | -| 3 | Product gallery thumbnail grid; tab content transitions; variation swatches | -| 4 | Cart item thumbnail sizing; mini-cart offcanvas width | -| 5 | Checkout sticky sidebar offset; payment method description animation | -| 6 | Account navigation active state; order status badge colours | -| 8 | Email inline styles (separate `wc-email-*` classes, no Bootstrap dependency) | - -### WooCommerce CSS Overrides - -WooCommerce ships its own CSS that conflicts with Bootstrap. Key overrides: - -```css -/* Reset WooCommerce grid in favour of Bootstrap */ -.woocommerce ul.products { display: contents; } - -/* Ensure Bootstrap form styles take precedence */ -.woocommerce .form-row input.input-text { /* inherit from .form-control */ } - -/* Price styling consistency */ -.woocommerce .price del { @extend .text-decoration-line-through, .text-body-secondary; } -.woocommerce .price ins { text-decoration: none; @extend .text-danger, .fw-bold; } -``` - -### Dark Mode - -All templates use Bootstrap's adaptive utilities (`bg-body-tertiary`, `text-body-secondary`, `border-*`) which automatically adapt via `data-bs-theme="dark"`. No manual dark-mode CSS should be needed except for: - -- Custom sale badge colours -- Star rating fill colour -- Email templates (separate palette) - ---- - -## JavaScript Strategy - -Minimal custom JS. Bootstrap 5 JS (from parent theme) handles: - -- Offcanvas (mini-cart, mobile sidebar) -- Collapse (shipping calculator, coupon form, login form) -- Tabs (product tabs) -- Modal (image lightbox, if replacing PhotoSwipe) -- Tooltips/popovers (optional) -- Alert dismiss (notices) - -Custom JS needed for: - -| Feature | Location | Purpose | -| ------- | -------- | ------- | -| Quantity +/- buttons | `assets/js/quantity.js` | Increment/decrement input value, trigger `change` event for WC JS | -| Variation swatches | `assets/js/variations.js` | Sync Bootstrap form-select with WC variation JS (if needed) | -| Mini-cart AJAX | `assets/js/mini-cart.js` | Update offcanvas cart count after add-to-cart | -| Sticky cart totals | Inline or CSS-only | `position: sticky; top: 1rem` on checkout/cart sidebar | - ---- - -## Template Naming Convention - -All theme overrides mirror the plugin's directory structure exactly: - -```txt -woocommerce/templates/cart/cart.php - --> wc-bootstrap/templates/cart/cart.html.twig - -woocommerce/templates/single-product/tabs/tabs.php - --> wc-bootstrap/templates/single-product/tabs/tabs.html.twig -``` - ---- - -## Component Reuse Map - -Common Bootstrap patterns extracted into reusable Twig components: - -| Component | File | Used By | -| --------- | ---- | ------- | -| Product card | `components/card.html.twig` | Archive, related, cross-sells, up-sells | -| Pagination | `components/pagination.html.twig` | Archive, orders, downloads | -| Price display | `components/price.html.twig` | Loop, single product, cart, order details | -| Star rating | `components/rating.html.twig` | Loop, single product | -| Address card | `components/address-card.html.twig` | My Account addresses, order details, checkout | -| Status badge | `components/status-badge.html.twig` | Orders list, view order | -| Quantity input | `components/quantity-input.html.twig` | Cart, single product add-to-cart | -| Form field | `components/form-field.html.twig` | Checkout, account forms, address forms | - ---- - -## Order Status Badge Colours - -| Status | Bootstrap Class | -| ------ | --------------- | -| Pending | `bg-warning text-dark` | -| Processing | `bg-info text-dark` | -| On Hold | `bg-secondary` | -| Completed | `bg-success` | -| Cancelled | `bg-danger` | -| Refunded | `bg-dark` | -| Failed | `bg-danger` | - ---- - -## Accessibility Checklist - -Every template must meet: - -- [ ] Semantic HTML (`