PATH:
home
/
ediuae
/
petalwellnessspa.com
/
wp-content
/
plugins
/
simply-schedule-appointments
/
includes
<?php /** * Simply Schedule Appointments Shortcodes. * * @since 0.0.3 * @package Simply_Schedule_Appointments */ /** * Simply Schedule Appointments Shortcodes. * * @since 0.0.3 */ class SSA_Shortcodes { /** * Parent plugin class. * * @since 0.0.3 * * @var Simply_Schedule_Appointments */ protected $plugin = null; protected $script_handle_whitelist = array(); protected $style_handle_whitelist = array(); protected $custom_script_handle_whitelist = array(); protected $disable_third_party_styles = false; protected $disable_third_party_scripts = false; /** * Constructor. * * @since 0.0.3 * * @param Simply_Schedule_Appointments $plugin Main plugin object. */ public function __construct( $plugin ) { $this->plugin = $plugin; $this->hooks(); } /** * Initiate our hooks. * * @since 0.0.3 */ public function hooks() { add_shortcode( 'ssa_booking', array( $this, 'ssa_booking' ) ); add_shortcode( 'tec_ssa_booking', array( $this, 'tec_ssa_booking' ) ); add_shortcode( 'mepr_ssa_booking', array( $this, 'mepr_ssa_booking' ) ); add_shortcode( 'ssa_past_appointments', array( $this, 'ssa_past_appointments' ) ); add_shortcode( 'ssa_upcoming_appointments', array( $this, 'ssa_upcoming_appointments' ) ); add_shortcode( 'ssa_admin_upcoming_appointments', array( $this, 'ssa_admin_upcoming_appointments' ) ); add_shortcode( 'ssa_admin', array( $this, 'ssa_admin' ) ); add_shortcode( 'ssa_confirmation', array( $this, 'ssa_confirmation' ) ); add_action( 'init', array( $this, 'store_enqueued_styles_scripts' ), 1 ); add_action( 'wp_enqueue_scripts', array( $this, 'register_styles' ) ); add_action( 'init', array( $this, 'register_scripts' ) ); add_action( 'wp_enqueue_scripts', array( $this, 'enqueue_styles' ) ); add_action( 'wp_enqueue_scripts', array( $this, 'maybe_enqueue_scripts_sitewide' ), 0 ); add_action( 'wp_enqueue_scripts', array( $this, 'disable_third_party_scripts' ), 9999999 ); add_action( 'wp_enqueue_scripts', array( $this, 'disable_third_party_styles' ), 9999999 ); add_action( 'init', array( $this, 'custom_rewrite_basic' ) ); add_action('init', array( $this, 'prevent_breakdance_conflict_with_appointment_edit_url' ) ); add_action( 'query_vars', array( $this, 'register_query_var' ) ); add_filter( 'template_include', array( $this, 'hijack_booking_page_template' ) ); add_filter( 'template_include', array( $this, 'hijack_embedded_page' ), 9999999 ); add_filter( 'template_include', array( $this, 'hijack_appointment_edit_page' ), 9999999 ); add_filter( 'template_include', array( $this, 'hijack_appointment_edit_url' ), 9999999 ); add_action( 'template_redirect', array( $this, 'prevent_thrive_themes_conflict_with_appointment_edit_url' ), 8 ); // REST API Endpoint to pull generate output from shortcode add_action( 'rest_api_init', array( $this, 'register_rest_routes' ) ); } /** * Withou this, BreakDance would force the appointment edit URL to load the home page. * */ public function prevent_breakdance_conflict_with_appointment_edit_url(){ if ( empty( $_GET['appointment_action'] ) || 'edit' !== $_GET['appointment_action'] || empty( $_GET['appointment_token'] ) ) { return; } if (has_filter('template_include', 'Breakdance\ActionsFilters\template_include')) { remove_filter('template_include', 'Breakdance\ActionsFilters\template_include', 1000000); } } public function prevent_thrive_themes_conflict_with_appointment_edit_url() { if ( empty( $_GET['appointment_action'] ) || 'edit' !== $_GET['appointment_action'] || empty( $_GET['appointment_token'] ) ) { return; } remove_action( 'template_redirect', 'tcb_custom_editable_content', 9 ); // this is ThriveTheme's nuclear function that removes *all* template_include filters } public function custom_rewrite_basic() { add_rewrite_rule( '^ssa-embed?', 'index.php?ssa_embed=yes', 'top' ); } public function register_query_var( $vars ) { $vars[] = 'ssa_embed'; return $vars; } public function store_enqueued_styles_scripts() { if ( is_admin() ) { return; } global $wp_scripts; if ( empty( $wp_scripts->queue ) ) { $this->script_handle_whitelist = array(); } else { $this->script_handle_whitelist = $wp_scripts->queue; } } public function disable_third_party_scripts() { if ( ! $this->disable_third_party_scripts ) { return; } global $wp_scripts; if ( ! empty( $wp_scripts->queue ) ) { foreach ( $wp_scripts->queue as $key => $handle ) { if ( strpos( $handle, 'ssa-' ) === 0 ) { continue; } if ( in_array( $handle, $this->script_handle_whitelist ) || in_array( $handle, $this->custom_script_handle_whitelist ) ) { continue; } wp_dequeue_script( $handle ); } } } public function disable_third_party_styles() { if ( ! $this->disable_third_party_styles ) { return; } global $wp_styles; if ( ! empty( $wp_styles->queue ) ) { foreach ( $wp_styles->queue as $key => $handle ) { if ( strpos( $handle, 'ssa-' ) === 0 ) { continue; } if ( in_array( $handle, $this->style_handle_whitelist ) || in_array( $handle, $this->custom_script_handle_whitelist ) ) { continue; } wp_dequeue_style( $handle ); } } } public function is_booking_page() { $page_id = get_queried_object_id(); $settings = $this->plugin->settings->get(); if ( empty( $page_id ) || $page_id != $settings['global']['booking_post_id'] ) { return false; } return true; } public function get_appointment_edit_permalink() { return apply_filters( 'ssa/booking/appointment_edit_permalink', 'appointments/change' ); } public function is_embedded_page() { $query_var = get_query_var( 'ssa_embed' ); if ( ! empty( $query_var ) ) { return true; } if ( ! empty( $_GET['ssa_embed'] ) ) { return true; } global $wp; if ( ! empty( $wp->matched_rule ) && $wp->matched_rule === '^ssa-embed?' ) { return true; } if ( $wp->request === 'ssa-embed' ) { return true; } return false; } public function hijack_embedded_page( $template ) { if ( ! $this->is_embedded_page() ) { return $template; } return $this->plugin->dir( 'booking-app-new/iframe-inner.php' ); } public function hijack_booking_page_template( $template ) { if ( ! $this->is_booking_page() ) { return $template; } return $this->plugin->dir( 'booking-app-new/fullscreen-page.php' ); } public function hijack_appointment_edit_page( $template ) { $appointment_edit_permalink = $this->get_appointment_edit_permalink(); global $wp; $uri = sanitize_text_field( $wp->request ); if ( strpos( $uri, $appointment_edit_permalink ) !== 0 ) { return $template; } $uri = str_replace( $appointment_edit_permalink, '', $uri ); $uri = ltrim( $uri, '/' ); $uri = rtrim( $uri, '/' ); $parts = explode( '-', $uri ); $provided_hash = $parts['0']; $provided_hash = substr( $uri, 0, 32 ); $appointment_id = substr( $uri, 32 ); if ( ! $this->plugin->appointment_model->verify_id_token( $appointment_id, $provided_hash ) ) { die( 'An error occurred, please check the URL' ); // phpcs:ignore } add_filter( 'show_admin_bar', '__return_false' ); global $ssa_current_appointment_id; $ssa_current_appointment_id = $appointment_id; return $this->plugin->dir( 'booking-app-new/page-appointment-edit.php' ); } public function hijack_appointment_edit_url( $template ) { // If Appointment Action is not edit if ( empty( $_GET['appointment_action'] ) || 'edit' !== $_GET['appointment_action'] || empty( $_GET['appointment_token'] ) ) { return $template; } /** * Prevent hijacking the PAGE if this is a Gravity Forms custom confirmation * The URL is already hijacked by now */ if( ! empty( $_GET['ssa_gf_custom_confirmation'] ) ) { return $template; } $settings_global = ssa()->settings->get()['global']; $edit_appointment_page_id = $settings_global['edit_appointment_page_id']; // If Edit Appointment Page is found and has the shortcode ssa_confirmation if ( ! empty ( $edit_appointment_page_id ) && get_queried_object_id() == $edit_appointment_page_id ) { $post = get_post($edit_appointment_page_id); if ($post && has_shortcode( $post->post_content, 'ssa_confirmation' )) { /** * Allow hijacking the page if the admin is editing as customer from within SSA admin app * @see admin-app/src/components/Appointment/Appointment.vue */ if ( empty( $_GET['redirect_from'] ) || $_GET['redirect_from'] !== 'ssa_admin' ) { return $template; } } } else if ( !is_front_page() && ! is_home() ) { return $template; } $this->disable_third_party_scripts = true; $this->disable_third_party_styles = true; $appointment_token = sanitize_text_field( $_GET['appointment_token'] ); $provided_hash = substr( $appointment_token, 0, 32 ); $appointment_id = substr( $appointment_token, 32 ); if ( ! $this->plugin->appointment_model->verify_id_token( $appointment_id, $provided_hash ) ) { die( 'An error occurred, please check the URL' ); // phpcs:ignore } if ( isset( $_GET['admin'] ) && current_user_can( 'ssa_manage_site_settings' ) ) { wp_redirect( ssa()->appointment_model->get_admin_edit_url( $appointment_id ), 302 ); exit; } add_filter( 'show_admin_bar', '__return_false' ); global $ssa_current_appointment_id; $ssa_current_appointment_id = $appointment_id; return $this->plugin->dir( 'booking-app-new/page-appointment-edit.php' ); } public function body_class( $classes ) { $classes = "$classes ssa-admin-app"; return $classes; } public function register_scripts() { wp_register_script( 'ssa-iframe-inner', $this->plugin->url( 'assets/js/iframe-inner.js' ), array(), Simply_Schedule_Appointments::VERSION, true ); wp_register_script( 'ssa-iframe-outer', $this->plugin->url( 'assets/js/iframe-outer.js' ), array(), Simply_Schedule_Appointments::VERSION, true ); wp_register_script( 'ssa-tracking', $this->plugin->url( 'assets/js/ssa-tracking.js' ), array(), Simply_Schedule_Appointments::VERSION, true ); wp_register_script( 'ssa-form-embed', $this->plugin->url( 'assets/js/ssa-form-embed.js' ), array( 'jquery' ), Simply_Schedule_Appointments::VERSION, true ); wp_register_script( 'ssa-unsupported-script', $this->plugin->url( 'assets/js/unsupported.js' ), array(), Simply_Schedule_Appointments::VERSION ); } public function register_styles() { wp_register_style( 'ssa-booking-material-icons', $this->plugin->url( 'assets/css/material-icons.css' ), array(), Simply_Schedule_Appointments::VERSION ); wp_register_style( 'ssa-booking-style', $this->plugin->url( 'booking-app/dist/static/css/app.css' ), array(), Simply_Schedule_Appointments::VERSION ); wp_register_style( 'ssa-booking-roboto-font', $this->plugin->url( 'assets/css/roboto-font.css' ), array(), Simply_Schedule_Appointments::VERSION ); wp_register_style( 'ssa-iframe-inner', $this->plugin->url( 'assets/css/iframe-inner.css' ), array(), Simply_Schedule_Appointments::VERSION ); wp_register_style( 'ssa-styles', $this->plugin->url( 'assets/css/ssa-styles.css' ), array(), Simply_Schedule_Appointments::VERSION ); wp_register_style( 'ssa-unsupported-style', $this->plugin->url( 'assets/css/unsupported.css' ), array(), Simply_Schedule_Appointments::VERSION ); wp_register_style( 'ssa-upcoming-appointments-card-style', $this->plugin->url( 'assets/css/upcoming-appointments.css' ), array(), Simply_Schedule_Appointments::VERSION ); } public function enqueue_styles() { global $post; if ( $this->is_embedded_page() ) { wp_enqueue_style( 'ssa-unsupported-style' ); wp_enqueue_style( 'ssa-booking-material-icons' ); wp_enqueue_style( 'ssa-booking-style' ); wp_enqueue_style( 'ssa-booking-roboto-font' ); wp_enqueue_style( 'ssa-iframe-inner' ); } elseif ( is_a( $post, 'WP_Post' ) ) { wp_enqueue_style( 'ssa-upcoming-appointments-card-style' ); wp_enqueue_style( 'ssa-styles' ); } } public function maybe_enqueue_scripts_sitewide() { $developer_settings = $this->plugin->developer_settings->get(); if ( empty( $developer_settings['enqueue_everywhere'] ) ) { return; } if ( $this->is_embedded_page() ) { return; } wp_enqueue_script( 'ssa-iframe-outer' ); wp_enqueue_script( 'ssa-tracking' ); wp_enqueue_script( 'ssa-form-embed' ); } public function tec_ssa_booking( $atts = array() ) { // sanitize all atts $atts = array_map( 'sanitize_text_field', $atts ); $post_id = get_the_ID(); if ( ! function_exists( 'tribe_is_event' ) || ! tribe_is_event( $post_id ) ) { return $this->ssa_booking( $atts ); } $event = tribe_get_event( $post_id ); if ( empty( $atts ) ) { $atts = array(); } $atts = array_merge( array( 'availability_start_date' => $event->dates->start_utc->format( 'Y-m-d H:i:s' ), 'availability_end_date' => $event->dates->end_utc->format( 'Y-m-d H:i:s' ), ), $atts ); return $this->ssa_booking( $atts ); } public function get_ssa_booking_arg_defaults() { return array( 'integration' => '', // internal use only for integrations 'type' => '', 'label' => '', 'types' => '', 'edit' => '', 'view' => '', 'payment_provider' => '', // use to indicate to the frontend what payment provider was used 'ssa_locale' => SSA_Translation::get_locale(), 'ssa_is_rtl' => SSA_Translation::is_rtl(), 'sid' => sha1( gmdate( 'Ymd' ) . get_current_user_id() ), // busts full-page caching so each URL is user-specific (daily) and doesn't leak sensitive data 'availability_start_date' => '', 'availability_end_date' => '', 'suggest_first_available' => '', 'suggest_first_available_within_minutes' => '', 'flow' => '', 'fallback_flow' => '', 'time_view' => '', 'date_view' => '', 'appointment_types_view' => '', 'version' => '', 'accent_color' => '', 'background' => '', 'padding' => '', 'font' => '', 'booking_url' => urlencode( get_permalink() ), 'booking_post_id' => urlencode( get_the_ID() ), 'booking_title' => urlencode( get_the_title() ), '_wpnonce' => wp_create_nonce( 'wp_rest' ), 'redirect_post_id' => '', // MemberPress Integration 'mepr_membership_id' => '' ); } public function get_passed_args() { $passed_args = array_diff_key( $_GET, $this->get_ssa_booking_arg_defaults() ); return $passed_args; } public function ssa_confirmation() { $appointment_token = isset($_GET['appointment_token']) ? esc_attr($_GET['appointment_token']): (isset($_POST["appointment_token"]) ? esc_attr( $_POST["appointment_token"]): ''); $error_message = ''; $paypal_success = isset($_GET['paypal_success']) ? esc_attr($_GET['paypal_success']): ''; $paypal_cancel = isset($_GET['paypal_cancel']) ? esc_attr($_GET['paypal_cancel']): ''; if(empty($appointment_token)) { if ( current_user_can( 'ssa_manage_site_settings' ) ) { $error_message = '<h3 style="text-align: center">'. __('Simply Schedule Appointments Booking Confirmation' , 'simply-schedule-appointments') . '</h3>'; } return $error_message; } // Validate Token and Appointment ID $provided_hash = substr($appointment_token, 0, 32); $appointment_id = substr($appointment_token, 32); if ( ! $this->plugin->appointment_model->verify_id_token( $appointment_id, $provided_hash ) ) { $error_message = '<h3 style="text-align: center">'. __('An error occurred, please check the URL.' , 'simply-schedule-appointments' ) . '</h3>'; return $error_message; } // at this point, we know the appointment is valid, we continue to show the confirmation $appointment = new SSA_Appointment_Object( $appointment_id ); $customer_locale = $appointment->customer_locale; $atts = array( 'edit' => $appointment_id ); if ( ! current_user_can( 'ssa_manage_appointments' ) ) { if ( ! empty( $customer_locale ) ) { $atts['ssa_locale'] = $customer_locale; } } if ( "1" === $paypal_cancel ) { $atts = array_merge(array( 'view' => 'canceled_payment', 'payment_provider' => 'paypal' ), $atts); } else if ( ! empty( $paypal_success ) || ! empty( $paypal_cancel ) ) { // continue to show ssa_booking - consider appointment abandoned $atts = array_merge(array( 'view' => "confirm_payment", 'payment_provider' => 'paypal' ), $atts); } if( isset( $_GET['stripe_payment'] ) && $_GET['stripe_payment'] === 0 ){ if( isset( $_GET['redirect_status'] ) && $_GET['redirect_status'] === "failed" ){ $atts = array_merge(array( 'view' => "canceled_payment", 'payment_provider' => 'stripe' ), $atts); } else { // Here we assume $_GET['redirect_status'] is "success" // We show the user confirm_payment view // The frontend will take over and only show the confirmation if the appointment status was updated to be booked $atts = array_merge(array( 'view' => "confirm_payment", 'payment_provider' => 'stripe' ), $atts); } } return $this->ssa_booking( $atts ); } public function ssa_booking( $atts, $is_embedded_page = false ) { // sanitize all atts $atts = array_map( 'sanitize_text_field', $atts ); $atts = shortcode_atts( $this->get_ssa_booking_arg_defaults(), $atts, 'ssa_booking' ); $atts = apply_filters( 'ssa_booking_shortcode_atts', $atts ); // escape JS $atts = array_map( 'esc_attr', $atts ); $paypal_payment = isset($_GET['paypal_payment']) ? esc_attr($_GET['paypal_payment']): ''; $stripe_payment = isset($_GET['stripe_payment']) ? esc_attr($_GET['stripe_payment']): ''; if(isset($_GET["paypal_cancel"]) && "1" === $_GET["paypal_cancel"]){ $_GET["paypal_cancel"] = true; return $this->ssa_confirmation(); } if($paypal_payment){ $_GET["paypal_payment"] = 0; return $this->ssa_confirmation(); } if( $stripe_payment ){ $_GET['stripe_payment'] = 0; return $this->ssa_confirmation(); } // Override atts types/type/label if mepr_membership_id is set if( ! empty( $atts['mepr_membership_id'] ) ) { $atts = $this->convert_mepr_membership_id_to_appt_types_ids( $atts ); if ( ! empty( $atts['error_message'] ) ) { return $atts['error_message']; } } // First validate atts['types'] if set if( ! empty( $atts['types'] ) ){ $types = sanitize_text_field( esc_attr( $atts['types'] ) ); $is_valid = $this->is_valid_types_attribute( $types ); if( ! $is_valid ){ $error_message = '<h3>' . __('Sorry, no appointment types available, please check back later.', 'simply-schedule-appointments') . '</h3>'; if ( current_user_can( 'ssa_manage_site_settings' ) ) { $error_message .= '<code>' . sprintf( __('The specified appointment types \'%1$s\' can\'t be found %2$s (this message is only viewable to site administrators)', 'simply-schedule-appointments'), $types, '</code>' ); } return $error_message; } } // Check for atts['label'] if set, and convert it to atts['types'] if( ! empty( $atts['label'] ) ) { $label = sanitize_text_field( esc_attr( $atts['label'] ) ); $ids = $this->convert_label_to_appt_types_ids( $label ); if ( empty( $ids ) ) { $error_message = '<h3>' . __('Sorry, no appointment types available for this label, please check back later.', 'simply-schedule-appointments') . '</h3>'; if ( current_user_can( 'ssa_manage_site_settings' ) ) { $error_message .= '<code>' . sprintf( __('The specified appointment type label \'%1$s\' can\'t be found, or has no appointment types available %2$s (this message only viewable to site administrators)', 'simply-schedule-appointments'), $label, '</code>' ); } return $error_message; } else { $atts['types'] = $ids; } } $appointment_type = ''; if ( ! empty( $atts['type'] ) ) { if ( $atts['type'] == (string) (int) $atts['type'] ) { // integer ID provided $appointment_type_id = (int) sanitize_text_field( $atts['type'] ); } else { // slug provided $appointment_types = $this->plugin->appointment_type_model->query( array( 'slug' => sanitize_text_field( $atts['type'] ), 'status' => 'publish', ) ); if ( ! empty( $appointment_types['0']['id'] ) ) { $appointment_type_id = $appointment_types['0']['id']; } if ( empty( $appointment_type_id ) ) { $type = sanitize_text_field( esc_attr( $atts['type'] ) ); $error_message = '<h3>' . __('Sorry this appointment type isn\'t available, please check back later', 'simply-schedule-appointments') . '</h3>'; if ( current_user_can( 'ssa_manage_site_settings' ) ) { $error_message .= '<code>' . sprintf( __('The specified appointment type \'%1$s\' can\'t be found %2$s (this message only viewable to site administrators)', 'simply-schedule-appointments'), $type, '</code>' ); } return $error_message; } } if ( ! empty( $appointment_type_id ) ) { $appointment_type = $this->plugin->appointment_type_model->get( $appointment_type_id ); if ( empty( $atts['types'] ) ) { $atts['types'] = $appointment_type_id; } } } if ( $is_embedded_page || $this->is_embedded_page() ) { // wp_localize_script( 'ssa-booking-app', 'ssaBookingParams', array( // 'apptType' => $appointment_type, // 'translatedStrings' => array( // ), // ) ); wp_localize_script( 'ssa-booking-app', 'ssa', $this->plugin->bootstrap->get_api_vars() ); wp_localize_script( 'ssa-booking-app', 'ssa_translations', $this->get_translations() ); wp_enqueue_script( 'ssa-unsupported-script' ); wp_enqueue_script( 'ssa-booking-manifest' ); wp_enqueue_script( 'ssa-booking-vendor' ); wp_enqueue_script( 'ssa-booking-app' ); wp_enqueue_script( 'ssa-iframe-inner' ); return ' <div id="ssa-booking-app"> <noscript> <div class="unsupported"> <div class="unsupported-container"> <h1 class="unsupported-label">' . __( 'Simply Schedule Appointments requires JavaScript', 'simply-schedule-appointments' ) . '</h1> <p class="unsupported-description">' . __( 'To book an appointment, please make sure you enable JavaScript in your browser.', 'simply-schedule-appointments' ) . '</p> </div> </div> </noscript> </div> <div id="ssa-unsupported" style="display:none;"> <div class="unsupported"> <div class="unsupported-container"> <h1 class="unsupported-label">' . __( 'Unsupported Browser', 'simply-schedule-appointments' ) . '</h1> <p class="unsupported-description">' . __( 'To book an appointment, please update your browser to something more modern. We recommend Firefox or Chrome.', 'simply-schedule-appointments' ) . '</p> </div> </div> </div> '; } wp_localize_script( 'ssa-iframe-outer', 'ssa', $this->plugin->bootstrap->get_api_vars() ); wp_enqueue_script( 'ssa-iframe-outer' ); if ( $this->plugin->settings_installed->is_enabled( 'tracking' ) ) { wp_enqueue_script( 'ssa-tracking' ); } if ( ! empty( $atts['integration'] ) ) { wp_enqueue_script( 'ssa-form-embed' ); } $settings = $this->plugin->settings->get(); // $link = get_page_link( $settings['global']['booking_post_id'] ); $api_vars = $this->plugin->bootstrap->get_api_vars(); if ( ! empty( $atts['edit'] ) ) { $appointment_id = sanitize_text_field( $atts['edit'] ); if ( ! empty( $appointment_id ) ) { $appointment = SSA_Appointment_Object::instance( $appointment_id ); $appointment_type_id = $appointment->get_appointment_type()->id; if ( empty( $atts['types'] ) ) { $atts['types'] = $appointment_type_id; } } } $link = add_query_arg( $atts, $api_vars['api']['root'] . '/embed-inner' ); if ( ! empty( $atts['edit'] ) ) { $appointment_id = sanitize_text_field( $atts['edit'] ); // if it's an integration form, and the appointment status is 'pending_form', load the appointment on a pre confirmed state. if ( ! empty( $atts['integration'] ) && $appointment->is_reserved() ) { $appointment_id_token = ! empty( $atts['token'] ) ? $atts['token'] : $this->plugin->appointment_model->get_id_token( array( 'id' => sanitize_text_field( $atts['edit'] ) ) ); $link = add_query_arg( array( 'token' => $appointment_id_token ), $link ); $link = $link . '#/load-appointment/' . $appointment_id; } else { $appointment_id_token = $this->plugin->appointment_model->get_id_token( array( 'id' => $appointment_id ) ); $link = $link . '#/change/' . $appointment_id_token . $appointment_id; } } else { $link = $link . '#/'; } if ( ! empty( $atts['integration'] ) ) { $link = str_replace( '#/', '#/integration/' . esc_attr( $atts['integration'] ) . '/', $link ); } if ( ! empty( $atts['view'] ) ) { $link .= '/view/' . $atts['view']; } $link = SSA_Bootstrap::maybe_fix_protocol( $link ); $escaped_passed_args = array(); foreach ( $this->get_passed_args() as $passed_key => $passed_value ) { if ( ! is_string( $passed_key ) || ! is_string( $passed_value ) ) { continue; // needed to prevent error rendering gutenberg block } // at this point any escaped passed value has been decoded // the encode step below will handle the affected characters $passed_value = urlencode( $passed_value ); if ( $passed_key === 'Email' ) { $passed_value = str_replace( '+', '%2B', trim( $passed_value ) ); // since + is a URL equivalent of %20, an email like 'example+123@gmail.com' needs to be re-encoded to prevent it from becoming 'example 123@gmail.com' } // if the first char of phone is a +, meaning the URL contained a literal unescaped +, it should be encoded to %2B if ( $passed_key === 'Phone' ) { $passed_value = preg_replace( '/^(\+)(.*)/', '%2B$2', $passed_value ); } $escaped_passed_args[ htmlspecialchars( $passed_key ) ] = htmlspecialchars( $passed_value ); } $link = add_query_arg( $escaped_passed_args, $link ); $lazy_load_mode = apply_filters( 'ssa/performance/lazy_load', false ); if ( false === $lazy_load_mode ) { $iframe_src = '<iframe src="' . $link . '" height="400px" width="100%" name="ssa_booking" loading="eager" frameborder="0" data-skip-lazy="1" class="ssa_booking_iframe skip-lazy" title="' . esc_attr__( 'Book a time', 'simply-schedule-appointments' ) . '"></iframe>'; } elseif ( true === $lazy_load_mode ) { $iframe_src = '<iframe src="' . $link . '" height="400px" width="100%" name="ssa_booking" loading="lazy" frameborder="0" class="ssa_booking_iframe" title="' . esc_attr__( 'Book a time', 'simply-schedule-appointments' ) . '"></iframe>'; } else { $iframe_src = '<iframe src="' . $link . '" height="400px" width="100%" name="ssa_booking" frameborder="0" class="ssa_booking_iframe" title="' . esc_attr__( 'Book a time', 'simply-schedule-appointments' ) . '"></iframe>'; } return $iframe_src; } public function ssa_admin_upcoming_appointments( $atts ) { // sanitize - currently the shortcode is hardcoded but sanitize anyway $atts = array_map( 'sanitize_text_field', $atts ); $atts = shortcode_atts( array( 'recursive' => -1, // omit the unneeded details 'status' => 'booked', 'number' => 5, 'orderby' => 'start_date', 'order' => 'ASC', 'customer_id' => '', 'staff_ids_any' => current_user_can( 'ssa_manage_others_appointments' ) ? []: [ $this->plugin->staff_model->get_staff_id_for_user_id( get_current_user_id() ) ], 'no_results_message' => __( 'No upcoming appointments', 'simply-schedule-appointments' ), 'logged_out_message' => '', 'start_date_min' => ssa_datetime()->sub( new DateInterval( 'PT1H' ) )->format( 'Y-m-d H:i:s' ), 'details_link_displayed' => true, 'details_link_label' => __( 'View Details', 'simply-schedule-appointments' ), 'all_appointments_link_label' => __( 'View all upcoming appointments', 'simply-schedule-appointments' ), 'web_meeting_link_label' => __( 'Open Web Meeting', 'simply-schedule-appointments' ), 'web_meeting_url' => true, 'appointment_type_displayed' => false, 'team_members_displayed' => true, ), $atts, 'ssa_admin_upcoming_appointments' ); ob_start(); include $this->plugin->dir( 'templates/dashboard/dashboard-upcoming-appointments-widget.php' ); $output = ob_get_clean(); return $output; } public function ssa_past_appointments( $atts ) { $atts = array_map( 'sanitize_text_field', $atts ); $atts = shortcode_atts( array( 'status' => 'booked', 'number' => 10, 'orderby' => 'start_date', 'order' => 'DESC', 'customer_id' => get_current_user_id(), 'no_results_message' => __( 'No past appointments', 'simply-schedule-appointments' ), 'logged_out_message' => '', 'end_date_max' => ssa_datetime()->format( 'Y-m-d H:i:s' ), 'details_link_displayed' => true, 'details_link_label' => __( 'View Details', 'simply-schedule-appointments' ), 'web_meeting_url' => false, 'appointment_type_displayed' => false, ), $atts, 'ssa_upcoming_appointments' ); ob_start(); include $this->plugin->dir( 'templates/customer/past-appointments.php' ); $output = ob_get_clean(); return $output; } public function ssa_upcoming_appointments( $atts ) { $atts = array_map( 'sanitize_text_field', $atts ); $block_settings = isset($atts['block_settings']) ? $atts['block_settings'] : array(); $atts = shortcode_atts( array( 'status' => 'booked', 'number' => -1, 'orderby' => 'start_date', 'order' => 'ASC', 'customer_id' => get_current_user_id(), 'customer_information' => wp_get_current_user()->user_email, 'no_results_message' => __( 'No upcoming appointments', 'simply-schedule-appointments' ), 'logged_out_message' => '', 'start_date_min' => ssa_datetime()->sub( new DateInterval( 'PT1H' ) )->format( 'Y-m-d H:i:s' ), 'details_link_displayed' => true, 'details_link_label' => __( 'View Details', 'simply-schedule-appointments' ), 'web_meeting_url' => true, 'appointment_type_displayed' => false, 'block_settings' => $block_settings, ), $atts, 'ssa_upcoming_appointments' ); ob_start(); include $this->plugin->dir( 'templates/customer/upcoming-appointments.php' ); $output = ob_get_clean(); return $output; } public function ssa_admin() { if( ! is_user_logged_in() ) { return; } // If current user or visitor can't manage appointments, display a warning message. if ( ! current_user_can( 'ssa_manage_appointments' ) ) { return '<div class="ssa-admin-warning">' . __( 'It looks like you\'re not allowed to see this screen. Please check with your site administrator if you think this message is an error.', 'simply-schedule-appointments' ) . '</div>'; } // Make sure we have the nonce for the admin page. $nonce = wp_create_nonce( 'wp_rest' ); wp_localize_script( 'ssa-iframe-outer', 'ssa', $this->plugin->bootstrap->get_api_vars() ); wp_enqueue_script( 'ssa-iframe-outer' ); $api_vars = $this->plugin->bootstrap->get_api_vars(); $link = add_query_arg( array( '_wpnonce' => $nonce, ), $api_vars['api']['root'] . '/embed-inner-admin' ); // Check if we have a 'ssa_state' url parameter on the current page. If so, we need to add it to the iframe src as a url hash. $ssa_state = isset( $_GET['ssa_state'] ) ? sanitize_text_field( esc_attr( $_GET['ssa_state'] ) ) : ''; if ( ! empty( $ssa_state ) ) { // sanitize to avoid reflected xss $link = $link . '#' . $ssa_state; } $link = SSA_Bootstrap::maybe_fix_protocol( $link ); return '<iframe src="' . $link . '" height="400px" width="100%" name="ssa_admin" loading="eager" frameborder="0" data-skip-lazy="1" class="ssa_booking_iframe skip-lazy"></iframe>'; } public function get_translations() { include $this->plugin->dir( 'languages/booking-app-new-translations.php' ); return $translations; } /** * Register the routes for the objects of the controller. */ public function register_rest_routes() { $version = '1'; $namespace = 'ssa/v' . $version; $base = 'embed'; register_rest_route( $namespace, '/' . $base, array( array( 'methods' => WP_REST_Server::READABLE, 'callback' => array( $this, 'get_embed_output' ), 'permission_callback' => '__return_true', 'args' => array(), ), ) ); register_rest_route( $namespace, '/' . 'embed-inner', array( array( 'methods' => WP_REST_Server::READABLE, 'callback' => array( $this, 'get_embed_inner_output' ), 'permission_callback' => '__return_true', 'args' => array(), ), ) ); register_rest_route( $namespace, '/' . 'embed-inner-admin', array( array( 'methods' => WP_REST_Server::READABLE, 'callback' => array( $this, 'get_embed_inner_admin_output' ), 'permission_callback' => array( $this, 'current_user_can_manage_appointments' ), 'args' => array(), ), ) ); } public function current_user_can_manage_appointments() { return current_user_can( 'ssa_manage_appointments' ); } /** * Takes $_REQUEST params and returns the booking shortcode output. * * @since 3.7.6 * * @param WP_REST_Request $request * @return WP_REST_Response */ public function get_embed_output( WP_REST_Request $request ) { $params = $request->get_params(); $args = array(); if ( ! empty( $params['appointment_type'] ) ) { $args['type'] = esc_attr( $params['appointment_type'] ); } if ( ! empty( $params['mepr_membership_id'] ) ) { $args['mepr_membership_id'] = esc_attr( $params['mepr_membership_id'] ); } if ( ! empty( $params['accent_color'] ) ) { $args['accent_color'] = ltrim( esc_attr( $params['accent_color'] ), '#' ); } if ( ! empty( $params['background_color'] ) ) { $args['background'] = ltrim( esc_attr( $params['background_color'] ), '#' ); } if ( ! empty( $params['font'] ) ) { $args['font'] = esc_attr( $params['font'] ); } if ( ! empty( $params['padding'] ) ) { $args['padding'] = esc_attr( $params['padding'] ); } $output = ssa()->shortcodes->ssa_booking( $args ); return new WP_REST_Response( $output, 200 ); } /** * Takes $_REQUEST params and returns the booking shortcode output. * * @since 3.7.6 * * @param WP_REST_Request $request * @return WP_REST_Response */ public function get_embed_inner_output( WP_REST_Request $request ) { header( 'Content-Type: text/html' ); // Include new booking app always include $this->plugin->dir( 'booking-app-new/iframe-inner.php' ); exit; } /** * Takes $_REQUEST params and returns the admin shortcode output. * * @since 3.7.6 * * @param WP_REST_Request $request * @return WP_REST_Response */ public function get_embed_inner_admin_output( WP_REST_Request $request ) { $params = $request->get_params(); $args = array(); header( 'Content-Type: text/html' ); include $this->plugin->dir( 'admin-app/iframe-inner.php' ); // $output = ssa()->shortcodes->ssa_booking( $params, true ); // echo $output; exit; // return new WP_REST_Response( $output, 200 ); } /** * Convert label id or name to a string of appointment types ids separated by commas * * @param string|int $args * @return string */ public function convert_label_to_appt_types_ids( $args ){ if ( $args == (string) (int) $args ) { // integer ID provided $label_id = (int) sanitize_text_field( $args ); } else { // Label name provided $label = $this->plugin->appointment_type_label_model->query( array( 'name' => sanitize_text_field( $args ), ) ); if( empty( $label ) ) { return ''; } $label_id = $label['0']['id']; } $appointment_types = $this->plugin->appointment_type_model->query( array( 'label_id' => $label_id, 'status' => 'publish', ) ); if( empty( $appointment_types ) ) { return ''; } $ids = array_map( function($type){ return $type['id']; }, $appointment_types); $ids_to_str = implode(',', $ids); return $ids_to_str; } /** * Validator to check for invalid params passed to atts['types'] * If any of the slugs/ids is valid return true * If all are invalid return false * * @param string $types * @return boolean */ public function is_valid_types_attribute( $types ){ $appointment_types = $this->plugin->appointment_type_model->query( array( 'status' => 'publish' ) ); $ids = array_column($appointment_types, 'id'); $slugs = array_column($appointment_types, 'slug'); $restricted_types = explode( ',', $types ); foreach ($restricted_types as $restricted_type) { if( in_array( $restricted_type, $ids ) || in_array( $restricted_type, $slugs ) ) { return true; } } return false; } /** * Override atts types/type/label if mepr_membership_id is set * Handle any issue or error. * * @param array $atts * @return array */ public function convert_mepr_membership_id_to_appt_types_ids( $atts ) { if ( empty( $atts['mepr_membership_id'] ) || empty( sanitize_text_field( esc_attr( $atts['mepr_membership_id'] ) ) ) ) { return $atts; } $membership_id = sanitize_text_field( esc_attr( $atts['mepr_membership_id'] ) ); $is_admin = current_user_can( 'ssa_manage_site_settings' ); $error_message = ''; // MemberPress is not installed or active if ( ! class_exists( 'SSA_Memberpress') || ! $this->plugin->memberpress->is_ssa_mepr_integration_active() ) { $error_message .= '<h3 style="text-align: center">' . __('Sorry, no appointment types available, please check back later.', 'simply-schedule-appointments') . '</h3>'; if ( $is_admin ) { $error_message .= '<code>' . __('The MemberPress plugin is not available or not activated. Please ensure that the plugin is installed and activated.', 'simply-schedule-appointments') . '</code>'; $error_message .= '<code>' . __('(this message is only viewable to site administrators)', 'simply-schedule-appointments') . '</code>'; } $atts['error_message'] = $error_message; return $atts; } // Invalid input membership_id if ( is_numeric( $membership_id ) ) { $membership_id = (int) $membership_id; } else { $error_message .= '<h3 style="text-align: center">' . __('Sorry, no appointment types available, please check back later.', 'simply-schedule-appointments') . '</h3>'; if ( $is_admin ) { $error_message .= '<code>' . __('The membership ID provided is not valid.', 'simply-schedule-appointments') . '</code>'; $error_message .= '<code>' . __('(this message is only viewable to site administrators)', 'simply-schedule-appointments') . '</code>'; } $atts['error_message'] = $error_message; return $atts; } $current_user = wp_get_current_user(); // We don't have a logged in user if ( empty( $current_user ) || empty( $current_user->ID ) ) { $must_login_err_msg = apply_filters( 'ssa/mepr/shortcode/must_login_msg', __( 'You must be logged in to schedule an appointment. Please log in or register.', 'simply-schedule-appointments' ) ); $error_message .= '<h3 class="ssa_mepr_shortcode_msg ssa_mepr_shortcode__must_login_msg">' . $must_login_err_msg . '</h3>'; $atts['error_message'] = $error_message; return $atts; } $user = new SSA_Mepr_User( $current_user->ID ); $appointment_type_ids = $user->get_bookable_types_for_membership( $membership_id ); if ( empty( $appointment_type_ids ) ) { $error_message .= '<h3 style="text-align: center">' . __('Sorry, no appointment types available, please check back later.', 'simply-schedule-appointments') . '</h3>'; if ( $is_admin ) { $error_message .= '<code>' . __('The provided membership ID does not have any associated appointment types. Please ensure that the membership ID is correct and associated with valid appointment types.', 'simply-schedule-appointments') . '</code>'; $error_message .= '<code>' . __('(this message is only viewable to site administrators)', 'simply-schedule-appointments') . '</code>'; } $atts['error_message'] = $error_message; return $atts; } if ( empty( $atts['types'] ) && empty( $atts['type'] ) ) { $atts['types'] = implode( ',', $appointment_type_ids ); } return $atts; } /** * MemberPress Integration * The SSA - mepr shortcode wrapper [mepr_ssa_booking] * * @return string */ public function mepr_ssa_booking() { $is_admin = current_user_can( 'ssa_manage_site_settings' ); $error_message = ''; if ( ! class_exists( 'SSA_Memberpress') || ! $this->plugin->memberpress->is_ssa_mepr_integration_active() ) { $error_message .= '<h3 style="text-align: center">' . __('Sorry, no appointment types available, please check back later.', 'simply-schedule-appointments') . '</h3>'; if ( $is_admin ) { $error_message .= '<code>' . __('The MemberPress plugin is not available or not activated. Please ensure that the plugin is installed and activated.', 'simply-schedule-appointments') . '</code>'; $error_message .= '<code>' . __('(this message is only viewable to site administrators)', 'simply-schedule-appointments') . '</code>'; } return $error_message; } $current_user = wp_get_current_user(); // We don't have a logged in user if ( empty( $current_user ) || empty( $current_user->ID ) ) { $must_login_err_msg = apply_filters( 'ssa/mepr/shortcode/must_login_msg', __( 'You must be logged in to schedule an appointment. Please log in or register.', 'simply-schedule-appointments' ) ); return '<h3 class="ssa_mepr_shortcode_msg ssa_mepr_shortcode__must_login_msg">' . $must_login_err_msg . '</h3>'; } $user = new SSA_Mepr_User( $current_user->ID ); $bookable_memberships = $user->get_bookable_memberships(); if ( empty( $bookable_memberships ) ) { $no_bookable_err_msg = apply_filters( 'ssa/mepr/shortcode/no_bookable_err_msg', __( 'You do not have any memberships that allow booking.', 'simply-schedule-appointments' ) ); return '<h3 class="ssa_mepr_shortcode_msg ssa_mepr_shortcode__no_bookable_msg">' . $no_bookable_err_msg . '</h3>'; } $output = ''; if ( count( $bookable_memberships ) > 1 ) { // Let add a title in this case so users can tell which iframe for which $booking_title = apply_filters( 'ssa/mepr/shortcode/booking_title', __('Booking for %s Membership', 'simply-schedule-appointments' ) ); foreach ($bookable_memberships as $membership) { $output .= '<h3 class="ssa_mepr_shortcode_msg ssa_mepr_shortcode__booking_title" >' . sprintf( $booking_title, $membership->get_title() ) . '</h3>'; $atts = array( 'mepr_membership_id' => $membership->get_product_id() ); $output .= $this->ssa_booking( $atts ); } } elseif ( count( $bookable_memberships ) === 1 ) { $atts = array( 'mepr_membership_id' => $bookable_memberships[0]->get_product_id() ); $output .= $this->ssa_booking( $atts ); } return $output; } }
[-] class-settings.php
[edit]
[-] class-hooks.php
[edit]
[-] class-availability-query.php
[edit]
[-] class-appointment-model.php
[edit]
[-] class-beaver-builder.php
[edit]
[-] class-web-meetings.php
[edit]
[-] class-availability-model.php
[edit]
[-] class-recipient-admin.php
[edit]
[-] class-recipient-customer.php
[edit]
[-] class-constants.php
[edit]
[-] class-async-action-model.php
[edit]
[-] class-support.php
[edit]
[-] class-google-calendar-client.php
[edit]
[+]
..
[-] class-capabilities.php
[edit]
[-] class-encryption.php
[edit]
[-] class-availability-cache-invalidation.php
[edit]
[-] class-calendar-events-settings.php
[edit]
[-] class-settings-global.php
[edit]
[-] class-translation.php
[edit]
[-] class-cli.php
[edit]
[-] class-missing.php
[edit]
[-] class-action-scheduler.php
[edit]
[-] class-templates-api.php
[edit]
[-] class-blackout-dates.php
[edit]
[-] class-calendar-events-object.php
[edit]
[-] class-divi.php
[edit]
[-] class-templates.php
[edit]
[-] class-wp-admin.php
[edit]
[-] class-appointment-factory.php
[edit]
[-] class-scheduling-max-per-day.php
[edit]
[-] class-notifications-api.php
[edit]
[-] class-shortcodes.php
[edit]
[-] class-validation.php
[edit]
[-] class-resource-group-object-factory.php
[edit]
[-] class-payment-object.php
[edit]
[-] class-locale.php
[edit]
[-] class-ics-exporter.php
[edit]
[-] class-filesystem.php
[edit]
[-] class-recipient-shared.php
[edit]
[-] class-availability-schedule.php
[edit]
[-] class-block-upcoming-appointments.php
[edit]
[-] class-elementor.php
[edit]
[-] class-appointment-meta-model.php
[edit]
[-] class-revision-meta-model.php
[edit]
[+]
divi
[-] class-notifications.php
[edit]
[-] class-upgrade.php
[edit]
[-] class-utils.php
[edit]
[-] class-availability-functions.php
[edit]
[-] class-external-calendar-api.php
[edit]
[-] class-csv-exporter.php
[edit]
[-] class-external-google-calendar-api.php
[edit]
[-] class-twig-extension.php
[edit]
[-] class-bootstrap.php
[edit]
[-] class-notices.php
[edit]
[-] class-availability-schedule-factory.php
[edit]
[-] class-blackout-dates-settings.php
[edit]
[-] class-support-status.php
[edit]
[-] class-block-booking.php
[edit]
[-] class-advanced-scheduling-availability.php
[edit]
[-] class-exception.php
[edit]
[-] class-styles-settings.php
[edit]
[-] class-forms.php
[edit]
[-] class-recipient-staff.php
[edit]
[+]
beaver-builder
[-] class-users.php
[edit]
[-] class-sequence-factory.php
[edit]
[+]
third-party
[-] class-locales.php
[edit]
[-] class-db-model.php
[edit]
[-] class-db.php
[edit]
[-] class-availability-default.php
[edit]
[-] class-staff-settings.php
[edit]
[-] class-notification-model.php
[edit]
[-] class-settings-installed.php
[edit]
[-] class-appointment-object.php
[edit]
[-] class-notices-api.php
[edit]
[-] class-translation-settings.php
[edit]
[-] class-support-status-api.php
[edit]
[-] class-notices-data.php
[edit]
[-] class-appointment-type-object.php
[edit]
[-] class-appointment-type-object-factory.php
[edit]
[-] class-availability-block-factory.php
[edit]
[-] class-recipient.php
[edit]
[-] class-revision-model.php
[edit]
[-] class-customers.php
[edit]
[-] class-settings-api.php
[edit]
[-] class-cache.php
[edit]
[-] class-availability-detective-case.php
[edit]
[-] class-styles.php
[edit]
[-] class-capacity-settings.php
[edit]
[-] class-gcal-exporter.php
[edit]
[-] class-advanced-scheduling-settings.php
[edit]
[-] class-appointment-type-model.php
[edit]
[-] class-notifications-settings.php
[edit]
[-] class-period.php
[edit]
[-] class-external-api.php
[edit]
[-] class-error-notices.php
[edit]
[-] class-availability-cache.php
[edit]
[-] class-developer-settings.php
[edit]
[-] class-dashboard-upcoming-appointments-widget.php
[edit]
[-] class-availability-external-model.php
[edit]
[-] class-availability-block.php
[edit]
[-] class-customer-information.php
[edit]
[+]
elementor
[-] class-appointment-type-label-model.php
[edit]
[-] class-embed-booking-app-api.php
[edit]
[+]
lib
[-] class-sequence.php
[edit]
[-] class-debug.php
[edit]
[-] class-appointment-types-db.php
[edit]