Add Bootstrap 5 product archive with card grid and sidebar

Replace WooCommerce's default shop/category page rendering with a
Bootstrap 5 card grid layout featuring responsive columns, sale badges,
star ratings, and an offcanvas sidebar for filters on mobile.

Key implementation details:

- Bypass parent theme's TemplateController for product archives via
  wp_bootstrap_should_render_template filter, render at template_redirect
  priority 11 using the same page shell injection pattern as plugin pages

- Add archive-product.php (Bootstrap layout with optional sidebar) and
  content-product.php (PHP bridge for wc_get_template_part interception)

- Inject global $product into Twig context in TemplateOverride to fix
  empty price/add-to-cart/rating/sale-flash in loop sub-templates — Twig
  has isolated variable scopes and cannot access PHP globals directly

- Fix pagination URLs: use get_pagenum_link() instead of ?page= query
  param (WordPress uses 'paged' for archive pagination, not 'page')

- Fix double-escaped – in result count by adding |raw filter

- Reset WooCommerce float-based layout CSS (woocommerce-layout.css) for
  shop pages to prevent conflicts with Bootstrap flex grid

- Register shop-sidebar widget area with Bootstrap-styled markup

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-02-28 15:06:33 +01:00
parent 7034134678
commit 00872a6568
9 changed files with 416 additions and 23 deletions

View File

@@ -109,6 +109,104 @@
width: 100%;
}
/* Product link wrapping card content — remove underline, inherit text color */
.product.card a.woocommerce-LoopProduct-link {
text-decoration: none;
color: inherit;
}
/* Product title in card body */
.product.card .woocommerce-loop-product__title {
font-size: 1rem;
font-weight: 600;
margin-bottom: 0.5rem;
}
/* Push price to bottom of card body for even card heights */
.product.card .card-body .price {
margin-top: auto;
}
/* Add-to-cart button — Bootstrap btn-outline-primary style */
.product.card .button {
display: inline-block;
width: 100%;
font-weight: 400;
line-height: 1.5;
text-align: center;
text-decoration: none;
vertical-align: middle;
cursor: pointer;
padding: 0.375rem 0.75rem;
font-size: 0.875rem;
border-radius: var(--bs-border-radius);
color: var(--bs-primary);
border: var(--bs-border-width) solid var(--bs-primary);
background-color: transparent;
transition: color 0.15s ease-in-out, background-color 0.15s ease-in-out, border-color 0.15s ease-in-out;
}
.product.card .button:hover {
color: #fff;
background-color: var(--bs-primary);
border-color: var(--bs-primary);
}
/* "View options" button for variable products */
.product.card .button.product_type_variable {
color: var(--bs-secondary);
border-color: var(--bs-secondary);
}
.product.card .button.product_type_variable:hover {
color: #fff;
background-color: var(--bs-secondary);
border-color: var(--bs-secondary);
}
/* "Read more" button for external/non-purchasable products */
.product.card .button.product_type_external {
color: var(--bs-info);
border-color: var(--bs-info);
}
.product.card .button.product_type_external:hover {
color: #fff;
background-color: var(--bs-info);
border-color: var(--bs-info);
}
/* Added-to-cart visual feedback */
.product.card .added_to_cart {
display: inline-block;
width: 100%;
text-align: center;
font-size: 0.875rem;
margin-top: 0.5rem;
color: var(--bs-success);
text-decoration: none;
}
/* WooCommerce result count and ordering bar */
.woocommerce-result-count {
margin-bottom: 0;
line-height: 2.5;
}
.woocommerce-ordering select {
display: inline-block;
padding: 0.375rem 2.25rem 0.375rem 0.75rem;
font-size: 0.875rem;
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;
appearance: auto;
}
/* ==========================================================================
Sale Badge
Positioning for the sale overlay badge on product cards.
@@ -179,12 +277,37 @@
}
/* ==========================================================================
WooCommerce Grid Override
Reset WooCommerce's default grid to let Bootstrap handle layout.
Shop / Archive Layout
Reset WooCommerce's default float grid to let Bootstrap handle layout.
Override woocommerce-layout.css float-based widths and clearfixes.
========================================================================== */
.woocommerce ul.products {
display: contents;
/* Reset float-based result count / ordering bar — use flexbox instead */
.post-type-archive-product .woocommerce-result-count,
.tax-product_cat .woocommerce-result-count,
.tax-product_tag .woocommerce-result-count,
.post-type-archive-product .woocommerce-ordering,
.tax-product_cat .woocommerce-ordering,
.tax-product_tag .woocommerce-ordering {
float: none;
}
/* Reset WooCommerce's product grid floats and widths */
.woocommerce ul.products,
.woocommerce .products {
list-style: none;
padding: 0;
margin: 0;
width: 100%;
clear: both;
}
.woocommerce ul.products li.product,
.woocommerce .products .product {
float: none;
width: auto;
margin: 0;
padding: 0;
}
/* ==========================================================================
@@ -285,7 +408,10 @@ header.sticky-top.is-stuck {
.woocommerce-account main .woocommerce,
.woocommerce-cart main .woocommerce,
.woocommerce-checkout main .woocommerce {
.woocommerce-checkout main .woocommerce,
.post-type-archive-product main .woocommerce,
.tax-product_cat main .woocommerce,
.tax-product_tag main .woocommerce {
max-width: none;
}