Files
wc-tier-and-package-prices/includes/class-wc-tpp-cart.php
magdev 3e06137559 Release version 1.1.1 - Cart quantity field hiding
Enhanced package quantity restriction enforcement by hiding the cart
quantity input field when restrictions are enabled. This prevents
customers from modifying quantities in the cart to bypass package
restrictions.

Changes:
- Added cart quantity input hiding for restricted products
- Implemented woocommerce_cart_item_quantity filter hook
- Created maybe_hide_cart_quantity_input() method in WC_TPP_Cart
- Fixed cart quantity bypass vulnerability
- Cart displays quantity as read-only text for restricted products

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2025-12-21 17:21:40 +01:00

162 lines
6.7 KiB
PHP

<?php
/**
* Cart price calculation for tier and package pricing
*/
if (!defined('ABSPATH')) {
exit;
}
class WC_TPP_Cart {
public function __construct() {
add_action('woocommerce_before_calculate_totals', array($this, 'apply_tier_package_pricing'), 10, 1);
add_filter('woocommerce_cart_item_price', array($this, 'display_cart_item_price'), 10, 3);
add_filter('woocommerce_cart_item_subtotal', array($this, 'display_cart_item_subtotal'), 10, 3);
add_filter('woocommerce_add_to_cart_validation', array($this, 'validate_package_quantity'), 10, 3);
add_filter('woocommerce_cart_item_quantity', array($this, 'maybe_hide_cart_quantity_input'), 10, 3);
}
public function apply_tier_package_pricing($cart) {
if (is_admin() && !defined('DOING_AJAX')) {
return;
}
// Prevent infinite loops
if (did_action('woocommerce_before_calculate_totals') >= 2) {
return;
}
// Check if cart object is valid
if (!$cart || !is_a($cart, 'WC_Cart')) {
return;
}
foreach ($cart->get_cart() as $cart_item_key => $cart_item) {
$product_id = $cart_item['product_id'];
$quantity = $cart_item['quantity'];
$product = $cart_item['data'];
// Validate product object
if (!$product || !is_a($product, 'WC_Product')) {
continue;
}
// Check for exact package match first
$package_price = null;
if (get_option('wc_tpp_enable_package_pricing') === 'yes') {
$package_price = WC_TPP_Frontend::get_package_price($product_id, $quantity);
}
if ($package_price !== null) {
// Apply package pricing (total price divided by quantity)
$unit_price = $package_price / $quantity;
$product->set_price($unit_price);
// Store pricing information in cart item for display
WC()->cart->cart_contents[$cart_item_key]['wc_tpp_pricing_type'] = 'package';
WC()->cart->cart_contents[$cart_item_key]['wc_tpp_total_price'] = $package_price;
} else {
// Apply tier pricing if no package match
if (get_option('wc_tpp_enable_tier_pricing') === 'yes') {
$tier_price = WC_TPP_Frontend::get_tier_price($product_id, $quantity);
if ($tier_price !== null) {
$product->set_price($tier_price);
// Store pricing information in cart item for display
WC()->cart->cart_contents[$cart_item_key]['wc_tpp_pricing_type'] = 'tier';
WC()->cart->cart_contents[$cart_item_key]['wc_tpp_unit_price'] = $tier_price;
}
}
}
}
}
public function display_cart_item_price($price, $cart_item, $cart_item_key) {
if (isset($cart_item['wc_tpp_pricing_type'])) {
if ($cart_item['wc_tpp_pricing_type'] === 'package') {
$total_price = isset($cart_item['wc_tpp_total_price']) ? $cart_item['wc_tpp_total_price'] : $cart_item['line_total'];
$unit_price = $total_price / $cart_item['quantity'];
return wc_price($unit_price) . ' <small class="wc-tpp-notice">(' . __('Package price', 'wc-tier-package-prices') . ')</small>';
} elseif ($cart_item['wc_tpp_pricing_type'] === 'tier') {
$unit_price = isset($cart_item['wc_tpp_unit_price']) ? $cart_item['wc_tpp_unit_price'] : $cart_item['data']->get_price();
return wc_price($unit_price) . ' <small class="wc-tpp-notice">(' . __('Volume discount', 'wc-tier-package-prices') . ')</small>';
}
}
return $price;
}
public function display_cart_item_subtotal($subtotal, $cart_item, $cart_item_key) {
if (isset($cart_item['wc_tpp_pricing_type']) && $cart_item['wc_tpp_pricing_type'] === 'package') {
$total_price = isset($cart_item['wc_tpp_total_price']) ? $cart_item['wc_tpp_total_price'] : $cart_item['line_total'];
return wc_price($total_price);
}
return $subtotal;
}
public function validate_package_quantity($passed, $product_id, $quantity) {
// Check if restriction is enabled globally or for this product
$global_restrict = get_option('wc_tpp_restrict_package_quantities', 'no') === 'yes';
$product_restrict = get_post_meta($product_id, '_wc_tpp_restrict_to_packages', true) === 'yes';
if (!$global_restrict && !$product_restrict) {
return $passed;
}
// Get packages for this product
$packages = get_post_meta($product_id, '_wc_tpp_packages', true);
if (empty($packages) || !is_array($packages)) {
return $passed;
}
// Check if the quantity matches any package
$valid_quantity = false;
$available_quantities = array();
foreach ($packages as $package) {
$available_quantities[] = $package['qty'];
if ($quantity == $package['qty']) {
$valid_quantity = true;
break;
}
}
if (!$valid_quantity) {
$product = wc_get_product($product_id);
$product_name = $product ? $product->get_name() : __('this product', 'wc-tier-package-prices');
wc_add_notice(
sprintf(
__('The quantity %1$d is not available for %2$s. Please choose from the available package sizes: %3$s', 'wc-tier-package-prices'),
$quantity,
$product_name,
implode(', ', $available_quantities)
),
'error'
);
return false;
}
return $passed;
}
public function maybe_hide_cart_quantity_input($product_quantity, $cart_item_key, $cart_item) {
$product_id = $cart_item['product_id'];
// Check if restriction is enabled globally or for this product
$global_restrict = get_option('wc_tpp_restrict_package_quantities', 'no') === 'yes';
$product_restrict = get_post_meta($product_id, '_wc_tpp_restrict_to_packages', true) === 'yes';
// Get packages for this product
$packages = get_post_meta($product_id, '_wc_tpp_packages', true);
// If restriction is enabled and packages exist, show quantity as text only
if (($global_restrict || $product_restrict) && !empty($packages)) {
return sprintf('<span class="wc-tpp-cart-quantity">%s</span>', $cart_item['quantity']);
}
return $product_quantity;
}
}
new WC_TPP_Cart();