使用jQuery调整WooCommerce购物车产品属性显示顺序
Hey there, let's work through this WooCommerce cart attribute ordering problem you're dealing with. I see you're using multiple plugins to handle custom cabinet door specs, but the attribute order in the cart is messed up—especially when the Boring option is selected. Let's break down how to fix this properly.
The Problem in Detail
Your store uses WooCommerce for custom cabinet doors, with plugins calculating various specs. Right now, when a customer selects the Boring option, the related attributes (Boring, Unit, Specs - Distance 1/2) show up before width/height/area, which isn't ideal. When Boring isn't selected, the order is okay, but we need consistency when it is selected.
Current Cart Display
- With Boring selected:
Wood Type: Thickness of Door: Boring ($7.50): Unit: Specs - Distance 1: Specs - Distance 2: Width (in): Height (in): Total Area (sq. ft.)
Corresponding HTML:<dl class="variation"> <dt class="variation-WoodType">Wood Type:</dt> <dd class="variation-WoodType"><p>Mahogany</p></dd> <dt class="variation-ThicknessofDoor">Thickness of Door:</dt> <dd class="variation-ThicknessofDoor"><p>3/4"</p></dd> <dt class="variation-Boringspanclasswoocommerce-Price-amountamountspanclasswoocommerce-Price-currencySymbol36span750span">Boring (<span class="woocommerce-Price-amount amount"><span class="woocommerce-Price-currencySymbol">$</span>7.50</span>):</dt> <dd class="variation-Boringspanclasswoocommerce-Price-amountamountspanclasswoocommerce-Price-currencySymbol36span750span"><p>Yes</p></dd> <dt class="variation-Unit">Unit:</dt> <dd class="variation-Unit"><p>Inches</p></dd> <dt class="variation-Specs-Distance1">Specs - Distance 1:</dt> <dd class="variation-Specs-Distance1"><p>1</p></dd> <dt class="variation-Specs-Distance2">Specs - Distance 2:</dt> <dd class="variation-Specs-Distance2"><p>2</p></dd> <dt class="variation-Widthin">Width (in):</dt> <dd class="variation-Widthin"><p>13</p></dd> <dt class="variation-Heightin">Height (in):</dt> <dd class="variation-Heightin"><p>18</p></dd> <dt class="variation-TotalAreasqft">Total Area (sq. ft.):</dt> <dd class="variation-TotalAreasqft"><p>1.63</p></dd> </dl> - Without Boring selected:
Wood Type: Thickness of Door: Width (in): Height (in): Total Area (sq. ft.)
Corresponding HTML:<dl class="variation"> <dt class="variation-WoodType">Wood Type:</dt> <dd class="variation-WoodType"><p>Poplar</p></dd> <dt class="variation-ThicknessofDoor">Thickness of Door:</dt> <dd class="variation-ThicknessofDoor"><p>3/4"</p></dd> <dt class="variation-Widthin">Width (in):</dt> <dd class="variation-Widthin"><p>22</p></dd> <dt class="variation-Heightin">Height (in):</dt> <dd class="variation-Heightin"><p>22</p></dd> <dt class="variation-TotalAreasqft">Total Area (sq. ft.):</dt> <dd class="variation-TotalAreasqft"><p>3.36</p></dd> </dl>
What You Want
You want all Boring-related attributes to come after the width, height, and total area, like this:Wood Type: Thickness of Door: Width (in): Height (in): Total Area (sq. ft.): Boring ($7.50): Unit: Specs - Distance 1: Specs - Distance 2:
What You Tried (and Why It Broke)
Your initial jQuery code targeted all .variation elements globally, which is why elements from other cart items got moved into the first one. When you tried each(), you probably didn't properly scope the elements to the current cart item, leading to duplicate elements.
The Fix: Scoped jQuery for Per-Item Processing
The key is to process each cart item's variation list individually. Here's the corrected jQuery code that won't mix up elements between items:
(function ($) { // Run on page load AND after WooCommerce updates the cart via AJAX $(document).on('updated_cart_totals', reorderCartAttributes); $(reorderCartAttributes); function reorderCartAttributes() { // Loop through every variation list in the cart $('.variation').each(function() { var $currentVariation = $(this); // Grab the Total Area attribute (dt + dd) — this is our anchor point var $totalArea = $currentVariation.find('.variation-TotalAreasqft') .add($currentVariation.find('.variation-TotalAreasqft').next('dd')); // Collect all Boring-related attribute pairs (dt + dd) var $boringAttributes = $currentVariation.find('.variation-Boringspanclasswoocommerce-Price-amountamountspanclasswoocommerce-Price-currencySymbol36span750span') .add($currentVariation.find('.variation-Boringspanclasswoocommerce-Price-amountamountspanclasswoocommerce-Price-currencySymbol36span750span').next('dd')) .add($currentVariation.find('.variation-Unit')) .add($currentVariation.find('.variation-Unit').next('dd')) .add($currentVariation.find('.variation-Specs-Distance1')) .add($currentVariation.find('.variation-Specs-Distance1').next('dd')) .add($currentVariation.find('.variation-Specs-Distance2')) .add($currentVariation.find('.variation-Specs-Distance2').next('dd')); // Only move the attributes if they exist in this variation if ($boringAttributes.length) { $totalArea.after($boringAttributes); } }); } })(jQuery);
Why This Works
- Scoped to each cart item: The
each()loop ensures we only work with elements inside the current.variationdl, so no cross-item mixing. - Handles AJAX updates: The
updated_cart_totalsevent makes sure the code runs again if the cart is updated (like changing quantities), which is crucial for WooCommerce. - Keeps dt/dd pairs together: We always select both the label (
dt) and its value (dd) to avoid splitting attribute pairs. - Conditional execution: It only runs the reordering if Boring attributes exist, so it doesn't affect carts where Boring isn't selected.
Even Better: Server-Side PHP Solution
If you want a more reliable fix (no client-side JS dependencies), use WooCommerce's built-in filter to reorder attributes on the server. Add this to your theme's functions.php or a custom plugin:
add_filter('woocommerce_get_item_data', 'custom_reorder_cart_attributes', 10, 2); function custom_reorder_cart_attributes($item_data, $cart_item) { // Define your desired attribute order (match the labels exactly) $desired_order = [ 'Wood Type', 'Thickness of Door', 'Width (in)', 'Height (in)', 'Total Area (sq. ft.)', 'Boring', 'Unit', 'Specs - Distance 1', 'Specs - Distance 2' ]; $sorted_attributes = []; // First add attributes in your desired order foreach ($desired_order as $label) { foreach ($item_data as $key => $attribute) { if (strpos($attribute['name'], $label) !== false) { $sorted_attributes[] = $attribute; unset($item_data[$key]); break; } } } // Add any leftover attributes (in case you add new ones later) $sorted_attributes = array_merge($sorted_attributes, $item_data); return $sorted_attributes; }
This method works regardless of AJAX updates and avoids any potential JS conflicts. It directly tells WooCommerce the order you want attributes to appear in the cart.
内容的提问来源于stack exchange,提问作者Luke Miller

