Skip to content

Conversation

@dev-shahed
Copy link
Member

@dev-shahed dev-shahed commented Sep 3, 2025

  • Updated discount calculation to use the current price (sale price if available) instead of the regular price.
  • Improved product data handling in the EnqueueScript class to reflect accurate pricing for both simple and variable products.
  • Added hooks to manage target product removal and cart quantity updates, ensuring proper cleanup of related bump products.
  • Implemented validation for bump products when target products are removed from the cart.

Summary by CodeRabbit

  • New Features

    • Bump offers now auto-remove when target products/categories are removed or quantities reach zero.
    • Improved support for variable products in bump offers and pricing.
  • Bug Fixes

    • Price displays now use the current price (including sale prices) for both simple and variable products.
    • More accurate discount calculation on bump offers.
    • Added safeguards to prevent issues from missing or invalid variation data.
  • Refactor

    • Enhanced target matching and ID handling for greater reliability.
    • Standardized numeric formatting for prices to ensure consistent display.

@coderabbitai
Copy link

coderabbitai bot commented Sep 3, 2025

Walkthrough

Updates pricing logic to use current price for discounts in frontend and PHP, refactors price handling for simple/variable products, normalizes IDs and categories, and adds hooks and cleanup logic to remove orphaned bump products when cart items are removed or quantities become zero.

Changes

Cohort / File(s) Summary of Changes
Frontend discount calc
modules/upsell-order-bump/assets/src/components/appearance/template/overview-area/OverViewArea.js
Introduced local currentPrice and recalculated discount using current price; added clarifying comment; no API changes.
Script enqueue pricing
modules/upsell-order-bump/includes/EnqueueScript.php
Switched to get_price() for current price across simple/variable products; added numeric normalization; included both regular_price and current_price in outputs; improved variation handling and defensive checks.
Order bump hooks and cleanup
modules/upsell-order-bump/includes/OrderBump.php
Added hooks for cart item removal and quantity updates; reworked target matching using intersections; normalized IDs/categories; adjusted price calculation to prefer sale/current price; implemented cleanup to remove bump items when targets leave the cart; added public handlers and private helpers.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  participant WC as WooCommerce Cart
  participant OB as OrderBump
  participant Cart as Cart Contents

  WC->>OB: woocommerce_cart_item_removed(cart_item_key, cart)
  OB->>OB: derive removed product_id/variation_id
  OB->>Cart: inspect remaining cart items
  OB->>OB: get_remaining_target_products(bump)
  alt No remaining targets
    OB->>Cart: remove bump product (handle_orphaned_bump_product)
  else Targets remain
    OB-->>WC: no action
  end
Loading
sequenceDiagram
  autonumber
  participant WC as WooCommerce Cart
  participant OB as OrderBump
  participant View as Bump Frontend View

  WC->>OB: woocommerce_after_cart_item_quantity_update(key, qty, oldQty, cart)
  alt qty == 0
    OB->>OB: validate_bump_products_after_removal()
  else qty > 0
    OB-->>WC: no cleanup
  end

  View->>OB: bump_product_frontend_view()
  OB->>OB: collect product/variation IDs and category IDs (ints)
  OB->>OB: compute current_price (sale or current), apply discount/fixed offer
  OB-->>View: render data with normalized IDs and prices
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

Suggested labels

Need Testing, Dev Review Done

Suggested reviewers

  • Aunshon

Poem

A carrot of code in the shopping cart glows,
I nibble the prices where the current one flows.
When targets hop out, the bumps take a bow—
I sweep the trail clean with a twitch of my brow.
Discounts recomputed, neat as a burrow—let’s go! 🥕🐇

✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch fix/order-bump-issue

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

CodeRabbit Commands (Invoked using PR/Issue comments)

Type @coderabbitai help to get the list of available commands.

Other keywords and placeholders

  • Add @coderabbitai ignore or @coderabbit ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Status, Documentation and Community

  • Visit our Status Page to check the current availability of CodeRabbit.
  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Base automatically changed from refactor/bogo-unified-data-source to develop September 4, 2025 05:07
- Updated discount calculation to use the current price (sale price if available) instead of the regular price.
- Improved product data handling in the EnqueueScript class to reflect accurate pricing for both simple and variable products.
- Added hooks to manage target product removal and cart quantity updates, ensuring proper cleanup of related bump products.
- Implemented validation for bump products when target products are removed from the cart.
- Updated pricing logic to utilize the get_price() method for both simple and variable products, ensuring accurate current price representation.
- Adjusted the formatting of price data to maintain consistency across product types.
- Enhanced clarity in the code by removing redundant price calculations.
- Added validation for numeric price values to ensure accurate formatting for both simple and variable products.
- Updated the retrieval of regular and sale prices to improve consistency and reliability in price representation.
- Implemented checks for valid variation products to prevent errors during price processing.
- Replaced sale price retrieval with current price for accurate pricing representation.
- Adjusted conditions to check for current price instead of regular price for simple products.
- Removed redundant sale price calculations to streamline price data handling.
@mrabbani mrabbani force-pushed the fix/order-bump-issue branch from caca2f0 to e9fe589 Compare September 4, 2025 07:50
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

🧹 Nitpick comments (4)
modules/upsell-order-bump/assets/src/components/appearance/template/overview-area/OverViewArea.js (1)

59-63: Strike-through should reflect the same “base” price used for discount

If you discount from current price (sale), showing the regular price as the crossed-out anchor is misleading. Consider showing the current price as the struck-through “was” value, and format amounts instead of string-appending “.00”.

-                    <span style={{textDecoration:'line-through'}}>
-                        ${createBumpData.offer_product_regular_price?createBumpData.offer_product_regular_price:999999999}.00
-                    </span>&nbsp;&nbsp;
-                    <span style={{textDecoration:'underline'}}>
-                        ${offerAmout}.00
-                    </span>
+                    <span style={{textDecoration:'line-through'}}>
+                      ${ (createBumpData.offer_product_current_price ?? createBumpData.current_price ?? createBumpData.offer_product_regular_price ?? 0) }
+                    </span>&nbsp;&nbsp;
+                    <span style={{textDecoration:'underline'}}>
+                      ${ offerAmout }
+                    </span>
modules/upsell-order-bump/includes/EnqueueScript.php (1)

186-196: Avoid pre-escaping before wc_price and don’t hide zero-priced items

  • Pass numeric to wc_price directly; wc_price handles escaping.
  • Checking truthiness can drop “0” prices. Prefer is_numeric.
-			$price = esc_html( $current_price );
-			$price = wp_strip_all_tags( html_entity_decode( wc_price( $price ) ) );
+			$price = wp_strip_all_tags( html_entity_decode( wc_price( (float) $current_price ) ) );
...
-			if ( $_product->is_type( 'simple' ) && $current_price ) {
+			if ( $_product->is_type( 'simple' ) && is_numeric( $current_price ) ) {

Also applies to: 209-217

modules/upsell-order-bump/includes/OrderBump.php (2)

51-74: Consider deduping product IDs as well

You already array_unique category IDs; do the same for product/variation IDs to keep intersections lean.

 		}
 		
 		// Remove duplicate category IDs
 		$all_cart_category_ids = array_unique( $all_cart_category_ids );
+		// Remove duplicate product IDs (including variations)
+		$all_cart_product_ids  = array_values( array_unique( $all_cart_product_ids, SORT_NUMERIC ) );

Also applies to: 76-78


279-283: Normalize target product IDs before intersection

Ensures consistent comparisons with int cart/variation IDs.

-				$target_products = ! empty( $bump_info->target_products ) ? wc_clean( $bump_info->target_products ) : array();
+				$target_products = ! empty( $bump_info->target_products ) ? array_map( 'intval', (array) wc_clean( $bump_info->target_products ) ) : array();
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 071069c and e9fe589.

📒 Files selected for processing (3)
  • modules/upsell-order-bump/assets/src/components/appearance/template/overview-area/OverViewArea.js (1 hunks)
  • modules/upsell-order-bump/includes/EnqueueScript.php (5 hunks)
  • modules/upsell-order-bump/includes/OrderBump.php (5 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
modules/upsell-order-bump/includes/OrderBump.php (1)
modules/upsell-order-bump/includes/Ajax.php (1)
  • bump_list (81-103)
🔇 Additional comments (3)
modules/upsell-order-bump/includes/EnqueueScript.php (2)

262-276: Simple products: current/regular price retrieval looks correct

Using get_price()/get_regular_price with numeric guards aligns with the PR goal.


284-309: Variable products: robust current vs regular price handling

Fetching the variation product and exposing both current_price and regular_price with numeric normalization looks good.

modules/upsell-order-bump/includes/OrderBump.php (1)

31-33: Hooks registered correctly with proper argument counts

The actions and accepted args match WooCommerce signatures.

Comment on lines +18 to +20
// Use the current price (sale price if available, otherwise regular price) for discount calculation
const currentPrice = createBumpData.offer_product_regular_price;
offerAmout = currentPrice - currentPrice*createBumpData.offer_amount/100;
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Use current price for discount calc and coerce/round numerics

Comment says “current price” but code still uses regular price. Also ensure numeric coercion and 2-decimal rounding to avoid float artifacts.

-        // Use the current price (sale price if available, otherwise regular price) for discount calculation
-        const currentPrice = createBumpData.offer_product_regular_price;
-        offerAmout = currentPrice - currentPrice*createBumpData.offer_amount/100;
+        // Use the current price (sale if available) for discount calculation
+        const currentPrice = Number(
+          createBumpData.offer_product_current_price
+          ?? createBumpData.current_price
+          ?? createBumpData.offer_product_regular_price
+          ?? 0
+        );
+        const discountPct = Number(createBumpData.offer_amount ?? 0);
+        offerAmout = Math.round((currentPrice - (currentPrice * discountPct / 100)) * 100) / 100;
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
// Use the current price (sale price if available, otherwise regular price) for discount calculation
const currentPrice = createBumpData.offer_product_regular_price;
offerAmout = currentPrice - currentPrice*createBumpData.offer_amount/100;
// Use the current price (sale if available) for discount calculation
const currentPrice = Number(
createBumpData.offer_product_current_price
?? createBumpData.current_price
?? createBumpData.offer_product_regular_price
?? 0
);
const discountPct = Number(createBumpData.offer_amount ?? 0);
offerAmout = Math.round((currentPrice - (currentPrice * discountPct / 100)) * 100) / 100;
🤖 Prompt for AI Agents
In
modules/upsell-order-bump/assets/src/components/appearance/template/overview-area/OverViewArea.js
around lines 18-20, the code assigns currentPrice to the regular price but
should use the sale price when present, and it doesn’t coerce/round numeric
values; update currentPrice to use createBumpData.offer_product_sale_price if
truthy else createBumpData.offer_product_regular_price, coerce prices and
offer_amount to Number, compute the discounted amount as currentPrice -
(currentPrice * offer_amount / 100), and round the final offerAmount to two
decimals (e.g., Math.round(value * 100) / 100 or Number(value.toFixed(2))) so
there are no floating-point artifacts.

Comment on lines +90 to +98
$_product = wc_get_product( $offer_product_id );
$regular_price = $_product->get_regular_price();
// Use sale price if available, otherwise use regular price for discount calculation
$current_price = $_product->get_sale_price() ? $_product->get_sale_price() : $regular_price;
if ( 'discount' === $offer_type ) {
$offer_price = ( $current_price - ( $current_price * $offer_amount / 100 ) );
} else {
$offer_price = $offer_amount;
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Use get_price() for “current” price (respects schedules/filters)

get_sale_price() ignores sale schedules and filter-based pricing. get_price() returns the effective “current” price.

-		$_product      = wc_get_product( $offer_product_id );
-		$regular_price = $_product->get_regular_price();
-		// Use sale price if available, otherwise use regular price for discount calculation
-		$current_price = $_product->get_sale_price() ? $_product->get_sale_price() : $regular_price;
-		if ( 'discount' === $offer_type ) {
-			$offer_price = ( $current_price - ( $current_price * $offer_amount / 100 ) );
-		} else {
-			$offer_price = $offer_amount;
-		}
+		$_product      = wc_get_product( $offer_product_id );
+		$current_price = (float) $_product->get_price();
+		$regular_price = (float) $_product->get_regular_price();
+		if ( 'discount' === $offer_type ) {
+			$offer_price = round( $current_price - ( $current_price * ( (float) $offer_amount / 100 ) ), 2 );
+		} else {
+			$offer_price = (float) $offer_amount;
+		}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
$_product = wc_get_product( $offer_product_id );
$regular_price = $_product->get_regular_price();
// Use sale price if available, otherwise use regular price for discount calculation
$current_price = $_product->get_sale_price() ? $_product->get_sale_price() : $regular_price;
if ( 'discount' === $offer_type ) {
$offer_price = ( $current_price - ( $current_price * $offer_amount / 100 ) );
} else {
$offer_price = $offer_amount;
}
$_product = wc_get_product( $offer_product_id );
$current_price = (float) $_product->get_price();
$regular_price = (float) $_product->get_regular_price();
if ( 'discount' === $offer_type ) {
$offer_price = round( $current_price - ( $current_price * ( (float) $offer_amount / 100 ) ), 2 );
} else {
$offer_price = (float) $offer_amount;
}
🤖 Prompt for AI Agents
In modules/upsell-order-bump/includes/OrderBump.php around lines 90 to 98, the
code uses get_regular_price() and get_sale_price() to determine the current
price, which ignores sale schedules and filters; replace that logic to call
$_product->get_price() to obtain the effective current price, cast it to a float
for math safety, then compute $offer_price as before (if 'discount' calculate
current_price - (current_price * offer_amount / 100), else use the fixed
offer_amount). Ensure you handle an empty/non-numeric price by defaulting to 0.0
before the calculation.

Comment on lines +162 to +178
public function handle_target_product_removal( $cart_item_key, $cart ) {
$removed_item = $cart->removed_cart_contents[ $cart_item_key ];
if ( ! $removed_item ) {
return;
}

$removed_product_id = $removed_item['product_id'];
$removed_variation_id = isset( $removed_item['variation_id'] ) ? $removed_item['variation_id'] : 0;

// For variable products, check both parent and variation IDs
$removed_item_ids = array( $removed_product_id );
if ( $removed_variation_id > 0 ) {
$removed_item_ids[] = $removed_variation_id;
}

$this->validate_bump_products_after_removal( $removed_item_ids );
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Guard against undefined index on removed_cart_contents

Directly indexing can emit notices. Check with isset/empty first.

-	public function handle_target_product_removal( $cart_item_key, $cart ) {
-		$removed_item = $cart->removed_cart_contents[ $cart_item_key ];
-		if ( ! $removed_item ) {
-			return;
-		}
+	public function handle_target_product_removal( $cart_item_key, $cart ) {
+		if ( empty( $cart->removed_cart_contents[ $cart_item_key ] ) ) {
+			return;
+		}
+		$removed_item = $cart->removed_cart_contents[ $cart_item_key ];
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
public function handle_target_product_removal( $cart_item_key, $cart ) {
$removed_item = $cart->removed_cart_contents[ $cart_item_key ];
if ( ! $removed_item ) {
return;
}
$removed_product_id = $removed_item['product_id'];
$removed_variation_id = isset( $removed_item['variation_id'] ) ? $removed_item['variation_id'] : 0;
// For variable products, check both parent and variation IDs
$removed_item_ids = array( $removed_product_id );
if ( $removed_variation_id > 0 ) {
$removed_item_ids[] = $removed_variation_id;
}
$this->validate_bump_products_after_removal( $removed_item_ids );
}
public function handle_target_product_removal( $cart_item_key, $cart ) {
- $removed_item = $cart->removed_cart_contents[ $cart_item_key ];
- if ( ! $removed_item ) {
- return;
if ( empty( $cart->removed_cart_contents[ $cart_item_key ] ) ) {
return;
}
$removed_item = $cart->removed_cart_contents[ $cart_item_key ];
$removed_product_id = $removed_item['product_id'];
$removed_variation_id = isset( $removed_item['variation_id'] ) ? $removed_item['variation_id'] : 0;
// For variable products, check both parent and variation IDs
$removed_item_ids = array( $removed_product_id );
if ( $removed_variation_id > 0 ) {
$removed_item_ids[] = $removed_variation_id;
}
$this->validate_bump_products_after_removal( $removed_item_ids );
}
🤖 Prompt for AI Agents
In modules/upsell-order-bump/includes/OrderBump.php around lines 162-178, the
code directly accesses $cart->removed_cart_contents[$cart_item_key], which can
raise undefined index notices; first verify that removed_cart_contents exists
and that the specific key is set (e.g., use isset($cart->removed_cart_contents)
&& isset($cart->removed_cart_contents[$cart_item_key]) or empty checks) and
return early if not; then proceed to read product_id/variation_id and build
$removed_item_ids as before.

Comment on lines +188 to +205
public function handle_cart_quantity_update( $cart_item_key, $quantity, $old_quantity, $cart ) {
// If quantity was reduced to 0, the item is effectively removed
if ( $quantity === 0 && $old_quantity > 0 ) {
$cart_item = $cart->cart_contents[ $cart_item_key ];
if ( $cart_item ) {
$product_id = $cart_item['product_id'];
$variation_id = isset( $cart_item['variation_id'] ) ? $cart_item['variation_id'] : 0;

// For variable products, check both parent and variation IDs
$item_ids = array( $product_id );
if ( $variation_id > 0 ) {
$item_ids[] = $variation_id;
}

$this->validate_bump_products_after_removal( $item_ids );
}
}
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Also guard cart_contents access on quantity update

Prevents notices when key is absent.

-		if ( $quantity === 0 && $old_quantity > 0 ) {
-			$cart_item = $cart->cart_contents[ $cart_item_key ];
-			if ( $cart_item ) {
+		if ( $quantity === 0 && $old_quantity > 0 ) {
+			if ( isset( $cart->cart_contents[ $cart_item_key ] ) ) {
+				$cart_item = $cart->cart_contents[ $cart_item_key ];
 				$product_id = $cart_item['product_id'];
 				$variation_id = isset( $cart_item['variation_id'] ) ? $cart_item['variation_id'] : 0;
 				
 				// For variable products, check both parent and variation IDs
 				$item_ids = array( $product_id );
 				if ( $variation_id > 0 ) {
 					$item_ids[] = $variation_id;
 				}
 
 				$this->validate_bump_products_after_removal( $item_ids );
-			}
+			}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
public function handle_cart_quantity_update( $cart_item_key, $quantity, $old_quantity, $cart ) {
// If quantity was reduced to 0, the item is effectively removed
if ( $quantity === 0 && $old_quantity > 0 ) {
$cart_item = $cart->cart_contents[ $cart_item_key ];
if ( $cart_item ) {
$product_id = $cart_item['product_id'];
$variation_id = isset( $cart_item['variation_id'] ) ? $cart_item['variation_id'] : 0;
// For variable products, check both parent and variation IDs
$item_ids = array( $product_id );
if ( $variation_id > 0 ) {
$item_ids[] = $variation_id;
}
$this->validate_bump_products_after_removal( $item_ids );
}
}
}
public function handle_cart_quantity_update( $cart_item_key, $quantity, $old_quantity, $cart ) {
// If quantity was reduced to 0, the item is effectively removed
if ( $quantity === 0 && $old_quantity > 0 ) {
if ( isset( $cart->cart_contents[ $cart_item_key ] ) ) {
$cart_item = $cart->cart_contents[ $cart_item_key ];
$product_id = $cart_item['product_id'];
$variation_id = isset( $cart_item['variation_id'] ) ? $cart_item['variation_id'] : 0;
// For variable products, check both parent and variation IDs
$item_ids = array( $product_id );
if ( $variation_id > 0 ) {
$item_ids[] = $variation_id;
}
$this->validate_bump_products_after_removal( $item_ids );
}
}
}
🤖 Prompt for AI Agents
In modules/upsell-order-bump/includes/OrderBump.php around lines 188 to 205, the
code accesses $cart->cart_contents[$cart_item_key] without ensuring that key
exists which can raise notices; before reading $cart_item, add a guard using
isset($cart->cart_contents[$cart_item_key]) (or empty check) and return early if
missing so the function only proceeds when the cart item is present, then
continue with the existing product/variation ID logic and call to
validate_bump_products_after_removal.

Comment on lines +224 to +244
$bump_type = ! empty( $bump_info->bump_type ) ? esc_html( $bump_info->bump_type ) : 'products';
$offer_product_id = $bump_info->offer_product;

// Check if the removed item was a target for this bump offer
$was_target = false;

if ( $bump_type === 'products' ) {
$target_products = ! empty( $bump_info->target_products ) ? wc_clean( $bump_info->target_products ) : array();
$was_target = ! empty( array_intersect( $removed_item_ids, $target_products ) );
} else {
// For category-based bumps, check if removed product was in target categories
$was_target = false;
foreach ( $removed_item_ids as $removed_item_id ) {
$removed_product_categories = wp_get_post_terms( $removed_item_id, 'product_cat', array( 'fields' => 'ids' ) );
$target_categories = ! empty( $bump_info->target_categories ) ? wc_clean( $bump_info->target_categories ) : array();
if ( ! empty( array_intersect( $removed_product_categories, $target_categories ) ) ) {
$was_target = true;
break;
}
}
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Category-based cleanup misses variation removals (parent categories)

Variations don’t carry product_cat terms; you need to resolve to the parent product before checking categories. Otherwise orphaned bumps can persist.

-			} else {
-				// For category-based bumps, check if removed product was in target categories
-				$was_target = false;
-				foreach ( $removed_item_ids as $removed_item_id ) {
-					$removed_product_categories = wp_get_post_terms( $removed_item_id, 'product_cat', array( 'fields' => 'ids' ) );
-					$target_categories = ! empty( $bump_info->target_categories ) ? wc_clean( $bump_info->target_categories ) : array();
-					if ( ! empty( array_intersect( $removed_product_categories, $target_categories ) ) ) {
-						$was_target = true;
-						break;
-					}
-				}
-			}
+			} else {
+				// For category-based bumps, check parent categories for variations
+				$was_target = false;
+				$target_categories = ! empty( $bump_info->target_categories ) ? wc_clean( $bump_info->target_categories ) : array();
+				foreach ( $removed_item_ids as $removed_item_id ) {
+					$prod           = wc_get_product( $removed_item_id );
+					$term_source_id = ( $prod && $prod->is_type( 'variation' ) ) ? $prod->get_parent_id() : $removed_item_id;
+					$removed_product_categories = wp_get_post_terms( $term_source_id, 'product_cat', array( 'fields' => 'ids' ) );
+					if ( ! empty( array_intersect( $removed_product_categories, $target_categories ) ) ) {
+						$was_target = true;
+						break;
+					}
+				}
+			}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
$bump_type = ! empty( $bump_info->bump_type ) ? esc_html( $bump_info->bump_type ) : 'products';
$offer_product_id = $bump_info->offer_product;
// Check if the removed item was a target for this bump offer
$was_target = false;
if ( $bump_type === 'products' ) {
$target_products = ! empty( $bump_info->target_products ) ? wc_clean( $bump_info->target_products ) : array();
$was_target = ! empty( array_intersect( $removed_item_ids, $target_products ) );
} else {
// For category-based bumps, check if removed product was in target categories
$was_target = false;
foreach ( $removed_item_ids as $removed_item_id ) {
$removed_product_categories = wp_get_post_terms( $removed_item_id, 'product_cat', array( 'fields' => 'ids' ) );
$target_categories = ! empty( $bump_info->target_categories ) ? wc_clean( $bump_info->target_categories ) : array();
if ( ! empty( array_intersect( $removed_product_categories, $target_categories ) ) ) {
$was_target = true;
break;
}
}
}
} else {
// For category-based bumps, check parent categories for variations
$was_target = false;
$target_categories = ! empty( $bump_info->target_categories )
? wc_clean( $bump_info->target_categories )
: array();
foreach ( $removed_item_ids as $removed_item_id ) {
$prod = wc_get_product( $removed_item_id );
$term_source_id = ( $prod && $prod->is_type( 'variation' ) )
? $prod->get_parent_id()
: $removed_item_id;
$removed_product_categories = wp_get_post_terms(
$term_source_id,
'product_cat',
array( 'fields' => 'ids' )
);
if ( ! empty( array_intersect( $removed_product_categories, $target_categories ) ) ) {
$was_target = true;
break;
}
}
}
🤖 Prompt for AI Agents
modules/upsell-order-bump/includes/OrderBump.php lines 224-244: category-based
removal check fails for product variations because variations don’t have
product_cat terms; update the loop so for each $removed_item_id you resolve the
parent product ID (use the variation’s post_parent or WooCommerce product API to
get_parent_id) and then fetch categories from the parent product ID before
intersecting with $target_categories; ensure $target_categories is normalized to
an array of ints and use the parent ID only when it exists so category-based
bumps are correctly detected and cleaned up.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants