skip to Main Content

Each product has its own custom field called 'prices' that includes an array for quantity and bulk pricing – example array:

{"USD":[{"unit_break":3000,"unit_price":"0.0850"},{"unit_break":6000,"unit_price":"0.0819"},{"unit_break":12000,"unit_price":"0.0795"},{"unit_break":18000,"unit_price":"0.0771"},{"unit_break":24000,"unit_price":"0.0742"},{"unit_break":30000,"unit_price":"0.0731"},{"unit_break":300000,"unit_price":"0.0719"}]}

What I need to do is if the quantity in the cart is less than or equal to each 'unit_break', then the price should reflect the 'unit_price' in the same array column.

Something like this maybe?

if cartquantity <= 'unit_break[0]' {
product price = 'unit_break[0]' => 'unit_price[0]
} else if cartquantity <= 'unit_break[1]' {
Product price = 'unit_break[1]' => 'unit_price[1]
}

… and so on.

There could be any number of unit breaks per product so these numbers need to be dynamic.

I’ve tried iterating over each array but I can’t figure that out either.

Below is the code I currently have so far, which gets me as far as the first unit_break/unit_price in the array, but nothing after.

add_action( 'woocommerce_before_calculate_totals', 'quantity_based_bulk_pricing', 9999, 1 );
function quantity_based_bulk_pricing( $cart ) {

    if ( is_admin() && ! defined( 'DOING_AJAX' ) ) 
        return;

    if ( did_action( 'woocommerce_before_calculate_totals' ) >= 2 ) 
        return;


    // Loop through cart items
    foreach( $cart->get_cart() as $cart_item_key => $cart_item ) {
        // Get the bulk price from product custom field
        $prices = get_post_meta( $cart_item['product_id'], 'prices', true);
        $prices = json_decode($prices, true);

        $s = 0;

        foreach($prices as $price) {
            foreach($price as $unit) {
                $bulk_price = $unit['unit_break'];
                $qty_threshold = $unit['unit_price'];
            }
            $bulk_price = $price[$s]['unit_price'];
            $qty_threshold = $price[$s]['unit_break'];

            // Check if  item quantity has reached the defined threshold
            if( $cart_item['quantity'] <= $qty_threshold) {
                // Set the bulk price
                $cart_item['data']->set_price( $bulk_price );
            }


            //echo $qty_threshold.'<br>';
            //echo $bulk_price;
        }

    }
}

Any help is greatly appreciated.

2

Answers


  1. Chosen as BEST ANSWER

    Using Kristián Filo's answer, I had to modify so that if the cart quantity is greater than the last breakpoint in the array, to use that last breakpoint price as it was resetting to zero.

    add_action( 'woocommerce_before_calculate_totals', 'quantity_based_bulk_pricing', 9999, 1 );
    function quantity_based_bulk_pricing( $cart ) {
    
        if ( is_admin() && ! defined( 'DOING_AJAX' ) ) 
            return;
    
        if ( did_action( 'woocommerce_before_calculate_totals' ) >= 2 ) 
            return;
    
        // If you have multiple currencies in 'prices' meta, you should set target currency
        $target_currency = 'USD';
    
        // Loop through cart items
        foreach( $cart->get_cart() as $cart_item_key => $cart_item ) {
    
            // Get prices from post meta
            $prices = get_post_meta( $cart_item['product_id'], 'prices', true);
            $prices = json_decode( $prices, true );
    
            // Get cart item quantity
            $cart_qty = $cart_item['quantity'];
    
            // Loop through each currency
            foreach ( $prices as $currency => $breakpoints ) {
                // If this is not the target currency, continue
                if ( $currency != $target_currency ) {
                    continue;
                }
                
                // get the last $qty_threshold and $target price in array
                $last_qty = end($breakpoints)['unit_break'];
                $last_price = end($breakpoints)['unit_price'];
    
                // Loop through each price breakpoint
                foreach ( $breakpoints as $breakpoint ) {
                    $target_price = $breakpoint['unit_price'];
                    $qty_threshold = $breakpoint['unit_break'];
    
                    // If the quantity matches this breakpoint, set the price and break the loop
                    if ( $cart_qty <= $qty_threshold ) {
                        $cart_item['data']->set_price($target_price);
                        break;
                    }
                    if ( $cart_qty >= $last_qty ) {
                        $cart_item['data']->set_price($last_price);
                        break;
                    }
                }
            }
        }
    }
    

  2. Assuming the array structure in your example is correct, the code below should work. I am not sure whether the prices meta could have multiple currencies within (you only have USD in your example), but if it does, feel free to adjust the code as you wish.

    This is the altered code for your main $cart->get_cart() foreach loop:

    // If you have multiple currencies in 'prices' meta, you should set target currency
    $target_currency = 'USD';
    
    // Loop through cart items
    foreach( $cart->get_cart() as $cart_item_key => $cart_item ) {
        
        // Get prices from post meta
        $prices = get_post_meta( $cart_item['product_id'], 'prices', true);
        $prices = json_decode( $prices, true );
        
        // Get cart item quantity
        $cart_qty = $cart_item['quantity'];
    
        // If 'prices' is defined for this product
        if( $prices ) {
            
            // Loop through each currency
            foreach ( $prices as $currency => $breakpoints ) {
    
                // If this is not the target currency, continue
                if ( $currency != $target_currency ) {
                    continue;
                }
    
                // Loop through each price breakpoint
                foreach ( $breakpoints as $breakpoint ) {
                    $target_price = $breakpoint->unit_price;
                    $qty_threshold = $breakpoint->unit_break;
    
                    // If the quantity matches this breakpoint, set the price and break the loop
                    if ( $cart_qty <= $qty_threshold ) {
                        $cart_item['data']->set_price($target_price);
                        break;
                    }
                }
            }
        }
    }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search