0
votes

I am trying to change meta for all the bookable products which are already in cart, more specifically - end_date and duration, but with no result for several days already... I need to do it in woocommerce_before_calculate_totals action. I have tried this code:

if ( $my_condition ) {
    foreach ( WC()->cart->get_cart() as $cart_item_key => $cart_item ) {
        if ( isset( $cart_item['booking'] ) ) {
            $cart_item['booking']->set_duration( $my_new_duration );
        }
    }
}

And thousands of other ways, which were unsuccessful.

A similar method works well with set_price(), it changes the price, but bookable product meta like duration and end date seems impossible to change for products already in cart! Google seems to be helpless on this as while searching for days I could only find how to change the price itself, not the duration or other meta.

Could anyone help me out? Thanks!

EDIT: Simply put, here's what Im trying to achieve - Let's say I have these items in my cart:

  • Product1 booked from 2018-05-10 10:00 to 2018-05-10 16:00
  • Product2 booked from 2018-05-10 10:00 to 2018-05-10 17:00

and when my function triggers, both of these products booking range in my cart should change to 2018-05-10 10:00 to 2018-05-10 13:30

1

1 Answers

4
votes

when my function triggers, both of these products booking range in my cart should change to 2018-05-10 10:00 to 2018-05-10 13:30

If you just want to set a fixed end time (e.g. 13:30 as in your example case), then try the following function, which I've tried and tested working properly on WordPress 4.9.5 with WooCommerce 3.3.5 and WooCommerce Bookings 1.11.1.

However, the product's Booking duration (in the General tab on the Edit product page in admin) is expected to be Customer-defined blocks of {n} Hours; i.e. the type is customer and unit is hour.

// Use `WC_Cart::set_cart_contents()` to actually update the cart (contents).
// See `recalc_bookings_duration()` for an example of how to use this function.
function change_booking_end_time( array &$cart_item, $end_time ) {
    if ( ! isset( $cart_item['data'] ) ) {
        return false;
    }

    if ( ! preg_match( '/^\d{2}:\d{2}$/', $end_time ) ) {
        return false;
    }

    if ( ! is_wc_booking_product( $cart_item['data'] ) ) {
        //echo 'Not a Bookable product..<br>';
        return false;
    }

    if (
        'hour' !== $cart_item['data']->get_duration_unit() ||
        'customer' !== $cart_item['data']->get_duration_type()
    ) {
        //echo 'Duration unit/type error.<br>';
        return false;
    }

    $booking_id = $cart_item['booking']['_booking_id'];
    $booking = get_wc_booking( $booking_id );

    if ( $booking ) {
        // Set the end time in 24-hour clock format.
        $new_end_time = $end_time;

        // Get the timestamp of the `$new_end_time`.
        $start_time = $booking->get_start();
        $end_time = @strtotime( $new_end_time, $start_time );
        if ( ! $end_time ) {
            return false;
        }

        // Update the booking data; in the database.
        $_end_time = (int) $booking->get_end();
        if ( $end_time !== $_end_time ) {
            $booking->set_end( $end_time );
            $booking->save();

            // Update failed.
            $_end_time = (int) $booking->get_end();
            if ( $end_time !== $_end_time ) {
                //echo '$booking->save() error.<br>';
                return false;
            }
        // The end time / duration already changed.
        } else {
            //echo 'End time already match.<br>';
            return false;
        }

        // Re-calculate the duration (number of hours).
        $duration = abs( $end_time - $start_time ) / ( 60 * 60 );
        $cart_item['data']->set_duration( $duration );

        // Check/adjust the maximum duration.
        $max_duration = $cart_item['data']->get_max_duration();
        if ( is_numeric( $max_duration ) && $duration > $max_duration ) {
            $cart_item['data']->set_max_duration( ceil( $duration ) );
        }

        // Check/adjust the minimum duration.
        $min_duration = $cart_item['data']->get_min_duration();
        if ( is_numeric( $min_duration ) && $duration < $min_duration ) {
            $cart_item['data']->set_min_duration( floor( $duration ) );
        }

        // Update the product data; in the cart.
        $cart_item['data']->apply_changes();

        // Update the booking data; in the cart.
        $cart_item['booking']['_duration'] = $duration;
        $cart_item['booking']['duration'] = $duration . ' ' .
            _n( 'hour', 'hours', $duration, 'woocommerce-bookings' );
        $cart_item['booking']['_end_date'] = $booking->get_end();

        return true;
    }
}

Example Usage

add_action( 'woocommerce_before_calculate_totals', 'recalc_bookings_duration' );
function recalc_bookings_duration( WC_Cart $cart ) {
    $cart_items = $cart->get_cart_contents();
    $update_cart = false;

    foreach ( $cart_items as $cart_item_key => $cart_item ) {
        if ( change_booking_end_time( $cart_item, '13:30' ) ) {
            $cart_items[ $cart_item_key ] = $cart_item;
            $update_cart = true;
        }
    }

    if ( $update_cart ) {
        $cart->set_cart_contents( $cart_items );
    }
}