Woocommerce update shipping methods in checkout via ajax

What i’m trying to accomplish: In woocommerce, I need to check a date delivered via a datepicker field when user selects a date, and then update shipping options accordingly via ajax, so that things like free shipping can be taken out when they are not appropriate.

What I currently know/have figured out: I currently have the jQuery event firing and sending through a date to a custom script, which is kinda where I need to do. I have not been able to find a function within woocommerce classes that returns just the shipping data, so I don’t think I can call that and return it as a fragment, as they do for the checkout already.

Read More

However, I did find that

WC_AJAX::update_order_review()

has an action call within it, and I have successfully hooked a function onto that action, AND i’ve been able to fire off the

t( 'body' ).trigger( 'update_checkout' );

which fires off the action that updates the checkout review block.

My real question: All this is great, and I’ts looking like its heading in the right direction, but I don’t know woocommerce well enough to know how to get the shipping methods within my hooked action to unset them as necessary. Does anyone know if I can get them through the $woocommerce global object, and then have them be read by the rest of that WC_AJAX method??

Any help here would be greatly appreciated.

** notes: yes, I know thats a ‘t’ and not a ‘$’ in the jQuery. Not a mistake

Related posts

Leave a Reply

3 comments

  1. So, for those of you who may need this, it required a little finagling in woocommerce, because of the way they handle output of cart/checkout values for shipping and payment options, but in the end, I could make it happen using woocommerce’s hooks, and very little plugin modification, so, a pretty clean solution.

    Basically what I did was use woocommerce sessions, two hooks, and a javascript trigger that refreshes the checkout order review.

    Through a combination of the woocommerce_checkout_update_order_review hook that happens in the WC_AJAX::update_order_review and use of the aformentioned $( 'body' ).trigger( 'update_checkout' ); call, I could hook in to the action that updates the checkout review block. So far so good.

    What I did in this function was check if the field had a value, and if it did, save it in the WC()->session. THEN, since WC_AJAX::update_order_review calls woocommerce_order_review() to grab all the updated cart and shipping methods, I looked into the template associated with that function and found another hook, woocommerce_review_order_before_shipping, which allows me to modify the shipping methods before the cart template loops through and builds the shipping options in wc_cart_totals_shipping_html().

    Now, I know, you’re thinking, wait, I need checkout shipping methods, not cart ones, but in reality, they seem to be one and the same.

    Hopefully my wasted hours will help someone else with a similar problem.

    Cheers.

  2. EDIT: This answer is probably outdated.

    If anybody wants to update the cart:

    foreach (WC()->cart->get_cart() as $key => $value) {
        WC()->cart->set_quantity($key, $value['quantity']+1);
        WC()->cart->set_quantity($key, $value['quantity']);
        break;
    }
    

    Change the quantity, then change it back. Then Woocommerce recalculates the shipping.

    (It took more than 5 hours of code browsing. Next time, I will write my own ecom where I can use a good framework that is fully customizable.)

  3. So Trevor’s answer didn’t exactly work for me (maybe WC has changed since it was made), it did lead me in the right direction though.

    I used some slightly different filters. The problem I needed to solve was add/remove certain shipping options, based on a custom field.

    add_action('woocommerce_checkout_update_order_review', function ($rawFields) {
                // This function checks for the value of my custom field on the checkout page.
                parse_str($rawFields, $checkoutFields);
                $this->myField = $checkoutFields['my_field'] ?? null;
    });
    
    add_filter('woocommerce_shipping_packages', 'modifyShippingPackages']);
    
    public function modifyShippingPackages($packages)
        {
            if ($this->myField) {
                //.. modify $packages. In my case, I had to remove shipping methods.
                $rates = $packages[0]['rates'];
    
                $newRates = array_filter($rates, function ($shippingRate)
                {
                    // figure out what should be in the rates
                });
    
                $packages[0]['rates'] = $newRates;
    
                $session = WC()->session;
                $session->set('shipping_method_counts', [count($newRates)]);
                $session->set('chosen_shipping_methods', [$newRates[0]->id]);
            }
    
            return $packages;
        }
    

    The above snippet is an incomplete version of my code, but should get the point across. It can be tested easily by typing jQuery( 'body' ).trigger( 'update_checkout' ); in your javascript console.

    Thanks for the hints Trevor.