Skip to content

Add opt-in decimal quantity support - #270

Open
sultann wants to merge 1 commit into
masterfrom
feature/decimal-quantity
Open

Add opt-in decimal quantity support#270
sultann wants to merge 1 commit into
masterfrom
feature/decimal-quantity

Conversation

@sultann

@sultann sultann commented Apr 20, 2026

Copy link
Copy Markdown
Contributor

Summary

Supersedes #261 (closed). Adds optional decimal quantity support to the plugin using WooCommerce's official woocommerce_stock_amount filter extension point. Feature is off by default so existing installs are unaffected.

How it works

When the "Allow decimal quantities" setting is enabled:

  1. Plugin::bootstrap() removes WC's default intval filter on woocommerce_stock_amount and registers floatval instead. WC then funnels every quantity (add-to-cart, cart updates, checkout, order items, emails, REST) through floatval — no $_POST hijacking, no static state, no reentrancy bugs.
  2. All comparison / math / display sites in Cart.php branch on wc_is_stock_amount_integer() (WC 10.1+, with a function_exists fallback that assumes integer mode on older WC).
  3. Helpers in functions.php centralize the branching: wcmmq_is_integer_qty(), wcmmq_format_qty(), wcmmq_is_valid_step().
  4. Admin quantity inputs get step="any" so decimals can be entered when the feature is on.

Why not "just widen casts to float"

Two traps the previous PR (#261) fell into:

  • WC's intval filter wins by default. add_filter('woocommerce_stock_amount', 'floatval') alone runs after WC's intval, which has already truncated the decimal. Data loss. Must remove_filter first.
  • Integer math hides in many places. absint(), % (PHP forces int operands), and number_format() without precision all silently strip or round decimals. With step=0.5 and max_qty set, absint(0.5) is 0, and $max % 0 fatal-errors on PHP 8+. These needed direct replacement with wc_is_stock_amount_integer() branches.

Pro plugin coordination

Pro plugin PR submitted in parallel: https://github.com/pluginever/wc-min-max-quantities-pro/pull/new/feature/decimal-quantity. These must merge and ship together — the free plugin widens limit storage to float, and Pro's Cart.php was casting back to int via the wc_min_max_quantities_product_limits filter. Shipping only one would break the other.

Files changed

File Change
includes/Plugin.php Gated remove_filter(intval) + add_filter(floatval) in bootstrap()
includes/functions.php Added 3 helpers, widened limit casts to (float)
includes/Cart.php Replaced absint()/%/number_format() with helper calls at 20+ sites
includes/Admin/Settings.php New wcmmq_decimal_quantities checkbox + warning copy + step="any" on qty fields
includes/Admin/MetaBoxes.php step="any" on product step field

Test plan

Setting OFF (default) — must behave identically to v2.2.9

  • Fresh install, default settings → integer quantities enforced as before
  • Integer min/max/step on a product → existing validation behavior
  • Cart/checkout flows unchanged
  • wc_is_stock_amount_integer() returns true

Setting ON

  • Enable setting → confirm WC input inputmode becomes decimal (WC handles this automatically)
  • Set product min=0.5, max=5, step=0.5 → add 2.5 to cart, no fatal, validation passes
  • Set step=0.5, max=3.5 → divisibility check passes (canonical fmod + epsilon)
  • Set step=0.3 → fmod(3.6, 0.3) case, precision tolerance works
  • Cart-level min_qty=2.5 → error message shows "2.5", not rounded
  • Exceed max_qty=2.5 with 3 items → error uses wcmmq_format_qty(), shows "2.5"
  • Variable product with decimal variation step → quantity input respects decimal step
  • Store API block cart → min/max/multiple_of flow through correctly
  • Order completion + order emails → quantities preserve decimals

WC version fallback

  • Force function_exists('wc_is_stock_amount_integer') to false (simulate WC < 10.1) → helpers fall back to integer mode, no fatals

Pro plugin coordination

  • Both branches active → role-based limits with decimal values work
  • Category-level decimal limits work end-to-end
  • Variation override with decimal values respected

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.

1 participant