RiotAct RiotAct - 7 months ago 63
PHP Question

WooCommerce, change item price if another specific item is in the cart

I am using WooCommerce Memberships and want to extend a free membership to first time members if they purchase a specific product. I can get some of this to work separately, but am having trouble getting it to all come together.

There is also a sale price on the item they have to purchase, so I am also checking the dates to see if the item is in the sale window. That part is working.

It seems that when I add the argument to check if the item is in the cart, this whole thing breaks. If I run the two functions separately, they both work.

function mps_registration_price($cart_object) {
global $post, $product;

// Bail if memberships is not active
if ( ! function_exists( 'wc_memberships' ) ) {
return;
}

$user_id = get_current_user_id();
date_default_timezone_set("America/Chicago");
$today = time();

// Check if user was never a member
if ( !wc_memberships_get_user_memberships( $user_id )) {
if( mps_check_for_product() ) {

foreach ( $cart_object->get_cart() as $cart_item ) {

// get the product id (or the variation id)
$id = $cart_item['data']->get_id();

if($id == 17) {
$salePrice = get_post_meta($id, '_sale_price', true);
$saleFrom = get_post_meta($id, '_sale_price_dates_from', true);
$saleTo = get_post_meta($id, '_sale_price_dates_to', true);

if( !empty($salePrice) && $today >= $saleFrom && $today <= $saleTo ) {
$new_price = $salePrice;
} else {
$new_price = get_post_meta($id, '_regular_price', true);
}
// Updated cart item price
$cart_item['data']->set_price( $new_price );
}
}
} else {

foreach ( $cart_object->get_cart() as $cart_item ) {

// get the product id (or the variation id)
$id = $cart_item['data']->get_id();

if($id == 17) {
$salePrice = get_post_meta($id, '_sale_price', true);
$saleFrom = get_post_meta($id, '_sale_price_dates_from', true);
$saleTo = get_post_meta($id, '_sale_price_dates_to', true);

if( !empty($salePrice) && $today >= $saleFrom && $today <= $saleTo ) {
$new_price = $salePrice + 50;
} else {
$new_price = get_post_meta($id, '_regular_price', true);
}
// Updated cart item price
$cart_item['data']->set_price( $new_price );
}
}
}
}

}

add_filter( 'woocommerce_before_calculate_totals', 'mps_registration_price', 10, 1 );

function mps_check_for_product() {

$product_id = 11;
$product_cart_id = WC()->cart->generate_cart_id( $product_id );
$in_cart = WC()->cart->find_product_in_cart( $product_cart_id );

if ( $in_cart ) {
return true;
} else {
return false;
}
}

add_action('woocommerce_before_cart', 'mps_check_for_product');

Answer Source

You have complicated everything here as you just want to add to a specific product (ID 17) on sale an additional cost when customer is not yet member.

You don't need 2 separated functions for this and your 2nd function is doing it in the wrong way. It don't need to be hooked if you are calling it in your first hooked function.

I have revisited your code completely, using WC_Product methods instead of get_post_meta()

Also the WC_Product method is_on_sale() manage everything like from/to dates for on sale product prices. So you don't need to get that in your function.

In your code there is no differences when product 11 is in cart or is NOT in cart within your 2 Cart loops… So you should may be need to make some changes there.

So your code is now very compact:

add_filter( 'woocommerce_before_calculate_totals', 'mps_registration_price', 10, 1 );
function mps_registration_price( $cart_object ) {

    // Bail if memberships is not active
    if ( ! function_exists( 'wc_memberships' ) ) return; // Exit

    // Only for non members
    $user_id = get_current_user_id();
    if ( wc_memberships_get_user_memberships( $user_id ) ) return; // Exit

    // First loop to check if product 11 is in cart
    foreach ( $cart_object->get_cart() as $cart_item ){
        $is_in_cart = $cart_item['product_id'] == 11 ? true : false;
    }

    // Second loop change prices
    foreach ( $cart_object->get_cart() as $cart_item ) {

        // Get an instance of the WC_Product object (or the variation product object)
        $product = $cart_item['data'];

        // Method is_on_sale() manage everything (dates…)
        // Here we target product ID 17
        if( $product->is_on_sale() && $product->get_id() == 17 ) {

            // When product 11 is not cart
            if( ! $is_in_cart ){
                $product->set_price( $product->get_sale_price() + 50);
            }
        }
    }
}

Code goes in function.php file of your active child theme (or active theme) or in any plugin file.

Tested and works.

Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download