?
<?php
/**
* Plugin Name: gAppointments
* Description: Appointment booking addon for Gravity Forms.
* Author: WpCrunch
* Version: 1.8.12
* Author URI: https://codecanyon.net/user/wpcrunch
*/
//ini_set('display_errors', 1);
//ini_set('display_startup_errors', 1);
//error_reporting(E_ALL);
defined( 'ABSPATH' ) or exit; // Exit if accessed directly
define( 'ga_base_path', dirname( __FILE__ ) );
new ga_appointments_addon();
class ga_appointments_addon {
private $assets_ver = '1.2.6';
// CONSTANTS //
public function define_constants() {
define( 'GA_GFORM_AFFILIATE_URL', 'https://www.gravityforms.com/' );
}
function __construct() {
add_action( 'init', array( $this, 'init' ) );
}
// INITIALIZE //
public function init() {
$this->define_constants();
if( $this->is_gravity_forms_active() ) {
// Helper Functions
require_once('includes/functions.php');
// Admin settings/pages/post-types
require_once('admin/page_settings.php'); // Settings page
require_once('admin/page_ga_appointments.php'); // Appointments Post Type
require_once('admin/page_ga_services.php'); // Services Post Type
require_once('admin/page_ga_providers.php'); // Providers Post Type
require_once('admin/page_activity.php'); // Activity Page
require_once('admin/includes/ga_work_schedule.php'); // Work Schedule HTML Class
require_once('admin/includes/ga_cron.php'); // Ga Cron
// Styles & Scripts
if( is_admin() ) {
add_action( 'admin_enqueue_scripts', array($this, 'admin_styles_scripts' ) );
} else {
add_action( 'wp_loaded', array($this, 'frontend_styles_scripts' ) );
add_action( 'gform_enqueue_scripts', array($this, 'gform_enqueue_form_scripts'), 10, 2 );
}
// Ajax Actions
$this->ga_ajax_actions();
// CMB2 framework
require_once('includes/cmb2/init.php');
// Appointment Shortcodes
require_once('includes/shortcodes.php');
// GF CUSTOM FIELDS
require_once('gf-fields/gf-form-settings.php');
require_once('gf-fields/ga-calendar.php');
require_once('gf-fields/gf-booking-services.php');
require_once('gf-fields/gf-booking-providers.php');
require_once('gf-fields/gf-booking-calendar.php');
require_once('gf-fields/gf-booking-cost.php');
} else {
add_action( 'admin_notices', array($this, 'gravity_not_active_message' ) );
}
}
// IS GF ACTIVE
public function is_gravity_forms_active() {
return class_exists('GFCommon');
}
// GF NOT ACTIVE MESSAGE
public function gravity_not_active_message() {
$message = sprintf(__('Gravity Forms is required in order to use gAppointments. Activate it now or %1$spurchase it today!%2$s', 'ga_appointments'),
'<a href="' . GA_GFORM_AFFILIATE_URL . '" target="_blank">', '</a>');
echo '<div id="ga_error" class="error is-dismissible"><p>'.$message.'</p></div>';
}
/**
* Admin scripts & styles
*/
public function admin_styles_scripts($hook) {
global $post_type;
$valid_post_types = array('ga_appointments', 'ga_services', 'ga_providers');
if( $hook == 'toplevel_page_ga_appointments_settings' || in_array($post_type, $valid_post_types) ) {
// Datepicker UI
wp_enqueue_script('jquery-ui-datepicker');
// Datepicker Css
wp_enqueue_style('jquery-ui-datepicker-base-theme', plugins_url( 'assets/datepicker.css', __FILE__ ), false, $this->assets_ver);
// Add the color picker css file
wp_enqueue_style( 'wp-color-picker' );
}
if( in_array($post_type, $valid_post_types) ) {
// Auto-save disabled to fix popup alert
wp_dequeue_script( 'autosave' );
}
// Admin css
wp_enqueue_style( 'ga_appointments_admin_css', plugins_url( 'assets/admin.css', __FILE__ ), false, $this->assets_ver );
// Schedule css
wp_enqueue_style( 'ga_appointments_schedule_css', plugins_url( 'assets/schedule.css', __FILE__ ), false, $this->assets_ver );
// Grid css
wp_enqueue_style( 'ga_appointments_calendar_css_grid', plugins_url( 'assets/grid.css', __FILE__ ), false, $this->assets_ver );
// Admin scripts
wp_enqueue_script( 'ga_appointments_calendar_script', plugins_url( 'assets/admin.js', __FILE__ ), array( 'wp-color-picker' ), $this->assets_ver, true );
// Schedule scripts
wp_enqueue_script( 'ga_appointments_schedule_script', plugins_url( 'assets/schedule.js', __FILE__ ), false, $this->assets_ver, true );
// AJAX: Service delete term
wp_localize_script( 'ga_appointments_calendar_script', 'ga_service_delete_term_obj', array('ajax_url' => admin_url('admin-ajax.php')) ); // bb_appointments_calendar_obj = for ajax reference
// AJAX: Service delete term
wp_localize_script( 'ga_appointments_calendar_script', 'ga_service_add_slot_obj', array('ajax_url' => admin_url('admin-ajax.php')) ); // bb_appointments_calendar_obj = for ajax reference
}
/**
* Frontend scripts & styles
*/
public function frontend_styles_scripts() {
// GF Chosen
wp_enqueue_script( 'gform_chosen' );
// Frontend css
wp_enqueue_style( 'ga_appointments_calendar_css', plugins_url( 'assets/calendar.css', __FILE__ ), false, $this->assets_ver );
// Schedule css
wp_enqueue_style( 'ga_appointments_schedule_css', plugins_url( 'assets/schedule.css', __FILE__ ), false, $this->assets_ver );
// Frontend grid css
wp_enqueue_style( 'ga_appointments_calendar_css_grid', plugins_url( 'assets/grid.css', __FILE__ ), false, $this->assets_ver );
// WP Dashicons
wp_enqueue_style( 'dashicons' );
// Font awesome
wp_enqueue_style( 'ga-font-awesome', plugins_url( 'assets/font-awesome.min.css', __FILE__ ), false, $this->assets_ver );
// Main javascipt file
wp_enqueue_script( 'ga_appointments_calendar_script', plugins_url( 'assets/main.js', __FILE__ ), false, $this->assets_ver, true );
// Schedule scripts
wp_enqueue_script( 'ga_appointments_schedule_script', plugins_url( 'assets/schedule.js', __FILE__ ), false, $this->assets_ver, true );
// AJAX: Services
wp_localize_script( 'ga_appointments_calendar_script', 'ga_calendar_services_obj', array('ajax_url' => admin_url('admin-ajax.php')) ); // ga_calendar_services_obj = for ajax reference
// AJAX: Providers
wp_localize_script( 'ga_appointments_calendar_script', 'ga_calendar_providers_obj', array('ajax_url' => admin_url('admin-ajax.php')) ); // ga_calendar_services_obj = for ajax reference
// AJAX: Next Month
wp_localize_script( 'ga_appointments_calendar_script', 'ga_calendar_next_month_obj', array('ajax_url' => admin_url('admin-ajax.php')) ); // ga_calendar_next_month_obj = for ajax reference
// AJAX: Prev Month
wp_localize_script( 'ga_appointments_calendar_script', 'ga_calendar_prev_month_obj', array('ajax_url' => admin_url('admin-ajax.php')) ); // ga_calendar_prev_month_obj = for ajax reference
// AJAX: Time Slots
wp_localize_script( 'ga_appointments_calendar_script', 'ga_calendar_time_slots_obj', array('ajax_url' => admin_url('admin-ajax.php')) ); // ga_calendar_time_slots_obj = for ajax reference
// AJAX: Update Schedule
wp_localize_script( 'ga_appointments_schedule_script', 'ga_calendar_schedule_obj', array('ajax_url' => admin_url('admin-ajax.php')) ); // ga_calendar_time_slots_obj = for ajax reference
// AJAX: Cancel/Update Appointment
wp_localize_script( 'ga_appointments_calendar_script', 'ga_update_appointment_status_obj', array('ajax_url' => admin_url('admin-ajax.php')) ); // bb_appointments_calendar_obj = for ajax reference
}
/**
* Add cost to total field
*/
public function gform_enqueue_form_scripts( $form, $is_ajax ) {
if( gf_field_type_exists( $form, 'appointment_calendar' ) && gf_field_type_exists( $form, 'total' ) ) {
// Appointment Total Script
wp_enqueue_script( 'ga_appointments_calendar_total', plugins_url( 'assets/total.js', __FILE__ ), false, $this->assets_ver, true );
}
if( gf_field_type_exists( $form, 'appointment_cost' ) ) {
// Main javascipt file
wp_enqueue_script( 'gform_gravityforms' );
}
}
/**
* Ajax Actions
*/
public function ga_ajax_actions() {
// Select Service
add_action( 'wp_ajax_ga_calendar_select_service', array($this, 'ga_calendar_select_service') );
add_action( 'wp_ajax_nopriv_ga_calendar_select_service', array($this, 'ga_calendar_select_service') );
// Select Provider
add_action( 'wp_ajax_ga_calendar_select_provider', array($this, 'ga_calendar_select_provider') );
add_action( 'wp_ajax_nopriv_ga_calendar_select_provider', array($this, 'ga_calendar_select_provider') );
// Next month
add_action( 'wp_ajax_ga_calendar_next_month', array($this, 'ga_calendar_next_month') );
add_action( 'wp_ajax_nopriv_ga_calendar_next_month', array($this, 'ga_calendar_next_month') );
// Prev month
add_action( 'wp_ajax_ga_calendar_prev_month', array($this, 'ga_calendar_prev_month') );
add_action( 'wp_ajax_nopriv_ga_calendar_prev_month', array($this, 'ga_calendar_prev_month') );
// Generate Time Slots
add_action( 'wp_ajax_ga_calendar_time_slots', array($this, 'ga_calendar_time_slots') );
add_action( 'wp_ajax_nopriv_ga_calendar_time_slots', array($this, 'ga_calendar_time_slots') ); //
// Provider Schedule Update
add_action( 'wp_ajax_ga_provider_schedule_update', array($this, 'ga_provider_schedule_update') );
// Service delete category term
add_action( 'wp_ajax_ga_service_delete_term', array($this, 'ga_service_delete_term') );
// Service add custom slot
add_action( 'wp_ajax_ga_service_add_slot', array($this, 'ga_service_add_slot') );
}
/**
* Ajax: Delete service term
*/
public function ga_service_delete_term() {
if( !is_admin() ) {
return;
}
$term_id = isset( $_POST['term_id'] ) ? $_POST['term_id'] : false;
if( $term_id ) {
if( wp_delete_term( $term_id, 'ga_service_cat' ) ) {
$response = array( 'success' => true );
wp_send_json_success($response);
wp_die();
} else {
$response = array( 'success' => false );
wp_send_json_error($response);
wp_die();
}
} else {
$response = array( 'success' => false );
wp_send_json_error($response);
wp_die();
}
}
/**
* Get Providers Select Options
*/
public function get_providers_options( $service_id ) {
// The Query
$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 );
$options = '';
// The Loop
if ( $the_query->have_posts() ) {
while ( $the_query->have_posts() ) {
$the_query->the_post();
$title = get_the_title();
if( !empty( $title ) ) {
$options .= '<option value="'.get_the_ID().'">'.$title.'</option>' . PHP_EOL;
}
}
wp_reset_postdata();
} else {
$options .= '<option value="0">No preference</option>' . PHP_EOL;
}
return $options;
}
/**
* AJAX: Select Service
*/
public function ga_calendar_select_service() {
$response = array(
'providers' => '<option value="">Providers not found</option>',
'calendar' => '<p>Something went wrong.</p>'
);
$service_id = isset( $_POST['service_id'] ) ? (int) $_POST['service_id'] : 0;
$form_id = isset( $_POST['form_id'] ) ? (int) $_POST['form_id'] : 0;
if( 'ga_services' == get_post_type($service_id) ) {
$response['providers'] = $this->get_providers_options( $service_id );
$provider_id = ga_get_provider_id( $service_id ) ? ga_get_provider_id( $service_id ) : 0;
$current_date = ga_current_date_with_timezone();
// 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() ));
}
}
$ga_calendar = new GA_Calendar( $form_id, $current_date->format('n'), $current_date->format('Y'), $service_id, $provider_id );
$response['calendar'] = $ga_calendar->show();
wp_send_json_success($response);
wp_die();
} else {
wp_send_json_success($response);
wp_die();
}
}
/**
* AJAX: Select Provider
*/
public function ga_calendar_select_provider() {
$service_id = isset( $_POST['service_id'] ) ? (int) $_POST['service_id'] : 0;
$provider_id = isset( $_POST['provider_id'] ) && 'ga_providers' == get_post_type($_POST['provider_id']) ? (int) $_POST['provider_id'] : 0;
$form_id = isset( $_POST['form_id'] ) ? (int) $_POST['form_id'] : 0;
if( 'ga_services' == get_post_type($service_id) ) {
$current_date = ga_current_date_with_timezone();
// 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() ));
}
}
$ga_calendar = new GA_Calendar( $form_id, $current_date->format('n'), $current_date->format('Y'), $service_id, $provider_id );
echo $ga_calendar->show();
} else {
wp_die('Something went wrong.');
}
wp_die(); // Don't forget to stop execution afterward.
}
/**
* AJAX: Calendar Previous Month
*/
public function ga_calendar_prev_month() {
$current_date = isset( $_POST['current_month'] ) ? esc_html($_POST['current_month']) : '';
$service_id = isset( $_POST['service_id'] ) ? (int) $_POST['service_id'] : 0;
$provider_id = isset( $_POST['provider_id'] ) && 'ga_providers' == get_post_type($_POST['provider_id']) ? (int) $_POST['provider_id'] : 0;
$form_id = isset( $_POST['form_id'] ) ? (int) $_POST['form_id'] : 0;
if( 'ga_services' == get_post_type($service_id) && ga_valid_year_month_format( $current_date ) ) {
$timezone = ga_time_zone();
$date = new DateTime( $current_date, new DateTimeZone( $timezone ) );
$date->modify('-1 month');
$ga_calendar = new GA_Calendar( $form_id, $date->format('n'), $date->format('Y'), $service_id, $provider_id );
echo $ga_calendar->show();
} else {
wp_die("Something went wrong.");
}
wp_die(); // Don't forget to stop execution afterward.
}
/**
* AJAX: Calendar Next Month
*/
public function ga_calendar_next_month() {
$current_date = isset( $_POST['current_month'] ) ? esc_html($_POST['current_month']) : '';
$service_id = isset( $_POST['service_id'] ) ? (int) $_POST['service_id'] : 0;
$provider_id = isset( $_POST['provider_id'] ) && 'ga_providers' == get_post_type($_POST['provider_id']) ? (int) $_POST['provider_id'] : 0;
$form_id = isset( $_POST['form_id'] ) ? (int) $_POST['form_id'] : 0;
if( 'ga_services' == get_post_type($service_id) && ga_valid_year_month_format( $current_date ) ) {
$timezone = ga_time_zone();
$date = new DateTime( $current_date, new DateTimeZone( $timezone ) );
$date->modify('+1 month');
$ga_calendar = new GA_Calendar( $form_id, $date->format('n'), $date->format('Y'), $service_id, $provider_id );
echo $ga_calendar->show();
} else {
wp_die("Something went wrong.");
}
wp_die(); // Don't forget to stop execution afterward.
}
/**
* AJAX: Generate Time Slots
*/
public function ga_calendar_time_slots() {
// Timezone
$timezone = ga_time_zone();
// Service & Provider ID
$current_date = isset( $_POST['current_month'] ) ? esc_html($_POST['current_month']) : '';
$service_id = isset( $_POST['service_id'] ) ? (int) $_POST['service_id'] : 0;
$provider_id = isset( $_POST['provider_id'] ) && 'ga_providers' == get_post_type($_POST['provider_id']) ? (int) $_POST['provider_id'] : 0;
$form_id = isset( $_POST['form_id'] ) ? (int) $_POST['form_id'] : 0;
if( 'ga_services' == get_post_type($service_id) && ga_valid_date_format( $current_date ) ) {
# ok
} else {
wp_die('Something went wrong.');
}
// Date Caption
$date = new DateTime( $current_date, new DateTimeZone( $timezone ) );
// Generate Slots
$ga_calendar = new GA_Calendar( $form_id, $date->format('n'), $date->format('Y'), $service_id, $provider_id );
echo $ga_calendar->calendar_time_slots($date);
wp_die();
}
/**
* Ajax: Update Provider Schedule
*/
public function ga_provider_schedule_update() {
$error = array( 'success' => false, 'message' => '<div class="ga_alert ga_alert_danger">' .ga_get_translated_data('error') . '</div>' );
if( !is_user_logged_in_a_provider() ) {
wp_send_json_error( $error );
wp_die();
}
// Data
$posted = isset( $_POST ) ? $_POST : array();
// Provider Post ID
$provider_id = get_logged_in_provider_id();
// Policies options
$policies = get_option( 'ga_appointments_policies' );
// Provider own calendar schedule
$calendar = get_post_meta( $provider_id, 'ga_provider_calendar', true );
// Provider manages its schedule on the front-end
$manage = isset($policies['provider_manages_schedule']) && in_array($policies['provider_manages_schedule'], array('yes', 'no')) ? $policies['provider_manages_schedule'] : 'yes';
if( isset($posted['action']) && $posted['action'] == 'ga_provider_schedule_update' && $calendar == 'on' && $manage == 'yes' ) {
if( !class_exists('ga_work_schedule') ) {
require_once( ga_base_path . '/admin/includes/ga_work_schedule.php' );
}
$schedule = new ga_work_schedule( $provider_id );
$work_schedule = isset( $_POST['ga_provider_work_schedule'] ) ? $_POST['ga_provider_work_schedule'] : array();
$breaks = isset( $_POST['ga_provider_breaks'] ) ? $_POST['ga_provider_breaks'] : array();
$holidays = isset( $_POST['ga_provider_holidays'] ) ? $_POST['ga_provider_holidays'] : array();
update_post_meta( $provider_id, 'ga_provider_work_schedule', $schedule->validate_work_schedule($work_schedule) );
update_post_meta( $provider_id, 'ga_provider_breaks', $schedule->validate_breaks($breaks) );
update_post_meta( $provider_id, 'ga_provider_holidays', $schedule->validate_holidays($holidays) );
$success = array( 'success' => true, 'html' => ga_provider_schedule_form( $provider_id ), 'message' => '<div class="ga_alert ga_alert_success">' .ga_get_translated_data('schedule_updated') . '</div>' );
wp_send_json_success( $success );
wp_die();
} else {
wp_send_json_error( $error );
wp_die();
}
}
/**
* Ajax: Delete service term
*/
public function ga_service_add_slot() {
$name = 'ga_service_custom_slots';
$id = uniqid();
?>
<tr>
<td>
<select name="<?php echo "{$name}[{$id}][start]"; ?>">
<?php
foreach( get_ga_appointment_time() as $time => $text ) {
echo '<option value='. $time .'>'. $text .'</option>';
}
?>
</select>
</td>
<td>
<select name="<?php echo "{$name}[{$id}][end]"; ?>">
<?php
foreach( get_ga_appointment_time($out = false, $_24 = true) as $time => $text ) {
echo '<option value='. $time .'>'. $text .'</option>';
}
?>
</select>
</td>
<td>
<?php
foreach( array('monday', 'tuesday', 'wednesday', 'thursday', 'friday', 'saturday', 'sunday') as $key => $week ) {
$week_short = substr( ucfirst($week), 0, 1 );
echo "<div class='ga_week_day'>
<label>
<input type='checkbox' name='{$name}[{$id}][availability][]' value='{$week}'>
<span>{$week_short}</span>
</label>
</div>";
}
?>
</td>
<td>
<select name="<?php echo "{$name}[{$id}][capacity]"; ?>">
<?php
foreach( ga_services_capacity_options() as $num => $text ) {
echo '<option value='. $num .'>'. $text .'</option>';
}
?>
</select>
</td>
<td>
<?php echo gf_get_currency_symbol(); ?> <input type="text" class="cmb2-text-small" name="<?php echo "{$name}[{$id}][price]"; ?>" id="" value="">
</td>
<td>
<div class="slot-delete">Delete</div>
</td>
</tr>
<?php
wp_die();
}
} // end class