There were a couple security issues and error checking that I did see. Try these:
<?php
add_action('wp_ajax_get_timeslot_data', 'get_timeslot_data');
add_action('wp_ajax_nopriv_get_timeslot_data', 'get_timeslot_data');
function get_timeslot_data() {
if (!isset($_POST['activityId']) || !ctype_digit($_POST['activityId'])) {
wp_send_json_error("Invalid activity ID");
}
global $wpdb;
$activity_id = intval($_POST['activityId']);
$table_name = $wpdb->prefix . 'booking_seasons'; // Support custom table prefixes
$result = $wpdb->get_row($wpdb->prepare("SELECT timeslot_dates FROM $table_name WHERE id = %d", $activity_id));
if (!$result || empty($result->timeslot_dates)) {
wp_send_json_error("No time slots found");
}
$time_slots = maybe_unserialize($result->timeslot_dates);
if (!is_array($time_slots)) {
wp_send_json_error("Invalid time slot data format");
}
$events = [];
foreach ($time_slots as $slot => $dates) {
$times = explode(" - ", $slot);
if (count($times) !== 2) {
continue; // Skip invalid time slot format
}
foreach ($dates as $date) {
$events[] = [
'title' => sanitize_text_field($slot),
'start' => esc_html($date . "T" . trim($times[0])),
'end' => esc_html($date . "T" . trim($times[1]))
];
}
}
wp_send_json_success($events);
}
?>
-
Supports dynamic table prefix ($wpdb->prefix)
-
Ensures activity ID is numeric (ctype_digit())
-
Uses maybe_unserialize() for safer data handling
-
Handles invalid time slot formats Uses sanitize_text_field()
-
esc_html() to prevent security issues
jQuery(document).ready(function() { if (typeof activityData !== 'undefined' && activityData.activityId) { var activityId = activityData.activityId; } else { console.error("activityData is undefined or missing activityId."); return; } console.log(activityId); console.log("jQuery is working"); var calendarEl = jQuery('#calendar-' + activityId); if (!calendarEl.length) { console.error("Calendar element not found for activity ID:", activityId); return; } var calendar = new FullCalendar.Calendar(calendarEl[0], { initialView: 'timeGridWeek', slotDuration: '00:15:00', selectable: true, allDaySlot: false, events: function(fetchInfo, successCallback, failureCallback) { console.log('Activity ID inside events:', activityId); if (typeof my_ajax_object === 'undefined' || !my_ajax_object.ajaxurl) { console.error("my_ajax_object.ajaxurl is undefined."); failureCallback("AJAX URL missing"); return; } jQuery.ajax({ url: my_ajax_object.ajaxurl, type: 'POST', data: { action: 'get_timeslot_data', activityId: activityId, }, success: function(response) { if (response.success) { successCallback(response.data); } else { console.error("Error fetching events:", response.data); failureCallback("Error fetching events"); } }, error: function(xhr, status, error) { console.error("AJAX Error:", error); failureCallback("Failed to fetch events: " + error); } }); }, headerToolbar: { left: 'prev,next today', center: 'title', right: 'timeGridDay,timeGridWeek,dayGridMonth' }, }); calendar.render(); });
-
Prevents errors if activityData or calendarEl is missing
-
Ensures my_ajax_object.ajaxurl exists before making the AJAX request
-
Improved error handling for failureCallback
Without knowing your error, I’m not checking with actual usage, those are what I can see.