Event calendars are a powerful tool that keeps track of upcoming events, schedules, appointments, and deadlines.
I am using FullCalendar plugin to create a calendar layout and make it dynamic using PHP and MySQL. Plugin is not dependent on any library, responsive, and automatically fits on the page. Different types of options and events are available to customize and control it.
In this tutorial, I show how you can create an event, update and delete an existing event, and load events in the FullCalendar JavaScript library using PHP AJAX and MySQL.
I am using FullCalendar v6 in the example and sweetAlert library to display an alert box to add/edit events.
Table of Content
- Create a Table
- Create a Database connection file
- Download and Include FullCalendar
- HTML – Setting Up the FullCalendar Container
- Create a PHP File to Load All Events in FullCalendar
- Create a PHP File to Manage AJAX Requests
- jQuery: Initializing FullCalendar and Managing Events
- Demo
- Conclusion
1. Create a Table
I am using events
table in the example. It has the following structure –
CREATE TABLE `events` ( `id` int(10) NOT NULL, `title` varchar(190) NOT NULL, `description` text NOT NULL, `start_date` date NOT NULL, `end_date` date NOT NULL ); ALTER TABLE `events` ADD PRIMARY KEY (`id`); ALTER TABLE `events` MODIFY `id` int(10) NOT NULL AUTO_INCREMENT;
2. Create a Database connection file
Create a config.php
for database configuration.
<?php $host = "localhost"; /* Host name */ $user = "root"; /* User */ $password = ""; /* Password */ $dbname = "tutorial"; /* Database name */ $con = mysqli_connect($host, $user, $password,$dbname); // Check connection if (!$con) { die("Connection failed: " . mysqli_connect_error()); }
3. Download and Include FullCalendar
- Download Fullcalendar and sweetAlert libraries.
- Also included a jQuery library to send AJAX requests.
<!-- jQuery --> <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.3/jquery.min.js"></script> <!-- Fullcalendar --> <script type="text/javascript" src="fullcalendar-6.1.4/dist/index.global.min.js"></script> <!-- Sweetalert --> <script src="https://cdn.jsdelivr.net/npm/sweetalert2@11"></script>
4. HTML – Setting Up the FullCalendar Container
Creating an index.php
file.
Within this file, use PHP to store the current date in a $currentData
variable. This date will be used to set the starting point for FullCalendar.
Next, create <div id='calendar' >
to initialize FullCalendar.
<?php $currentData = date('Y-m-d'); ?> <!-- Calendar Container --> <div id='calendar-container'> <div id='calendar'></div> </div>
5. Create a PHP File to Load All Events in FullCalendar
- Create
fetchevents.php
file to load all created events list in FullCalendar. - Retrieve all event records from the
events
table. This gathered information will be stored in the$eventsList
variable. - Loop through the
$eventsList
. During each iteration, gather key event details such as ‘eventid’, ‘title’, ‘description’, ‘start’, and ‘end’ dates. These details will be compiled into a convenient$response
array. - To ensure seamless integration with FullCalendar, convert the
$response
array into JSON format.
<?php include "config.php"; // Fetch all records $sql = "SELECT * FROM events"; $eventsList = mysqli_query($con,$sql); $response = array(); while($row = mysqli_fetch_assoc($eventsList)){ $response[] = array( "eventid" => $row['id'], "title" => $row['title'], "description" => $row['description'], "start" => $row['start_date'], "end" => $row['end_date'], ); } echo json_encode($response); exit;
6. Create a PHP File to Manage AJAX Requests
Create ajaxfile.php
file to handle 4 requests:
1. Adding a New Event (addEvent)
- Reading the POST data and assigning it to variables.
- Check if the required variables have non-empty values.
- If all conditions are met, insert a new record into the
events
table. - Capture the last inserted ID in the
$eventid
variable and set$status
to 1. - Construct a
$response
array with keys such as ‘eventid’, ‘status’ and ‘message’. Assign the$eventid
to the'eventid'
key, set'status'
to 1, and provide a success message. - In case the record isn’t inserted, set
$status
to 0 and include an error message. - Return the
$response
array in JSON format.
2. Updating Event Dates (moveEvent)
- Retrieve the new dates from the POST request and update the relevant event’s ID.
- Ensure
$eventid
is greater than 0 and that bothstart_date
andend_date
are not empty. - Check if the event ID exists in the
events
table. If it does, update thestart_date
andend_date
fields and set$status
to 1. - In the
$response
array, set ‘status’ to 1 and provide a success message upon successful update. - If the update fails, set ‘status’ to 0 and include an error message.
- Return the
$response
array in JSON format.
3. Editing Event Details (editEvent)
- Read the POST data containing event details and update the corresponding event ID.
- Ensure
$eventid
is greater than 0 and that both ‘title’ and ‘description’ are not empty. - Check if the event ID exists in the
events
table. If it does, update the ‘title’ and ‘description’ fields with the new POST values. - Set
$status
to 1 and construct the$response
array with ‘status’ set to 1 and a success message. - If the update fails, set ‘status’ to 0 and include an error message.
- Return the
$response
array in JSON format.
4. Deleting an Event (deleteEvent)
- Read the POST event ID and verify if it’s greater than 0.
- Check if the event ID exists in the
events
table. If it does, delete the corresponding record and set$status
to 1. - In the
$response
array, set ‘status’ to 1 and provide a success message upon successful deletion. - If deletion fails, set ‘status’ to 0 and include an error message.
- Return the
$response
array in JSON format.
<?php include "config.php"; $request = ""; // Read $_GET value if(isset($_POST['request'])){ $request = $_POST['request']; } // Add New event if($request == 'addEvent'){ // POST data $title = ""; $description = ""; $start_date = ""; $end_date = ""; if(isset($_POST['title'])){ $title = $_POST['title']; } if(isset($_POST['description'])){ $description = $_POST['description']; } if(isset($_POST['start_date'])){ $start_date = $_POST['start_date']; } if(isset($_POST['start_date'])){ $end_date = $_POST['end_date']; } $response = array(); $status = 0; if(!empty($title) && !empty($description) && !empty($start_date) && !empty($end_date) ){ // Insert record $sql = "INSERT INTO events(title,description,start_date,end_date) VALUES('".$title."','".$description."','".$start_date."','".$end_date."')"; if(mysqli_query($con,$sql)){ $eventid = mysqli_insert_id($con); $status = 1; $response['eventid'] = $eventid; $response['status'] = 1; $response['message'] = 'Event created successfully.'; } } if($status == 0){ $response['status'] = 0; $response['message'] = 'Event not created.'; } echo json_encode($response); exit; } // Move event if($request == 'moveEvent'){ // POST data $eventid = 0; $start_date = ""; $end_date = ""; if(isset($_POST['eventid']) && is_numeric($_POST['eventid'])){ $eventid = $_POST['eventid']; } if(isset($_POST['start_date'])){ $start_date = $_POST['start_date']; } if(isset($_POST['end_date'])){ $end_date = $_POST['end_date']; } $response = array(); $status = 0; // Check event id $sql = "SELECT id FROM events WHERE id=".$eventid; $result = mysqli_query($con,$sql); if(mysqli_num_rows($result)){ // Update record $sql = "UPDATE events SET start_date='".$start_date."',end_date='".$end_date."' WHERE id=".$eventid; if(mysqli_query($con,$sql)){ $status = 1; $response['status'] = 1; $response['message'] = 'Event date updated successfully.'; } } if($status == 0){ $response['status'] = 0; $response['message'] = 'Event date not updated.'; } echo json_encode($response); exit; } // Update event if($request == 'editEvent'){ // POST data $eventid = 0; if(isset($_POST['eventid']) && is_numeric($_POST['eventid'])){ $eventid = $_POST['eventid']; } if(isset($_POST['title'])){ $title = $_POST['title']; } if(isset($_POST['description'])){ $description = $_POST['description']; } $response = array(); if($eventid > 0 && !empty($title) && !empty($description) ){ // Check event id $sql = "SELECT id FROM events WHERE id=".$eventid; $result = mysqli_query($con,$sql); if(mysqli_num_rows($result)){ // Update record $sql = "UPDATE events SET title='".$title."', description='".$description."' WHERE id=".$eventid; if(mysqli_query($con,$sql)){ $status = 1; $response['status'] = 1; $response['message'] = 'Event updated successfully.'; } } } if($status == 0){ $response['status'] = 0; $response['message'] = 'Event not updated.'; } echo json_encode($response); exit; } // Delete Event if($request == 'deleteEvent'){ // POST data $eventid = 0; if(isset($_POST['eventid']) && is_numeric($_POST['eventid'])){ $eventid = $_POST['eventid']; } $response = array(); $status = 0; if($eventid > 0){ // Check event id $sql = "SELECT id FROM events WHERE id=".$eventid; $result = mysqli_query($con,$sql); if(mysqli_num_rows($result)){ // Delete record $sql = "DELETE FROM events WHERE id=".$eventid; if(mysqli_query($con,$sql)){ $status = 1; $response['status'] = 1; $response['message'] = 'Event deleted successfully.'; } } } if($status == 0){ $response['status'] = 0; $response['message'] = 'Event not deleted.'; } echo json_encode($response); exit; }
7. jQuery: Initializing FullCalendar and Managing Events
jQuery script to set up FullCalendar and manage events:
1. Initializing FullCalendar: Initiating FullCalendar within the <div id='calendar'>
element. Specify several options for customization, such as:
- initialDate – By default, FullCalendar shows the current month but you can also specify a date in
yyyy-mm-dd
format. - height – By default, it fits on the whole screen but you change its height using this option. I set it to 600px.
- selectable – Allow event selection. The default value is
true
. - editable – Allow event drag and drop on a different date. The default value is
false
. - dayMaxEvents – It shows a more button if many events are set on a date. The default value is
false
. - events – Load existing events. Specify the file from where need to load events. Set to
fetchevents.php
. - select – This event trigger when click on a day. Using this to add a new event by displaying a popup box to enter event details.
2. Creating New Events: When a user selects a date, a pop-up alert will appear, allowing them to add an event. This alert includes input fields for the event title and description. Here’s the process:
- When the confirmation button is clicked, the entered details are captured.
- AJAX POST request is sent to
ajaxfile.php
withrequest: 'addEvent'
and event details. - Upon successful insertion
(response.status == 1)
, a new event is created usingcalendar.addEvent()
. - Display a success or error message using the SweetAlert library.
3. Moving Events: When an event is dragged and dropped to a new date, the following steps occur:
- The event’s new start and end dates are captured.
- AJAX POST request is sent to
ajaxfile.php
withrequest: 'moveEvent'
and updated event details. - Interaction is synchronous
(async: false)
to ensure proper handling.
4. Editing and Deleting Events: When an existing event is clicked, an alert appears with options to edit or delete the event. Here’s what happens:
- The alert displays the event’s title and description in the input fields.
- If ‘Update’ is confirmed, a new AJAX POST request is sent to
ajaxfile.php
withrequest: 'editEvent'
and updated event details. - Upon success
(response.status == 1)
, all events are refetched usingcalendar.refetchEvents()
. - If ‘Delete’ is clicked, another AJAX POST request with
request: 'deleteEvent'
and event ID is sent. - On success, the event is removed from the calendar using
arg.event.remove()
.
Make sure to insert this script at the end of the </body>
section in your index.php
file.
document.addEventListener('DOMContentLoaded', function() { var calendarEl = document.getElementById('calendar'); var calendar = new FullCalendar.Calendar(calendarEl, { initialDate: '<?= $currentData ?>', height: '600px', selectable: true, editable: true, dayMaxEvents: true, // allow "more" link when too many events events: 'fetchevents.php', // Fetch all events select: function(arg) { // Create Event // Alert box to add event Swal.fire({ title: 'Add New Event', showCancelButton: true, confirmButtonText: 'Create', html: '<input id="eventtitle" class="swal2-input" placeholder="Event name" style="width: 84%;" >' + '<textarea id="eventdescription" class="swal2-input" placeholder="Event description" style="width: 84%; height: 100px;"></textarea>', focusConfirm: false, preConfirm: () => { return [ document.getElementById('eventtitle').value, document.getElementById('eventdescription').value ] } }).then((result) => { if (result.isConfirmed) { var title = result.value[0].trim(); var description = result.value[1].trim(); var start_date = arg.startStr; var end_date = arg.endStr; if(title != '' && description != ''){ // AJAX - Add event $.ajax({ url: 'ajaxfile.php', type: 'post', data: {request: 'addEvent',title: title,description: description,start_date: start_date,end_date: end_date}, dataType: 'json', success: function(response){ if(response.status == 1){ // Add event calendar.addEvent({ eventid: response.eventid, title: title, description: description, start: arg.start, end: arg.end, allDay: arg.allDay }) // Alert message Swal.fire(response.message,'','success'); }else{ // Alert message Swal.fire(response.message,'','error'); } } }); } } }) calendar.unselect() }, eventDrop: function (event, delta) { // Move event // Event details var eventid = event.event.extendedProps.eventid; var newStart_date = event.event.startStr; var newEnd_date = event.event.endStr; // AJAX request $.ajax({ url: 'ajaxfile.php', type: 'post', data: {request: 'moveEvent',eventid: eventid,start_date: newStart_date, end_date: newEnd_date}, dataType: 'json', async: false, success: function(response){ console.log(response); } }); }, eventClick: function(arg) { // Edit/Delete event // Event details var eventid = arg.event._def.extendedProps.eventid; var description = arg.event._def.extendedProps.description; var title = arg.event._def.title; // Alert box to edit and delete event Swal.fire({ title: 'Edit Event', showDenyButton: true, showCancelButton: true, confirmButtonText: 'Update', denyButtonText: 'Delete', html: '<input id="eventtitle" class="swal2-input" placeholder="Event name" style="width: 84%;" value="'+ title +'" >' + '<textarea id="eventdescription" class="swal2-input" placeholder="Event description" style="width: 84%; height: 100px;">' + description + '</textarea>', focusConfirm: false, preConfirm: () => { return [ document.getElementById('eventtitle').value, document.getElementById('eventdescription').value ] } }).then((result) => { if (result.isConfirmed) { // Update var newTitle = result.value[0].trim(); var newDescription = result.value[1].trim(); if(newTitle != ''){ // AJAX - Edit event $.ajax({ url: 'ajaxfile.php', type: 'post', data: {request: 'editEvent',eventid: eventid,title: newTitle, description: newDescription}, dataType: 'json', async: false, success: function(response){ if(response.status == 1){ // Refetch all events calendar.refetchEvents(); // Alert message Swal.fire(response.message, '', 'success'); }else{ // Alert message Swal.fire(response.message, '', 'error'); } } }); } } else if (result.isDenied) { // Delete // AJAX - Delete Event $.ajax({ url: 'ajaxfile.php', type: 'post', data: {request: 'deleteEvent',eventid: eventid}, dataType: 'json', async: false, success: function(response){ if(response.status == 1){ arg.event.remove(); // Alert message Swal.fire(response.message, '', 'success'); }else{ // Alert message Swal.fire(response.message, '', 'error'); } } }); } }) } }); calendar.render(); });
8. Demo
9. Conclusion
In the example, I have used sweetAlert plugin to display a popup box to enter and display details. You can also use any other plugin with which you are compatible.
You have to create a separate file to fetch all events. It is not possible to manage it from a single file to handle all Fullcalendar actions – update/delete. It will cause problems during refetch events after editing an event.
If you found this tutorial helpful then don't forget to share.