From 784b400c46c2922b52c6b5dffe525ecf11cd09ad Mon Sep 17 00:00:00 2001 From: magdev Date: Sun, 1 Mar 2026 03:33:31 +0100 Subject: [PATCH] Fix 10 known bugs: catalog, single product, and account pages (v0.1.5) Catalog: page title via woocommerce_page_title(), breadcrumbs, category template rename (underscore), 3-column grid, single chevron on sort. Single product: variable form data attributes + disabled CSS class fix (WC JS only toggles CSS classes, not HTML disabled attribute), dark mode select specificity (0,5,1) to beat WC's (0,4,3) background shorthand, gallery main image in thumbnail strip with empty URL guard, related/ upsells setup_postdata for correct global $product, grouped product loop logic rewrite. Account: downloads via wc_get_customer_available_downloads(). New: product-gallery.js, sanitize_title filter, wc_setup_product_data() and wp_reset_postdata() Twig functions, product-thumbnails.html.twig suppressor. Removed obsolete PLAN.md and SETUP.md. Co-Authored-By: Claude Opus 4.6 --- .gitignore | 1 + CHANGELOG.md | 29 + CLAUDE.md | 60 +- PLAN.md | 652 ------------------ README.md | 10 +- SETUP.md | 182 ----- assets/css/wc-bootstrap.css | 31 +- assets/js/product-gallery.js | 56 ++ functions.php | 13 +- inc/Twig/WooCommerceExtension.php | 28 + style.css | 2 +- ...tml.twig => content-product_cat.html.twig} | 0 templates/loop/header.html.twig | 11 +- templates/loop/loop-start.html.twig | 2 +- templates/myaccount/downloads.html.twig | 1 + .../add-to-cart/grouped.html.twig | 56 +- .../add-to-cart/variable.html.twig | 46 +- .../variation-add-to-cart-button.html.twig | 3 +- .../single-product/product-image.html.twig | 48 +- .../product-thumbnails.html.twig | 13 + templates/single-product/related.html.twig | 6 +- templates/single-product/up-sells.html.twig | 6 +- woocommerce/archive-product.php | 6 + 23 files changed, 340 insertions(+), 922 deletions(-) delete mode 100644 PLAN.md delete mode 100644 SETUP.md create mode 100644 assets/js/product-gallery.js rename templates/{content-product-cat.html.twig => content-product_cat.html.twig} (100%) create mode 100644 templates/single-product/product-thumbnails.html.twig 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 (`