0

My question is based on code provided in answer (by LoicTheAztec and Xandl) to another question 'Set Product sale price conditionally based on custom fields in Woocommerce'. Whilst the foundation code is based on answers to that question, I have developed it a little further to meet a slightly more complex requirement.

The question: How do I automate regular price changes based on a static date within a custom field for both simple and variable products?

To give a bit more of an explanation; I am trying to create automated price drops to the regular price of a WooCommerce product based on a static date entered into a custom field 'wooct_time_start'.

The code snippet below works fine for simple products and is currently set to change the price to the number of '$remaining_days' before the 'wooct_time_start' date/time, but I cannot seem to get the second half of code to work with variable products and this is where I need some help?

add_filter('woocommerce_product_get_price', 'conditional_product_sale_price', 20, 6);
add_filter('woocommerce_product_get_sale_price', 'conditional_product_sale_price', 20, 6);
add_filter('woocommerce_product_variation_get_price', 'conditional_product_sale_price', 20, 6);
add_filter('woocommerce_product_variation_get_sale_price', 'conditional_product_sale_price', 20, 6);
add_filter('woocommerce_variation_prices_price', 'conditional_product_sale_price', 20, 6);
add_filter('woocommerce_variation_prices_sale_price', 'conditional_product_sale_price', 20, 6);

function conditional_product_sale_price($price, $product){
    
    if($product->is_type('simple')){

        $date = get_post_meta($product->get_id(), 'wooct_time_start', true);

        if(!empty($date)){
            $date_time = (int) strtotime($date);
            $now_time = (int) strtotime("now");
            $remaining_days = floor(($date_time - $now_time) / 86400);
    
            if($remaining_days <= 30){
                $price = $remaining_days;
            }elseif($remaining_days >= 31 && $remaining_days <= 60){
                $price = $remaining_days;
            }elseif($remaining_days >= 61 && $remaining_days <= 90){
                $price = $remaining_days;
            }elseif($remaining_days >= 91 && $remaining_days <= 120){
                $price = $remaining_days;
            }elseif($remaining_days >= 121 && $remaining_days <= 150){
                $price = $remaining_days;
            }elseif($remaining_days > 150){
                $price = $remaining_days;
            }
        }
        
        return $price;
            
    }if($product->is_type('variable')){

            $children_ids = $product->get_children();
            $date = get_post_meta($product->get_id(), 'wooct_time_start', true);
            
            foreach( $children_ids as $child_id ){

                $variation = wc_get_product($child_id);
                $var_price = $variation->get_price();
                
                if(!empty($date)){
                    $date_time = (int) strtotime($date);
                    $now_time = (int) strtotime("now");
                    $remaining_days = floor(($date_time - $now_time) / 86400);
                    
                    if($remaining_days <= 30){
                        $var_price = $remaining_days;
                    }elseif($remaining_days >= 31 && $remaining_days <= 60){
                        $var_price = $remaining_days;
                    }elseif($remaining_days >= 61 && $remaining_days <= 90){
                        $var_price = $remaining_days;
                    }elseif($remaining_days >= 91 && $remaining_days <= 120){
                        $var_price = $remaining_days;
                    }elseif($remaining_days >= 121 && $remaining_days <= 150){
                        $var_price = $remaining_days;
                    }elseif($remaining_days > 150){
                        $var_price = $remaining_days;
                    }
                }
                
                return $price;
                
            }
    }   
}

I have attempted various iterations to the code, but without success:

  • Changing the position of the line $date = get_post_meta($product->get_id(), 'wooct_time_start', true);
  • Changing the line $var_price = $variation->get_price(); to $var_price = $product->get_price();
  • I have played with the code relating to woocommerce_get_variation_prices_hash becasue of the stored transients, but I still do not know how it directly relates to my code despite several hours of research online.

UPDATE:

I have been able to create the following updated code using the answers provided in the article 'Change product prices via a hook in WooCommerce 3+'.

This new code has one remaining issue - It doesn't seem to successfully be updating the prices for any of the 'variations'. It is working for 'Simple' and 'Variable' products however!

If anyone is able to get this new code working with 'variations' too, then this would answer the question.

function product_life_cycle_main_function($price, $product){

        $date = get_post_meta($product->get_id(), 'wooct_time_start', true);

        if(!empty($date)){
            $date_time = (int) strtotime($date);
            $now_time = (int) strtotime("now");
            $remaining_days = floor(($date_time - $now_time) / 86400);
    
            if($remaining_days <= 30){
                $price = $remaining_days;
            }elseif($remaining_days >= 31 && $remaining_days <= 60){
                $price = $remaining_days;
            }elseif($remaining_days >= 61 && $remaining_days <= 90){
                $price = $remaining_days;
            }elseif($remaining_days >= 91 && $remaining_days <= 120){
                $price = $remaining_days;
            }elseif($remaining_days >= 121 && $remaining_days <= 150){
                $price = $remaining_days;
            }elseif($remaining_days > 150){
                $price = $remaining_days;
            }
        }
        return $price;
}

add_filter('woocommerce_product_get_price', 'product_life_cycle_custom_price', 99, 2);
add_filter('woocommerce_product_get_regular_price', 'product_life_cycle_custom_price', 99, 2);
add_filter('woocommerce_product_variation_get_regular_price', 'product_life_cycle_custom_price', 99, 2);
add_filter('woocommerce_product_variation_get_price', 'product_life_cycle_custom_price', 99, 2);
    function product_life_cycle_custom_price($price, $product) {
        return product_life_cycle_main_function($price, $product);
    }

add_filter('woocommerce_variation_prices_price', 'product_life_cycle_custom_variable_price', 99, 3);
add_filter('woocommerce_variation_prices_regular_price', 'product_life_cycle_custom_variable_price', 99, 3);
    function product_life_cycle_custom_variable_price($price, $variation, $product) {
        wc_delete_product_transients($variation->get_id());
        return product_life_cycle_main_function($price, $product);
    }

add_filter('woocommerce_get_variation_prices_hash', 'product_life_cycle_variation_prices_hash', 99, 3);
    function product_life_cycle_variation_prices_hash($price_hash, $product, $for_display) {
        $price_hash[] = product_life_cycle_main_function($price, $product);
        return $price_hash;
    }
aynber
  • 22,380
  • 8
  • 50
  • 63
  • 1
    Do variations have the `wooct_time_start` meta stored against them, or is it stored against the parent product? In the second case, you would have to call `get_post_meta($product->get_parent_id(), 'wooct_time_start', true);` for variations. – Diego Jun 28 '21 at 17:50
  • It was the second - They were stored in the parent, however both iterations were required in the final piece of code depending on which price was being updated at the time. I have included it all within the accepted answer. Thank you! – LionHeart-Nerd Jun 28 '21 at 18:09
  • Excellent, I'm glad that you managed to address the issue. :) – Diego Jun 29 '21 at 20:17

2 Answers2

1

I would suggest to rewrite the logic that fetches the data to make it more robust. The checks described in the accepted answer fails if the product is not simple, variable or variation, but it can be made more generic. Here's an example of how to do that:

function product_life_cycle_main_function($price, $product){
    // Determine the product ID to use
    // - Parent product ID for variations
    // - Product ID for all other products
    $meta_product_id = $product->is_type('variation') ? $product->get_parent_id() : $product->get_id();

    // The above can also be simplified as follows:
    // - If the product has a parent, take the meta from the parent
    // - If the product doesn't have a parent, take the meta from the product
    //
    // This check would also work with other product types, such as bundled products, subscriptions, etc
    //$meta_product_id = ($product->get_parent_id() > 0) ? $product->get_parent_id() : $product->get_id();

    $date = get_post_meta($meta_product_id, 'wooct_time_start', true);

    // Rest of the code...

    return $price;
}
Diego
  • 7,312
  • 5
  • 31
  • 38
0

Using the advice given by Diego, I was able to add the following to make the code work correctly:

function product_life_cycle_main_function($price, $product){
    
    $product_id = ($product->get_parent_id() > 0) ? $product->get_parent_id() : $product->get_id();
    
    $date = get_post_meta($product_id, 'wooct_time_start', true);

        if(!empty($date)){
            $date_time = (int) strtotime($date);
            $now_time = (int) strtotime("now");
            $remaining_days = floor(($date_time - $now_time) / 86400);
    
            if($remaining_days <= 30){
                $price = $remaining_days;
            }elseif($remaining_days >= 31 && $remaining_days <= 60){
                $price = $remaining_days;
            }elseif($remaining_days >= 61 && $remaining_days <= 90){
                $price = $remaining_days;
            }elseif($remaining_days >= 91 && $remaining_days <= 120){
                $price = $remaining_days;
            }elseif($remaining_days >= 121 && $remaining_days <= 150){
                $price = $remaining_days;
            }elseif($remaining_days > 150){
                $price = $remaining_days;
            }
        }
        
        return $price;
        
}

add_filter('woocommerce_product_get_price', 'product_life_cycle_custom_price', 99, 2);
add_filter('woocommerce_product_get_regular_price', 'product_life_cycle_custom_price', 99, 2);
add_filter('woocommerce_product_variation_get_regular_price', 'product_life_cycle_custom_price', 99, 2);
add_filter('woocommerce_product_variation_get_price', 'product_life_cycle_custom_price', 99, 2);
    function product_life_cycle_custom_price($price, $product) {
        return product_life_cycle_main_function($price, $product);
    }

add_filter('woocommerce_variation_prices_price', 'product_life_cycle_custom_variable_price', 99, 3);
add_filter('woocommerce_variation_prices_regular_price', 'product_life_cycle_custom_variable_price', 99, 3);
    function product_life_cycle_custom_variable_price($price, $variation, $product) {
        wc_delete_product_transients($variation->get_id());
        return product_life_cycle_main_function($price, $product);
    }

add_filter('woocommerce_get_variation_prices_hash', 'product_life_cycle_variation_prices_hash', 99, 3);
    function product_life_cycle_variation_prices_hash($price_hash, $product, $for_display) {
        global $price;
        $price_hash[] = product_life_cycle_main_function($price, $product);
        return $price_hash;
    }
  • 1
    Why do you use multiple if/elseif conditions? while in each condition `$price = $remaining_days;`. That makes no sense – 7uc1f3r Jun 28 '21 at 19:52
  • 2
    @7uc1f3r - It's because the core question here is 'changes (based on a static date)' - not 'change'. Plural. For demonstration purposes, the ```$price``` is set to show the same value, yes, but this can easily be changed by anyone wanting to use the code - The important bit is the fact that the if/elseif conditions allow for multiple price breaks based on differing date ranges - Which as previously mentioned - Is exactly what I required in my original question. – LionHeart-Nerd Jun 29 '21 at 12:45