1

I have three subscription products, yearly, half-yearly and monthly. By default, prices are shown per year, per every 6 months and per month on my Shop page.

Based on "Change product prices via a hook in WooCommerce 3" answer code, I am trying to display all the prices per month, so to change the price display based on the subscription term:

// Utility function to change the prices with a multiplier (number)
function get_price_multiplier($var_product) {
    switch($var_product) {
        case 111:
            // Annual
            return 12;
            break;
        case 222:
            // Semiannual
            return 6;
            break;
        case 333:
            // Month
            return 1;
            break;          
        default:
            return 1;
            break;
    }
}

add_filter('woocommerce_product_variation_get_price', 'custom_price', 99, 2 );
function custom_price( $price, $product ) {
    $var_product = $product->get_id();
    return $price / get_price_multiplier($var_product);
}

This worked but when a product is added to the cart, the price is not the regular price but the modified price from the function above.

Based on "Set programmatically product sale price and cart item prices in Woocommerce 3" answer code, I have been able to fix that:

add_action( 'woocommerce_before_calculate_totals', 'set_cart_item_sale_price', 20, 1 );
function set_cart_item_sale_price( $cart ) {
    if ( is_admin() && ! defined( 'DOING_AJAX' ) )
        return;

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

    // Iterate through each cart item
    foreach( $cart->get_cart() as $cart_item ) {
        $regular_price = $cart_item['data']->get_regular_price();
        $variation_id = $cart_item['variation_id'];
        $cart_item['data']->set_price( $regular_price * get_price_multiplier($variation_id) );
    }
}

This reset the cart price and it seems to work although one of the prices is off by a penny.

Is this all convoluted and prone to problems or is it a solid way to achieve what I am after: to show the price per subscription term on the shop page?

LoicTheAztec
  • 229,944
  • 23
  • 356
  • 399
YourBudWeiser
  • 77
  • 1
  • 10
  • I would like to display the subscription variation prices on the Shop page like I described without having to modify the price. If I can't do that, then the question is am I doing it right? – YourBudWeiser Mar 06 '19 at 18:33

1 Answers1

1

You are doing it in the right way… There is 2 ways (the last is the best one):

Note: The calculation and the price change is not needed when the multiplier is equal to 1.

1) First alternative: Improved code version that is very similar to yours.

Here is my commented code:

// Utility function that increase conditionally the variation price with a multiplier (int)
function get_variation_calculated_price( $variation_id, $price, $multiplier = true ) {
    switch( $variation_id ) {
        case 111: // Annual
            $rate = 12;
            break;

        case 222: // Semi-annual
            $rate = 6;
            break;

        default: // Month (and others)
            $rate = 1;
            break;
    }
    // Return calculated price (or false when multiplier is 1, as calculation is not needed)
    return $rate !== 1 ? ( $multiplier ? $price * $rate : $price / $rate ) : false;
}


// Change variations calculated prices
add_filter('woocommerce_product_variation_get_price', 'custom_price', 99, 2 );
function custom_price( $price, $variation ) {
    if( $new_price = get_variation_calculated_price( $variation->get_id(), $price, false ) )
        return $new_price;

    return $price;
}

// Customizing cart item prices
add_action( 'woocommerce_before_calculate_totals', 'set_cart_item_sale_price', 20, 1 );
function set_cart_item_sale_price( $cart ) {
    if ( is_admin() && ! defined( 'DOING_AJAX' ) )
        return;

    // Required since Woocommerce version 3.2 for cart items properties changes
    if ( did_action( 'woocommerce_before_calculate_totals' ) >= 2 )
        return;

    // Loop  through cart items
    foreach( $cart->get_cart() as $cart_item ) {
        // Only for variations
        if( $cart_item['variation_id'] > 0 ) {
            if( $new_price = get_variation_calculated_price( $cart_item['variation_id'], $cart_item['data']->get_price() ) ) {
                $cart_item['data']->set_price( $new_price );
            }
        }
    }
}

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


2) Second Alternative: much more accurate and lighter, restricting the product price avoiding price change on cart, checkout and backend.

Note: You will need to avoid displaying Cross-sells products in cart page (as the prices will not be changed like in shop page).

So the code will be more light, compact and efficient:

// Utility function that increase conditionally the variation price with a multiplier (int)
function get_variation_calculated_price( $variation_id, $price ) {
    switch( $variation_id ) {
        case 111: // Annual
            $rate = 12;
            break;

        case 939: // Semi-annual
            $rate = 6;
            break;

        default: // Month (and others)
            $rate = 1;
            break;
    }
    // Return calculated price (or false when multiplier is 1, as calculation is not needed)
    return $rate !== 1 ? $price / $rate : false;
}


// Change variations calculated prices
add_filter('woocommerce_product_variation_get_price', 'custom_price', 99, 2 );
function custom_price( $price, $variation ) {
    // Not in cart, checkout and admin
    if( is_cart() || is_checkout() || is_admin() ) 
        return $price;

    if( $new_price = get_variation_calculated_price( $variation->get_id(), $price ) )
        return $new_price;

    return $price;
}

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

LoicTheAztec
  • 229,944
  • 23
  • 356
  • 399
  • Thanks a lot for the updated code. There's one problem, when the subscription is for 1 month, i'm getting a price of 0. – YourBudWeiser Mar 06 '19 at 19:29
  • @YourBudWeiser Sorry there was an oversight when I have made some changes… It's updated and works for 1 month subscriptions now (with no price calculation). – LoicTheAztec Mar 06 '19 at 20:22
  • @YourBudWeiser I have added a 2nd much better alternative to my answer… Please try it. – LoicTheAztec Mar 06 '19 at 20:39
  • Yes the 2nd function works, just needed to change is_checkout to is_checkout(). Also, the price in the cart is off by 1 cent for the annual and seminannual price. Otherwise, super code! – YourBudWeiser Mar 06 '19 at 21:11