?
gf-booking-providers.php 0000666 00000025317 15126233304 0011325 0 ustar 00 <?php
defined( 'ABSPATH' ) or exit; // Exit if accessed directly
if ( class_exists( 'GFForms' ) ) {
class GF_Appointment_Booking_Providers extends GF_Field {
public $type = 'appointment_providers';
public function get_form_editor_field_title() {
return esc_attr__( 'Booking Providers', 'gravityforms' );
}
/*
* Where to assign this widget
*/
public function get_form_editor_button() {
return array(
'group' => 'appointment_calendar',
'text' => $this->get_form_editor_field_title()
);
}
/*
* Add button to the group
*/
public function add_button( $field_groups ) {
$field_groups = $this->ga_appointment_providers_gf_group( $field_groups );
return parent::add_button( $field_groups );
}
/*
* Add our group
*/
public function ga_appointment_providers_gf_group( $field_groups ) {
foreach ( $field_groups as $field_group ) {
if ( $field_group['name'] == 'appointment_calendar' ) {
return $field_groups;
}
}
$field_groups[] = array(
'name' => 'appointment_calendar',
'label' => __( 'Appointment Booking', 'simplefieldaddon' ),
'fields' => array(
)
);
return $field_groups;
}
/*
* Widget settings
*/
function get_form_editor_field_settings() {
return array(
'enable_enhanced_ui_setting',
'label_setting',
'error_message_setting',
'label_placement_setting',
'admin_label_setting',
'size_setting',
'description_setting',
'css_class_setting',
'rules_setting',
'conditional_logic_field_setting',
'visibility_setting'
);
}
public function is_conditional_logic_supported() {
return true;
}
/**
* Field Markups
*/
public function get_field_input( $form, $value = '', $entry = null ) {
$form_id = absint( $form['id'] );
$is_entry_detail = $this->is_entry_detail();
$is_form_editor = $this->is_form_editor();
$id = $this->id;
$field_id = $is_entry_detail || $is_form_editor || $form_id == 0 ? "input_$id" : 'input_' . $form_id . "_$id";
$logic_event = $this->get_conditional_logic_event( 'change' );
$size = $this->size;
$class_suffix = $is_entry_detail ? '_admin' : '';
$chosenUI = $this->enableEnhancedUI ? ' chosen-select' : '';
$providers_class = ' appointment_provider_id';
$class = $size . $class_suffix . $chosenUI . $providers_class;
$css_class = trim( esc_attr( $class ) . ' gfield_select' );
$tabindex = $this->get_tabindex();
$disabled_text = $is_form_editor ? 'disabled="disabled"' : '';
$required_attribute = $this->isRequired ? 'aria-required="true"' : '';
$invalid_attribute = $this->failed_validation ? 'aria-invalid="true"' : 'aria-invalid="false"';
$select_providers = '';
if( $this->is_entry_edit() ) {
$select_providers .= sprintf( "<div class='ginput_container ginput_container_select'><select name='input_%d' id='%s' $logic_event class='%s' $tabindex %s %s %s>%s</select></div>", $id, $field_id, $css_class, $disabled_text, $required_attribute, $invalid_attribute, $this->get_providers_entry_choices($form, $value) );
} elseif( !$this->is_form_editor() ) {
if( ga_service_id($form) && gf_field_type_exists( $form, 'appointment_services' ) ) {
$select_providers .= sprintf( "<div class='ginput_container ginput_container_select'><select name='input_%d' id='%s' $logic_event class='%s' $tabindex %s %s %s form_id='%d'>%s</select></div>", $id, $field_id, $css_class, $disabled_text, $required_attribute, $invalid_attribute, $form_id, $this->get_providers_choices($form, $value) );
} else {
$select_providers .= '<p>' .ga_get_form_translated_data($form = false, 'error_no_services'). '</p>';
}
}
return $select_providers;
}
/**
* Is Entry Edit
*/
public function is_entry_edit() {
if ( rgget( 'page' ) == 'gf_entries' && rgget( 'view' ) == 'entry' && rgpost( 'screen_mode' ) == 'edit' ) {
return true;
}
return false;
}
/**
* Returns TRUE if the current page is the form editor page. Otherwise, returns FALSE
*/
public function is_form_editor() {
if ( rgget( 'page' ) == 'gf_edit_forms' && ! rgempty( 'id', $_GET ) && rgempty( 'view', $_GET ) ) {
return true;
}
return false;
}
/**
* Get Provider Select Options
*/
public function get_providers_choices($form, $value) {
if( !ga_service_id($form) ) {
return '';
}
$options = '';
$service_id = absint( ga_service_id($form) );
$provider_id = '';
// Form submited services field value
if( gf_field_type_exists($form, 'appointment_services') ) {
$services_field_value = gf_get_field_type_value($form, 'appointment_services');
if( is_numeric($services_field_value) && 'ga_services' == get_post_type($services_field_value) ) {
$service_id = $services_field_value;
}
if( is_numeric($value) ) {
$provider_id = $value;
}
}
$args = array( 'post_type' => 'ga_providers', 'posts_per_page' => -1, 'orderby' => 'date', 'order' => 'DESC', 'meta_query' => array(array('key' => 'ga_provider_services', 'value' => serialize( strval( $service_id ) ), 'compare' => 'LIKE') ) );
$the_query = new WP_Query( $args );
wp_reset_postdata();
// The Loop
if ( $the_query->have_posts() ) {
while ( $the_query->have_posts() ) {
$the_query->the_post();
$post = get_post( get_the_id() );
$selected = $provider_id == get_the_id() ? ' selected="selected"' : '';
$options .= '<option value="'.get_the_ID().'"'.$selected.'>'.$post->post_title.'</option>' . PHP_EOL;
}
wp_reset_postdata();
} else {
$options .= '<option value="0">No preference</option>' . PHP_EOL;
}
return $options;
}
/**
* Get Providers Entry Options
*/
public function get_providers_entry_choices($form, $value) {
$args = array( 'post_type' => 'ga_providers', 'posts_per_page' => -1, 'orderby' => 'date', 'order' => 'DESC' );
$the_query = new WP_Query( $args );
wp_reset_postdata();
$options = '<option value="0">No preference</option>' . PHP_EOL;
// The Loop
if ( $the_query->have_posts() ) {
while ( $the_query->have_posts() ) {
$the_query->the_post();
$post = get_post( get_the_id() );
$selected = $value == get_the_id() ? ' selected="selected"' : '';
$options .= '<option value="'.get_the_ID().'"'.$selected.'>'.$post->post_title.'</option>' . PHP_EOL;
}
wp_reset_postdata();
}
return $options;
}
/**
* Validation Failed
*/
private function validationFailed( $message = '' ) {
$this->failed_validation = true;
$message = esc_html__( $message, 'gravityforms' );
$this->validation_message = empty( $this->errorMessage ) ? $message : $this->errorMessage;
}
/**
* Validation
*/
public function validate( $value, $form ) {
$form_id = absint( $form['id'] );
// Check if services widget is found
if( gf_field_type_exists( $form, 'appointment_services' ) && 'ga_services' == get_post_type( gf_get_field_type_value( $form, 'appointment_services' ) ) ) {
# service exists
} else {
$this->validationFailed( ga_get_form_translated_error_message($form_id, 'error_required_service') );
return;
}
// Service field value
$service_id = gf_get_field_type_value( $form, 'appointment_services' );
// Selected service exists in form category term
$form_cat_slug = rgar($form, 'ga_service_category');
$cat = term_exists( $form_cat_slug, 'ga_service_cat' );
if( $cat ) {
if( has_term( $cat, 'ga_service_cat', $service_id ) ) {
# valid
} else {
$this->validationFailed( ga_get_form_translated_error_message($form_id, 'error_required_service') );
return;
}
}
// Service has a provider assigned, this function will get first provider ID
if( ga_get_provider_id($service_id) && is_numeric($value) ) {
$provider_id = $value;
// Provider has the selected service
if( ga_provider_has_service($service_id, $provider_id) ) {
} else {
$this->validationFailed( ga_get_form_translated_error_message($form_id, 'error_providers_service') );
return;
}
} elseif( !ga_get_provider_id($service_id) && $value == 0 ) {
# Service doesn't have any providers assigned but still valid as 0 for no provider
//$this->validationFailed( 'Service doesn\'t have providers' );
//return;
} else {
$this->validationFailed( ga_get_form_translated_error_message($form_id, 'error_required_provider') );
return;
}
}
/**
* Save value
*/
public function get_value_save_entry( $value, $form, $input_name, $entry_id, $entry ) {
//$post_id = absint( $_POST['appointment_booking_provider'] );
//$value = get_the_title( $post_id );
return $value;
}
/**
* Show provider title on entry single & GP Preview Plugin
*/
public function get_value_entry_detail( $value, $currency = '', $use_text = false, $format = 'html', $media = 'screen' ) {
$post_id = absint( $value );
if( 'ga_providers' == get_post_type($post_id) ) {
$value = get_the_title( $post_id );
return esc_html( $value );
}
if( $value == 0 ) {
return 'No preference';
}
}
/*
* Show provider title on entry list
* To sanitize values before being output in the entry list page
*/
/*
public function get_value_entry_list( $value, $entry, $field_id, $columns, $form ) {
$post_id = absint( $value );
if( 'ga_providers' == get_post_type($post_id) ) {
$value = get_the_title( $post_id );
return esc_html( $value );
}
if( $value == 0 ) {
return 'No preference';
}
}
*/
/**
* Merge tag, on notifications, confirmations
*/
public function get_value_merge_tag( $value, $input_id, $entry, $form, $modifier, $raw_value, $url_encode, $esc_html, $format, $nl2br ) {
$post_id = absint( $value );
if( 'ga_providers' == get_post_type($post_id) ) {
$value = get_the_title( $post_id );
return esc_html( $value );
}
if( $value == 0 ) {
return 'No preference';
}
}
public function get_form_editor_inline_script_on_page_render() {
return "
gform.addFilter('gform_form_editor_can_field_be_added', function (canFieldBeAdded, type) {
if (type == 'appointment_providers') {
if (GetFieldsByType(['appointment_providers']).length > 0) {
alert(" . json_encode( esc_html__( 'Only one Booking Providers field can be added to the form', 'gravityformscoupons' ) ) . ");
return false;
}
}
return canFieldBeAdded;
});";
}
} // end class
GF_Fields::register( new GF_Appointment_Booking_Providers() );
} // end if
ga-calendar.php 0000666 00000114456 15126233304 0007431 0 ustar 00 <?php
defined( 'ABSPATH' ) or exit; // Exit if accessed directly
class GA_Calendar {
private $month;
private $year;
private $selected_date;
private $selected_slot;
private $days_of_week = array('Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat');
private $week_starts;
private $num_days;
private $date_info;
private $day_of_week;
private $time_zone;
private $service_id;
private $provider_id;
private $form_id = 0;
public function __construct( $form_id, $month, $year, $service_id, $provider_id, $selected_date = false, $selected_slot = false ) {
// FORM ID
$this->form_id = $form_id ? $form_id : 0;
// MONTH & DATE
$this->month = $month;
$this->year = $year;
$this->selected_date = $selected_date ? $selected_date : false;
$this->selected_slot = $selected_slot ? $selected_slot : false;
// SERVICE & PROVIDER ID
$this->service_id = (int) $service_id;
$this->provider_id = (int) $provider_id;
// TIMEZONE
$this->time_zone = ga_time_zone();
// DATEINFO
$date = new DateTime();
$date->setTimezone( new DateTimeZone( $this->time_zone ) );
$this->date_info = $date->setDate( (int) $this->year, (int) $this->month, 1 );
$this->num_days = $date->format('t');
$this->day_of_week = $this->date_info->format('w');
// Days of week translated
$this->days_of_week = ga_get_form_translated_data($this->form_id, 'weeks');
// Week starts on
$calendar = get_option('ga_appointments_calendar');
$this->week_starts = isset( $calendar['week_starts'] ) ? $calendar['week_starts'] : 'sunday';
}
/**
* Get Available Days from Schedule
*/
private function get_available_days($array, $timestamp) {
// SERVICE PERIOD TYPE
$period_type = (string) get_post_meta($this->service_id, 'ga_service_period_type', true);
if( $period_type == 'date_range' ) {
$range = (array) get_post_meta($this->service_id, 'ga_service_date_range', true);
$dates = array();
if( isset($range['from']) && ga_valid_date_format($range['from']) && isset($range['to']) && ga_valid_date_format($range['to']) ) {
$period = new DatePeriod(
new DateTime($range['from']),
new DateInterval('P1D'),
new DateTime($range['to'])
);
foreach ($period as $key => $value) {
$dates[] = $value->format('Y-m-j');
}
$dates[] = $range['to'];
}
return $dates;
}
if( $period_type == 'custom_dates' ) {
$custom_dates = (array) get_post_meta($this->service_id, 'ga_service_custom_dates', true);
return $custom_dates;
}
$array = (array) $array;
$weeks = array('sunday' ,'monday', 'tuesday', 'wednesday', 'thursday', 'friday', 'saturday');
$dates = array();
foreach( $array as $week ) {
if( in_array($week, $weeks) ) {
$date = new DateTime();
$date->setTimezone( new DateTimeZone( $this->time_zone ) );
$date->setTimestamp($timestamp);
$date->modify("first $week of this month");
$thisMonth = $date->format('m');
while ($date->format('m') == $thisMonth) {
$dates[] = $date->format('Y-m-j');
$date->modify("next $week");
}
}
}
return $dates;
}
/**
* Get Date Timestamp
*/
private function get_date_timestamp($year, $month, $day = false) {
$date = new DateTime();
$date->setTimezone( new DateTimeZone( $this->time_zone ) );
$day = $day ? $day : 1;
$date->setDate( (int) $year, (int) $month, $day );
return $date->getTimestamp();
}
/**
* Display Calendar
*/
public function show() {
// Calendar caption header
$output = '<div class="ga_appointments_calendar_header">' . PHP_EOL;
// Previous Month
if( $this->previous_month() ) {
$output .= '<a class="arrow-left" date-go="'. $this->date_info->format('Y-m') .'" service_id="'.$this->service_id.'" provider_id="'.$this->provider_id.'" id="ga_calendar_prev_month"><i class="fa fa-caret-left" aria-hidden="true"></i></a>' . PHP_EOL;
}
// Translation: Month/Year Caption
$month = $this->date_info->format('F');
$year = $this->date_info->format('Y');
$lang = ga_get_form_translated_month( $this->form_id, $month, $year );
$output .= '<h3>'. $lang .'</h3>' . PHP_EOL;
// Next Month
if( $this->next_month() ) {
$output .= '<a class="arrow-right" date-go="'. $this->date_info->format('Y-m') .'" service_id="'.$this->service_id.'" provider_id="'.$this->provider_id.'" id="ga_calendar_next_month"><i class="fa fa-caret-right" aria-hidden="true"></i></a>' . PHP_EOL;
}
$output .= '</div>' . PHP_EOL;
// Table start
$output .= '<table class="table_fixed" width="100%">' . PHP_EOL;
$output .= '<thead>' . PHP_EOL;
$output .= '<tr>' . PHP_EOL;
// Week starts on monday
if( $this->week_starts == 'monday' ) {
$sunday = $this->days_of_week['sun'];
unset( $this->days_of_week['sun'] );
$this->days_of_week['sun'] = $sunday;
$this->day_of_week = $this->day_of_week - 1;
if ($this->day_of_week < 0) {
$this->day_of_week = 6;
}
}
// Days of the week header
foreach( $this->days_of_week as $day ) {
$output .= '<th class="ga_header">' . $day . '</th>' . PHP_EOL;
}
// Close header row and open first row of days
$output .= '</tr>' . PHP_EOL;
$output .= '</thead>' . PHP_EOL;
$output .= '<tbody id="service-working-days">' . PHP_EOL;
$output .= '<tr>' . PHP_EOL;
// If first day of a month does not fall on a Sunday, then we need to fill
if( $this->day_of_week > 0 ) {
$output .= str_repeat( '<td class="ga_day_past"></td>', $this->day_of_week );
}
// start num_days counter
$current_day = 1;
// available days
$available_days = $this->get_available_days( array_keys( $this->get_week_day_schedule() ), $this->get_date_timestamp($this->year, $this->month) );
if( $this->month_passed() ) {
$available_days = array();
}
$service_price = $this->service_price(); // false for array
// Loop and build days
while( $current_day <= $this->num_days ) {
// Reset 'days of week' counter and close each row if end of row
$current_date = new DateTime( $this->date_info->format("Y-m-$current_day"), new DateTimeZone( $this->time_zone ) );
$slots_booked = count( $this->get_slots( $current_date ) ) > 0 ? false : true;
$classes = in_array($current_date->format('Y-m-j'), $available_days)
&& !in_array( $current_date->format("Y-m-j"), $this->get_holidays() )
&& !$slots_booked
&& !$this->date_passed($current_date)
&& !$this->max_schedule_days( $current_date )
? 'day_available ga_time_slots' : 'day_unavailable ga_time_slots';
// Date selected from form submission
$selected = '';
if( $this->selected_date && in_array($this->selected_date->format('Y-m-j'), $available_days) ) {
// Add selected class
if( $this->selected_date->format('Y-m-j') == $current_date->format('Y-m-j') ) {
$selected = ' selected';
$classes .= $selected;
}
// Date Slots Mode
if( $this->available_times_mode() == 'no_slots' ) {
# do nothing
} else {
// Time Slots Mode
$placed_it = clone $this->selected_date;
$placed_it->modify("next {$this->week_starts}");
if( $current_date->format('Y-m-j') == $placed_it->format('Y-m-j') && $this->day_of_week = 7 ) {
$output .= '</tr><tr id="gappointments_calendar_slots"><td colspan="7" class="calendar_slots"><div class="calendar_time_slots">';
$output .= $this->calendar_time_slots($this->selected_date, $this->selected_slot);
$output .= '</div></td>';
}
}
}
// Date selected from form submission
// Reset 'days of week' counter and close each row if end of row
if( $this->day_of_week == 7 ) {
$output .= '</tr><tr>' . PHP_EOL;
$this->day_of_week = 0;
}
// Current date is today
if( $this->is_today( $current_date ) ) {
$today = ' ga_today';
$classes .= $today;
} else {
$today = '';
}
// Date Slots Mode
if( $this->available_times_mode() == 'no_slots' ) {
if( $this->is_date_available($current_date) && !$this->max_schedule_days($current_date) ) {
// Translation Support
$month = $current_date->format("F");
$day = $current_date->format("j");
$year = $current_date->format("Y");
$translate = ga_get_form_translated_slots_date( $this->form_id, $month, $day, $year );
$lang_slot = ' lang_slot="'.$translate.'"';
// Translation Support
// Date is available
$classes = "day_available{$today} ga_date_slots{$selected}";
// Multiple Slots selection
$multi_select = (string) get_post_meta($this->service_id, 'ga_service_multiple_selection', true);
$max_bookings = ga_get_service_max_bookings($this->service_id);
$max_total = ga_get_service_max_selection($this->service_id);
$double = ga_get_service_double_bookings($this->service_id);
$multiple = $multi_select == 'yes' ? ' multi-select="enabled" select-total="'.$max_total.'" no_double="'.$double.'"' : '';
// Capacity available
if( $count = $this->date_capacity_text($current_date) ) {
$capacity = $count == 1 ? ga_get_form_translated_space($this->form_id, $count) : ga_get_form_translated_spaces($this->form_id, $count);
$classes .= ' ga_tooltip';
$output .= '<td class="'.$classes.'" ga-tooltip="'.$capacity.'" date-go="'.$this->date_info->format("Y-m-$current_day").'" service_cost="'.$service_price.'" service_id="'.$this->service_id.'" provider_id="'.$this->provider_id.'"'. $multiple . $lang_slot . 'capacity="'.$count.'"><span>'. $current_day .'</span></td>' . PHP_EOL;
} else {
$output .= '<td class="'.$classes.'" date-go="'.$this->date_info->format("Y-m-$current_day").'" service_cost="'.$service_price.'" service_id="'.$this->service_id.'" provider_id="'.$this->provider_id.'"'. $multiple . $lang_slot .' capacity="1"><span>'. $current_day .'</span></td>' . PHP_EOL;
}
} else {
// Date not available
$classes = "day_unavailable{$today} ga_date_slots";
$output .= '<td class="'.$classes.'" date-go="'.$this->date_info->format("Y-m-$current_day").'" service_cost="'.$service_price.'"><span>'. $current_day .'</span></td>' . PHP_EOL;
}
} else {
// Time Slots Mode
$output .= '<td class="'.$classes.'" date-go="'.$this->date_info->format("Y-m-$current_day").'" service_id="'.$this->service_id.'" provider_id="'.$this->provider_id.'" service_cost="'.$service_price.'"><span>'. $current_day .'</span></td>' . PHP_EOL;
}
// Increment counters
$current_day++;
$this->day_of_week++;
}
// Once num_days counter stops, if day of week counter is not 7, then we
// need to fill remaining space on the row using colspan
if( $this->day_of_week != 7 ) {
$remaining_days = 7 - $this->day_of_week;
$output .= str_repeat( '<td class="ga_day_future"></td>', $remaining_days );
}
// Date selected from form submission
// Place at the end
if( $this->available_times_mode() == 'no_slots' ) {
# do nothing
} else {
if( $this->selected_date && in_array($this->selected_date->format('Y-m-j'), $available_days) ) {
// Last day of month from selected date
$month_end = clone $this->selected_date;
$month_end->modify("last day of this month");
// Next sunday from selected date
$placed_end = clone $this->selected_date;
$placed_end->modify("next {$this->week_starts}");
//var_dump( $placed_end > $month_end );
if( $placed_end > $month_end ) {
$output .= '</tr><tr id="gappointments_calendar_slots"><td colspan="7" class="calendar_slots"><div class="calendar_time_slots">';
$output .= $this->calendar_time_slots($this->selected_date, $this->selected_slot);
$output .= '</div></td>';
}
}
}
// Date selected from form submission
// Close final row and table
$output .= '</tr>' . PHP_EOL;
$output .= '</tbody>' . PHP_EOL;
$output .= '</table>' . PHP_EOL;
return $output;
//echo $output;
}
/**
* Slot Available Query
*/
public function slot_availability_query( $dateTime, $slot ) {
$slot_start = $slot['start'];
if( $this->schedule_lead_time( $dateTime, $slot_start ) ) {
# valid time & date
} else {
return false;
}
$date = $dateTime->format("Y-m-j");
$slot_end = ga_get_time_end($slot_start, $this->service_id);
global $wpdb;
$querystr = "
SELECT $wpdb->posts.ID
FROM
$wpdb->posts,
$wpdb->postmeta AS app_date,
$wpdb->postmeta AS provider,
$wpdb->postmeta AS time1,
$wpdb->postmeta AS time2
WHERE
$wpdb->posts.ID = app_date.post_id
AND
$wpdb->posts.ID = provider.post_id
AND
$wpdb->posts.ID = time1.post_id
AND
$wpdb->posts.ID = time2.post_id
AND $wpdb->posts.post_type = 'ga_appointments'
AND $wpdb->posts.post_status IN ('completed', 'publish', 'payment', 'pending')
AND app_date.meta_key = 'ga_appointment_date'
AND app_date.meta_value = %s
AND provider.meta_key = 'ga_appointment_provider'
AND provider.meta_value = %s
AND time1.meta_key = 'ga_appointment_time_end'
AND time1.meta_value > %s
AND time2.meta_key = 'ga_appointment_time'
AND time2.meta_value < %s
";
$sql_prepare = $wpdb->prepare($querystr, $date, $this->provider_id, $slot_start, $slot_end);
$appointments = $wpdb->get_results( $sql_prepare, ARRAY_A );
//var_dump( count($appointments) );
return count($appointments);
}
/**
* Is slot available
*/
public function is_slot_available( $dateTime, $slot ) {
$appointments = $this->slot_availability_query( $dateTime, $slot );
if( $appointments === false ) {
return false;
}
if( $appointments == 0 ) {
return true;
}
if( $this->available_times_mode() == 'custom' ) {
$capacity = $slot['capacity'];
} else {
$capacity = $this->service_capacity();
}
if ( $appointments >= $capacity ) {
return false;
}
return true;
}
/**
* Capacity Available Text
*/
public function slot_capacity_text( $dateTime, $slot ) {
$appointments = $this->slot_availability_query( $dateTime, $slot );
if( $appointments === false ) {
return false;
}
if( $this->available_times_mode() == 'custom' ) {
$capacity = $slot['capacity'];
} else {
$capacity = $this->service_capacity();
}
if( $appointments > 0 && $appointments < $capacity ) {
return ($capacity - $appointments);
} elseif( $appointments == 0 && $capacity > 1 ) {
return $capacity;
}
return false;
}
/**
* Date Available Query
*/
public function date_availability_query( $dateTime ) {
if( $this->schedule_lead_time_days( $dateTime ) ) {
# valid date
} else {
return false;
}
$date = $dateTime->format("Y-m-j");
$appointments = new WP_QUERY(
array(
'post_type' => 'ga_appointments',
'posts_per_page' => -1,
'post_status' => array( 'completed', 'publish', 'payment', 'pending' ),
'orderby' => 'meta_value',
'order' => 'ASC',
'meta_query' => array( 'relation' => 'AND',
array( 'key' => 'ga_appointment_date', 'value' => $date ),
array( 'key' => 'ga_appointment_provider', 'value' => $this->provider_id ),
),
)
);
return $appointments;
}
/**
* Date Available
*/
public function is_date_available( $dateTime ) {
// Week day shedule is not out
$week_day = (string) strtolower( $dateTime->format('l') );
$schedule = $this->get_week_day_schedule();
if( isset($schedule[$week_day]) ) {
$schedule = $schedule[$week_day];
} else {
return false;
}
$appointments = $this->date_availability_query( $dateTime );
if( !$appointments || $this->date_slot_passed($dateTime) ) {
return false;
}
$available_days = $this->get_available_days( array_keys( $this->get_week_day_schedule() ), $this->get_date_timestamp($this->year, $this->month) );
if( $this->month_passed() ) {
$available_days = array();
}
if( in_array($dateTime->format('Y-m-j'), $available_days) && !in_array($dateTime->format("Y-m-j"), $this->get_holidays()) ) {
# valid
} else {
return false;
}
$capacity = $this->service_capacity();
if ( $appointments->have_posts() && $capacity <= $appointments->post_count ) {
return false;
}
return true;
}
/**
* Date Capacity Text
*/
public function date_capacity_text( $dateTime ) {
$appointments = $this->date_availability_query( $dateTime );
if( !$appointments ) {
return false;
}
$capacity = $this->service_capacity();
if( $appointments->post_count > 0 && $appointments->post_count < $capacity ) {
return ($capacity - $appointments->post_count);
} elseif( $appointments->post_count == 0 && $capacity > 1 ) {
return $capacity;
}
return false;
}
/**
* New appointment lead time require for new appointments
* @ returns true if valid
*/
public function schedule_lead_time( $dateTime, $slot_start ) {
// Lead time minutes
$service_lead_time = get_post_meta($this->service_id, 'ga_service_schedule_lead_time_minutes', true);
$lead_time = $service_lead_time && array_key_exists( $service_lead_time, ga_schedule_lead_time_minutes() ) ? $service_lead_time : '240';
// Today's date
$today = ga_current_date_with_timezone();
//var_dump( $lead_time );
// Slot time with date
$slot_time = new DateTime( $slot_start, new DateTimeZone( $this->time_zone ) );
$slot_time->setDate( $dateTime->format("Y"), $dateTime->format("m"), $dateTime->format("j") );
// If no lead time, is slot dateTime less or equal then today
if( $lead_time == 'no' ) {
if( $slot_time <= $today ) {
return false;
}
return true;
}
$lead = $today;
$lead = $lead->modify("+{$lead_time} minutes");
//print_r( "Start: {$slot_time->format('Y-m-j H:i')} | End: {$lead->format('Y-m-j H:i')}" . '<br>');
if( $slot_time <= $lead ) {
//echo "Not valid: {$slot_time->format('Y-m-j H:i')} | Lead end: {$lead->format('Y-m-j H:i')}<br>";
return false;
}
return true;
}
/**
* New appointment lead time require for bookable dates
* @ returns true if valid
*/
public function schedule_lead_time_days( $dateTime ) {
// Lead time minutes
$service_lead_time = get_post_meta($this->service_id, 'ga_service_schedule_lead_time_minutes', true);
$lead_time = $service_lead_time && array_key_exists( $service_lead_time, ga_schedule_lead_time_minutes() ) ? $service_lead_time : '240';
// Today's date
$today = ga_current_date_with_timezone();
//var_dump( $lead_time );
// If no lead time, is slot dateTime less or equal then today
if( $lead_time == 'no' ) {
$dateTime->setTime(23, 59);
if( $dateTime <= $today ) {
return false;
}
return true;
}
$lead = $today;
$lead = $lead->modify("+{$lead_time} minutes");
if( $dateTime <= $lead ) {
//echo "Not valid: {$slot_time->format('Y-m-j H:i')} | Lead end: {$lead->format('Y-m-j H:i')}<br>";
return false;
}
return true;
}
/**
* Display Slots
*/
public function get_slots( $date ) {
switch ( $this->available_times_mode() ) {
case 'interval':
return $this->generate_time_slots( $date );
case 'custom':
return $this->get_custom_slots( $date );
case 'no_slots':
return array();
default:
return array();
}
}
/**
* Get Date Schedule
*/
public function get_date_schedule( $date ) {
$week_day = (string) strtolower( $date->format('l') );
$schedule = $this->get_week_day_schedule();
$available_days = $this->get_available_days( array_keys( $this->get_week_day_schedule() ), $this->get_date_timestamp($this->year, $this->month) );
if( !in_array($date->format('Y-m-j'), $available_days) || $this->date_passed($date) || $this->max_schedule_days($date) ) {
return false;
}
if( isset($schedule[$week_day]) ) {
return $schedule[$week_day];
} else {
return false;
}
}
/**
* Custom Time Slots
*/
public function get_custom_slots( $date ) {
$week_day = (string) strtolower( $date->format('l') );
if( !is_array( $this->custom_slots() ) || $this->get_date_schedule( $date ) === false ) {
return array();
}
$slots = array();
foreach( $this->custom_slots() as $slot_id => $slot ) {
if( isset($slot['availability']) && in_array($week_day, $slot['availability']) ) {
if( $this->is_slot_available( $date, $slot ) ) {
$startTime = new DateTime( $slot['start'] );
$endTime = new DateTime( $slot['end'] );
$slots[$slot['start']] = $slot;
$slots[$slot['start']]['text'] = $this->slot_text( $startTime, $endTime );
$slots[$slot['start']]['duration'] = $this->get_slot_duration( $startTime, $endTime );
}
//echo '<pre>'; print_r( $slots ); echo '</pre>';
//die();
}
}
//echo '<pre>'; print_r( $slots ); echo '</pre>';
return $slots;
}
public function get_slot_duration( $startTime, $endTime ) {
$diff = $startTime->diff( $endTime );
$minutes = ($diff->days * 24 * 60) + ($diff->h * 60) + $diff->i;
return $minutes;
}
/**
* Generate Time Slots
*/
public function generate_time_slots( $date ) {
$week_day = (string) strtolower( $date->format('l') );
if( $this->get_date_schedule( $date ) === false ) {
return array();
} else {
$schedule = $this->get_date_schedule( $date );
}
$duration = (int) get_post_meta($this->service_id, 'ga_service_duration', true);
$cleanup = (int) get_post_meta($this->service_id, 'ga_service_cleanup', true);
$start = (string) $schedule['begin'];
$end = (string) $schedule['end'];
$start = new DateTime($start);
$end = new DateTime($end);
$interval = new DateInterval("PT" . $duration . "M");
$cleanupInterval = new DateInterval("PT" . $cleanup . "M");
$slots = array();
$exclude_slots = array();
for ($intStart = $start; $intStart < $end; $intStart->add($interval)->add($cleanupInterval)) {
$endPeriod = clone $intStart;
$endPeriod->add($interval);
if( $endPeriod > $end ) {
break;
}
if( $this->get_breaks( $week_day ) ) {
foreach( $this->get_breaks( $week_day ) as $break_start => $break_end ) {
$break_start = new DateTime( $break_start );
$break_end = new DateTime( $break_end );
if( $intStart >= $break_end || $endPeriod <= $break_start ) {
// Slot available
if( $this->is_slot_available( $date, $this->generate_slot_data($intStart, $endPeriod) ) ) {
$slots[$intStart->format('H:i')] = $this->generate_slot_data($intStart, $endPeriod);
}
} else {
$exclude_slots[$intStart->format('H:i')] = $this->generate_slot_data($intStart, $endPeriod);
if( $this->reduce_gaps() ) {
$intStart = $break_end;
$resetInterval = new DateInterval("PT0M");
$intStart->add($resetInterval)->add($cleanupInterval);
$endPeriod = clone $intStart;
$endPeriod->add($interval);
// Reset interval greater than end time
if( $endPeriod > $end ) {
break;
}
// Slot available
if( $this->is_slot_available($date, $this->generate_slot_data($intStart, $endPeriod)) ) {
$slots[$intStart->format('H:i')] = $this->generate_slot_data($intStart, $endPeriod);
}
}
}
} // endforeach
} else {
// Slot available
if( $this->is_slot_available($date, $this->generate_slot_data($intStart, $endPeriod)) ) {
$slots[$intStart->format('H:i')] = $this->generate_slot_data($intStart, $endPeriod);
}
}
}
//echo '<pre>'; print_r( $slots ); echo '</pre>';
//$slots = array_unique($slots);
//$exclude_slots = array_unique($exclude_slots);
return array_diff_key($slots, $exclude_slots);
}
private function generate_slot_data( $start, $end ) {
$slot = array();
$slot['start'] = $start->format('H:i');
$slot['end'] = $end->format('H:i');
$slot['text'] = $this->slot_text($start, $end);
return $slot;
}
/**
* Schedule Available Week Days
*/
public function get_week_day_schedule() {
$provider_schedule = $this->get_calendar_schedule();
if( $this->provider_id == 0 ) {
# do nothing
} else {
$provider_calendar = (string) get_post_meta( $this->provider_id, 'ga_provider_calendar', true );
if( $provider_calendar == 'on' ) {
$provider_schedule = (array) get_post_meta( $this->provider_id, 'ga_provider_work_schedule', true );
}
}
foreach( $provider_schedule as $key => $schedule ) {
if( $schedule['begin'] == 'out' ) {
unset( $provider_schedule[$key] );
}
}
return $provider_schedule;
}
/**
* Schedule Available Breaks
*/
private function get_breaks( $week_day ) {
$sort = array();
$breaks = $this->get_calendar_breaks();
if( $this->provider_id == 0 ) {
# do nothing
} else {
$provider_calendar = (string) get_post_meta( $this->provider_id, 'ga_provider_calendar', true );
if( $provider_calendar == 'on' ) {
$breaks = (array) get_post_meta( $this->provider_id, 'ga_provider_breaks', true );
}
}
if( isset( $breaks[$week_day] ) && count($breaks[$week_day]) > 0 ) {
$breaks = $breaks[$week_day];
} else {
return array();
}
foreach($breaks as $key => $part) {
$sort[$key] = new DateTime($part);
}
array_multisort($sort, SORT_ASC, $breaks);
//$print = '<pre>' . print_r($breaks, true);
//wp_die( $print );
return $breaks;
}
/**
* Holidays
*/
public function get_holidays() {
$provider_holidays = $this->get_calendar_holidays();
if( $this->provider_id == 0 ) {
# do nothing
} else {
$provider_calendar = (string) get_post_meta( $this->provider_id, 'ga_provider_calendar', true );
if( $provider_calendar == 'on' ) {
$provider_holidays = (array) get_post_meta( $this->provider_id, 'ga_provider_holidays', true );
}
}
return $provider_holidays;
}
private function get_calendar_schedule() {
$options = get_option( 'ga_appointments_work_schedule' );
$work_schedule = $options && is_array($options) ? $options : $this->get_calendar_defauls();
return $work_schedule;
}
private function get_calendar_breaks() {
$options = get_option( 'ga_appointments_schedule_breaks' );
$breaks = (array) $options;
return $breaks;
}
private function get_calendar_holidays() {
$options = get_option( 'ga_appointments_holidays' );
$holidays = (array) $options;
return $holidays;
}
/**
* Default Schedule
*/
private function get_calendar_defauls() {
$schedule = array( 'sunday' => array('begin' => 'out', 'end' => 'out'),
'monday' => array('begin' => '09:00', 'end' => '17:00'),
'tuesday' => array('begin' => '09:00', 'end' => '17:00'),
'wednesday' => array('begin' => '09:00', 'end' => '17:00'),
'thursday' => array('begin' => '09:00', 'end' => '17:00'),
'friday' => array('begin' => 'out', 'end' => 'out'),
'saturday' => array('begin' => 'out', 'end' => 'out'),
);
return $schedule;
}
/**
* Reduce gaps
*/
private function reduce_gaps() {
$reduce_gaps = get_post_meta( $this->service_id, 'ga_service_reduce_gaps', true );
// Reduce Gaps
if( $reduce_gaps && in_array($reduce_gaps, array('yes', 'no')) ) {
$gaps = $reduce_gaps;
} else {
$gaps = 'yes'; // days
}
if( $gaps == 'yes' ) {
return true;
}
return false;
}
/**
* Prior Days To Book Appointment
*/
private function max_schedule_days( $date_input ) {
$max_days = get_post_meta( $this->service_id, 'ga_service_schedule_max_future_days', true );
$max_days = $max_days && array_key_exists( $max_days, ga_schedule_max_future_days() ) ? $max_days : 90;
// SERVICE PERIOD TYPE
$period_type = (string) get_post_meta($this->service_id, 'ga_service_period_type', true);
if( $period_type == 'date_range' ) {
$range = (array) get_post_meta($this->service_id, 'ga_service_date_range', true);
if( isset($range['from']) && ga_valid_date_format($range['from']) && isset($range['to']) && ga_valid_date_format($range['to']) ) {
$end_range = new DateTime($range['to'], new DateTimeZone( $this->time_zone ));
$end_range->setTime(24,00);
//print_r( $end_range );
return $date_input > $end_range;
}
return true;
}
if( $period_type == 'custom_dates' ) {
$custom_dates = (array) get_post_meta($this->service_id, 'ga_service_custom_dates', true);
if( is_array($custom_dates) && count($custom_dates) > 0 && ga_valid_date_format(end($custom_dates)) ) {
$end_custom_date = new DateTime(end($custom_dates), new DateTimeZone( $this->time_zone ));
$end_custom_date->setTime(24,00);
return $date_input > $end_custom_date;
}
return true;
}
// Future Days Period
$date = new DateTime();
$date->setTimezone( new DateTimeZone( $this->time_zone ) );
$date->add(new DateInterval( "P" . $max_days . "D" ));
$date->setTime(00, 00);
$calendar = $date_input; // DateTime Object
$calendar->setTimezone( new DateTimeZone( $this->time_zone ) );
$calendar->setTime(00, 00);
return $calendar > $date;
}
public function calendar_time_slots($date, $sel_slot = false) {
$ga_slots = $this->get_slots( $date );
// Translation Support
$month = $date->format("F");
$week = $date->format("l");
$day = $date->format("j");
$year = $date->format("Y");
$text = ga_get_form_translated_slots_date($this->form_id, $month, $day, $year);
// Translation Support
// Slot size
$slots_size = $this->show_end_times() ? 'slot_large grid-lg-12 grid-md-12 grid-sm-12 grid-xs-12' : 'slot_small grid-lg-3 grid-md-3 grid-sm-3 grid-xs-6';
// Time Format Display
$time_display = ga_service_time_format_display($this->service_id);
// Multiple Slots selection
$multi_select = (string) get_post_meta($this->service_id, 'ga_service_multiple_selection', true);
$max_bookings = ga_get_service_max_bookings($this->service_id);
$max_total = ga_get_service_max_selection($this->service_id);
$double = ga_get_service_double_bookings($this->service_id);
$time_format = (string) get_post_meta($this->service_id, 'ga_service_time_format', true);
$remove_am_pm = (string) get_post_meta($this->service_id, 'ga_service_remove_am_pm', true);
$multiple = $multi_select == 'yes' ? ' multi-select="enabled" select-max="'.$max_bookings.'" select-total="'.$max_total.'" time_format="'.$time_format.'" remove_am_pm="'.$remove_am_pm.'" no_double="'.$double.'"' : '';
$out = '';
if( count($ga_slots) > 0 ) {
$out .= '<h3 class="slots-title">' .$text. '</h3>'; // eg. February 24, 2018
$out .= '<div class="grid-row grid_no_pad">';
foreach( $ga_slots as $slot ) {
$sel_class = $sel_slot && $sel_slot == $slot['start'] ? ' time_selected' : '';
$slot_cost = $this->available_times_mode() == 'custom' ? $slot['price'] : $this->service_price();
// Slot Language
if( $multi_select == 'yes' ) {
$time = new DateTime($slot['start'], new DateTimeZone( $this->time_zone ));
$slot_time = $time->format($time_display);
$translate = ga_get_form_translated_date_time( $this->form_id, $month, $week, $day, $year, $slot_time );
$lang_slot = ' lang_slot="'. esc_html($translate) .'"';
} else {
$lang_slot = '';
}
// Slot Language
if( $this->slot_capacity_text( $date, $slot ) ) {
$count = $this->slot_capacity_text( $date, $slot );
$capacity = $count == 1 ? ga_get_form_translated_space($this->form_id, $count) : ga_get_form_translated_spaces($this->form_id, $count);
$out .= '<div class="'.$slots_size.' grid_no_pad">
<label class="time_slot ga_tooltip'.$sel_class.'" time_slot="'.$slot['start'].'" ga-tooltip="'.$capacity.'"'.$multiple . $lang_slot.' capacity="'.$count.'" service_id="'.$this->service_id.'" slot_cost="'.$slot_cost.'"><div>'.$slot['text'].'</div></label>
</div>';
} else {
$out .= '<div class="'.$slots_size.' grid_no_pad">
<label class="time_slot'.$sel_class.'" time_slot="'.$slot['start'].'" '.$multiple . $lang_slot.' capacity="1" service_id="'.$this->service_id.'" slot_cost="'.$slot_cost.'"><div>'.$slot['text'].'</div></label>
</div>';
}
}
$out .= '</div>';
} else {
$out .= '<div id="no_time_slots"><i class="fa fa-calendar-times-o" aria-hidden="true"></i><div>No time slots</div></div>';
}
return $out;
}
/**
* Slot Text
*/
private function slot_text($intStart, $endPeriod) {
$remove_am_pm = $this->remove_am_pm() == 'no' ? 'A' : '';
$time_format = $this->time_format() == '24h' ? "G:i {$remove_am_pm}" : "g:i {$remove_am_pm}";
$start = ga_get_form_translated_am_pm($this->form_id, $intStart->format($time_format));
$end = ga_get_form_translated_am_pm($this->form_id, $endPeriod->format($time_format));
if( $this->show_end_times() ) {
return $start . ' - ' . $end;
} else {
return $start;
}
}
/**
* Show End Times
*/
public function show_end_times() {
$show_end_times = get_post_meta( $this->service_id, 'ga_service_show_end_times', true );
// Show End Times
if( $show_end_times && in_array($show_end_times, array('yes', 'no')) ) {
$end_times = $show_end_times;
} else {
$end_times = 'no'; // days
}
if( $end_times == 'yes' ) {
return true;
}
return false;
}
/**
* Time Format
*/
public function time_format() {
$time_format = get_post_meta( $this->service_id, 'ga_service_time_format', true );
// Time Format
if( $time_format && in_array($time_format, array('12h', '24h')) ) {
$format = $time_format;
} else {
$format = '12h'; // 12h format
}
return $format;
}
/**
* Time Format
*/
public function remove_am_pm() {
$remove_am_pm = get_post_meta( $this->service_id, 'ga_service_remove_am_pm', true );
// Time Format
if( $remove_am_pm && in_array($remove_am_pm, array('no', 'yes')) ) {
$remove = $remove_am_pm;
} else {
$remove = 'no'; // 12h format
}
return $remove;
}
/**
* Current Date Today
*/
private function is_today( $current_date ) {
$today = ga_current_date_with_timezone();
return $today->format('Y-m-j') == $current_date->format('Y-m-j');
}
/**
* Date Passed
*/
private function date_passed($dateTime) {
$day = $dateTime->format('j');
$now = ga_current_date_with_timezone();
$calendar = new DateTime();
$calendar->setTimezone( new DateTimeZone( $this->time_zone ) );
$calendar->setDate( (int) $this->year, (int) $this->month, $day );
return $now > $calendar;
}
/**
* Date Slot Passed
*/
private function date_slot_passed($dateTime) {
$now = ga_current_date_with_timezone();
return $now > $dateTime;
}
/**
* Month Passed
*/
private function month_passed() {
$month = new DateTime();
$month->setTimezone( new DateTimeZone( $this->time_zone ) );
$month->setDate( $month->format('Y'), $month->format('n'), 1 );
$now = ga_current_date_with_timezone();;
return $month > $now;
}
/**
* Previous Month
*/
private function previous_month() {
$previous = new DateTime();
$previous->setTimezone( new DateTimeZone( $this->time_zone ) );
$previous->setDate( $this->date_info->format('Y'), $this->date_info->format('n'), 1 );
$previous->modify( 'last day of previous month' );
// SERVICE PERIOD TYPE
$period_type = (string) get_post_meta($this->service_id, 'ga_service_period_type', true);
if( $period_type == 'date_range' ) {
$range = (array) get_post_meta($this->service_id, 'ga_service_date_range', true);
if( isset($range['from']) && ga_valid_date_format($range['from']) && isset($range['to']) && ga_valid_date_format($range['to']) ) {
$begin_range = new DateTime($range['from'], new DateTimeZone( $this->time_zone ));
return $previous > $begin_range;
}
return false;
}
if( $period_type == 'custom_dates' ) {
$custom_dates = (array) get_post_meta($this->service_id, 'ga_service_custom_dates', true);
if( is_array($custom_dates) && count($custom_dates) > 0 && ga_valid_date_format(reset($custom_dates)) ) {
$begin_custom_date = new DateTime(reset($custom_dates), new DateTimeZone( $this->time_zone ));
return $previous > $begin_custom_date;
}
return false;
}
return $previous >= ga_current_date_with_timezone();
}
/**
* Next Month
*/
private function next_month() {
$next = new DateTime();
$next->setTimezone( new DateTimeZone( $this->time_zone ) );
$next->setDate( $this->date_info->format('Y'), $this->date_info->format('n'), 1 );
$next->modify( 'first day of next month' );
if( $this->max_schedule_days($next) ) {
return false;
}
return true;
}
/**
* Month future
*/
private function month_future() {
$now = new DateTime();
$now->setTimezone( new DateTimeZone( $this->time_zone ) );
$now->setDate( $now->format('Y'), $now->format('n'), 1 );
return $now > $this->date_info;
}
private function available_times_mode() {
return (string) get_post_meta( $this->service_id, 'ga_service_available_times_mode', true );
}
private function service_capacity() {
return (int) get_post_meta( $this->service_id, 'ga_service_capacity', true );
}
private function custom_slots() {
return get_post_meta( $this->service_id, 'ga_service_custom_slots', true );
}
private function service_price() {
return get_post_meta( $this->service_id, 'ga_service_price', true );
}
} // end class
gf-booking-services.php 0000666 00000023125 15126233304 0011126 0 ustar 00 <?php
defined( 'ABSPATH' ) or exit; // Exit if accessed directly
if ( class_exists( 'GFForms' ) ) {
class GF_Appointment_Booking_Services extends GF_Field {
public $type = 'appointment_services';
public function get_form_editor_field_title() {
return esc_attr__( 'Booking Services', 'gravityforms' );
}
/*
* Where to assign this widget
*/
public function get_form_editor_button() {
return array(
//'group' => 'advanced_fields',
'group' => 'appointment_calendar',
'text' => $this->get_form_editor_field_title()
);
}
/*
* Add button to the group
*/
public function add_button( $field_groups ) {
$field_groups = $this->ga_appointment_services_gf_group( $field_groups );
return parent::add_button( $field_groups );
}
/*
* Add our group
*/
public function ga_appointment_services_gf_group( $field_groups ) {
foreach ( $field_groups as $field_group ) {
if ( $field_group['name'] == 'appointment_calendar' ) {
return $field_groups;
}
}
$field_groups[] = array(
'name' => 'appointment_calendar',
'label' => __( 'Appointment Booking', 'simplefieldaddon' ),
'fields' => array(
)
);
return $field_groups;
}
/*
* Widget settings
*/
function get_form_editor_field_settings() {
return array(
'enable_enhanced_ui_setting',
'label_setting',
'error_message_setting',
'label_placement_setting',
'admin_label_setting',
'size_setting',
'description_setting',
'css_class_setting',
'rules_setting',
'conditional_logic_field_setting',
'visibility_setting',
);
}
public function is_conditional_logic_supported() {
return true;
}
/**
* Field Markup
*/
public function get_field_input( $form, $value = '', $entry = null ) {
$form_id = absint( $form['id'] );
$is_entry_detail = $this->is_entry_detail();
$is_form_editor = $this->is_form_editor();
$id = $this->id;
$field_id = $is_entry_detail || $is_form_editor || $form_id == 0 ? "input_$id" : 'input_' . $form_id . "_$id";
$logic_event = $this->get_conditional_logic_event( 'change' );
$size = $this->size;
$class_suffix = $is_entry_detail ? '_admin' : '';
$chosenUI = $this->enableEnhancedUI ? ' chosen-select' : '';
$field_class = ' appointment_service_id';
$class = $size . $class_suffix . $chosenUI . $field_class;
$css_class = trim( esc_attr( $class ) . ' gfield_select' );
$tabindex = $this->get_tabindex();
$disabled_text = $is_form_editor ? 'disabled="disabled"' : '';
$required_attribute = $this->isRequired ? 'aria-required="true"' : '';
$invalid_attribute = $this->failed_validation ? 'aria-invalid="true"' : 'aria-invalid="false"';
$choices = '';
if( $this->is_entry_edit() ) {
$choices .= sprintf( "<div class='ginput_container ginput_container_select'><select name='input_%s' id='%s' $logic_event class='%s' $tabindex %s %s %s>%s</select></div>", $id, $field_id, $css_class, $disabled_text, $required_attribute, $invalid_attribute, $this->get_services_entry_choices($value, $form) );
} elseif( !$this->is_form_editor() ) {
$choices .= sprintf( "<div class='ginput_container ginput_container_select'><select name='input_%s' id='%s' $logic_event class='%s' $tabindex %s %s %s form_id='%d'>%s</select></div>", $id, $field_id, $css_class, $disabled_text, $required_attribute, $invalid_attribute, $form_id, $this->get_services_choices($value, $form) );
}
return $choices;
}
/**
* Is Entry Edit
*/
public function is_entry_edit() {
if ( rgget( 'page' ) == 'gf_entries' && rgget( 'view' ) == 'entry' && rgpost( 'screen_mode' ) == 'edit' ) {
return true;
}
return false;
}
/**
* Returns TRUE if the current page is the form editor page. Otherwise, returns FALSE
*/
public function is_form_editor() {
if ( rgget( 'page' ) == 'gf_edit_forms' && ! rgempty( 'id', $_GET ) && rgempty( 'view', $_GET ) ) {
return true;
}
return false;
}
/**
* Get Services Select Options
*/
public function get_services_choices($value, $form) {
$options = '';
$form_cat_slug = rgar($form, 'ga_service_category');
$cat = term_exists( $form_cat_slug, 'ga_service_cat' );
// The Query
if( $cat ) {
$args = array('post_type' => 'ga_services', 'post_status' => 'publish', 'posts_per_page' => -1, 'orderby' => 'date', 'order' => 'DESC', 'tax_query' => array( array(
'taxonomy' => 'ga_service_cat', // taxonomy name
'field' => 'slug', // term_id, slug or name
'terms' => $form_cat_slug // term id, term slug or term name
))
); // end array
} else {
$args = array('post_type' => 'ga_services', 'post_status' => 'publish', 'posts_per_page' => -1, 'orderby' => 'date', 'order' => 'DESC' );
}
$the_query = new WP_Query( $args );
wp_reset_postdata();
// The Loop
if ( $the_query->have_posts() ) {
while ( $the_query->have_posts() ) {
$the_query->the_post();
$post = get_post( get_the_id() );
$selected = $value == get_the_id() ? ' selected="selected"' : '';
$options .= '<option value="'.get_the_id().'"'.$selected.'>'.$post->post_title.'</option>' . PHP_EOL;
}
wp_reset_postdata();
} else {
// no services found
}
return $options;
}
/**
* Get Services Entry Options
*/
public function get_services_entry_choices($value, $form) {
$options = '';
$args = array('post_type' => 'ga_services', 'post_status' => 'publish', 'posts_per_page' => -1, 'orderby' => 'date', 'order' => 'DESC' );
$the_query = new WP_Query( $args );
wp_reset_postdata();
// The Loop
if ( $the_query->have_posts() ) {
while ( $the_query->have_posts() ) {
$the_query->the_post();
$post = get_post( get_the_id() );
$selected = $value == get_the_id() ? ' selected="selected"' : '';
$options .= '<option value="'.get_the_id().'"'.$selected.'>'.$post->post_title.'</option>' . PHP_EOL;
}
wp_reset_postdata();
} else {
// no services found
}
return $options;
}
/**
* Validation Failed
*/
private function validationFailed( $message = '' ) {
$this->failed_validation = true;
$message = esc_html__( $message, 'gravityforms' );
$this->validation_message = empty( $this->errorMessage ) ? $message : $this->errorMessage;
}
/**
* Validation
*/
public function validate( $value, $form ) {
$form_id = absint( $form['id'] );
if( 'ga_services' == get_post_type($value) && get_post_status( $value ) == 'publish' ) {
# valid field
$service_id = $value;
// Selected service exists in form category term
$form_cat_slug = rgar($form, 'ga_service_category');
$cat = term_exists( $form_cat_slug, 'ga_service_cat' );
if( $cat ) {
if( has_term( $cat, 'ga_service_cat', $service_id ) ) {
# valid
} else {
$this->validationFailed( ga_get_form_translated_error_message($form_id, 'error_required_service') );
return;
}
}
} else {
$this->validationFailed( ga_get_form_translated_error_message($form_id, 'error_required_service') );
return;
}
// Check if calendar widget is found
if( !gf_field_type_exists( $form, 'appointment_calendar' ) ) {
$this->validationFailed( ga_get_form_translated_error_message($form_id, 'error_required_date') );
return;
}
}
/**
* Save value
*/
public function get_value_save_entry( $value, $form, $input_name, $entry_id, $entry ) {
//$post_id = absint( $_POST['appointment_booking_service'] );
//$value = get_the_title( $post_id );
return $value;
}
/**
* Show service title entry single
*/
public function get_value_entry_detail( $value, $currency = '', $use_text = false, $format = 'html', $media = 'screen' ) {
$post_id = absint( $value );
if( 'ga_services' == get_post_type($post_id) ) {
// $value = '<a href="'.get_edit_post_link( $post_id ).'">' .get_the_title( $post_id ). '</a>'; //
$value = get_the_title( $post_id );
return esc_html( $value );
} else {
return esc_html( $value );
}
}
/**
* Merge tag, on notifications, confirmations
*/
public function get_value_merge_tag( $value, $input_id, $entry, $form, $modifier, $raw_value, $url_encode, $esc_html, $format, $nl2br ) {
$post_id = absint( $value );
if( 'ga_services' == get_post_type($post_id) ) {
$value = get_the_title( $post_id );
return esc_html( $value );
} else {
return esc_html( $value );
}
}
/*
* Show service title on entry list
*/
/*
public function get_value_entry_list( $value, $entry, $field_id, $columns, $form ) {
$post_id = absint( $value );
if( 'ga_services' == get_post_type($post_id) ) {
$value = get_the_title( $post_id );
return esc_html( $value );
} else {
return esc_html( $value );
}
}
*/
public function get_form_editor_inline_script_on_page_render() {
return "
gform.addFilter('gform_form_editor_can_field_be_added', function (canFieldBeAdded, type) {
if (type == 'appointment_services') {
if (GetFieldsByType(['appointment_services']).length > 0) {
alert(" . json_encode( esc_html__( 'Only one Booking Services field can be added to the form', 'gravityformscoupons' ) ) . ");
return false;
}
}
return canFieldBeAdded;
});";
}
} // end class
GF_Fields::register( new GF_Appointment_Booking_Services() );
} // end if
gf-booking-calendar.php 0000666 00000077167 15126233304 0011073 0 ustar 00 <?php
defined( 'ABSPATH' ) or exit; // Exit if accessed directly
if ( class_exists( 'GFForms' ) ) {
class GF_Appointment_Booking_Calendar extends GF_Field {
public $type = 'appointment_calendar';
public function get_form_editor_field_title() {
return esc_attr__( 'Booking Calendar', 'gravityforms' );
}
/*
* Where to assign this widget
*/
public function get_form_editor_button() {
return array(
//'group' => 'advanced_fields',
'group' => 'appointment_calendar',
'text' => $this->get_form_editor_field_title()
);
}
/*
* Add button to the group
*/
public function add_button( $field_groups ) {
$field_groups = $this->ga_appointment_services_gf_group( $field_groups );
return parent::add_button( $field_groups );
}
/*
* Add our group
*/
public function ga_appointment_services_gf_group( $field_groups ) {
foreach ( $field_groups as $field_group ) {
if ( $field_group['name'] == 'appointment_calendar' ) {
return $field_groups;
}
}
$field_groups[] = array(
'name' => 'appointment_calendar',
'label' => __( 'Appointment Booking', 'simplefieldaddon' ),
'fields' => array(
)
);
return $field_groups;
}
/*
* Widget settings
*/
function get_form_editor_field_settings() {
return array(
'label_setting',
'error_message_setting',
'label_placement_setting',
'admin_label_setting',
'description_setting',
'css_class_setting',
'rules_setting',
'size_setting',
'conditional_logic_field_setting',
);
}
public function is_conditional_logic_supported() {
return true;
}
public function is_value_submission_empty($form_id) {
return false;
}
/**
* Field Markup
*/
public function get_field_input( $form, $value = '', $entry = null ) {
$form_id = absint( $form['id'] );
$is_entry_detail = $this->is_entry_detail();
$is_form_editor = $this->is_form_editor();
$id = $this->id;
//$field_id = 'gf_appointment_booking_calendar'; // the html id
$field_id = $is_entry_detail || $is_form_editor || $form_id == 0 ? "input_$id" : 'input_' . $form_id . "_$id";
$logic_event = ! $is_form_editor && ! $is_entry_detail ? $this->get_conditional_logic_event( 'keyup' ) : '';
$size = $this->size;
$class_suffix = $is_entry_detail ? '_admin' : '';
$class = $size . $class_suffix;
$css_class = trim( esc_attr( $class ) . ' gfield_select' );
$tabindex = $this->get_tabindex();
$disabled_text = $is_form_editor ? 'disabled="disabled"' : '';
$required_attribute = $this->isRequired ? 'aria-required="true"' : '';
$invalid_attribute = $this->failed_validation ? 'aria-invalid="true"' : 'aria-invalid="false"';
$calendar = "<div class='ginput_container'>";
if( $this->is_entry_edit() ) {
$calendar .= 'This field is not editable';
$calendar .= "<input type='hidden' name='input_{$id}' id='{$field_id}' value='{$value}'/>";
} elseif( !$this->is_form_editor() ) {
ob_start();
$calendar .= '<div class="grid-row"><div class="'.$this->field_size().' grid-sm-12 grid-xs-12" id="gappointments_calendar">' . PHP_EOL;
if( ga_service_id($form) && gf_field_type_exists( $form, 'appointment_services' ) ) {
$current_date = ga_current_date_with_timezone();
$service_id = ga_service_id($form);
// Form submited service ID
$services_field_value = gf_get_field_type_value( $form, 'appointment_services' );
if( is_numeric($services_field_value) && 'ga_services' == get_post_type($services_field_value) ) {
$service_id = $services_field_value;
}
$provider_id = ga_get_provider_id( $service_id ) ? ga_get_provider_id( $service_id ) : 0;
// Form submited provider ID
if( gf_field_type_exists( $form, 'appointment_providers' ) ) {
$providers_field_value = gf_get_field_type_value( $form, 'appointment_providers' );
if( is_numeric($providers_field_value) && ga_get_provider_id($service_id) && 'ga_providers' == get_post_type($providers_field_value) ) {
$provider_id = $providers_field_value;
}
}
// Booking Date/Time Fields
$date_val = '';
$time_val = '';
$cost_val = '0';
if ( is_array( $value ) ) {
$date_val = isset($value['date']) ? $value['date'] : $date_val;
$time_val = isset($value['time']) ? $value['time'] : $time_val;
$cost_val = isset($value['cost']) ? $value['cost'] : $cost_val;
}
// Service period type
$period_type = (string) get_post_meta($service_id, 'ga_service_period_type', true);
if( $period_type == 'date_range' ) {
$range = (array) get_post_meta($service_id, 'ga_service_date_range', true);
if( isset($range['from']) && ga_valid_date_format($range['from']) && isset($range['to']) && ga_valid_date_format($range['to']) ) {
$current_date = new DateTime($range['from'], new DateTimeZone( ga_time_zone() ));
}
}
if( $period_type == 'custom_dates' ) {
$custom_dates = (array) get_post_meta($service_id, 'ga_service_custom_dates', true);
if( is_array($custom_dates) && count($custom_dates) > 0 && ga_valid_date_format(reset($custom_dates)) ) {
$current_date = new DateTime(reset($custom_dates), new DateTimeZone( ga_time_zone() ));
}
}
// Form submited date & time
$selected_date = false;
$selected_slot = false;
if( ga_valid_date_format($date_val) ) {
$current_date = new DateTime( $date_val, new DateTimeZone(ga_time_zone()) );
$selected_date = clone $current_date;
}
if( ga_valid_time_format($time_val) ) {
$selected_slot = $time_val;
}
// Form submited date & time
// Calendar HTML
$calendar .= '<div id="ga_appointments_calendar" form_id="'.$form_id.'"><div class="ga_monthly_schedule_wrapper">' . PHP_EOL;
$ga_calendar = new GA_Calendar( $form_id, $current_date->format('m'), $current_date->format('Y'), $service_id, $provider_id, $selected_date, $selected_slot );
$calendar .= $ga_calendar->show();
$calendar .= '</div></div>' . PHP_EOL; // end #ga_appointments_calendar
// End Calendar HTML
// Multiple Slots Selection
$calendar .= '<div id="ga_selected_bookings">' . PHP_EOL;
$calendar .= $this->multiple_bookings_markup($form_id, $value, $service_id, $provider_id);
$calendar .= '</div>' . PHP_EOL; // end #ga_selected_bookings
// Multiple Slots Selection
} else {
return '<p>' .ga_get_form_translated_data($form_id, 'error_no_services'). '</p>';
}
$calendar .= '</div></div>' . PHP_EOL; // end grid-row
$calendar .= "<input type='hidden' name='input_{$id}[date]' id='{$field_id}' class='{$class} ginput_{$this->type}_input appointment_booking_date' value='{$date_val}' {$logic_event}/>";
$calendar .= "<input type='hidden' name='input_{$id}[time]' id='{$field_id}_time' class='{$class} ginput_{$this->type}_input appointment_booking_time' value='{$time_val}'/>";
// Appointment cost hidden field just in case
$calendar .= "<input type='hidden' name='input_{$id}[cost]' class='ginput_appointment_cost_input gform_hidden' value='{$cost_val}'/>";
$calendar .= ob_get_clean();
}
$calendar .= '</div>' . PHP_EOL; // end ginput_container
return $calendar;
}
/**
* Is Entry Edit
*/
public function is_entry_edit() {
if ( rgget( 'page' ) == 'gf_entries' && rgget( 'view' ) == 'entry' && rgpost( 'screen_mode' ) == 'edit' ) {
return true;
}
return false;
}
/**
* Returns TRUE if the current page is the form editor page. Otherwise, returns FALSE
*/
public function is_form_editor() {
if ( rgget( 'page' ) == 'gf_edit_forms' && ! rgempty( 'id', $_GET ) && rgempty( 'view', $_GET ) ) {
return true;
}
return false;
}
/**
* Is Entry View
*/
public function is_entry_view() {
if ( rgget( 'page' ) == 'gf_entries' && rgget( 'view' ) == 'entry' && rgpost( 'screen_mode' ) == 'view' ) {
return true;
}
return false;
}
public function get_inline_price_styles() {
return '';
}
/**
* Multiple Bookings Markup
*/
public function multiple_bookings_markup($form_id, $value, $service_id, $provider_id) {
$id = $this->id;
$out = '';
// Service multiple slots
$multiple_slots = (string) get_post_meta( $service_id, 'ga_service_multiple_selection', true );
if( $multiple_slots != 'yes' ) {
return '';
}
// Time Format Display
$time_display = ga_service_time_format_display($service_id);
// Service price
$service_price = get_post_meta($service_id, 'ga_service_price', true);
// Service mode
$available_times_mode = (string) get_post_meta( $service_id, 'ga_service_available_times_mode', true );
// Get Bookings
$bookings = ga_get_multiple_bookings($value, $service_id, $provider_id);
if( count($bookings) > 0 ) {
foreach( $bookings as $key => $booking ) {
//$format = $available_times_mode == 'no_slots' ? 'F j, Y' : 'F j, Y \a\t ' . $time_display;
$date = new dateTime($booking);
// Translation Support
if( $available_times_mode == 'no_slots' ) {
$month = $date->format('F');
$day = $date->format('j');
$year = $date->format('Y');
$appointment_date = ga_get_form_translated_slots_date($form_id, $month, $day, $year);
} else {
$month = $date->format('F');
$week = $date->format('l');
$day = $date->format('j');
$year = $date->format('Y');
$_time = $date->format($time_display);
$appointment_date = ga_get_form_translated_date_time($form_id, $month, $week, $day, $year, $_time);
}
if( $available_times_mode == 'custom' ) {
$slot_price = ga_get_slot_price( $form_id, $date, $service_id, $provider_id);
} else {
$slot_price = $service_price;
}
$out .= '<div class="ga_selected_booking">';
$out .= '<div class="ga_delete_booking"><i class="fa fa-times-circle"></i></div>';
$out .= '<input type="hidden" class="ga_hidden_input" name="input_'.$id.'[bookings][]" value="'.$booking.'" slot_cost="'.$slot_price.'">'.$appointment_date;
$out .= '</div>';
}
}
return $out;
}
/**
* Field Size Class
*/
public function field_size() {
if( isset( $this->size ) ) {
switch ($this->size) {
case "small":
$gf_size = 'ga_wrapper_small grid-lg-4 grid-md-4 grid-sm-6 grid-sx-12';
break;
case "medium":
$gf_size = 'ga_wrapper_medium grid-lg-6 grid-md-6';
break;
case "large":
$gf_size = 'ga_wrapper_large grid-lg-12 grid-md-12';
break;
default:
$gf_size = 'ga_wrapper_medium here grid-lg-6 grid-md-6';
}
} else {
$gf_size = 'ga_wrapper_medium grid-lg-6 grid-md-6';
}
return $gf_size;
}
/**
* Validation Failed Message
*/
private function validationFailed( $message = '' ) {
$this->failed_validation = true;
$message = esc_html__( $message, 'gravityforms' );
$this->validation_message = empty( $this->errorMessage ) ? $message : $this->errorMessage;
}
/**
* Validate
*/
public function validate( $value, $form ) {
$form_id = absint( $form['id'] );
$date = '';
$time = '';
if ( is_array( $value ) ) {
$date = isset($value['date']) ? $value['date'] : $date;
$time = isset($value['time']) ? $value['time'] : $time;
}
// Check if services field exists
if( gf_field_type_exists($form, 'appointment_services') && 'ga_services' == get_post_type( gf_get_field_type_value($form, 'appointment_services') ) ) {
// Service & Provider ID
$service_id = gf_get_field_type_value( $form, 'appointment_services' );
$provider_id = gf_field_type_exists($form, 'appointment_providers') && 'ga_providers' == get_post_type(gf_get_field_type_value($form, 'appointment_providers'))
? gf_get_field_type_value($form, 'appointment_providers')
: 0;
if( ga_get_provider_id($service_id) && $provider_id == 0 ) {
$provider_id = ga_get_provider_id($service_id);
}
// Selected service exists in form category term
$form_cat_slug = rgar($form, 'ga_service_category');
$cat = term_exists( $form_cat_slug, 'ga_service_cat' );
if( $cat ) {
if( has_term( $cat, 'ga_service_cat', $service_id ) ) {
# valid
} else {
$this->validationFailed( ga_get_form_translated_error_message($form_id, 'error_required_service') );
return;
}
}
} else {
$this->validationFailed( ga_get_form_translated_error_message($form_id, 'error_required_service') );
return;
}
$available_times_mode = (string) get_post_meta( $service_id, 'ga_service_available_times_mode', true );
/**
* Multiple Bookings Validation
*/
// Service multiple slots
$multiple_slots = (string) get_post_meta( $service_id, 'ga_service_multiple_selection', true );
// Get bookings
$bookings = ga_get_multiple_bookings($value, $service_id, $provider_id);
if( $multiple_slots == 'yes' ) {
if( count($bookings) > 0 ) {
foreach ($bookings as $key => $date) {
$dateTime = new DateTime( $date, new DateTimeZone( ga_time_zone() ) );
// Date Slots Mode
if( $available_times_mode == 'no_slots' ) {
# date validation failed
if( $this->date_valid($form, $service_id, $provider_id, $dateTime) !== true) {
$message = $this->date_valid($form, $service_id, $provider_id, $dateTime);
$this->validationFailed( $message );
return;
}
continue;
}
// Client max bookings
$client_max_bookings = $this->client_max_bookings( $form, $service_id, $dateTime, $bookings );
if( $client_max_bookings ) {
$max_bookings = ga_get_service_max_bookings($service_id);
$booked = $dateTime->format('F j, Y');
// Translation
$month = $dateTime->format('F');
$day = $dateTime->format('j');
$year = $dateTime->format('Y');
$booked = ga_get_form_translated_slots_date($form_id, $month, $day, $year);
$booked = ga_get_form_translated_error_max_bookings($form_id, $booked, $max_bookings);
// Translation
$this->validationFailed( "{$booked}" );
return;
}
// Time Slots Mode
$time = $dateTime->format('H:i');
if( $this->slot_valid($form, $service_id, $provider_id, $dateTime, $time) !== true ) {
# time & date validation failed
$message = $this->slot_valid($form, $service_id, $provider_id, $dateTime, $time);
$this->validationFailed( $message );
return;
}
}
}
if( count($bookings) < 1 ) {
$this->validationFailed( ga_get_form_translated_error_message($form_id, 'error_required') );
return;
}
return;
}
// Multiple Bookings Validation
/**
* Single Bookings Validation
*/
if( ga_valid_date_format($date) ) {
$dateTime = new DateTime( $date, new DateTimeZone( ga_time_zone() ) );
// Date Slots Mode
if( $available_times_mode == 'no_slots' ) {
if( $this->date_valid($form, $service_id, $provider_id, $dateTime) !== true) {
$message = $this->date_valid($form, $service_id, $provider_id, $dateTime);
$this->validationFailed( $message );
return;
}
return;
}
// Client max bookings
$client_max_bookings = $this->client_max_bookings( $form, $service_id, $dateTime, $bookings = array($dateTime->format('Y-m-j')) );
if( $client_max_bookings ) {
$booked = $dateTime->format('F j, Y');
// Translation
$month = $dateTime->format('F');
$day = $dateTime->format('j');
$year = $dateTime->format('Y');
$booked = ga_get_form_translated_slots_date($form_id, $month, $day, $year);
$reached = ga_get_form_translated_error_message($form_id, 'error_reached_max', $booked);
// Translation
$this->validationFailed( "{$reached}" );
return;
}
// Time Slots Mode
if( $this->slot_valid($form, $service_id, $provider_id, $dateTime, $time) !== true ) {
$message = $this->slot_valid($form, $service_id, $provider_id, $dateTime, $time);
$this->validationFailed( $message );
return;
}
} else {
$this->validationFailed( ga_get_form_translated_error_message($form_id, 'error_required_date') );
return;
}
} // end validate function
/**
* Date Valid
*/
private function date_valid( $form, $service_id, $provider_id, $dateTime ) {
$form_id = absint( $form['id'] );
// Date Validation
$date = $dateTime->format('Y-m-j');
// Translation
$month = $dateTime->format('F');
$day = $dateTime->format('j');
$year = $dateTime->format('Y');
$lang_date = ga_get_form_translated_slots_date($form_id, $month, $day, $year);
// Translation
if( !class_exists('GA_Calendar') ) {
require_once( ga_base_path . '/gf-fields/ga-calendar.php' );
}
$ga_calendar = new GA_Calendar( $form_id, $dateTime->format('n'), $dateTime->format('Y'), $service_id, $provider_id );
$date_available = $ga_calendar->is_date_available( $dateTime );
if( $date_available ) {
# valid date
if( $this->client_booked_date_slot($form, $service_id, $provider_id, $dateTime) ) {
return ga_get_form_translated_error_message($form_id, 'error_booked_date', $lang_date);
}
} else {
return ga_get_form_translated_error_message($form_id, 'error_date_valid', $lang_date);
}
return true;
}
/**
* Slot Valid
*/
private function slot_valid( $form, $service_id, $provider_id, $date, $time ) {
$form_id = absint( $form['id'] );
// Time Slots Validation
if( ga_valid_time_format($time) && array_key_exists($time, get_ga_appointment_time()) ) {
if( !class_exists('GA_Calendar') ) {
require_once( ga_base_path . '/gf-fields/ga-calendar.php' );
}
$ga_calendar = new GA_Calendar( $form_id, $date->format('n'), $date->format('Y'), $service_id, $provider_id );
$slot_available = $ga_calendar->get_slots( $date );
$time_display = ga_service_time_format_display($service_id);
// Translation
$human_date = new DateTime( "{$date->format('Y-m-j')} {$time}", new DateTimeZone(ga_time_zone()) );
$month = $human_date->format('F');
$week = $human_date->format('l');
$day = $human_date->format('j');
$year = $human_date->format('Y');
$_time = $human_date->format($time_display);
// Translation
$lang_date = ga_get_form_translated_date_time($form_id, $month, $week, $day, $year, $_time);
// Is slot available
$is_slot_available = array_key_exists($time, $slot_available);
if( !$is_slot_available ) {
return ga_get_form_translated_error_message($form_id, 'error_slot_valid', $lang_date);
}
// Client already booked slot
$already_booked_slot = $this->client_booked_slot( $form, $service_id, $provider_id, $date, $time );
if( $already_booked_slot ) {
return ga_get_form_translated_error_message($form_id, 'error_booked_date', $lang_date);
}
return true;
} else {
return ga_get_form_translated_error_message($form_id, 'error_required_slot');
}
}
/**
* Escape SQL RegexP
* Characters must be escaped such as: \ ^ . $ | ( ) [ ] * + ? { } ,
*/
private function esc_sql_regexp( $str ) {
return preg_replace('/[.\\\\+*?[\\^\\]$(){}=!|:,\\-]/', '\\\\\\\\\\\\${0}', $str);
}
/**
* Get Email Value From Submitted Form
*/
private function email_field_value( $form ) {
$email_value = gf_field_type_exists($form, 'email') ? esc_sql(gf_get_field_type_value($form, 'email')) : '';
return $this->esc_sql_regexp($email_value);
}
/**
* Get Phone Value From Submitted Form
*/
private function phone_field_value( $form ) {
$phone_value = gf_field_type_exists($form, 'phone') ? esc_sql(gf_get_field_type_value($form, 'phone')) : '';
return $this->esc_sql_regexp($phone_value);
}
/**
* Client Booked Time Slot
* @ $form array
* @ $service_id
* @ $provider_id
* @ $dateTime
* @ $slot_start
*/
private function client_booked_slot($form, $service_id, $provider_id, $dateTime, $slot_start) {
// Prevent Double Bookings
$double_bookings = ga_get_service_double_bookings($service_id);
if( $double_bookings == 'no' ) {
return false;
}
$date = $dateTime->format("Y-m-j");
$slot_end = ga_get_time_end($slot_start, $service_id);
// Client Booked Time Slot
$email_value = $this->email_field_value( $form );
$phone_value = $this->phone_field_value( $form );
global $wpdb;
$querystr = "SELECT $wpdb->posts.ID
FROM
$wpdb->posts,
$wpdb->postmeta AS app_date,
$wpdb->postmeta AS provider,
$wpdb->postmeta AS time1,
$wpdb->postmeta AS time2,
$wpdb->postmeta AS client
WHERE
$wpdb->posts.ID = app_date.post_id
AND
$wpdb->posts.ID = provider.post_id
AND
$wpdb->posts.ID = time1.post_id
AND
$wpdb->posts.ID = time2.post_id
AND
$wpdb->posts.ID = client.post_id
AND $wpdb->posts.post_type = 'ga_appointments'
AND $wpdb->posts.post_status IN ('completed', 'publish', 'payment', 'pending')
AND app_date.meta_key = 'ga_appointment_date'
AND app_date.meta_value = %s
AND provider.meta_key = 'ga_appointment_provider'
AND provider.meta_value = %s
AND time1.meta_key = 'ga_appointment_time_end'
AND time1.meta_value > %s
AND time2.meta_key = 'ga_appointment_time'
AND time2.meta_value < %s
AND client.meta_key = 'ga_appointment_new_client'
AND (client.meta_value REGEXP '\"email\";s:[1-9]+:\"{$email_value}\"'
OR client.meta_value REGEXP '\"phone\";s:[1-9]+:\"{$phone_value}\"')
";
$wpdb->query('SET SQL_BIG_SELECTS = 1');
$sql_prepare = $wpdb->prepare($querystr, $date, $provider_id, $slot_start, $slot_end);
$appointments = $wpdb->get_results( $sql_prepare, ARRAY_A );
//var_dump( count($appointments) );
//var_dump( $wpdb->last_query );
if ( count($appointments) > 0 ) {
return true;
} else {
return false;
}
}
/**
* Client Booked Date Slot
* @ $form array
* @ $service_id
* @ $provider_id
* @ $dateTime
*/
private function client_booked_date_slot( $form, $service_id, $provider_id, $dateTime ) {
$date = $dateTime->format("Y-m-j");
// Prevent Double Bookings
$double_bookings = ga_get_service_double_bookings($service_id);
if( $double_bookings == 'no' ) {
return false;
}
// Client Booked Date Slot
$email_value = $this->email_field_value( $form );
$phone_value = $this->phone_field_value( $form );
global $wpdb;
$querystr = "SELECT $wpdb->posts.ID
FROM
$wpdb->posts,
$wpdb->postmeta AS app_date,
$wpdb->postmeta AS provider,
$wpdb->postmeta AS client
WHERE
$wpdb->posts.ID = app_date.post_id
AND
$wpdb->posts.ID = provider.post_id
AND
$wpdb->posts.ID = client.post_id
AND $wpdb->posts.post_type = 'ga_appointments'
AND $wpdb->posts.post_status IN ('completed', 'publish', 'payment', 'pending')
AND app_date.meta_key = 'ga_appointment_date'
AND app_date.meta_value = %s
AND provider.meta_key = 'ga_appointment_provider'
AND provider.meta_value = %s
AND client.meta_key = 'ga_appointment_new_client'
AND (client.meta_value REGEXP '\"email\";s:[1-9]+:\"{$email_value}\"'
OR client.meta_value REGEXP '\"phone\";s:[1-9]+:\"{$phone_value}\"')
";
$wpdb->query('SET SQL_BIG_SELECTS = 1');
$sql_prepare = $wpdb->prepare($querystr, $date, $provider_id);
$appointments = $wpdb->get_results( $sql_prepare, ARRAY_A );
if ( count($appointments) > 0 ) {
return true;
} else {
return false;
}
}
/**
* Client Max Bookings
* @ $form array
* @ $service_id
* @ $dateTime
* @ $bookings count
*/
private function client_max_bookings( $form, $service_id, $dateTime, $bookings ) {
$date = $dateTime->format("Y-m-j");
$max_bookings = ga_get_service_max_bookings($service_id);
// Client Max Bookings
$email_value = $this->email_field_value( $form );
$phone_value = $this->phone_field_value( $form );
global $wpdb;
$querystr = "SELECT $wpdb->posts.ID
FROM
$wpdb->posts,
$wpdb->postmeta AS app_date,
$wpdb->postmeta AS service,
$wpdb->postmeta AS client
WHERE
$wpdb->posts.ID = app_date.post_id
AND
$wpdb->posts.ID = service.post_id
AND
$wpdb->posts.ID = client.post_id
AND $wpdb->posts.post_type = 'ga_appointments'
AND $wpdb->posts.post_status IN ('completed', 'publish', 'payment', 'pending')
AND app_date.meta_key = 'ga_appointment_date'
AND app_date.meta_value = %s
AND service.meta_key = 'ga_appointment_service'
AND service.meta_value = %s
AND client.meta_key = 'ga_appointment_new_client'
AND (client.meta_value REGEXP '\"email\";s:[1-9]+:\"{$email_value}\"'
OR client.meta_value REGEXP '\"phone\";s:[1-9]+:\"{$phone_value}\"')
";
$wpdb->query('SET SQL_BIG_SELECTS = 1');
$sql_prepare = $wpdb->prepare($querystr, $date, $service_id);
$appointments = $wpdb->get_results( $sql_prepare, ARRAY_A );
$found_dates = 0;
if( $matches = preg_grep("/^{$date}/i", $bookings) ) {
$found_dates = count($matches);
}
$post_count = count($appointments) + $found_dates;
if ( $post_count > $max_bookings ) {
return true;
}
return false;
}
/**
* Save value or save single entry edit
*/
public function get_value_save_entry( $value, $form, $input_name, $entry_id, $entry ) {
// GF Admin Entry Edit
if( is_admin() ) {
return $value;
}
$date = '';
$time = '';
if ( is_array( $value ) ) {
$date = isset($value['date']) ? $value['date'] : $date;
$time = isset($value['time']) ? $value['time'] : $time;
}
$form_id = absint( $form['id'] );
// Check if services field exists
if( gf_field_type_exists($form, 'appointment_services') && 'ga_services' == get_post_type( gf_get_field_type_value($form, 'appointment_services') ) ) {
// Service & Provider ID
$service_id = gf_get_field_type_value( $form, 'appointment_services' );
$provider_id = gf_field_type_exists($form, 'appointment_providers')
&& 'ga_providers' == get_post_type(gf_get_field_type_value($form, 'appointment_providers'))
? gf_get_field_type_value($form, 'appointment_providers')
: 0;
if( ga_get_provider_id($service_id) && $provider_id == 0 ) {
$provider_id = ga_get_provider_id($service_id);
}
if( !class_exists('GA_Calendar') ) {
require_once( ga_base_path . '/gf-fields/ga-calendar.php' );
}
// Time Format Display
$time_display = ga_service_time_format_display($service_id);
// Service Mode
$available_times_mode = (string) get_post_meta( $service_id, 'ga_service_available_times_mode', true );
// Service multiple slots
$multiple_slots = (string) get_post_meta( $service_id, 'ga_service_multiple_selection', true );
// Get Bookings
$bookings = ga_get_multiple_bookings($value, $service_id, $provider_id);
/**
* Multiple Bookings
*/
$booking_dates = array();
if( $multiple_slots == 'yes' ) {
if( count($bookings) > 0 ) {
foreach ($bookings as $key => $date) {
$dateTime = new DateTime( $date, new DateTimeZone( ga_time_zone() ) );
// Translation Support
if( $available_times_mode == 'no_slots' ) {
$month = $dateTime->format('F');
$day = $dateTime->format('j');
$year = $dateTime->format('Y');
$appointment_date = ga_get_form_translated_slots_date($form_id, $month, $day, $year);
} else {
$month = $dateTime->format('F');
$week = $dateTime->format('l');
$day = $dateTime->format('j');
$year = $dateTime->format('Y');
$_time = $dateTime->format($time_display);
$appointment_date = ga_get_form_translated_date_time($form_id, $month, $week, $day, $year, $_time);
}
$booking_dates[] = $appointment_date;
}
return implode("<br>", $booking_dates);
} else {
return array();
}
} else {
/**
* Single Booking
*/
// DATE
$app_date = (string) $date;
$date = ga_valid_date_format($app_date) ? new DateTime($app_date) : false;
$app_date_text = $date ? $date->format('l, F j Y') : '(Date not selected)';
// Time
$app_time = $time;
$time = ga_valid_time_format($app_time) ? new DateTime($app_time) : false;
$app_time_text = $time ? $time->format('g:i a') : '(Time not selected)';
// Translation Support
if( $available_times_mode == 'no_slots' ) {
if( $date ) {
$month = $date->format('F');
$day = $date->format('j');
$year = $date->format('Y');
$appointment_date = ga_get_form_translated_slots_date($form_id, $month, $day, $year);
} else {
$appointment_date = $app_date_text;
}
} else {
if( $date && $time ) {
$month = $date->format('F');
$week = $date->format('l');
$day = $date->format('j');
$year = $date->format('Y');
$_time = $time->format($time_display);
$appointment_date = ga_get_form_translated_date_time($form_id, $month, $week, $day, $year, $_time);
} else {
$appointment_date = "{$app_date_text} at {$app_time_text}";
}
}
}
$merge = apply_filters('ga_booking_merge_value', 'date_format');
return $merge == 'timestamp' && $date && $time ? $this->get_date_timestamp( "{$date->format('Y-m-j')} {$time->format('H:i')}" ) : $appointment_date;
} else {
return '';
}
}
/**
* Show date on entry single
*/
public function get_value_entry_detail( $value, $currency = '', $use_text = false, $format = 'html', $media = 'screen' ) {
return $value;
}
/**
* Merge tag, on notifications, confirmations
*/
public function get_value_merge_tag( $value, $input_id, $entry, $form, $modifier, $raw_value, $url_encode, $esc_html, $format, $nl2br ) {
$dates = explode('<br>', $value);
if( count($dates) > 1 ) {
return implode(', ', $dates);
} elseif( count($dates) == 1 ) {
return reset( $dates );
} else {
return '';
}
}
public function get_form_editor_inline_script_on_page_render() {
return "
gform.addFilter('gform_form_editor_can_field_be_added', function (canFieldBeAdded, type) {
if (type == 'appointment_calendar') {
if (GetFieldsByType(['appointment_calendar']).length > 0) {
alert(" . json_encode( esc_html__( 'Only one Booking Calendar field can be added to the form', 'gravityformscoupons' ) ) . ");
return false;
}
}
return canFieldBeAdded;
});";
}
/**
* Get timestamp from valid date
*/
public function get_date_timestamp( $date_time ) {
$date = new DateTime( $date_time, new DateTimeZone( ga_time_zone() ) );
return $date->getTimestamp();
}
} // end class
GF_Fields::register( new GF_Appointment_Booking_Calendar() );
} // end if
gf-booking-cost.php 0000666 00000017015 15126233304 0010254 0 ustar 00 <?php
defined( 'ABSPATH' ) or exit; // Exit if accessed directly
if ( class_exists( 'GFForms' ) ) {
class GF_Appointment_Booking_Cost extends GF_Field {
public $type = 'appointment_cost';
public function get_form_editor_field_title() {
return esc_attr__( 'Booking Cost', 'gravityforms' );
}
/*
* Where to assign this widget
*/
public function get_form_editor_button() {
return array(
//'group' => 'advanced_fields',
'group' => 'appointment_calendar',
'text' => $this->get_form_editor_field_title()
);
}
/*
* Add button to the group
*/
public function add_button( $field_groups ) {
$field_groups = $this->ga_appointment_services_gf_group( $field_groups );
return parent::add_button( $field_groups );
}
/*
* Add our group
*/
public function ga_appointment_services_gf_group( $field_groups ) {
foreach ( $field_groups as $field_group ) {
if ( $field_group['name'] == 'appointment_calendar' ) {
return $field_groups;
}
}
$field_groups[] = array(
'name' => 'appointment_calendar',
'label' => __( 'Appointment Booking', 'simplefieldaddon' ),
'fields' => array(
)
);
return $field_groups;
}
/*
* Widget settings
*/
function get_form_editor_field_settings() {
return array(
'label_setting',
'error_message_setting',
'label_placement_setting',
'admin_label_setting',
'description_setting',
'css_class_setting',
'conditional_logic_field_setting',
);
}
public function is_conditional_logic_supported() {
return true;
}
/**
* Field Markup
*/
public function get_field_input( $form, $value = '', $entry = null ) {
$form_id = absint( $form['id'] );
$is_entry_detail = $this->is_entry_detail();
$is_form_editor = $this->is_form_editor();
$id = $this->id;
$field_id = $is_entry_detail || $is_form_editor || $form_id == 0 ? "input_$id" : 'input_' . $form_id . "_$id";
$logic_event = ! $is_form_editor && ! $is_entry_detail ? $this->get_conditional_logic_event( 'keyup' ) : '';
$size = $this->size;
$class_suffix = $is_entry_detail ? '_admin' : '';
$class = $size . $class_suffix;
$css_class = trim( esc_attr( $class ) . ' gfield_select' );
$tabindex = $this->get_tabindex();
$output = '<div class="ginput_container">';
if( $this->is_entry_edit() ) {
$output .= 'This field is not editable';
$output .= "<input type='hidden' name='input_{$id}' id='{$field_id}' value='{$value}'/>";
} elseif( !$this->is_form_editor() ) {
$output .= '<script>jQuery("body").on("change", ".ginput_appointment_cost_input", function() { jQuery( this ).prev( "span" ).text( gformFormatMoney( this.value, true ) ); });</script>';
$output .= "<span class='ginput_{$this->type} ginput_product_price ginput_{$this->type}_{$form_id}_{$field_id}'>" . GFCommon::to_money( '0' ) . "</span>";
$output .= "<input type='hidden' name='input_{$id}' id='{$field_id}' style='{$this->get_inline_price_styles()}' class='{$class} ginput_{$this->type}_input gform_hidden' value='{$value}' {$tabindex} {$logic_event}/>";
}
$output .= '</div>';
return $output;
}
/**
* Is Entry Edit
*/
public function is_entry_edit() {
if ( rgget( 'page' ) == 'gf_entries' && rgget( 'view' ) == 'entry' && rgpost( 'screen_mode' ) == 'edit' ) {
return true;
}
return false;
}
/**
* Returns TRUE if the current page is the form editor page. Otherwise, returns FALSE
*/
public function is_form_editor() {
if ( rgget( 'page' ) == 'gf_edit_forms' && ! rgempty( 'id', $_GET ) && rgempty( 'view', $_GET ) ) {
return true;
}
return false;
}
public function get_inline_price_styles() {
return '';
}
/**
* Validation Failed Message
*/
private function validationFailed( $message = '' ) {
$this->failed_validation = true;
$message = esc_html__( $message, 'gravityforms' );
$this->validation_message = empty( $this->errorMessage ) ? $message : $this->errorMessage;
}
/**
* Validation
*/
public function validate( $value, $form ) {
$form_id = absint( $form['id'] );
if( !gf_field_type_exists( $form, 'appointment_services' ) ) {
$this->validationFailed( ga_get_form_translated_error_message($form_id, 'error_services_form') );
return;
}
if( 'ga_services' == get_post_type(gf_get_field_type_value($form, 'appointment_services' )) ) {
// Service field value
$service_id = gf_get_field_type_value( $form, 'appointment_services' );
// Selected service exists in form category term
$form_cat_slug = rgar($form, 'ga_service_category');
$cat = term_exists( $form_cat_slug, 'ga_service_cat' );
if( $cat ) {
if( has_term( $cat, 'ga_service_cat', $service_id ) ) {
# valid
} else {
$this->validationFailed( ga_get_form_translated_error_message($form_id, 'error_required_service') );
return;
}
}
} else {
$this->validationFailed( ga_get_form_translated_error_message($form_id, 'error_service_valid') );
return;
}
}
/**
* Save Cost with Currency Symbol
*/
public function get_value_save_entry( $value, $form, $input_name, $entry_id, $entry ) {
if( gf_field_type_exists( $form, 'appointment_services' ) ) {
$form_id = $form['id'];
// Service ID
$service_id = absint( gf_get_field_type_value( $form, 'appointment_services' ) );
// Provider ID
$provider_id = gf_field_type_exists($form, 'appointment_providers')
&& 'ga_providers' == get_post_type(gf_get_field_type_value($form, 'appointment_providers'))
? gf_get_field_type_value($form, 'appointment_providers')
: 0;
if( ga_get_provider_id($service_id) && $provider_id == 0 ) {
$provider_id = ga_get_provider_id($service_id);
}
// Service Price
$service_price = get_post_meta($service_id, 'ga_service_price', true);
/**
* Multiple Bookings
*/
$times_mode = (string) get_post_meta( $service_id, 'ga_service_available_times_mode', true );
$multiple_slots = (string) get_post_meta( $service_id, 'ga_service_multiple_selection', true );
if( $multiple_slots == 'yes' && gf_field_type_exists($form, 'appointment_calendar') ) {
$calendar = gf_get_field_type_value( $form, 'appointment_calendar' );
// Get bookings
$bookings = ga_get_multiple_bookings($calendar, $service_id, $provider_id);
if( $times_mode == 'custom' ) {
$value = gf_to_money( ga_get_slots_total( $form['id'], $service_id, $provider_id, $bookings ) );
} else {
$cost = $service_price * count($bookings);
$value = gf_to_money( $cost );
}
} else {
/**
* Single Booking
*/
if( $times_mode == 'custom' ) {
$calendar = gf_get_field_type_value( $form, 'appointment_calendar' );
$booking = ga_get_multiple_bookings($calendar, $service_id, $provider_id);
$service_price = ga_get_slots_total( $form_id, $service_id, $provider_id, $booking );
}
$value = gf_to_money( $service_price );
}
}
return $value;
}
/**
* Show appointment cost on entry single & GP Preview Plugin
*/
public function get_value_entry_detail( $value, $currency = '', $use_text = false, $format = 'html', $media = 'screen' ) {
return $value;
}
} // end class
GF_Fields::register( new GF_Appointment_Booking_Cost() );
} // end if