- Added GitHub spec-kit for development workflow - Standardized file signatures to Descomplicar® format - Updated development configuration 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
798 lines
27 KiB
PHP
798 lines
27 KiB
PHP
/**
|
|
* Descomplicar® Crescimento Digital
|
|
* https://descomplicar.pt
|
|
*/
|
|
|
|
<?php
|
|
/**
|
|
* KiviCare integration for Care Booking Block plugin
|
|
*
|
|
* @package CareBookingBlock
|
|
*/
|
|
|
|
// Prevent direct access
|
|
if (!defined('ABSPATH')) {
|
|
exit;
|
|
}
|
|
|
|
/**
|
|
* KiviCare integration class
|
|
*/
|
|
class Care_Booking_KiviCare_Integration
|
|
{
|
|
/**
|
|
* Database handler instance
|
|
*
|
|
* @var Care_Booking_Database_Handler
|
|
*/
|
|
private $db_handler;
|
|
|
|
/**
|
|
* Restriction model instance
|
|
*
|
|
* @var Care_Booking_Restriction_Model
|
|
*/
|
|
private $restriction_model;
|
|
|
|
/**
|
|
* Cache manager instance
|
|
*
|
|
* @var Care_Booking_Cache_Manager
|
|
*/
|
|
private $cache_manager;
|
|
|
|
/**
|
|
* Constructor
|
|
*
|
|
* @param Care_Booking_Database_Handler $db_handler Database handler instance
|
|
*/
|
|
public function __construct($db_handler)
|
|
{
|
|
$this->db_handler = $db_handler;
|
|
$this->restriction_model = new Care_Booking_Restriction_Model();
|
|
$this->cache_manager = new Care_Booking_Cache_Manager();
|
|
|
|
$this->init_hooks();
|
|
}
|
|
|
|
/**
|
|
* Initialize WordPress hooks
|
|
*/
|
|
private function init_hooks()
|
|
{
|
|
// Enhanced KiviCare filter hooks with multiple compatibility points
|
|
// Priority 10 for standard filtering, Priority 5 for early filtering
|
|
add_filter('kc_get_doctors_for_booking', [$this, 'filter_doctors'], 10, 1);
|
|
add_filter('kivicare_doctors_list', [$this, 'filter_doctors'], 10, 1);
|
|
add_filter('kivicare_get_doctors', [$this, 'filter_doctors'], 10, 1);
|
|
|
|
// Service filtering with multiple hook points
|
|
add_filter('kc_get_services_by_doctor', [$this, 'filter_services'], 10, 2);
|
|
add_filter('kivicare_services_list', [$this, 'filter_services'], 10, 2);
|
|
add_filter('kivicare_get_services', [$this, 'filter_services'], 10, 2);
|
|
|
|
// Enhanced CSS injection with optimized priority
|
|
add_action('wp_head', [$this, 'inject_restriction_css'], 15);
|
|
|
|
// Frontend JavaScript for graceful degradation
|
|
add_action('wp_enqueue_scripts', [$this, 'enqueue_frontend_scripts'], 10);
|
|
|
|
// Frontend CSS for base styles
|
|
add_action('wp_enqueue_scripts', [$this, 'enqueue_frontend_styles'], 10);
|
|
|
|
// KiviCare 3.0+ REST API hooks
|
|
add_filter('rest_pre_serve_request', [$this, 'filter_rest_api_response'], 10, 4);
|
|
|
|
// Admin bar integration (optional)
|
|
if (is_admin_bar_showing()) {
|
|
add_action('admin_bar_menu', [$this, 'add_admin_bar_menu'], 100);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Filter KiviCare doctors list to remove blocked doctors
|
|
*
|
|
* @param array $doctors Array of doctors from KiviCare
|
|
* @return array Filtered array of doctors
|
|
*/
|
|
public function filter_doctors($doctors)
|
|
{
|
|
// Validate input
|
|
if (!is_array($doctors)) {
|
|
return $doctors;
|
|
}
|
|
|
|
// Skip filtering in admin area (keep full access for administrators)
|
|
if (is_admin() && current_user_can('manage_options')) {
|
|
return $doctors;
|
|
}
|
|
|
|
try {
|
|
// Get blocked doctors (with caching)
|
|
$blocked_doctors = $this->restriction_model->get_blocked_doctors();
|
|
|
|
if (empty($blocked_doctors)) {
|
|
return $doctors;
|
|
}
|
|
|
|
// Filter out blocked doctors
|
|
$filtered_doctors = [];
|
|
foreach ($doctors as $key => $doctor) {
|
|
// Handle both array and object formats
|
|
$doctor_id = is_array($doctor) ? ($doctor['id'] ?? 0) : ($doctor->id ?? 0);
|
|
|
|
if (!in_array((int) $doctor_id, $blocked_doctors)) {
|
|
$filtered_doctors[$key] = $doctor;
|
|
}
|
|
}
|
|
|
|
return $filtered_doctors;
|
|
|
|
} catch (Exception $e) {
|
|
// Log error and return original array on failure
|
|
if (function_exists('error_log')) {
|
|
error_log('Care Booking Block: Doctor filtering error - ' . $e->getMessage());
|
|
}
|
|
|
|
return $doctors;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Filter KiviCare services list to remove blocked services for specific doctor
|
|
*
|
|
* @param array $services Array of services from KiviCare
|
|
* @param int $doctor_id Doctor ID
|
|
* @return array Filtered array of services
|
|
*/
|
|
public function filter_services($services, $doctor_id = null)
|
|
{
|
|
// Validate input
|
|
if (!is_array($services)) {
|
|
return $services;
|
|
}
|
|
|
|
// Skip filtering in admin area (keep full access for administrators)
|
|
if (is_admin() && current_user_can('manage_options')) {
|
|
return $services;
|
|
}
|
|
|
|
try {
|
|
$filtered_services = [];
|
|
|
|
// If no doctor_id provided, try to extract from services or context
|
|
if (!$doctor_id) {
|
|
$doctor_id = $this->extract_doctor_id_from_context($services);
|
|
}
|
|
|
|
// Get blocked services for this doctor (with enhanced caching)
|
|
$blocked_services = $doctor_id ?
|
|
$this->restriction_model->get_blocked_services($doctor_id) : [];
|
|
|
|
// Also get globally blocked doctors to filter services
|
|
$blocked_doctors = $this->restriction_model->get_blocked_doctors();
|
|
|
|
foreach ($services as $key => $service) {
|
|
// Handle both array and object formats
|
|
$service_id = is_array($service) ? ($service['id'] ?? 0) : ($service->id ?? 0);
|
|
$service_doctor_id = is_array($service) ?
|
|
($service['doctor_id'] ?? $doctor_id) :
|
|
($service->doctor_id ?? $doctor_id);
|
|
|
|
// Skip if service belongs to a blocked doctor
|
|
if ($service_doctor_id && in_array((int) $service_doctor_id, $blocked_doctors)) {
|
|
continue;
|
|
}
|
|
|
|
// Skip if service is specifically blocked for this doctor
|
|
if ($service_doctor_id && !empty($blocked_services) &&
|
|
in_array((int) $service_id, $blocked_services)) {
|
|
continue;
|
|
}
|
|
|
|
$filtered_services[$key] = $service;
|
|
}
|
|
|
|
return $filtered_services;
|
|
|
|
} catch (Exception $e) {
|
|
// Log error and return original array on failure
|
|
if (function_exists('error_log')) {
|
|
error_log('Care Booking Block: Service filtering error - ' . $e->getMessage());
|
|
}
|
|
|
|
return $services;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Extract doctor ID from service context or URL parameters
|
|
*
|
|
* @param array $services Services array
|
|
* @return int|null Doctor ID if found
|
|
*/
|
|
private function extract_doctor_id_from_context($services)
|
|
{
|
|
// Try to get from first service
|
|
if (!empty($services)) {
|
|
$first_service = reset($services);
|
|
$doctor_id = is_array($first_service) ?
|
|
($first_service['doctor_id'] ?? null) :
|
|
($first_service->doctor_id ?? null);
|
|
|
|
if ($doctor_id) {
|
|
return (int) $doctor_id;
|
|
}
|
|
}
|
|
|
|
// Try to get from URL parameters
|
|
if (isset($_GET['doctor_id'])) {
|
|
return (int) $_GET['doctor_id'];
|
|
}
|
|
|
|
// Try to get from POST data
|
|
if (isset($_POST['doctor_id'])) {
|
|
return (int) $_POST['doctor_id'];
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
/**
|
|
* Enqueue frontend JavaScript for graceful degradation
|
|
*/
|
|
public function enqueue_frontend_scripts()
|
|
{
|
|
// Only on frontend and if KiviCare is active
|
|
if (is_admin() || !$this->is_kivicare_active()) {
|
|
return;
|
|
}
|
|
|
|
// Check if we're on a page that might have KiviCare content
|
|
if (!$this->should_load_frontend_scripts()) {
|
|
return;
|
|
}
|
|
|
|
wp_enqueue_script(
|
|
'care-booking-frontend',
|
|
CARE_BOOKING_BLOCK_PLUGIN_URL . 'public/js/frontend.js',
|
|
['jquery'],
|
|
CARE_BOOKING_BLOCK_VERSION,
|
|
true
|
|
);
|
|
|
|
// Localize script with configuration
|
|
wp_localize_script('care-booking-frontend', 'careBookingConfig', [
|
|
'ajaxurl' => admin_url('admin-ajax.php'),
|
|
'nonce' => wp_create_nonce('care_booking_frontend'),
|
|
'debug' => defined('WP_DEBUG') && WP_DEBUG,
|
|
'fallbackEnabled' => true,
|
|
'retryAttempts' => 3,
|
|
'retryDelay' => 1000,
|
|
'selectors' => [
|
|
'doctors' => '.kivicare-doctor, .kc-doctor-item, .doctor-card',
|
|
'services' => '.kivicare-service, .kc-service-item, .service-card',
|
|
'forms' => '.kivicare-booking-form, .kc-booking-form',
|
|
'loading' => '.care-booking-loading'
|
|
]
|
|
]);
|
|
}
|
|
|
|
/**
|
|
* Check if frontend scripts should be loaded on current page
|
|
*
|
|
* @return bool True if scripts should be loaded
|
|
*/
|
|
private function should_load_frontend_scripts()
|
|
{
|
|
global $post;
|
|
|
|
// Always load on pages with KiviCare shortcodes
|
|
if ($post && has_shortcode($post->post_content, 'kivicare')) {
|
|
return true;
|
|
}
|
|
|
|
// Load on pages with KiviCare blocks
|
|
if ($post && has_block('kivicare/booking', $post->post_content)) {
|
|
return true;
|
|
}
|
|
|
|
// Load on template pages that might contain KiviCare
|
|
$template = get_page_template_slug();
|
|
if (in_array($template, ['page-booking.php', 'page-appointment.php'])) {
|
|
return true;
|
|
}
|
|
|
|
// Load if URL contains KiviCare parameters
|
|
if (isset($_GET['kivicare']) || isset($_GET['booking']) || isset($_GET['appointment'])) {
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Enqueue frontend CSS for base styles
|
|
*/
|
|
public function enqueue_frontend_styles()
|
|
{
|
|
// Only on frontend and if KiviCare is active
|
|
if (is_admin() || !$this->is_kivicare_active()) {
|
|
return;
|
|
}
|
|
|
|
// Check if we're on a page that might have KiviCare content
|
|
if (!$this->should_load_frontend_scripts()) {
|
|
return;
|
|
}
|
|
|
|
wp_enqueue_style(
|
|
'care-booking-frontend',
|
|
CARE_BOOKING_BLOCK_PLUGIN_URL . 'public/css/frontend.css',
|
|
[],
|
|
CARE_BOOKING_BLOCK_VERSION,
|
|
'all'
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Inject optimized CSS to hide blocked elements on frontend
|
|
*
|
|
* Priority 15 - After theme styles but before most plugins
|
|
*/
|
|
public function inject_restriction_css()
|
|
{
|
|
// Only inject on frontend
|
|
if (is_admin()) {
|
|
return;
|
|
}
|
|
|
|
// Skip if not on pages with KiviCare content (performance optimization)
|
|
if (!$this->should_inject_css()) {
|
|
return;
|
|
}
|
|
|
|
try {
|
|
// Get blocked doctors and services with caching
|
|
$blocked_doctors = $this->restriction_model->get_blocked_doctors();
|
|
$blocked_services = $this->get_all_blocked_services();
|
|
|
|
// Early return if no restrictions
|
|
if (empty($blocked_doctors) && empty($blocked_services)) {
|
|
return;
|
|
}
|
|
|
|
// Generate optimized CSS
|
|
$css = $this->generate_restriction_css($blocked_doctors, $blocked_services);
|
|
|
|
if (!empty($css)) {
|
|
// Output with proper caching headers and minification
|
|
echo "\n<!-- Care Booking Block Styles -->\n";
|
|
echo '<style id="care-booking-restrictions" data-care-booking="restriction-css" data-version="' . CARE_BOOKING_BLOCK_VERSION . '">';
|
|
|
|
// Add performance optimizations
|
|
if (defined('WP_DEBUG') && WP_DEBUG) {
|
|
echo "\n" . $css . "\n";
|
|
} else {
|
|
// Minified output for production
|
|
echo $this->minify_css($css);
|
|
}
|
|
|
|
echo '</style>';
|
|
echo "\n<!-- End Care Booking Block Styles -->\n";
|
|
}
|
|
|
|
} catch (Exception $e) {
|
|
// Silently fail to avoid breaking frontend
|
|
if (function_exists('error_log')) {
|
|
error_log('Care Booking Block: CSS injection error - ' . $e->getMessage());
|
|
}
|
|
|
|
// In debug mode, show a minimal error indicator
|
|
if (defined('WP_DEBUG') && WP_DEBUG) {
|
|
echo '<!-- Care Booking Block: CSS injection failed -->';
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Determine if CSS should be injected on current page
|
|
*
|
|
* @return bool True if CSS should be injected
|
|
*/
|
|
private function should_inject_css()
|
|
{
|
|
// Always inject if KiviCare is active and we have restrictions
|
|
if (!$this->is_kivicare_active()) {
|
|
return false;
|
|
}
|
|
|
|
// Use the same logic as frontend scripts
|
|
return $this->should_load_frontend_scripts();
|
|
}
|
|
|
|
/**
|
|
* Minify CSS for production
|
|
*
|
|
* @param string $css CSS to minify
|
|
* @return string Minified CSS
|
|
*/
|
|
private function minify_css($css)
|
|
{
|
|
// Remove comments
|
|
$css = preg_replace('!/\*[^*]*\*+([^/][^*]*\*+)*/!', '', $css);
|
|
|
|
// Remove whitespace
|
|
$css = str_replace(["\r\n", "\r", "\n", "\t"], '', $css);
|
|
|
|
// Remove extra spaces
|
|
$css = preg_replace('/\s+/', ' ', $css);
|
|
|
|
// Remove spaces around specific characters
|
|
$css = str_replace(['; ', ' {', '{ ', ' }', '} ', ': ', ', ', ' ,'], [';', '{', '{', '}', '}', ':', ',', ','], $css);
|
|
|
|
return trim($css);
|
|
}
|
|
|
|
/**
|
|
* Generate optimized CSS for hiding blocked elements
|
|
*
|
|
* @param array $blocked_doctors Array of blocked doctor IDs
|
|
* @param array $blocked_services Array of blocked service data
|
|
* @return string Generated CSS with optimization and caching
|
|
*/
|
|
private function generate_restriction_css($blocked_doctors, $blocked_services)
|
|
{
|
|
// Check cache first
|
|
$cache_key = 'care_booking_css_' . md5(serialize([$blocked_doctors, $blocked_services]));
|
|
$cached_css = get_transient($cache_key);
|
|
|
|
if ($cached_css !== false) {
|
|
return $cached_css;
|
|
}
|
|
|
|
$css_rules = [];
|
|
$css_comments = [];
|
|
|
|
// CSS for blocked doctors with enhanced selectors
|
|
if (!empty($blocked_doctors)) {
|
|
$doctor_selectors = [];
|
|
$css_comments[] = "/* Blocked doctors: " . count($blocked_doctors) . " */";
|
|
|
|
foreach ($blocked_doctors as $doctor_id) {
|
|
$doctor_id = (int) $doctor_id;
|
|
|
|
// KiviCare 3.0+ primary selectors
|
|
$doctor_selectors[] = ".kivicare-doctor[data-doctor-id=\"{$doctor_id}\"]";
|
|
$doctor_selectors[] = ".kc-doctor-item[data-id=\"{$doctor_id}\"]";
|
|
$doctor_selectors[] = ".doctor-card[data-doctor=\"{$doctor_id}\"]";
|
|
|
|
// Legacy selectors
|
|
$doctor_selectors[] = "#doctor-{$doctor_id}";
|
|
$doctor_selectors[] = ".kc-doctor-{$doctor_id}";
|
|
|
|
// Form selectors
|
|
$doctor_selectors[] = ".doctor-selection option[value=\"{$doctor_id}\"]";
|
|
$doctor_selectors[] = "select[name='doctor_id'] option[value=\"{$doctor_id}\"]";
|
|
|
|
// Booking form selectors
|
|
$doctor_selectors[] = ".booking-doctor-{$doctor_id}";
|
|
$doctor_selectors[] = ".appointment-doctor-{$doctor_id}";
|
|
}
|
|
|
|
if (!empty($doctor_selectors)) {
|
|
// Split into chunks for better CSS performance
|
|
$chunks = array_chunk($doctor_selectors, 50);
|
|
foreach ($chunks as $chunk) {
|
|
$css_rules[] = implode(',', $chunk) . ' { display: none !important; visibility: hidden !important; }';
|
|
}
|
|
}
|
|
}
|
|
|
|
// CSS for blocked services with enhanced context
|
|
if (!empty($blocked_services)) {
|
|
$service_selectors = [];
|
|
$css_comments[] = "/* Blocked services: " . count($blocked_services) . " */";
|
|
|
|
foreach ($blocked_services as $service_data) {
|
|
$service_id = (int) $service_data['service_id'];
|
|
$doctor_id = (int) $service_data['doctor_id'];
|
|
|
|
// KiviCare 3.0+ primary selectors
|
|
$service_selectors[] = ".kivicare-service[data-service-id=\"{$service_id}\"][data-doctor-id=\"{$doctor_id}\"]";
|
|
$service_selectors[] = ".kc-service-item[data-service=\"{$service_id}\"][data-doctor=\"{$doctor_id}\"]";
|
|
$service_selectors[] = ".service-card[data-service=\"{$service_id}\"][data-doctor=\"{$doctor_id}\"]";
|
|
|
|
// Legacy selectors
|
|
$service_selectors[] = "#service-{$service_id}-doctor-{$doctor_id}";
|
|
$service_selectors[] = ".kc-service-{$service_id}.kc-doctor-{$doctor_id}";
|
|
|
|
// Form selectors
|
|
$service_selectors[] = ".service-selection[data-doctor=\"{$doctor_id}\"] option[value=\"{$service_id}\"]";
|
|
$service_selectors[] = "select[name='service_id'][data-doctor=\"{$doctor_id}\"] option[value=\"{$service_id}\"]";
|
|
|
|
// Booking form selectors
|
|
$service_selectors[] = ".booking-service-{$service_id}.doctor-{$doctor_id}";
|
|
$service_selectors[] = ".appointment-service-{$service_id}.doctor-{$doctor_id}";
|
|
}
|
|
|
|
if (!empty($service_selectors)) {
|
|
// Split into chunks for better CSS performance
|
|
$chunks = array_chunk($service_selectors, 50);
|
|
foreach ($chunks as $chunk) {
|
|
$css_rules[] = implode(',', $chunk) . ' { display: none !important; visibility: hidden !important; }';
|
|
}
|
|
}
|
|
}
|
|
|
|
// Add graceful degradation styles
|
|
$css_rules[] = '.care-booking-fallback { opacity: 0.7; pointer-events: none; }';
|
|
$css_rules[] = '.care-booking-loading::after { content: "Loading..."; }';
|
|
|
|
// Combine CSS with optimization
|
|
$final_css = '';
|
|
|
|
if (!empty($css_comments)) {
|
|
$final_css .= implode(PHP_EOL, $css_comments) . PHP_EOL;
|
|
}
|
|
|
|
if (!empty($css_rules)) {
|
|
// Minify CSS in production
|
|
if (defined('WP_DEBUG') && !WP_DEBUG) {
|
|
$final_css .= implode('', $css_rules);
|
|
} else {
|
|
$final_css .= implode(PHP_EOL, $css_rules);
|
|
}
|
|
}
|
|
|
|
// Cache for 1 hour
|
|
set_transient($cache_key, $final_css, 3600);
|
|
|
|
return $final_css;
|
|
}
|
|
|
|
/**
|
|
* Get all blocked services across all doctors
|
|
*
|
|
* @return array Array of blocked service data
|
|
*/
|
|
private function get_all_blocked_services()
|
|
{
|
|
$blocked_services = [];
|
|
|
|
// Get all service restrictions
|
|
$service_restrictions = $this->restriction_model->get_by_type('service');
|
|
|
|
foreach ($service_restrictions as $restriction) {
|
|
if ($restriction->is_blocked) {
|
|
$blocked_services[] = [
|
|
'service_id' => (int) $restriction->target_id,
|
|
'doctor_id' => (int) $restriction->doctor_id
|
|
];
|
|
}
|
|
}
|
|
|
|
return $blocked_services;
|
|
}
|
|
|
|
/**
|
|
* Add admin bar menu for quick access
|
|
*
|
|
* @param WP_Admin_Bar $wp_admin_bar WordPress admin bar object
|
|
*/
|
|
public function add_admin_bar_menu($wp_admin_bar)
|
|
{
|
|
// Only show for users with manage_options capability
|
|
if (!current_user_can('manage_options')) {
|
|
return;
|
|
}
|
|
|
|
$wp_admin_bar->add_menu([
|
|
'id' => 'care-booking-control',
|
|
'title' => __('Care Booking', 'care-booking-block'),
|
|
'href' => admin_url('tools.php?page=care-booking-control'),
|
|
'meta' => [
|
|
'title' => __('Care Booking Control', 'care-booking-block')
|
|
]
|
|
]);
|
|
|
|
// Add submenu with statistics
|
|
$stats = $this->restriction_model->get_statistics();
|
|
|
|
$wp_admin_bar->add_menu([
|
|
'parent' => 'care-booking-control',
|
|
'id' => 'care-booking-stats',
|
|
'title' => sprintf(
|
|
__('Restrictions: %d doctors, %d services', 'care-booking-block'),
|
|
$stats['blocked_doctors'],
|
|
$stats['service_restrictions']
|
|
),
|
|
'href' => admin_url('tools.php?page=care-booking-control'),
|
|
]);
|
|
}
|
|
|
|
/**
|
|
* Check if specific doctor is blocked
|
|
*
|
|
* @param int $doctor_id Doctor ID
|
|
* @return bool True if blocked, false otherwise
|
|
*/
|
|
public function is_doctor_blocked($doctor_id)
|
|
{
|
|
return $this->restriction_model->is_doctor_blocked($doctor_id);
|
|
}
|
|
|
|
/**
|
|
* Check if specific service is blocked for a doctor
|
|
*
|
|
* @param int $service_id Service ID
|
|
* @param int $doctor_id Doctor ID
|
|
* @return bool True if blocked, false otherwise
|
|
*/
|
|
public function is_service_blocked($service_id, $doctor_id)
|
|
{
|
|
return $this->restriction_model->is_service_blocked($service_id, $doctor_id);
|
|
}
|
|
|
|
/**
|
|
* Get blocked doctors count
|
|
*
|
|
* @return int Number of blocked doctors
|
|
*/
|
|
public function get_blocked_doctors_count()
|
|
{
|
|
return count($this->restriction_model->get_blocked_doctors());
|
|
}
|
|
|
|
/**
|
|
* Get blocked services count for specific doctor
|
|
*
|
|
* @param int $doctor_id Doctor ID
|
|
* @return int Number of blocked services
|
|
*/
|
|
public function get_blocked_services_count($doctor_id)
|
|
{
|
|
return count($this->restriction_model->get_blocked_services($doctor_id));
|
|
}
|
|
|
|
/**
|
|
* Apply restrictions to KiviCare query (if supported)
|
|
*
|
|
* @param string $query SQL query
|
|
* @param string $context Query context
|
|
* @return string Modified query
|
|
*/
|
|
public function filter_kivicare_query($query, $context = '')
|
|
{
|
|
// This would be used if KiviCare provides query filtering hooks
|
|
// For now, return original query
|
|
return $query;
|
|
}
|
|
|
|
/**
|
|
* Handle KiviCare appointment booking validation
|
|
*
|
|
* @param array $booking_data Booking data
|
|
* @return bool|WP_Error True if allowed, WP_Error if blocked
|
|
*/
|
|
public function validate_booking($booking_data)
|
|
{
|
|
$doctor_id = $booking_data['doctor_id'] ?? 0;
|
|
$service_id = $booking_data['service_id'] ?? 0;
|
|
|
|
// Check if doctor is blocked
|
|
if ($this->is_doctor_blocked($doctor_id)) {
|
|
return new WP_Error(
|
|
'doctor_blocked',
|
|
__('This doctor is not available for booking.', 'care-booking-block')
|
|
);
|
|
}
|
|
|
|
// Check if service is blocked for this doctor
|
|
if ($service_id && $this->is_service_blocked($service_id, $doctor_id)) {
|
|
return new WP_Error(
|
|
'service_blocked',
|
|
__('This service is not available for this doctor.', 'care-booking-block')
|
|
);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Get integration status
|
|
*
|
|
* @return array Status information
|
|
*/
|
|
public function get_integration_status()
|
|
{
|
|
return [
|
|
'kivicare_active' => $this->is_kivicare_active(),
|
|
'hooks_registered' => [
|
|
'doctor_filter' => has_filter('kc_get_doctors_for_booking'),
|
|
'service_filter' => has_filter('kc_get_services_by_doctor'),
|
|
'css_injection' => has_action('wp_head')
|
|
],
|
|
'cache_status' => $this->cache_manager->get_cache_stats(),
|
|
'restrictions' => $this->restriction_model->get_statistics()
|
|
];
|
|
}
|
|
|
|
/**
|
|
* Filter KiviCare REST API responses for doctor and service listings
|
|
*
|
|
* @param mixed $served Whether the request has already been served
|
|
* @param WP_HTTP_Response $result The response object
|
|
* @param WP_REST_Request $request The request object
|
|
* @param WP_REST_Server $server The REST server instance
|
|
* @return mixed Original served value
|
|
*/
|
|
public function filter_rest_api_response($served, $result, $request, $server)
|
|
{
|
|
// Skip if already served or not a KiviCare endpoint
|
|
if ($served || !$this->is_kivicare_rest_endpoint($request)) {
|
|
return $served;
|
|
}
|
|
|
|
// Skip filtering in admin area for administrators
|
|
if (is_admin() && current_user_can('manage_options')) {
|
|
return $served;
|
|
}
|
|
|
|
try {
|
|
$data = $result->get_data();
|
|
|
|
if (is_array($data) && isset($data['data'])) {
|
|
$route = $request->get_route();
|
|
|
|
// Filter doctors endpoint
|
|
if (strpos($route, '/doctors') !== false && is_array($data['data'])) {
|
|
$data['data'] = $this->filter_doctors($data['data']);
|
|
$result->set_data($data);
|
|
}
|
|
|
|
// Filter services endpoint
|
|
if (strpos($route, '/services') !== false && is_array($data['data'])) {
|
|
$doctor_id = $request->get_param('doctor_id') ?: null;
|
|
$data['data'] = $this->filter_services($data['data'], $doctor_id);
|
|
$result->set_data($data);
|
|
}
|
|
}
|
|
} catch (Exception $e) {
|
|
// Log error but don't break API response
|
|
if (function_exists('error_log')) {
|
|
error_log('Care Booking Block: REST API filtering error - ' . $e->getMessage());
|
|
}
|
|
}
|
|
|
|
return $served;
|
|
}
|
|
|
|
/**
|
|
* Check if request is for a KiviCare REST endpoint
|
|
*
|
|
* @param WP_REST_Request $request The request object
|
|
* @return bool True if KiviCare endpoint
|
|
*/
|
|
private function is_kivicare_rest_endpoint($request)
|
|
{
|
|
$route = $request->get_route();
|
|
return strpos($route, '/kivicare/') !== false ||
|
|
strpos($route, '/kc/') !== false;
|
|
}
|
|
|
|
/**
|
|
* Check if KiviCare plugin is active
|
|
*
|
|
* @return bool True if KiviCare is active, false otherwise
|
|
*/
|
|
private function is_kivicare_active()
|
|
{
|
|
if (!function_exists('is_plugin_active')) {
|
|
include_once(ABSPATH . 'wp-admin/includes/plugin.php');
|
|
}
|
|
|
|
return is_plugin_active('kivicare/kivicare.php') ||
|
|
is_plugin_active('kivicare-clinic-management-system/kivicare.php');
|
|
}
|
|
} |