| @@ -80,8 +80,16 @@ | ||
| 80 | 80 | 'variation' => $variation, |
| 81 | 81 | 'product' => !$isCustom ? $variation->product : [] |
| 82 | 82 | ]); |
| 83 | 83 | |
| 84 | + // After the filter, not before: this path takes its quantity straight from a | |
| 85 | + // public URL param, and the filter above can replace it with anything. | |
| 86 | + $error = CartHelper::validateQuantity($quantity); | |
| 87 | + if ($error) { | |
| 88 | + return $error; | |
| 89 | + } | |
| 90 | + $quantity = (int)$quantity; | |
| 91 | + | |
| 84 | 92 | if ($variation->payment_type === 'subscription') { |
| 85 | 93 | $quantity = 1; |
| 86 | 94 | } |
| 87 | 95 | |
| @@ -215,11 +223,13 @@ | ||
| 215 | 223 | { |
| 216 | 224 | $itemId = Arr::get($data, 'id'); |
| 217 | 225 | $quantity = Arr::get($data, 'quantity', 1); |
| 218 | 226 | |
| 219 | - if ($quantity <= 0) { | |
| 227 | + // This path writes cart_data directly instead of going through Cart::addItem(). | |
| 228 | + $error = CartHelper::validateQuantity($quantity); | |
| 229 | + if ($error) { | |
| 220 | 230 | return static::makeErrorResponse([ |
| 221 | - ['code' => 403, 'message' => __('Quantity can not be negative.', 'fluent-cart')] | |
| 231 | + ['code' => 403, 'message' => $error->get_error_message()] | |
| 222 | 232 | ]); |
| 223 | 233 | } |
| 224 | 234 | |
| 225 | 235 | $cart = CartResource::get([ |
| @@ -404,9 +414,13 @@ | ||
| 404 | 414 | } |
| 405 | 415 | |
| 406 | 416 | $utmData = static::prepareUtmData($data); |
| 407 | 417 | if ($utmData) { |
| 408 | - $cart->utm_data = array_merge(is_array($cart->utm_data) ? $cart->utm_data : [], $utmData); | |
| 418 | + // Replaced, not merged. A cart row is reused across visits, so merging | |
| 419 | + // key by key accumulated a union of every touch that ever reached it and | |
| 420 | + // the column stopped describing any single one. The browser has already | |
| 421 | + // resolved which touch this is, so its block is the answer. | |
| 422 | + $cart->utm_data = $utmData; | |
| 409 | 423 | $cart->save(); |
| 410 | 424 | } |
| 411 | 425 | |
| 412 | 426 | return $cart; |
| @@ -577,8 +591,15 @@ | ||
| 577 | 591 | if ($updatedQuantity < 0) { |
| 578 | 592 | $updatedQuantity = 0; |
| 579 | 593 | } |
| 580 | 594 | |
| 595 | + if ($updatedQuantity > 0 && ($error = CartHelper::validateQuantity($updatedQuantity))) { | |
| 596 | + return [ | |
| 597 | + 'code' => 'failed', | |
| 598 | + 'message' => $error->get_error_message() | |
| 599 | + ]; | |
| 600 | + } | |
| 601 | + | |
| 581 | 602 | if (!$isFilteredItem) { |
| 582 | 603 | |
| 583 | 604 | if (!CartHelper::shouldAddItemToCart($productVariation, $updatedQuantity)) { |
| 584 | 605 | return [ |
| @@ -607,8 +628,16 @@ | ||
| 607 | 628 | |
| 608 | 629 | if ($quantity < 1) { |
| 609 | 630 | $quantity = 1; |
| 610 | 631 | } |
| 632 | + | |
| 633 | + if ($error = CartHelper::validateQuantity($quantity)) { | |
| 634 | + return [ | |
| 635 | + 'code' => 'failed', | |
| 636 | + 'message' => $error->get_error_message() | |
| 637 | + ]; | |
| 638 | + } | |
| 639 | + | |
| 611 | 640 | if (!$isFilteredItem) { |
| 612 | 641 | if (!CartHelper::shouldAddItemToCart($productVariation, $quantity)) { |
| 613 | 642 | return [ |
| 614 | 643 | 'code' => 'failed', |