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_field_data filter to update a dropdown field with the available options. We identify the correct select field by looking for a custom CSS class of dynamic-booking-times.

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 & Jared Atchison
 * @license    GPL-2.0+
 */

function ea_booking_field_dropdown( $field, $form_data ) {

	if( 'select' !== $field['type'] )
		return $field;

	$classes = explode( ' ', $form_data['fields'][ $field['id'] ]['css'] );
	if( ! in_array( 'dynamic-booking-times', $classes ) )
		return $field;

	$field['choices'] = ea_get_available_booking_times( $form_data );
	return $field;
}
add_filter( 'wpforms_field_data', 'ea_booking_field_dropdown', 20, 2 );

/**
 * Get Available Booking Times
 *
 */
function ea_get_available_booking_times( $form_data = array() ) {
     $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] );
                 }
             }
         }
     }

	 return $options;
}

/**
 * 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 ) );

	wpforms()->form->update( EA_BOOKING_FORM_ID, $form_data );

}
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 ) );

		wpforms()->form->update( EA_BOOKING_FORM_ID, $form_data );

        update_option( 'mct_updated_bookings_list', time() );

    }
}
add_action( 'shutdown', 'ea_delete_past_bookings' );

Bill Erickson

Bill Erickson is the co-founder and lead developer at CultivateWP, a WordPress agency focusing on high performance sites for web publishers.

About Me
Ready to upgrade your website?

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

Let's Talk