为WooCommerce产品属性筛选器小部件添加CSS类
I understand your frustration with the layout shift caused by jQuery—let's fix this by adding the active class directly in PHP, so the browser renders the correct state immediately on page load.
Core Idea
WooCommerce tracks active filter selections in the global $_chosen_attributes variable. We can tap into this to detect if a filter widget has active selections, then modify its output to include the active class on the container div.
Method 1: Override the WooCommerce Layered Nav Widget
This is the most reliable approach, as we're directly extending the widget's logic to add our custom class.
Replace the default widget with your custom version
Add this code to your theme'sfunctions.phpfile or a custom plugin:// Replace default WooCommerce layered nav widget with our custom one add_action('widgets_init', function() { unregister_widget('WC_Widget_Layered_Nav'); register_widget('Custom_WC_Widget_Layered_Nav'); }); class Custom_WC_Widget_Layered_Nav extends WC_Widget_Layered_Nav { public function widget($args, $instance) { global $_chosen_attributes; // Get the attribute taxonomy name for this widget $attribute_slug = isset($instance['attribute']) ? wc_attribute_taxonomy_name($instance['attribute']) : ''; $is_active = false; // Check if this attribute has any selected terms if (isset($_chosen_attributes[$attribute_slug]) && !empty($_chosen_attributes[$attribute_slug]['terms'])) { $is_active = true; } // Modify the after_title markup to add the active class if needed $original_after_title = $args['after_title']; $args['after_title'] = '</h2><div' . ($is_active ? ' class="active"' : '') . '>'; // Let the parent widget render the rest of the content parent::widget($args, $instance); // Restore the original after_title to avoid breaking other widgets $args['after_title'] = $original_after_title; } }Adjust your existing
dynamic_sidebar_paramsfilter
Remove the hardcoded<div>fromafter_titlesince we're now handling it in the widget:add_filter('dynamic_sidebar_params', function($params) { $params[0]['before_widget'] = '<section class="widget">'; $params[0]['after_widget'] = '</div></section>'; $params[0]['before_title'] = '<h2 class="widget-title">'; // Remove the old after_title line here return $params; });Update your CSS
Keep your base hide rule, then target the active class to show the widget:.widget > div { display: none; } .widget > div.active { display: block; }
How This Works
- We unregister WooCommerce's default layered nav widget and register our own extended version.
- In the widget's
widget()method, we check if the current attribute has any selected terms using$_chosen_attributes. - If it's active, we modify the
after_titlemarkup to includeclass="active"on the containerdiv. - The browser renders the widget in the correct state immediately—no jQuery needed, so no layout shift.
Bonus: Handle Non-Active Widget Expansion
To let users click non-active widgets to expand them, add a bit of CSS/JS (but this won't cause layout shift since it's only for interaction):
.widget-title { cursor: pointer; }
// Optional: Toggle non-active widgets on title click document.addEventListener('DOMContentLoaded', function() { document.querySelectorAll('.widget:not(.active) .widget-title').forEach(title => { title.addEventListener('click', function() { this.nextElementSibling.style.display = this.nextElementSibling.style.display === 'block' ? 'none' : 'block'; }); }); });
This way, active widgets stay expanded by default, and users can toggle inactive ones without layout issues.
内容的提问来源于stack exchange,提问作者MrCarrot

