Change Prices of Items added to Cart in WooCommerce

Luckily the Cart Object allows us to do cool stuff and create any condition.

First of all let me show you a very simple example, where we just set the custom price for all products in the cart.

add_action( 'woocommerce_before_calculate_totals', 'misha_recalc_price' );
 
function misha_recalc_price( $cart_object ) {
	foreach ( $cart_object->get_cart() as $hash => $value ) {
		$value['data']->set_price( 10 );
	}
}

My today’s task is the following: When a customer adds to the cart a certain amount (3 for example) of products of a specific category (ID 25), these products will receive 50% discount. But this shouldn’t affect the Lambo product (with ID 12345).

add_action( 'woocommerce_before_calculate_totals', 'misha_recalculate_price' );
 
function misha_recalculate_price( $cart_object ) {
 
    if ( is_admin() && ! defined( 'DOING_AJAX' ) )
        return;
 
    // you can always print_r() your object and look what's inside
    //print_r( $cart_object ); exit;
 
    // it is our quantity of products in specific product category
    $quantity = 0;
 
    // $hash = cart item unique hash
    // $value = cart item data
    foreach ( $cart_object->get_cart() as $hash => $value ) {
  
        // check if the product is in a specific category and check if its ID isn't 12345
        if( in_array( 25, $value['data']->get_category_ids() ) && $value['product_id'] != 12345 ) {
 
            // if yes, count its quantity
            $quantity += $value['quantity'];
 
        } 
 
    }
 
    // change prices
    if( $quantity > 3 ) {
        foreach ( $cart_object->get_cart() as $hash => $value ) {
  
            // I want to make discounts only for products in category with ID 25
            // and I never want to make discount for the product with ID 12345
            if( in_array( 25, $value['data']->get_category_ids() ) && $value['product_id'] != 12345 ) {
 
                $newprice = $value['data']->get_regular_price() / 2;
 
                // in case the product is already on sale and it is much cheeper with its own discount
                if( $value['data']->get_sale_price() > $newprice )
                    $value['data']->set_price( $newprice );
 
            } 
        }
    } 
}

If you’re wondering where I found all those methods like set_price()get_category_ids(), look at the Abstract Product Object, you can find it in the WooCommerce plugin directory in /includes/abstracts/abstract-wc-product.php. And by the way, Variations don’t have categories.

If you read my blog and still don’t know where to insert this type of code, it is sad. Try your current theme functions.php then.

If your cart in WooCommerce is custom coded and our hook doesn’t apply to it, use WC()->cart->calculate_totals().

P.S. While working with woocommerce_before_calculate_totals action hook, be careful with plugins that affect cart prices too, like YITH Dynamic Pricing and Discounts.