How to select the date first on Woocommerce Bookings
I know I am not alone in wanting the functionality for Woocommerce Bookings. This just makes logical sense, choose a date, then find out what resources are available on the date chosen. Bookings doesn’t do this out of the box.
Or read on for how to do it yourself.
I needed to create this functionality for a client. They hire mountain bikes out by the 1/2 day or full day. Who wants to select bikes again and again to see if they are available on any given day? No-one! So I rebuilt how Woocommerce bookings works. Essentially I flipped the booking process on it’s head. Reversing the events.
My solution was an indepth build of a custom plugin, but if you understand the core WC_Product_Booking which extends WC_Product used in the Woocommerce Plugin, you should be able to solve this for yourself. You find this class in your core Woocommerce Bookings Plugin woocommerce-bookings->includes->class-wc-product-booking.php. If you haven’t explored plugin files before, I encourage you to do it. It is the quickest way to understand how something is built and how you can use built in functionality to build something bespoke for your site.
To see my solution in action, please visit the bike hire page on Pedalabikeaway.
Within this class you have a function called, get_available_bookings, this is what you want to use. The answer is in the name. You will need to send 4 variables to this function to get your resource availability.
Because my client had the option of hiring a bike for the morning, afternoon, or full day, I had 3 different date groups to send to this function. I then compared all 3 to find out if they were all equal to 0 or more, only then did my query produce an available bike for that date.
function check_resource_avail($date, $product_id, $resource_id, $number = 1) { //first you need to generate a new $booking Object to find the available resource $booking =new WC_Product_Booking($product_id); //my hours for booking were 9:30 am to 12:30pm and 1pm to 5pm. $date_morn_b = $date + (9.5 *60*60); $date_morn_e = $date + (12.5 *60*60); $date_after_b = $date + (13 *60*60); $date_after_e = $date + (17 *60*60); //how many bikes (products) are available for the morning time $avail_morn = $booking->get_available_bookings($date_morn_b, $date_morn_e, $resource_id, $number ); //how many bikes (products) are available for the afternoon time $avail_after = $booking->get_available_bookings($date_after_b, $date_after_e, $resource_id, $number ); // make sure an integer is returned, if it's empty you get a WP commerce error if(is_int($avail_after)):$avail_after = $avail_after; else: $avail_after = 0;endif; if(is_int($avail_morn)):$avail_morn = $avail_morn; else: $avail_morn = 0;endif; //find the lowest number available $avail_day = min($avail_morn, $avail_after); if($avail_morn > 0): $morn = true; else: $morn = false; endif; if($avail_after > 0): $after = true; else: $after = false; endif; // check if morning and afternoon are available, then day will be too if(($avail_after > 0) && ($avail_morn > 0)): $day = true; else: $day = false; endif; $avail = array($morn, $avail_morn, $after, $avail_after, $day, $avail_day); return $avail; }
I call this function for each product (bike) that I want to check. It returns an array I can use to show how many bikes are available for a selected date and duration. I then use this array to create my drop down list of all bikes available selected on the given date and duration. Using the function above is really all you need. But sometimes having the full context that something is used in helps to explain things fully. You can stop here or carry on for my full solution.
To check what products are available on any given day we have to start out with the right group of products. Assuming you give your customer a choice here you need to create a post object based on these. For me, it was selecting a category of bikes, and then what the hire period is. You can ignore much of this other then the WP post query as the rest are my ajax calls to get the selected variables.
function show_bike_selection() { $nonce = wp_create_nonce("new_bike_nonce"); if ( !wp_verify_nonce( $_REQUEST['nonce'], "get_bike_nonce")) { exit("You are not allowed to use this function"); } if($_REQUEST["time"]):$time = $_REQUEST["time"];endif; if($_REQUEST["date"]):$date = $_REQUEST["date"]; endif; if(($time == 'morn') || ($time =='after')): $time_ck='hs-day'; else: $time_ck ='multi-day'; endif; if($_REQUEST["cat"]):$cat = $_REQUEST["cat"];else: $cat ='standard-mtb, premium-mtb, am-demo';endif; $args = array( 'post_type' => 'product', 'showposts' => '-1', 'tax_query' => array( 'relation' => 'AND', array( 'taxonomy' => 'product_tag', 'field' => 'slug', 'terms' => array($time_ck), ), array( 'taxonomy' => 'product_cat', 'field' => 'term_id', 'terms' => $cat, ), ), ); // this is the html I am going to generate to show my resource dropdown list $out .= '<div class="steps">Step 3 - Choose Your Bike Size</div><select id="choose_bike" name="choose_bike" class="form-control">' ; $out .="<option >Choose bike size</option>";
Using these arguements to filter I get a selection of products that I want to check resources against on the chosen date and period.
$bikes = get_posts($args); global $wpdb;
Also notice the call to the global variable $wpdb, this allows me to connect to the Woocommerce databases to select the exact products and resources I am looking to check. We need to do a little dirty database querying here. Nothing to be nervous of. Once you try it and use it, you’ll wonder why you didn’t use it before.
if($bikes) : $closed_out = array(); // I first need to find all bike ids for my filtered results foreach($bikes as $b): $bike_id = $b->ID; // I then use those IDs to find out what resources are associated with them // I use the bike IDs I found above, query the database and find the resulting resources $b_resources = $wpdb->get_results( $wpdb->prepare("SELECT * FROM wp_wc_booking_relationships WHERE product_id = %s", $bike_id)); //now fromt that result we need to find the ID associated with the resource. This is what is needed to query the Class fucntion foreach($b_resources as $r): $resource_id = $r->resource_id; //the bikes are my resources, for you it might be hotel rooms, or stylists, whatever your resource might be $the_bikes = $wpdb->get_results( $wpdb->prepare("SELECT * FROM wp_posts WHERE ID = %s", $resource_id)); foreach($the_bikes as $the_bike): //now for each resource your use the function you created above to find out what is availble on the selected dates $result = check_resource_avail($date, $bike_id, $resource_id, $number = 1); switch($time){ case 'morn': $avail = $result[1]; break; case 'after': $avail =$result[3]; break; case 'day': $avail =$result[5]; break; } //echo $time; // echo '<pre>';print_r($result); echo '</pre>'; // endif; $closed_out[] = $avail; //only if the resource is available will it show on my dropdown list if($avail > 0 && is_int($avail)) : $out .="<option value=".$bike_id." data-nonce=" . $nonce . " data-resource=".$resource_id." data-avail=".$avail.">" . $the_bike->post_title. " (".$avail ." Avail)</option>"; else: $out .= ""; endif; endforeach; endforeach; endforeach; else : $out .='No product matching your criteria.'; endif; //
Please review this working on my clients site. This is my first attempt at writing up my solutions for Woocommerce Bookings. I would greatly appreciate feedback and questions. I will answer all that I can.
Good luck!
Hi Beth –
Nice work! I agree – in many cases, it totally makes sense to allow the user to choose a date first, and then see if there’s any resource available. Do you know if your solution is still working in the latest version of WooCommerce/Woo Bookings?
Best wishes
Thanks Marcus. I think WooBookings created the plugin, then got too deep into it when they realised that date first is a must. They would need to rewrite the whole plugin to make the functionality part of the core..
My code hasn’t changed and is still working through all of the updates this past year. I’ve tidied my code a bit since this, but the functionality is the same. If you have any questions or get stuck give me a shout.
Best – Beth
[…] before seeing what they are able to book. You can see my write up to that selecting the date first, here. The other big one […]
Hi,
you got the point!
Pretty sure I am not the only one who needs to have a “check availabilty” widget for his website. I run a mountain hut in the alps and are building a new hp with woobooking right now for next season and a plugin that could do that would be really great!
Seems you are so deep in this, maybe it would be possible for you to offer a plugin that does exactly this:
# show availabilty widget
# show all available rooms for the selected date
# that´s all! Nothing more needed!
Best Regards
Stay tuned Gerold. I am going to release a first version of this, this week. I will add you to my email list. Thanks.
Thanks for the initiation of this plugin. I would think that Beth is right on the money about the devs acting before thinking (modeling) the Bookings add-on; picking a date would always be a first asked request. I would love to help develop this with you. Can you fork it on github as of yet… or do you plan on beta testers only with sales intent—could be a good route to go.
Thanks Larry. No, I haven’t committed it to GitHub yet. My plan is to build a more functional version as a plugin for sales. But as you found, you can download this Beta test and do with it whatever you like. I’ll keep you updated as things progress. Thanks so much for commenting.
It would be awesome, if f.e. you could have a calendar showing directly if any and how many bikes are available on each date visible in the calendar picker.
So people would not have to check a gazillion dates to find one where a bike is actually available or four bikes if a group is looking to rent one per person at the same time.
The difficulty with this is processing time. Allowing the user the see 1 day or even a few days availability would be okay, but a full 30 day calendar view would take more than a minute. This is one of the reasons that Woo Bookings is built the way it is.
I am working on something that allows a static view, see my post about availability calendars
Thanks for you reply!
I do have another question:
I would like to display the following first (__ is being selected by the customer:
Rental Start Date: __
Rental End Date: __
Then the tool should display all available resource during that time frame.
Is there a solution available from you, Beth?
Hi Sassi. I have created a mini-plugin for this. You can see it here, https://plugins.doitsimply.co.uk/example-of-simple-date-first/ or you can read the write up I did of it below. If you have any questions please be in touch.
Thanks.
https://plugins.doitsimply.co.uk/2018/06/10/super-simple-availability-search-for-woocommerce-bookings/
It does not wor with person types =[
My simple free plugin is not meant to work with person types.