• Resolved Dekadinious

    (@dekadinious)


    I am trying to set the price of a product to 0 in a nested foreach loop. Maybe I am thinking about the whole problem wrong, but I can’t get it to work. If I do $cart_item['data']->set_price('0'); at the top of the first foreach, it works (and sets the price to 0 for all products).

    But when doing it inside the last foreach, near the bottom of the code block below, nothing happens. The price is not visually set in the cart. I have checked the cart item object, and the changes:protected part of it is updated with the new price of 0.

    I have also checked that I actually reach that line of code. What I want is to set the price of the split item to 0, but not the other items that are not split.

    What am I doing wrong?

            if (is_admin() && !wp_doing_ajax()) {
                return;
            }
    
            if (did_action('woocommerce_before_calculate_totals') > 1) {
                return;
            }
    
            $compatible = false;
            $thecart = $cart->get_cart();
    
            //Check if we have any compatible items
            foreach ($thecart as $cart_item) {
    
                $postid = $cart_item['product_id'];
                $quantity = $cart_item['quantity'];
    
                //Check if the item is a 3for2 item
                if (!$this->get_3for2_status($postid)) {
                    //Not a 3for2 item
                    continue;
                }
    
                //If yes, check if the amount added is compatible with the 3 for 2 discount
                if ($quantity < 3) {
                    //Not compatible with discount
                    continue;
                }
    
                //Set compatible flag to true
                $compatible = true;
            }
    
            //Don't continue if we have no compatible products
            if ($compatible != true) {
                return;
            }
    
            //Get number of items to be free
    
            $quantity = 0;
    
            foreach ($thecart as $cart_item) {
    
                //Check if the item is a 3for2 item
                if (!$this->get_3for2_status($postid)) {
                    //Not a 3for2 item
                    continue;
                }
    
                $quantity += $cart_item['quantity'];
            }
    
            $freequantity = intdiv($quantity, 3);
    
            //Loop the cart to split free items from the cheapest item
            //Do this while we still have free items to give
    
            while ($freequantity > 0) {
    
                $pricearray = [];
    
                foreach ($thecart as $cart_item) {
                    $id = $cart_item['product_id'];
                    $price = $cart_item['data']->get_price();
    
                    //Don't add free products
                    if ($price > 0) {
                        $pricearray[$id] = $price;
                    }
                }
    
                //Split the lowest priced item into a free one
                $splititem = array_search(min($pricearray), $pricearray);
    
                foreach ($thecart as $cart_item_key => $cart_item) {
                    $id = $cart_item['product_id'];
    
                    //Only check the lowest priced item
                    if ($id != $splititem) {
                        continue;
                    }
    
                    $quantity = $cart_item['quantity'];
    
                    //If there is only one left, set price ... 
                    if ($quantity == 1) {
                        $cart_item['data']->set_price('0');
                        continue;
                    }
    
                    //... otherwise, split item
    
                    //Set quantity to quantity - 1 for the item
                    $cart->set_quantity($cart_item_key,  $quantity - 1);
    
                    //Then split 1 of the item
    
                    //Set a unique key.
                    $cart_item['unique_key'] = uniqid();
    
                    //Store the unique key
                    $uniqkey = $cart_item['unique_key'];
    
                    //Get variation vars
                    $variation_id = $cart_item['variation_id'];
                    $variation = $cart_item['variation'];
    
                    //Add the product as a new line item with the same variations that were passed
                    $cart->add_to_cart($id, 1, $variation_id, $variation, $cart_item);
    
                    //Do a new fetch of the cart and loop it again
                    foreach ($cart->get_cart() as $cart_item) {
    
                        //Check that we handle the correct item
                        if ($cart_item['unique_key'] != $uniqkey) {
                            continue;
                        }
    
                        //Set the price to be free
                        $cart_item['data']->set_price('0');
                    }
                }
    
                $freequantity -= 1;
            }
Viewing 5 replies - 1 through 5 (of 5 total)
  • Plugin Support con

    (@conschneider)

    Engineer

    Hi there,

    > What am I doing wrong?

    I would try to break it down and refactor a bit, splitting up your process into a couple smaller functions. This will make it easier for you to check your desired output each step of the way and also write unit tests (if you feel like it).

    Kind regards,

    Thread Starter Dekadinious

    (@dekadinious)

    Okay, now I have tried to run the minimal amount of code here in a fresh install with Storefront and no plugins.

    foreach ($cart->get_cart() as $cart_item_key => $cart_item) {
            $id = $cart_item['product_id'];
            $quantity = $cart_item['quantity'];
    
            if ($quantity < 3) {
                return;
            }
    
            //Split 1 of the item
            //Set quantity to quantity - 1 for the item
            $cart->set_quantity($cart_item_key,  $quantity - 1);
    
            //Get variation vars
            $variation_id = $cart_item['variation_id'];
            $variation = $cart_item['variation'];
    
            //Add the product as a new line item with the same variations that were passed
            $item_key = $cart->add_to_cart($id, 1, $variation_id, $variation, $cart_item);
                    
            //Set the price to be free
            $cart->get_cart()[$item_key]['data']->set_price('0');
        }

    If I comment out the return inside the if-statement, it works. I get three split items, of course, but it sets the price to 0 for all of them.

    If I have this return present, it splits out one item like I want it to do, but the price is not set to 0.

    If I log the price on the last line, my log shows the price is set to 0. Why then, does the cart not reflect this?

    How does set_price work? Is it not persistent? Does it not set the price in the cart for the session in the database?

    It seems the code execution has to reach set_price for each time the woocommerce_before_calculate_totals hook runs. But in this case, it won’t do that, because the quantity will only be >3 on the first run of the hook.

    So it will reach set_price when in the AJAX-call that updates the cart, but it won’t reach it when the page reloads. If setting the price was persistent for the session, this should not be a problem.

    How would you set the price of a dynamically added item like this?

    Thread Starter Dekadinious

    (@dekadinious)

    Does anybody know if set_price should be persistent?

    Plugin Support Hannah S.L.

    (@fernashes)

    Automattic Happiness Engineer

    This is a fairly complex development topic. I’m going to leave it open for a bit to see if anyone is able to chime in to help you out.

    I can also recommend the WooCommerce Developer Resources Portal for resources on developing for WooCommerce.

    You can also visit the WooCommerce Facebook group or the #developers channel of the WooCommerce Community Slack. We’re lucky to have a great community of open-source developers for WooCommerce, and many of our developers hang out there, as well.

    Plugin Support Hannah S.L.

    (@fernashes)

    Automattic Happiness Engineer

    No one has been able to chime in, so I’m going to close this thread. I can strongly recommend the resources in my previous reply for further help on this question.

Viewing 5 replies - 1 through 5 (of 5 total)
  • The topic ‘set_price() not working in nested foreach’ is closed to new replies.