How to Create a PHP Event Calendar with FullCalendar JS Library

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.

How to Create a PHP Event Calendar with FullCalendar JS Library


Contents

  1. Table structure
  2. Database Configuration
  3. Download and Include
  4. HTML
  5. PHP File – Fetch all events
  6. PHP File – Handle AJAX requests
  7. jQuery
  8. Demo
  9. Conclusion

1. Table structure

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. Database Configuration

Create a config.php for database configuration.

Completed Code

<?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

<!-- 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

Create index.php file.

Stored current date in $currentData, this is used to set the initial date of FullCalendar. Create <div id='calendar'> to initialize FullCalendar().

Completed Code

<?php 
$currentData = date('Y-m-d');
?>

<!-- Calendar Container -->
<div id='calendar-container'>
    <div id='calendar'></div>
</div>

5. PHP File – Fetch all events

Create fetchevents.php file to load all created events list in FullCalendar.

Fetch all records from the events table and assign it to $eventsList. Loop on the $eventsList and initialize $response Array with eventid, title, description, start, and end date.

Return $response in JSON format.

Completed Code

<?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. PHP File – Handle AJAX requests

Create ajaxfile.php file.

From here handle 4 requests –

  • addEvent – Add new event.
  • moveEvent – Update event date.
  • editEvent – Update event details.
  • deleteEvent – Delete event.

$request == ‘addEvent’ –

Read POST data and assign it to the variables. If variable values are not empty then insert a new record in the events table.

Store last insert id in $eventid variable and 1 to $status. Initialize $response Array with eventid, status, and message keys. Assign $eventid to eventid key, 1 to status, and success message to message key.

If a record is not inserted then store 0 to status and error message to message key in $response Array.

Return $response Array in JSON format.


$request == ‘moveEvent’ –

Read POST new dates and update event id. If $eventid > 0 and $start_date and $end_date is not empty then check if $eventid exists in the events table or not. If exists then update start_date and end_date fields and assign 1 to $status. In $response Array store 1 to status key and success message to message key.

If a record is not updated then store 0 to status key and error message to message key.

Return $response Array in JSON format.


$request == ‘editEvent’ –

Read POST event details and update event id. If $eventid > 0 and $title and $description is not empty then check if $eventid exists in the events table or not. If exists then update title and description fields value in the events table with new POST value.

Assign 1 to $status and store 1 to status key and success message to message key in $response Array.

If a record is not updated then store 0 to status key and error message to message key.

Return $response Array in JSON format.


$request == ‘deleteEvent’ –

Read POST event id and check if it is > 0 or not. If it is then check the record in the events table exists with $eventid id.

Delete the record if exists and assign 1 to $status. In the $response Array store 1 to status key and success message to message key.

If not deleted then assign 0 to status key and error message to message key in the $response Array.

Return $response Array in JSON format.

Completed Code

<?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

Initaiilze FullCalendar on <div id='calendar'>.

Here, I specified the following options –

  • initialDate – By default FullCalendar show the current month but you can also specify a date in yyyy-mm-dd format.
  • height – By default, it is fit 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 show 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.

Display sweetAlert confirm box that has a textbox to enter the event name and textarea to enter the description.

If confirm button gets clicked then read entered values and event start and end date. Send AJAX POST request to ajaxfile.php, pass request: 'addEvent' and event details. On successful callback check response status. If it is 1 means a record successfully inserted in the MySQL database, using calendar.addEvent(); create an event.

Here, I also set eventid, this is use to update/delete a record.

Display alert message according to the response.status.

  • eventDrop – This event trigger when drag & drop an item in the calendar. Using this update the event date.

Read selected event – eventid, new start and end date. Send AJAX POST request to ajaxfile.php, pass request: 'moveEvent', update event id, and dates.

  • eventClick – This event trigger when clicked on the existing event. Using this update/delete a event.

Read eventid, title and description. Create sweetAlert confirm box that has 3 buttons – Update, Delete, and Cancel. Set the title and description values in the textbox and textarea.

Edit Event

If result.isConfirmed is true means update button is clicked. Read entered values and send AJAX POST request to ajaxfile.php, pass request: 'editEvent', update event id, new title and description. On successful callback, if response.status == 1 then refetch all events by calling – calendar.refetchEvents(); and display the response message.

Delete Event

If result.isDenied is true means delete button is clicked. Send AJAX POST request to ajaxfile.php, pass request: 'deleteEvent', delete event id. On successful callback if response.status == 1 then remove the event from calendar by calling – arg.event.remove(); and display the response message.

NOTE – I added the script to the index.php file at the end of </body>.

Completed Code

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

View 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.

Leave a Comment