Codeinwp / Codeinwp/woocommerce-product-addon

Cart total recalculation crashes on non-numeric base price

Open
#720 1 comment 0 reactions 1 assignee View on GitHub

@Alexia-Soare is already working on this.

Since Sep 17, 2026.

bug-report bug-report-triage crash-report
Dominant language
PHP
Stars
15
Forks
9
Avg merge
3d 17h
Merged PRs (30d)
16

Description

Summary

Cart total recalculation can terminate an AJAX request with TypeError: Unsupported operand types: float + string when a PPOM-configured cart item has a non-numeric base-price value.

Expected behavior: Cart pricing handles an invalid or formatted base-price value without an uncaught PHP type error.

Actual behavior: The total-price calculation combines the addon total with the base-price value and throws a TypeError.

Impact: Affected carts cannot complete the recalculation request; telemetry recorded repeated occurrences on one production site.

Customer context

  • Product / area: PPOM cart pricing
  • Version: 34.0.8
  • Environment: WordPress 7.1; PHP 8.2.31 and 8.3.31
  • Integration / third party: Unknown from available evidence; pricing filters and a currency-conversion integration are present in the inspected path.
  • Reported error / symptom: TypeError: Unsupported operand types: float + string during an AJAX cart/session total recalculation.
  • Impact: 347 occurrences across one distinct production site in the telemetry query window.

Reproduction notes

  1. Use modern PPOM price mode and add a product with PPOM fields to the cart.
  2. During woocommerce_before_calculate_totals, cause the base-price path to return a non-numeric string, such as through an applicable price filter or integration.
  3. Trigger cart/session total recalculation through the AJAX flow.

Observed in production: The reported expression throws TypeError: Unsupported operand types: float + string.

Missing: The telemetry payload does not identify the value producer or exact third-party configuration.

Diagnosis

Conclusion

Production telemetry places the uncaught TypeError at Engine::before_calculate_totals() line 149. The inspected expression adds the normalized addon total to $price_info['price'], but the base-price path can return an unnormalized string. This is a confirmed unsafe operand-type path; the specific producer of the non-numeric string on the affected site is unknown.

Where this likely occurs
  • src/Pricing/Engine.phpPPOM\Pricing\Engine::before_calculate_totals() lines 119-149 computes $total_addon_price and then adds it to unvalidated $price_info['price'] at line 149.
  • src/Pricing/Engine.phpPPOM\Pricing\Engine::price_get_product_base() lines 1135-1136 assigns the currency-conversion result to $base_price; lines 1211-1216 return that value through ppom_price_info without a type boundary.
  • src/Hooks/Callbacks.phpCallbacks::convert_price_back() lines 98-123 documents float|string input and returns the supplied value unchanged when its currency branch does not run.
  • src/Cart/WooCommerceCartLifecycleHooks.phpWooCommerceCartLifecycleHooks::register() lines 27-40 attaches the wrapper to woocommerce_before_calculate_totals in modern price mode. inc/prices.phpppom_before_calculate_totals() lines 11-13 reaches the namespaced method from the reported stack.
  • The expression was introduced in a8f17ea580e3f737592b015c80ba5727fabe6735 and remains present in the inspected v34.0.8 source. No earlier working version boundary was established.
Engineering notes

The failure is in the free plugin repository, not the bundled Themeisle SDK. Addon row values pass through normalize_price_value() before their accumulator is returned at src/Pricing/Engine.phpEngine::price_get_addon_total() lines 878-906 and Engine::normalize_price_value() lines 941-952, while the base-price value on the failing expression has no equivalent normalization. The direct source of a non-numeric base-price value may be a pricing filter or currency-related integration; that runtime input was not captured by telemetry.

Test coverage status

tests/unit/src/Pricing/test-pricing-engine.phptest_price_get_addon_total_sums_addon_rows_with_quantity() lines 78-95 covers numeric addon strings. tests/unit/src/Pricing/test-engine-gaps.phptest_price_get_product_base_filter_can_override_result() lines 539-564 covers a numeric filter override. tests/unit/test-third-party-price-mutation.phptestAddonPriceSurvivesThirdPartySetPriceDuringTotals() lines 21-70 covers normal numeric cart recalculation. No relevant coverage was found during inspection for before_calculate_totals() receiving a non-numeric base price and avoiding this TypeError.

What to verify or explore next
  • Reproduce totals recalculation with a PPOM cart item whose base-price filter result is a formatted or non-numeric string under PHP 8.2 and 8.3.
  • Run the relevant PHPUnit pricing and third-party mutation suites in the repository's WordPress test environment.
  • Inspect runtime filters and enabled currency/price extensions on an affected environment to identify the source value.
Unknowns / follow-up
  • Telemetry does not include the base-price value or active third-party extensions.
  • No version comparison demonstrated that the behavior worked in an earlier release, so regression status remains unconfirmed.

Confidence

Confidence: 96/100

Production telemetry records 347 instances of the same uncaught float + string TypeError in version 34.0.8. The reported line performs arithmetic with a base price that the inspected plugin path leaves unnormalized, while addon totals are normalized.

Crash telemetry

Occurrences 347
Distinct sites 1
First seen 2026-08-29 03:51 UTC
Last seen 2026-08-30 12:48 UTC
Crash location product:src/Pricing/Engine.php:149
Request context ajax
Inside Themeisle SDK no
Product versions 34.0.8
WP versions 7.1
PHP versions 8.2.31, 8.3.31
SDK versions 3.3.57

Source: automated crash report — woocommerce-product-addon, fingerprint 87dd26a28a7adefd36f30ae6b3c61627
Generated by bug-report-triage (ID: bug-report-triage_6a9518fe103319.12500379)

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.