Search code examples
phpwordpresswoocommerceproductcustom-taxonomy

Set a specific product price conditionally on Woocommerce single product page & cart


In Woocommerce I would like to alter the price of a specific product (in this case with an ID of 87) on both the single product page and for related cart items.

The product price needs to be increased by $10 but only on the single product page and only externally (so that the internal price or price set in Woocommerce is not altered).

Additionally, this price should also be altered in the cart but only if products from a certain category are NOT also in the cart.

Context: If someone buys this product on its own, they should be charged $10 above the regular price. If someone buys this item in conjunction with products from a certain category, they should be charged the regular price. This is essentially an inverted discount (I don't want to use coupon functionality to charge extra).

For the cart functionality, so far I have this but it's not working - the cart price is coming out at $75 when the current regular/base price is $45. I have no idea where 75 is coming from when it should be 55.

function wc_cart_custom_price( $cart_object ) {
        if ( is_admin() && ! defined( 'DOING_AJAX' ) )
        return;

        // set our flag to be false until we find a product in that category
        $cat_check = false;

        // check each cart item for our category
        foreach ( WC()->cart->get_cart() as $cart_item_key => $cart_item ) {

            $product = $cart_item['data'];

            // replace 'your-category' with your category's slug
            if ( has_term( 'your-category', 'product_cat', $product->id ) ) {
                $cat_check = true;
                // break because we only need one "true" to matter here
                break;
            }
        }

        // if a product in the cart is in our category, stop there and don't change price
        if ( $cat_check ) {
            return;
        }
        // else continue and alter the product price
        else if ( $cart_item['product_id'] == 87 ) {
            // we have the right product, do what we want
            $price = $cart_item['data']->get_price(); // Get the product price
            $new_price = $price + 10; // the calculation
            $cart_item['data']->set_price( $new_price ); // Set the new price
            }
}
add_action( 'woocommerce_before_calculate_totals', 'wc_cart_custom_price' );

My code for changing the product page price is, at the moment:

function wc_change_product_price($price, $product) {
    if ( is_single('87') ) {
        $post_id = $product->id;

        $regular_price = get_post_meta( $post_id, '_regular_price', true);
        $custom_value = ( $regular_price + 10 );
        $price = $custom_value;

    return $price;
    }
}
add_filter('woocommerce_get_price', 'wc_change_product_price', 99);

It is a disaster and causing a 500 server error. What I am doing wrong? Any help is welcome.

References:

Change cart item prices in WooCommerce version 3.0

https://rudrastyh.com/woocommerce/change-product-prices-in-cart.html

https://www.skyverge.com/blog/checking-woocommerce-cart-contains-product-category/


Solution

  • Update 3 (Only for a defined product ID)

    To make it work as you want to change the simple products prices only on single product pages (without altering archives product prices, related product prices, upsells and cross-sells) if any cart item doesn't belong to a specific product category.

    Then you will need all this following code:

    // Change displayed price on single product pages
    add_action( 'woocommerce_single_product_summary', 'change_simple_product_price_html', 9 );
    function change_simple_product_price_html() {
        global $product;
    
        // Only for product ID 87
        if( $product->get_id() != 87 ) return;
    
        // HERE set your product category term ID, slug or name
        $product_category = 't-shirts';
    
        // Checking for the product category in cart items loop
        foreach ( WC()->cart->get_cart() as $cart_item ) {
            if ( has_term( $product_category, 'product_cat', $cart_item['product_id'] ) )
                return; // Product category found ==> We EXIT from this function
        }
    
        remove_action( 'woocommerce_single_product_summary', 'woocommerce_template_single_price', 10 );
        add_action( 'woocommerce_single_product_summary', 'custom_simple_product_price_html', 10 );
    }
    
    function custom_simple_product_price_html(){
        global $product;
    
        $addp = 10; // Here the price additional amount
    
        if ( '' !== $product->get_price() && ! $product->is_on_sale() ) {
            $price = wc_price( wc_get_price_to_display( $product ) + $addp ) . $product->get_price_suffix();
        }
        echo '<p class="price">' . apply_filters( 'woocommerce_get_price_html', $price, $product ) . '</p>';
    }
    
    // Add custom calculated price to cart item data
    add_filter( 'woocommerce_add_cart_item_data', 'add_cart_simple_product_custom_price', 20, 2 );
    function add_cart_simple_product_custom_price( $cart_item_data, $product_id ){
        // Only for product ID 87
        if( $product_id != 87 ) 
            return $cart_item_data;
    
        $product = wc_get_product($product_id); // The WC_Product Object
    
        // Only if product is not on sale
        if( $product->is_on_sale() ) 
            return $cart_item_data;
    
        $price = (float) $product->get_price();
    
        // Set the custom amount in cart object
        $cart_item_data['new_price'] = $price + 10;
    
        return $cart_item_data;
    }
    
    // Set custom calculated price to cart
    add_action( 'woocommerce_before_calculate_totals', 'set_cart_simple_product_custom_price', 20, 1 );
    function set_cart_simple_product_custom_price( $cart ) {
        if ( is_admin() && ! defined( 'DOING_AJAX' ) )
            return;
    
        if ( did_action( 'woocommerce_before_calculate_totals' ) >= 2 )
            return;
    
        // HERE set your product category term ID, slug or name
        $product_category = 't-shirts';
    
        // 1st cart items Loop: checking for the product category
        foreach ( $cart->get_cart() as $cart_item ) {
            if ( has_term( $product_category, 'product_cat', $cart_item['product_id'] ) )
                return; // Product category found ==> We EXIT from this function
        }
    
        // 2nd Loop: Changing cart item prices (Product category not found)
        foreach ( $cart->get_cart() as $cart_item ) {
            if( isset($cart_item['new_price']))
                $cart_item['data']->set_price( $cart_item['new_price'] );
        }
    }
    

    Code goes in function.php file of your active child theme (or active theme). Tested and works.