Release version 1.1.0 - Package quantity restriction feature

Added comprehensive package quantity restriction functionality that allows
limiting product purchases to predefined package sizes only.

Features:
- Global setting to enable package quantity restrictions
- Per-product override for quantity restrictions
- Automatic hiding of quantity input field when restricted
- Frontend validation with package selection UI
- Server-side cart validation
- User-friendly error messages
- Complete translations for all supported languages

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

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
2025-12-21 15:54:04 +01:00
parent dea2c5f0b3
commit e0a32821ee
22 changed files with 699 additions and 54 deletions

View File

@@ -13,6 +13,7 @@ class WC_TPP_Cart {
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);
}
public function apply_tier_package_pricing($cart) {
@@ -89,6 +90,53 @@ class WC_TPP_Cart {
}
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;
}
}
new WC_TPP_Cart();

View File

@@ -14,6 +14,7 @@ class WC_TPP_Frontend {
add_action('woocommerce_before_add_to_cart_button', array($this, 'display_pricing_table_before'), 20);
add_action('woocommerce_after_add_to_cart_button', array($this, 'display_pricing_table_after'), 10);
add_action('woocommerce_single_product_summary', array($this, 'display_pricing_table_after_price'), 15);
add_action('woocommerce_before_add_to_cart_quantity', array($this, 'maybe_hide_quantity_input'));
}
public function enqueue_scripts() {
@@ -50,6 +51,24 @@ class WC_TPP_Frontend {
}
}
public function maybe_hide_quantity_input() {
global $product;
if (!$product || !is_a($product, 'WC_Product')) {
return;
}
$product_id = $product->get_id();
$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';
$packages = get_post_meta($product_id, '_wc_tpp_packages', true);
// Hide quantity input if restriction is enabled and packages exist
if (($global_restrict || $product_restrict) && !empty($packages)) {
echo '<style>.quantity { display: none !important; }</style>';
}
}
public function display_pricing_table() {
global $product;
@@ -60,6 +79,8 @@ class WC_TPP_Frontend {
$product_id = $product->get_id();
$tiers = get_post_meta($product_id, '_wc_tpp_tiers', true);
$packages = get_post_meta($product_id, '_wc_tpp_packages', true);
$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 (empty($tiers) && empty($packages)) {
return;
@@ -68,7 +89,8 @@ class WC_TPP_Frontend {
WC_TPP_Template_Loader::get_instance()->display('frontend/pricing-table.twig', array(
'product' => $product,
'tiers' => $tiers,
'packages' => $packages
'packages' => $packages,
'restrict_to_packages' => $global_restrict || $product_restrict
));
}

View File

@@ -69,6 +69,15 @@ class WC_TPP_Product_Meta {
<p class="form-field">
<button type="button" class="button wc-tpp-add-package"><?php _e('Add Package', 'wc-tier-package-prices'); ?></button>
</p>
<?php
woocommerce_wp_checkbox(array(
'id' => '_wc_tpp_restrict_to_packages',
'label' => __('Restrict to Package Quantities', 'wc-tier-package-prices'),
'description' => __('Only allow quantities defined in packages above', 'wc-tier-package-prices'),
'desc_tip' => true,
));
?>
</div>
<script type="text/html" id="wc-tpp-tier-row-template">
@@ -151,6 +160,10 @@ class WC_TPP_Product_Meta {
} else {
delete_post_meta($post_id, '_wc_tpp_packages');
}
// Save package quantity restriction setting
$restrict_to_packages = isset($_POST['_wc_tpp_restrict_to_packages']) ? 'yes' : 'no';
update_post_meta($post_id, '_wc_tpp_restrict_to_packages', $restrict_to_packages);
}
}

View File

@@ -104,6 +104,15 @@ class WC_TPP_Settings extends WC_Settings_Page {
),
),
array(
'title' => __('Restrict to Package Quantities', 'wc-tier-package-prices'),
'desc' => __('Limit quantities to defined package sizes only', 'wc-tier-package-prices'),
'id' => 'wc_tpp_restrict_package_quantities',
'default' => 'no',
'type' => 'checkbox',
'desc_tip' => __('When enabled, customers can only purchase products in the exact quantities defined in packages. The quantity input field will be hidden and replaced with package selection buttons.', 'wc-tier-package-prices'),
),
array(
'type' => 'sectionend',
'id' => 'wc_tpp_settings',