Exceptions – pages without change over days functionality

If you are using change over days functionality - half day bookings but for some specific booking resource you need to have timeslots or full day bookings, then its possible to make such small customization.
To have change over days functionality only at the specific page(s).

Please open this file ../wp-content/plugins/{Booking Calendar Folder}/inc/_bs/biz_s.php
( you can check how to edit files in WordPress menu in this article https://wpbookingcalendar.com/faq/how-edit-file-in-wp-menu/ )

then find this code:

$exception_pages = array( '/page-no-change-over/' );

and replace it to this code:

$exception_pages = array( '/timesslosts/' );

So in this case, system will not apply change over days to this page.
Its means that you page with time-slots have to look like this: https://server.com/timesslots/

Showing only selected payment form, after booking process.

Its possible to configure to show only one payment system after booking process, if visitor selected payment system in booking form.
Example of configuration selectbox in the booking form at the Booking > Settings > Form page:

Select payment method: [select payment-method "All payment methods@@" "Stripe@@stripe_v3" "PayPal@@paypal" "Authorize.Net@@authorizenet" "Sage Pay@@sage" "Bank Transfer@@bank_transfer" "Pay in Cash@@pay_cash" "iPay88@@ipay88" "iDEAL@@ideal"]

Available only  in latest updates of Booking Calendar 8.5.2 or newer.

After visitor selected specific payment system in the booking form, only this payment form will be showing after submit of booking. Its also can be useful in the Booking Calendar Business Medium or higher versions, for setting additional "Payment system fee" (commission) at the Booking > Resources > Advanced cost page.
Check more about this feature here. Watch it in this video guide.

Unlimited bookings per same day(s) for specific booking resource(s)

By default option "Allow unlimited bookings per same day(s)" from Advanced section of Booking > Settings General page is working for all booking resources. What's if you need to activate this for specific booking resource(s).

By default its does not possible to configure this via settings in the Booking Calendar You need to make source code customization for having this functionality.

For example, let you having the booking resources with following ID:

- ID = 3 "Resource A" ( after booking having days as unavailable )
- ID = 4 "Resource B" (need to have option " Allow unlimited bookings per same day(s) " - days always available )
- ID = 5 "Resource C" (need to have option " Allow unlimited bookings per same day(s) " - days always available )

Please open this file ../wp-content/plugins/{Booking Calendar Folder}/core/lib/wpdev-booking-class.php
( you can check how to edit files in WordPress menu in this article https://wpbookingcalendar.com/faq/how-edit-file-in-wp-menu/ )

then find this code:

********************************

        $booking_is_days_always_available = get_bk_option( 'booking_is_days_always_available' );
//        if ( strpos($_SERVER['REQUEST_URI'],'page=wpbc-new') !== false ) { $booking_is_days_always_available = 'On'; }
        // if ( in_array( $bk_type, array( '12', '15', '17' ) ) ) $booking_is_days_always_available = 'On';     // Set  dates in calendar always available only  for specific resources with specific ID

********************************

and replace it to this code:

********************************

        $booking_is_days_always_available = get_bk_option( 'booking_is_days_always_available' );
//        if ( strpos($_SERVER['REQUEST_URI'],'page=wpbc-new') !== false ) { $booking_is_days_always_available = 'On'; }
if ( in_array( $bk_type, array( '4', '5' ) ) ) $booking_is_days_always_available = 'On';     // Set  dates in calendar always available only  for specific resources with specific ID

********************************

Of course, if you have the different ID (than 3 and 4) of such booking resources you need to make fixes in the code: array( '4', '5' ) .

Also at the Booking > Settings General page in calendar section, you need to be sure that these options was unchecked:
- "Use pending days as available"
- "Allow unlimited bookings per same day(s)"

Disclaimer. Please note, if you will modify the source code of the Booking Calendar, we will not guaranteed the correct work of plugin and do not support it.

Tracking form submission

1) Simple way of tracking after redirection to the "Thank you" page.
In case, if you do not have showing "Payment form(s)" after submission of the bookings (in paid versions of Booking Calendar), and you have defined the "Redirection to the "Thank you" page (instead o showing "Thank you" message) at the Booking > Settings General page in Form section, so then simplest way to add your "tracking code" (like Google Adwords code) inside of your "Thank you" page. Please open your "thank you" page for editing, switch to the "Text view mode" of your content editor (html view mode) and insert your Tracking code, which was provided by Google Adwords or some other tracking service.

2) Other more flexible way of tracking booking form submission is adding code in your functions.php file of your theme.
Firs of all please update your version of Booking Calendar to the update 8.6 or newer. You can request the new update of paid versions of Booking Calendar on this page.

After this add inside of the functions.php file of your theme code similar to this,
(you can check how to edit files in WordPress menu in this article):

function my_booking_tracking( $params ){
   ?><!-- Google Code for Booking Conversion Page -->
   <script type="text/javascript">
    /* Insert bellow your Google Tracking Code  */
   </script><?php
}
add_action( 'wpbc_track_new_booking', 'my_booking_tracking' );

Kind Regards.

How to show featured images and small text description in search availability results ?

If you need to show the description and the images in the search results like in this search availability demo.

Then the text  in search  results is getting from "Excerpt” section  of  post,  where you have inserted the booking form 
and the image - its "Favorite image" of this post.

In search  result form  at the Booking > Settings > Search page you will be need to  use these shortcodes:

[booking_featured_image] - featured image, taken from the featured image associated with the post,
[booking_info] - booking info, taken from the  excerpt associated with the post

In case if you are using pages with booking forms and not the posts.
You need to install  some other plugins,  like "page-excerpt" plugin, which will  add the excerpt section to the pages,  as well.
The "Featured Image" by  default is supporting in Pages,  as well. But this functionality  must  support by your theme.
So please contact  support of your theme,  about  adding ability to  use "Featured Images" in your pages.

How to add deselect dates button in booking form?

Please add this code int the booking form at the Booking > Settings > Form page, for ability to deselect dates in calendar by clicking on "Deselect" button:

	<a href="javascript:void(0)" onclick="javascript:reset_days_selection( this );" class="btn">Unselect Dates</a>
	<script type="text/javascript">
			function reset_days_selection( el ) {
				var br_id = jQuery( el ).closest( 'form' ).find( 'input[name^="bk_type"]' ).val();
				wpbc_unselect_all_days( br_id );
				if( typeof( showCostHintInsideBkForm ) == 'function' ) {  showCostHintInsideBkForm( br_id ); }
			}
   </script>

How to have times fields for 1 selected day and no time fields for multiple days?

You need to define the times selection in booking form at the Booking > Settings > Form page in a way like this:

<p class="times_section">Select Start times:<br />[select starttime class:start_selection "All day(s) booking@@00:00" "08:00" "08:30" "09:00" "09:30" "10:00" "10:30" "11:00" "11:30" "12:00" "12:30" "13:00" "13:30" "14:00" "14:30" "15:00" "15:30" "16:00" "16:30" "17:00" "17:30" "18:00" "18:30" "19:00" "19:30" "20:00" "20:30" "21:00"]</p> 
<p class="times_section time_duration_section">Select time duration:<br />[select durationtime class:duration_selection "All day booking@@24:00" "1 hour@@01:00" "2 hours@@02:00" "3 hours@@03:00" "4 hours@@04:00" "5 hours@@05:00" "6 hours@@06:00" "7 hours@@07:00" "8 hours@@08:00" "9 hours@@09:00" "10 hours@@10:00"]</p>

Please note, here is trick in start time selection. First option configured like this:
"All day(s) booking@@00:00"
Where value for this option "00:00" is means that entire day will be booked (its internal logic of Booking Calendar plugin).

2) Also you need to add custom JavaScript code, that will show the "duration of time", only in case, if you will select other value than "All day booking", and hide the times fields from the booking form, at all, if you select more than 1 day:

<script type="text/javascript">
    jQuery('.start_selection').on('change', function() {
       var start_time = jQuery(this).find(":selected").val();
	   if ( '00:00' == start_time ) {
       	  jQuery('.time_duration_section').hide();
		  jQuery('.duration_selection').val( '24:00' );
		  jQuery('.time_duration_section option:first').css('display', 'block'); 
	   } else {	   
          jQuery('.time_duration_section').show();
          jQuery('.duration_selection').val( '01:00' );
		  jQuery('.time_duration_section option:first').css('display', 'none');
	   }
     });
     jQuery(document).ready(function(){
		jQuery('.start_selection').val( '00:00' );
		jQuery('.duration_selection').val( '24:00' );
		jQuery('.time_duration_section').hide();
     });	
     jQuery( ".booking_form_div" ).on('date_selected', function(event, bk_type, date) {
           var dates_count =  date.split(',');
		   dates_count = dates_count.length;
		   if ( dates_count > 1 ) {
		       jQuery('.start_selection').val( '00:00' );
		       jQuery('.duration_selection').val( '24:00' );
		       jQuery('.times_section').hide();			   
		   } else {
		       jQuery('.start_selection').val( '00:00' );
		       jQuery('.duration_selection').val( '24:00' );
		       jQuery('.times_section').show();
			   jQuery('.time_duration_section').hide();
		   }
		 if (typeof(showCostHintInsideBkForm) == 'function') {
               showCostHintInsideBkForm( bk_type );
         }
     });	
</script>

So full minimum booking form configuration can look like this:

[calendar] 
<div class="form-hints"> 
          Dates:[selected_short_timedates_hint]  ([nights_number_hint] - night(s))<br><br> 
          Full cost of the booking: [cost_hint] <br> 
</div><hr/> 
<div class="times-form"> 
	<p class="times_section">Select Start times:<br />[select starttime class:start_selection "All day(s) booking@@00:00" "08:00" "08:30" "09:00" "09:30" "10:00" "10:30" "11:00" "11:30" "12:00" "12:30" "13:00" "13:30" "14:00" "14:30" "15:00" "15:30" "16:00" "16:30" "17:00" "17:30" "18:00" "18:30" "19:00" "19:30" "20:00" "20:30" "21:00"]</p> 
	<p class="times_section time_duration_section">Select time duration:<br />[select durationtime class:duration_selection "All day booking@@24:00" "1 hour@@01:00" "2 hours@@02:00" "3 hours@@03:00" "4 hours@@04:00" "5 hours@@05:00" "6 hours@@06:00" "7 hours@@07:00" "8 hours@@08:00" "9 hours@@09:00" "10 hours@@10:00"]</p>
<script type="text/javascript">
    jQuery('.start_selection').on('change', function() {
       var start_time = jQuery(this).find(":selected").val();
	   if ( '00:00' == start_time ) {
       	  jQuery('.time_duration_section').hide();
		  jQuery('.duration_selection').val( '24:00' );
		  jQuery('.time_duration_section option:first').css('display', 'block'); 
	   } else {	   
          jQuery('.time_duration_section').show();
          jQuery('.duration_selection').val( '01:00' );
		  jQuery('.time_duration_section option:first').css('display', 'none');
	   }
     });
     jQuery(document).ready(function(){
		jQuery('.start_selection').val( '00:00' );
		jQuery('.duration_selection').val( '24:00' );
		jQuery('.time_duration_section').hide();
     });	
     jQuery( ".booking_form_div" ).on('date_selected', function(event, bk_type, date) {
           var dates_count =  date.split(',');
		   dates_count = dates_count.length;
		   if ( dates_count > 1 ) {
		       jQuery('.start_selection').val( '00:00' );
		       jQuery('.duration_selection').val( '24:00' );
		       jQuery('.times_section').hide();			   
		   } else {
		       jQuery('.start_selection').val( '00:00' );
		       jQuery('.duration_selection').val( '24:00' );
		       jQuery('.times_section').show();
			   jQuery('.time_duration_section').hide();
		   }
		 if (typeof(showCostHintInsideBkForm) == 'function') {
               showCostHintInsideBkForm( bk_type );
         }
     });	
</script>		
     <p>First Name (required):<br />[text* name] </p> 
     <p>Last Name (required):<br />[text* secondname] </p> 
     <p>Email (required):<br />[email* email] </p>    
     <p>Adults:  [select visitors class:col-md-1 "1" "2" "3" "4"] Children: [select children class:col-md-1 "0" "1" "2" "3"]</p> 
     <p>[submit class:btn "Send"]</p> 
</div>

Deduction capacity in calendar based on “adults” and “children” selection

In Booking Calendar Business Large or higher versions possible to define capacity for booking resources (calendars), for ability to receive several bookings for the same date(s) in the same calendar (booking resource).

Please read more about it here.
You can test it in the live demo.
Watch video about this feature here.
And we highly recommend, to check this article about configuration of capacity and availability for booking resources.

Its means that during the booking process, user can book several "child booking resources" and deduct availability for selected date on number of booked "child booking resources". This number (how many items to book), can depend only from the number of visitors selection in the booking form at the Booking > Settings > Form page:

Visitors: [select visitors class:visitors "1" "2" "3" "4" "5" "6"]

Its often require to make such deduction of availability based on 2 parameters - selection of "adults" and "children" number.
In this case possible to make this JavaScript customization in the booking form, for automatic selection of specific number of visitors, depend from the selection of number of "adults" and "children" in booking form.
Example of configuration:

<p class="wpbc_visitors_selection">Visitors: [select visitors class:visitors "1" "2" "3" "4" "5" "6"] </p>
<p>Adults: [select adults class:adults "1" "2" "3"]</p>
<p>Children: [select children class:children "0" "1" "2" "3"]</p>
<script type="text/javascript">
   	jQuery( 'select.adults').on( 'change',  wpbc_set_visitors_number );
   	jQuery( 'select.children').on( 'change',  wpbc_set_visitors_number );
	function wpbc_set_visitors_number() {
		var s_adults   = jQuery('select.adults option:selected').val();
		var s_children = jQuery('select.children option:selected').val();
		var s_visitors = parseInt(s_adults) + parseInt(s_children);
console.log( s_visitors );
                jQuery('select.visitors option[value=' + s_visitors + ']').prop({selected: true});
		var bk_type = jQuery( "input[name^='bk_type']" ).val();
		if (typeof(showCostHintInsideBkForm) == 'function') {
		      showCostHintInsideBkForm( bk_type );
		}
	}
</script>

This code available for testing purpose. In case, if you need to hide the visitors selection (to have only adults and children selection) as visible option, so then please use this code:

<style type="text/css">
	.wpbc_visitors_selection select {
		width: 1px;
		height: 1px;
		border: none;
		margin: 0;
		padding: 0;
		display: inline;
	}
</style>
<p class="wpbc_visitors_selection">[select visitors class:visitors "1" "2" "3" "4" "5" "6"] </p>
<p>Adults: [select adults class:adults "1" "2" "3"]</p>
<p>Children: [select children class:children "0" "1" "2" "3"]</p>
<script type="text/javascript">
   	jQuery( 'select.adults').on( 'change',  wpbc_set_visitors_number );
   	jQuery( 'select.children').on( 'change',  wpbc_set_visitors_number );
	function wpbc_set_visitors_number() {
		var s_adults   = jQuery('select.adults option:selected').val();
		var s_children = jQuery('select.children option:selected').val();
		var s_visitors = parseInt(s_adults) + parseInt(s_children);
console.log( s_visitors );
                jQuery('select.visitors option[value=' + s_visitors + ']').prop({selected: true});
		var bk_type = jQuery( "input[name^='bk_type']" ).val();
		if (typeof(showCostHintInsideBkForm) == 'function') {
		      showCostHintInsideBkForm( bk_type );
		}
	}
</script>

How to show past bookings in usual calendar?

First of all, Booking Calendar can not show past months, because it’s does not possible to create bookings in past.
You can show past bookings in Timeline view, like in this demo.

But if by some reason, you need to show bookings in usual inline month view calendar, so then you will be need to make this fix.

Please make backup of your Booking Calendar folder at the ../wp-content/plugins/ for ability to restore it, if you will make some mistake, or just need original Booking Calendar version.

Important! Please note, its hack/trick customization. Its will not be supported in future updates. So you will need to make this customization each time after upfdate of plugin. If something is not work, please recheck this instruction once again. Its was test in Booking Calendar update 8.3.2 and working well.

Disclaimer. Unfortunately we can not start, right now, some personal customization or custom development, because almost have no free time.
Check more about new features here https://wpbookingcalendar.com/faq/need-new-feature/
Thank you for understanding.
Please note, if you will modify the source code of the Booking Calendar, we will not guaranteed the correct work of plugin and do not support it.

So let start.

1) Please open this file ../wp-content/plugins/{Booking Calendar Folder}/core/lib/wpdev-booking-class.php

( you can check how to edit files in WordPress menu in this article https://wpbookingcalendar.com/faq/how-edit-file-in-wp-menu/ )

then find this code:

        if ($approved == 'admin_blank') {

            $sql_req = "SELECT DISTINCT dt.booking_date

                     FROM {$wpdb->prefix}bookingdates as dt

                     INNER JOIN {$wpdb->prefix}booking as bk

                     ON    bk.booking_id = dt.booking_id

                     WHERE  dt.booking_date >= CURDATE() {$trash_bookings} AND bk.booking_type IN ($bk_type_additional) AND bk.form like '%admin@blank.com%'

                     ORDER BY dt.booking_date" ;
            $dates_approve = $wpdb->get_results(  $sql_req  );
            
        } else {
            
            if ($approved == 'all')
                $sql_req = apply_bk_filter('get_bk_dates_sql', "SELECT DISTINCT dt.booking_date

                     FROM {$wpdb->prefix}bookingdates as dt

                     INNER JOIN {$wpdb->prefix}booking as bk

                     ON    bk.booking_id = dt.booking_id

                     WHERE  dt.booking_date >= CURDATE() {$trash_bookings} AND bk.booking_type IN ($bk_type_additional)
                         
                     ". (($skip_booking_id != '') ? " AND dt.booking_id NOT IN ( ".$skip_booking_id." ) ":"") ."
                         
                     ORDER BY dt.booking_date", $bk_type_additional, 'all' , $skip_booking_id);

            else
                $sql_req = apply_bk_filter('get_bk_dates_sql', "SELECT DISTINCT dt.booking_date

                     FROM {$wpdb->prefix}bookingdates as dt

                     INNER JOIN {$wpdb->prefix}booking as bk

                     ON    bk.booking_id = dt.booking_id

                     WHERE  dt.approved = $approved AND dt.booking_date >= CURDATE() {$trash_bookings} AND bk.booking_type IN ($bk_type_additional)
                         
                     ". (($skip_booking_id != '') ? " AND dt.booking_id NOT IN ( ".$skip_booking_id." ) ":"") ."

                     ORDER BY dt.booking_date", $bk_type_additional, $approved, $skip_booking_id );
//$sql_req = str_replace( 'dt.booking_date >= CURDATE()  AND', '' , $sql_req);	//Show past bookings,  as well
            $dates_approve = apply_bk_filter('get_bk_dates', $wpdb->get_results( $sql_req ), $approved, 0,$bk_type );
        }

and replace it to this code:

        if ($approved == 'admin_blank') {

            $sql_req = "SELECT DISTINCT dt.booking_date

                     FROM {$wpdb->prefix}bookingdates as dt

                     INNER JOIN {$wpdb->prefix}booking as bk

                     ON    bk.booking_id = dt.booking_id

                     WHERE  1=1 {$trash_bookings} AND bk.booking_type IN ($bk_type_additional) AND bk.form like '%admin@blank.com%'

                     ORDER BY dt.booking_date" ;
            $dates_approve = $wpdb->get_results(  $sql_req  );
            
        } else {
            
            if ($approved == 'all')
                $sql_req = apply_bk_filter('get_bk_dates_sql', "SELECT DISTINCT dt.booking_date

                     FROM {$wpdb->prefix}bookingdates as dt

                     INNER JOIN {$wpdb->prefix}booking as bk

                     ON    bk.booking_id = dt.booking_id

                     WHERE  1=1 {$trash_bookings} AND bk.booking_type IN ($bk_type_additional)
                         
                     ". (($skip_booking_id != '') ? " AND dt.booking_id NOT IN ( ".$skip_booking_id." ) ":"") ."
                         
                     ORDER BY dt.booking_date", $bk_type_additional, 'all' , $skip_booking_id);

            else
                $sql_req = apply_bk_filter('get_bk_dates_sql', "SELECT DISTINCT dt.booking_date

                     FROM {$wpdb->prefix}bookingdates as dt

                     INNER JOIN {$wpdb->prefix}booking as bk

                     ON    bk.booking_id = dt.booking_id

                     WHERE  dt.approved = $approved AND 1=1 {$trash_bookings} AND bk.booking_type IN ($bk_type_additional)
                         
                     ". (($skip_booking_id != '') ? " AND dt.booking_id NOT IN ( ".$skip_booking_id." ) ":"") ."

                     ORDER BY dt.booking_date", $bk_type_additional, $approved, $skip_booking_id );
//$sql_req = str_replace( 'dt.booking_date >= CURDATE()  AND', '' , $sql_req);	//Show past bookings,  as well
            $dates_approve = apply_bk_filter('get_bk_dates', $wpdb->get_results( $sql_req ), $approved, 0,$bk_type );
        }

2) Please open this file ../wp-content/plugins/{Booking Calendar Folder}/js/client.js

( you can check how to edit files in WordPress menu in this article https://wpbookingcalendar.com/faq/how-edit-file-in-wp-menu/ )

then find this code:

var bkMinDate = 0;

and replace it to this code:

var bkMinDate = null;

3)
then find this code:

if (is_this_admin == false) {

and replace it to this code:

if  ( (false) && (is_this_admin == false) ) {

4) Please open this file ../wp-content/plugins/{Booking Calendar Folder}/js/wpbc_times.js

( you can check how to edit files in WordPress menu in this article https://wpbookingcalendar.com/faq/how-edit-file-in-wp-menu/ )

then find this code:

function isTimeTodayGone( myTime, sort_date_array ){

and replace it to this code:

function isTimeTodayGone( myTime, sort_date_array ){
   return false;

5) If you are using paid version of Booking Calendar, then
Please open this file ../wp-content/plugins/{Booking Calendar Folder}/inc/_ps/personal.php

( you can check how to edit files in WordPress menu in this article https://wpbookingcalendar.com/faq/how-edit-file-in-wp-menu/ )

then find this code:

        if ($approved == 'all')
              $sql_req =   "SELECT DISTINCT dt.booking_date

                 FROM {$wpdb->prefix}bookingdates as dt

                 INNER JOIN {$wpdb->prefix}booking as bk

                 ON    bk.booking_id = dt.booking_id

                 WHERE  dt.booking_date >= CURDATE() {$trash_bookings} AND bk.booking_type  IN ($bk_type) ".$skip_bookings."

                 ORDER BY dt.booking_date";

        else
             $sql_req = "SELECT DISTINCT dt.booking_date

                 FROM {$wpdb->prefix}bookingdates as dt

                 INNER JOIN {$wpdb->prefix}booking as bk

                 ON    bk.booking_id = dt.booking_id

                 WHERE  dt.approved = $approved AND dt.booking_date >= CURDATE() {$trash_bookings} AND bk.booking_type IN ($bk_type) ".$skip_bookings."

                 ORDER BY dt.booking_date" ;

and replace it to this code:

        if ($approved == 'all')
              $sql_req =   "SELECT DISTINCT dt.booking_date

                 FROM {$wpdb->prefix}bookingdates as dt

                 INNER JOIN {$wpdb->prefix}booking as bk

                 ON    bk.booking_id = dt.booking_id

                 WHERE  1=1 {$trash_bookings} AND bk.booking_type  IN ($bk_type) ".$skip_bookings."

                 ORDER BY dt.booking_date";

        else
             $sql_req = "SELECT DISTINCT dt.booking_date

                 FROM {$wpdb->prefix}bookingdates as dt

                 INNER JOIN {$wpdb->prefix}booking as bk

                 ON    bk.booking_id = dt.booking_id

                 WHERE  dt.approved = $approved AND 1=1 {$trash_bookings} AND bk.booking_type IN ($bk_type) ".$skip_bookings."

                 ORDER BY dt.booking_date" ;

6) If you are using Booking Calendar Business Large or higher version then, Please open this file ../wp-content/plugins/{Booking Calendar Folder}/inc/_bl/biz_l.php

( you can check how to edit files in WordPress menu in this article https://wpbookingcalendar.com/faq/how-edit-file-in-wp-menu/ )

then find this code:

WHERE ".$my_approve_rule." dt.booking_date >= CURDATE() {$trash_bookings} AND

and replace it to this code:

WHERE ".$my_approve_rule." 1=1 {$trash_bookings} AND

Test it.
Please do not forget to clear browser cache before testing these changes.

Is there any API or hooks for using with Booking Calendar ?

1) Currently there is no full API for using Booking Calendar plugin with other plugins or services.
Some hooks exist, but they does not documented well, yet. We are in process of improving this with future updates of plugin.

2) But still plugin have some useful functions and hooks for such purpose.
Please check this file ../{Booking Calendar Folder}/core/wpbc-dev-api.php
Here you can find some useful functions and hooks.