You've already forked wc-tier-and-package-prices
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>
162 lines
6.7 KiB
PHP
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();
|