You've already forked wc-bootstrap
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:
121
functions.php
121
functions.php
@@ -14,6 +14,7 @@ if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Define theme constants.
|
||||
*
|
||||
@@ -223,3 +224,123 @@ function wc_bootstrap_sticky_header_script(): void {
|
||||
<?php
|
||||
}
|
||||
add_action( 'wp_footer', 'wc_bootstrap_sticky_header_script' );
|
||||
|
||||
/**
|
||||
* Register the shop sidebar widget area.
|
||||
*
|
||||
* Provides a widget area for product filters and shop-specific widgets.
|
||||
* Uses Bootstrap-styled markup matching the parent theme's sidebar pattern.
|
||||
*
|
||||
* @since 0.1.0
|
||||
*/
|
||||
function wc_bootstrap_register_sidebars(): void {
|
||||
register_sidebar( array(
|
||||
'name' => __( 'Shop Sidebar', 'wc-bootstrap' ),
|
||||
'id' => 'shop-sidebar',
|
||||
'description' => __( 'Add widgets here to appear in the shop sidebar.', 'wc-bootstrap' ),
|
||||
'before_widget' => '<div id="%1$s" class="widget mb-4 %2$s">',
|
||||
'after_widget' => '</div>',
|
||||
'before_title' => '<h3 class="sidebar-heading h6 text-uppercase fw-semibold">',
|
||||
'after_title' => '</h3>',
|
||||
) );
|
||||
}
|
||||
add_action( 'widgets_init', 'wc_bootstrap_register_sidebars' );
|
||||
|
||||
/**
|
||||
* Set the number of product columns in the shop loop.
|
||||
*
|
||||
* @return int Number of columns.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
function wc_bootstrap_loop_columns(): int {
|
||||
return 4;
|
||||
}
|
||||
add_filter( 'loop_shop_columns', 'wc_bootstrap_loop_columns' );
|
||||
|
||||
/**
|
||||
* Remove WooCommerce's default sidebar hook.
|
||||
*
|
||||
* The child theme's archive-product.php renders the sidebar inline within the
|
||||
* Bootstrap grid layout, so the default woocommerce_sidebar hook must not render
|
||||
* a second sidebar outside the layout.
|
||||
*
|
||||
* @since 0.1.0
|
||||
*/
|
||||
function wc_bootstrap_remove_default_sidebar(): void {
|
||||
remove_action( 'woocommerce_sidebar', 'woocommerce_get_sidebar', 10 );
|
||||
}
|
||||
add_action( 'init', 'wc_bootstrap_remove_default_sidebar' );
|
||||
|
||||
/**
|
||||
* Prevent the parent theme from rendering product archives.
|
||||
*
|
||||
* The parent theme's TemplateController hooks template_redirect at priority 10
|
||||
* and renders pages/archive.html.twig for all archives (then exits). For product
|
||||
* archives, we need to render our own WooCommerce-specific Bootstrap layout instead.
|
||||
* Returning false tells the parent theme to skip rendering for this request.
|
||||
*
|
||||
* @param bool $should_render Whether the parent theme should render.
|
||||
* @return bool
|
||||
*
|
||||
* @since 0.1.0
|
||||
*/
|
||||
function wc_bootstrap_skip_parent_archive( bool $should_render ): bool {
|
||||
if ( is_post_type_archive( 'product' ) || is_page( wc_get_page_id( 'shop' ) ) ) {
|
||||
return false;
|
||||
}
|
||||
if ( function_exists( 'is_product_taxonomy' ) && is_product_taxonomy() ) {
|
||||
return false;
|
||||
}
|
||||
return $should_render;
|
||||
}
|
||||
add_filter( 'wp_bootstrap_should_render_template', 'wc_bootstrap_skip_parent_archive' );
|
||||
|
||||
/**
|
||||
* Render product archive pages with Bootstrap 5 layout.
|
||||
*
|
||||
* Since the parent theme's TemplateController is blocked for product archives
|
||||
* (via wp_bootstrap_should_render_template filter), we render the page ourselves
|
||||
* at priority 11 using the parent theme's TwigService and page shell.
|
||||
*
|
||||
* The archive-product.php file provides the Bootstrap layout (sidebar + product
|
||||
* grid) and is captured via output buffering, then injected into the parent
|
||||
* theme's page template — the same pattern as wc_bootstrap_render_page().
|
||||
*
|
||||
* @since 0.1.0
|
||||
*/
|
||||
function wc_bootstrap_render_product_archive(): void {
|
||||
$is_shop = is_post_type_archive( 'product' ) || is_page( wc_get_page_id( 'shop' ) );
|
||||
$is_tax = function_exists( 'is_product_taxonomy' ) && is_product_taxonomy();
|
||||
|
||||
if ( ! $is_shop && ! $is_tax ) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ( ! class_exists( '\WPBootstrap\Twig\TwigService' )
|
||||
|| ! class_exists( '\WPBootstrap\Template\ContextBuilder' ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Capture WooCommerce archive content via output buffering.
|
||||
ob_start();
|
||||
include get_stylesheet_directory() . '/archive-product.php';
|
||||
$content = ob_get_clean();
|
||||
|
||||
// Build parent theme context and inject archive content into page shell.
|
||||
$context_builder = new \WPBootstrap\Template\ContextBuilder();
|
||||
$theme_context = $context_builder->build();
|
||||
$twig = \WPBootstrap\Twig\TwigService::getInstance();
|
||||
|
||||
$theme_context['post'] = array_merge(
|
||||
$theme_context['post'] ?? [],
|
||||
[
|
||||
'content' => $content,
|
||||
'title' => '',
|
||||
'thumbnail' => '',
|
||||
]
|
||||
);
|
||||
|
||||
echo $twig->render( 'pages/page.html.twig', $theme_context );
|
||||
exit;
|
||||
}
|
||||
add_action( 'template_redirect', 'wc_bootstrap_render_product_archive', 11 );
|
||||
|
||||
Reference in New Issue
Block a user