$from, 'percent' => $pct); } ksort($out); return array_values($out); } public static function resolve_tier(array $tiers, $qty) { $qty = (int) $qty; if ($qty < 1 || empty($tiers)) { return null; } $match = null; foreach ($tiers as $tier) { if ($tier['from_qty'] <= $qty) { $match = $tier; } else { break; } } return $match; } public static function compute_discounted_price($base_price, array $tiers, $qty) { $base = (float) $base_price; if ($base <= 0.0 || empty($tiers)) { return $base; } $tier = self::resolve_tier($tiers, $qty); if (!$tier || $tier['percent'] <= 0.0) { return $base; } $discounted = $base * (1.0 - ($tier['percent'] / 100.0)); return round($discounted, wc_get_price_decimals()); } // ============================================================ // Admin UI: variation editor // ============================================================ public function render_variation_tier_editor($loop, $variation_data, $variation) { $parent_id = (int) $variation->post_parent; if (!Studiou_WC_FPP_Product::is_fpp_product($parent_id)) { return; } $tiers = self::get_tiers($variation->ID); ?>
$tier) : ?>

$from, 'percent' => $pct); } $sanitized = self::normalize_tiers($sanitized); if (empty($sanitized)) { delete_post_meta($variation_id, self::META_KEY); } else { update_post_meta($variation_id, self::META_KEY, $sanitized); } } // ============================================================ // Frontend: expose tiers on variation data + placeholder container // ============================================================ public function inject_variation_tier_data($variation_data, $product, $variation) { $parent_id = $variation->get_parent_id(); if (!Studiou_WC_FPP_Product::is_fpp_product($parent_id)) { return $variation_data; } $tiers = self::get_tiers($variation->get_id()); $base_price = get_post_meta($variation->get_id(), '_price', true); $variation_data['studiou_fpp_qty_tiers'] = $tiers; $variation_data['studiou_fpp_base_price'] = ($base_price !== '' && $base_price !== false) ? (float) $base_price : 0.0; return $variation_data; } public function render_tier_display_placeholder() { global $product; if (!$product || !Studiou_WC_FPP_Product::is_fpp_product($product->get_id())) { return; } echo ''; } /** * Render a persistent notice above the variations form summarising tier availability. * Only shown if at least one variation of the current product has tiers configured. */ public function render_preform_notice() { global $product; if (!$product || !Studiou_WC_FPP_Product::is_fpp_product($product->get_id())) { return; } if (!$product->is_type('variable')) { return; } $has_tiers = false; $max_discount = 0.0; foreach ($product->get_children() as $variation_id) { $tiers = self::get_tiers($variation_id); if (!empty($tiers)) { $has_tiers = true; foreach ($tiers as $tier) { if ($tier['percent'] > $max_discount) { $max_discount = $tier['percent']; } } } } if (!$has_tiers) { return; } $label = ($max_discount > 0) ? sprintf( /* translators: %s: maximum discount percentage */ __('Quantity discount available — save up to %s%%. Select a variant to see the full tier table.', 'studiou-wc-free-photo-product'), rtrim(rtrim(number_format($max_discount, 2, '.', ''), '0'), '.') ) : __('Quantity discount available — select a variant to see the full tier table.', 'studiou-wc-free-photo-product'); ?>
get_id())) { return; } if (!$product->is_type('variable')) { return; } $data = array(); foreach ($product->get_children() as $variation_id) { $tiers = self::get_tiers($variation_id); if (empty($tiers)) { continue; } $base_price = get_post_meta($variation_id, '_price', true); $data[(string) $variation_id] = array( 'tiers' => $tiers, 'base_price' => ($base_price !== '' && $base_price !== false) ? (float) $base_price : 0.0, ); } if (empty($data)) { return; } echo ''; } // ============================================================ // Cart runtime // ============================================================ public function apply_cart_discount($cart) { if (is_admin() && !defined('DOING_AJAX')) { return; } if (!$cart || !is_a($cart, 'WC_Cart')) { return; } foreach ($cart->get_cart() as $cart_item) { if (empty($cart_item['variation_id'])) { continue; } $product = isset($cart_item['data']) ? $cart_item['data'] : null; if (!$product) { continue; } $parent_id = $product->get_parent_id(); if (!Studiou_WC_FPP_Product::is_fpp_product($parent_id)) { continue; } $variation_id = (int) $cart_item['variation_id']; $tiers = self::get_tiers($variation_id); if (empty($tiers)) { continue; } // Read base price from meta to avoid compounding if the hook fires twice per request $base_price = get_post_meta($variation_id, '_price', true); if ($base_price === '' || $base_price === false) { continue; } $qty = (int) $cart_item['quantity']; $discounted = self::compute_discounted_price((float) $base_price, $tiers, $qty); if ($discounted > 0.0) { $product->set_price($discounted); } } } }