WPForms – Dynamic availability in booking form

I built an online booking form using WPForms that allowed customers to select from a list of available days/times.

There’s a few components you need:

  1. Client editable list of available days/times
  2. List of days already booked / manually added “unavailable” times
  3. Dynamically generate a list of available times by comparing the two.

I added a settings page to the form for specifying general availability (ex: Monday at 7:30am) and to edit a list of unavailable day/times (ex: Monday, January 28 at 7:30am). When the form is submitted, the selected date is automatically added to the unavailable day/times.

We’re using the wpforms_select_field_display filter to update a dropdown field with the available options. We use the list of general availability to build a list of the actual days/times available from now until 60 days out. We then remove any day/times that are already booked.

<?php
/**
* Core Functionality Plugin
*
* @package CoreFunctionality
* @since 1.0.0
* @copyright Copyright (c) 2014, Bill Erickson
* @license GPL-2.0+
*/
/**
* Booking Times in Dropdown
*
*/
function ea_booking_times_field( $field, $field_atts, $form_data ) {
if( ! in_array( 'dynamic-booking-times', $field_atts['field_class'] ) )
return $field;
$start = strtotime( $form_data['settings']['mct_book_before'], current_time( 'timestamp' ) );
$end = strtotime( $form_data['settings']['mct_book_after'], current_time( 'timestamp' ) );
$availability = explode( PHP_EOL, $form_data['settings']['mct_general_availability'] );
$days = array();
foreach( $availability as $option ) {
$option = explode( ' at ', $option );
$days[$option[0]][] = $option[1];
}
$options = array();
for( $current = $start; $current < $end; $current += DAY_IN_SECONDS ){
$day = date( 'l', $current );
if( isset( $days[$day] ) ) {
foreach( $days[$day] as $time ) {
$daytime = strtotime( date( 'l, F j, Y', $current ) . ' ' . $time );
if( $daytime < $end && $daytime > $start )
$options[] = array( 'label' => date( 'l, F j, Y', $daytime ) . ' at ' . date( 'g:ia', $daytime ), 'value' => $daytime );
}
}
}
$booked = explode( PHP_EOL, $form_data['settings']['mct_booked_times'] );
if( !empty( $booked ) ) {
foreach( $booked as $booked_time ) {
$booked_time = strtotime( str_replace( ' at ', ' ', $booked_time ) );
foreach( $options as $i => $option ) {
if( $option['value'] == $booked_time ) {
unset( $options[$i] );
}
}
}
}
$field['choices'] = $options;
return $field;
}
add_filter( 'wpforms_select_field_display', 'ea_booking_times_field', 10, 3 );
/**
* Update list of booked times on form completion
*
*/
function ea_update_list_of_booked_times( $fields, $entry, $form_data, $entry_id ) {
$booked = explode( PHP_EOL, $form_data['settings']['mct_booked_times'] );
$booked[] = $fields[2]['value'];
$form_data['settings']['mct_booked_times'] = implode( PHP_EOL, array_filter( $booked ) );
remove_filter('content_save_pre', 'wp_filter_post_kses');
remove_filter('content_filtered_save_pre', 'wp_filter_post_kses');
$form = array(
'ID' => EA_BOOKING_FORM_ID,
'post_content' => wp_slash( json_encode( $form_data ) ),
);
$form_id = wp_update_post( $form );
add_filter('content_save_pre', 'wp_filter_post_kses');
add_filter('content_filtered_save_pre', 'wp_filter_post_kses');
}
add_action( 'wpforms_process_complete_' . EA_BOOKING_FORM_ID, 'ea_update_list_of_booked_times', 10, 4 );
/**
* Delete past bookings
*
*/
function ea_delete_past_bookings() {
$last_updated = get_option( 'mct_updated_bookings_list' );
if( ! $last_updated || $last_updated < strtotime( '-24 hours' ) ) {
$form = wpforms()->form->get( EA_BOOKING_FORM_ID );
$form_data = wpforms_decode( $form->post_content );
$booked = explode( PHP_EOL, $form_data['settings']['mct_booked_times'] );
foreach( $booked as $i => $datetime ) {
if( !empty( $datetime ) ) {
$datetime = str_replace( ' at ', ' ', $datetime );
if( strtotime( $datetime ) < current_time( 'timestamp' ) ) {
unset( $booked[$i] );
}
}
}
$form_data['settings']['mct_booked_times'] = implode( PHP_EOL, array_filter( $booked ) );
remove_filter('content_save_pre', 'wp_filter_post_kses');
remove_filter('content_filtered_save_pre', 'wp_filter_post_kses');
$form = array(
'ID' => EA_BOOKING_FORM_ID,
'post_content' => wp_slash( json_encode( $form_data ) ),
);
$form_id = wp_update_post( $form );
add_filter('content_save_pre', 'wp_filter_post_kses');
add_filter('content_filtered_save_pre', 'wp_filter_post_kses');
update_option( 'mct_updated_bookings_list', time() );
}
}
add_action( 'shutdown', 'ea_delete_past_bookings' );
view raw booking-times.php hosted with ❤ by GitHub
<?php
/**
* Core Functionality Plugin
*
* @package CoreFunctionality
* @since 1.0.0
* @copyright Copyright (c) 2014, Bill Erickson
* @license GPL-2.0+
*/
/**
* Setting Panels
*
*/
function ea_setting_panels( $sections, $form_data ) {
if( $form_data['id'] == EA_BOOKING_FORM_ID ) {
$sections['mtc_booking_times'] = __( 'Booking Times', 'ea' );
}
return $sections;
}
add_filter( 'wpforms_builder_settings_sections', 'ea_setting_panels', 20, 2 );
/**
* Setting Panel Content
*
*/
function ea_setting_panel_content( $instance ) {
echo '<div class="wpforms-panel-content-section wpforms-panel-content-section-mtc_booking_times">';
echo '<div class="wpforms-panel-content-section-title">' . __( 'Booking Times', 'ea' ) . '</div>';
wpforms_panel_field(
'text',
'settings',
'mct_book_before',
$instance->form_data,
__( 'Must Book Before', 'ea' )
);
wpforms_panel_field(
'text',
'settings',
'mct_book_after',
$instance->form_data,
__( 'Cannot Book After', 'ea' )
);
wpforms_panel_field(
'textarea',
'settings',
'mct_general_availability',
$instance->form_data,
__( 'General Availability (one per line)', 'ea' ),
array( 'rows' => 20 )
);
wpforms_panel_field(
'textarea',
'settings',
'mct_booked_times',
$instance->form_data,
__( 'Booked Cleanings', 'ea' ),
array( 'rows' => 20 )
);
echo '</div>';
}
add_filter( 'wpforms_form_settings_panel_content', 'ea_setting_panel_content', 20 );
view raw form-settings.php hosted with ❤ by GitHub

Bill Erickson

Bill Erickson is a freelance WordPress developer and a contributing developer to the Genesis framework. For the past 14 years he has worked with attorneys, publishers, corporations, and non-profits, building custom websites tailored to their needs and goals.

Ready to upgrade your website?

I build custom WordPress websites that look great and are easy to manage.

Let's Talk