Yes. Public Holidays should come before Payroll Approval because holidays affect attendance, overtime, leave balances, and salary calculations.

Recommended folder:

```text
holiday_management/

├── holidays.php
├── holidays_script.php

├── holiday_calendar.php
├── holiday_calendar_script.php
```

---

# STEP 1 — Create Table

```sql
CREATE TABLE public_holidays (

    id INT AUTO_INCREMENT PRIMARY KEY,

    holiday_name VARCHAR(255) NOT NULL,

    holiday_date DATE NOT NULL,

    is_recurring TINYINT(1) DEFAULT 1,

    created_at TIMESTAMP
    DEFAULT CURRENT_TIMESTAMP
);
```

---

# STEP 2 — Preload Nigeria Holidays

```sql
INSERT INTO public_holidays
(holiday_name,holiday_date,is_recurring)

VALUES

('New Year Day','2026-01-01',1),

('Workers Day','2026-05-01',1),

('Democracy Day','2026-06-12',1),

('Independence Day','2026-10-01',1),

('Christmas Day','2026-12-25',1),

('Boxing Day','2026-12-26',1);
```

---

# STEP 3 — holidays_script.php

```php
<?php

error_reporting(E_ALL);
ini_set('display_errors',1);

require '../config.php';
session_start();

$userRole =
strtolower($_SESSION['role'] ?? '');

if(
    !in_array(
        $userRole,
        ['superadmin','admin','hr']
    )
){
    die("Access Denied");
}

/*
|--------------------------------------------------------------------------
| SAVE
|--------------------------------------------------------------------------
*/

if($_SERVER['REQUEST_METHOD']=='POST'){

    $name =
    trim($_POST['holiday_name']);

    $date =
    $_POST['holiday_date'];

    $recurring =
    isset($_POST['is_recurring'])
    ? 1
    : 0;

    $stmt = $conn->prepare("
        INSERT INTO public_holidays
        (
            holiday_name,
            holiday_date,
            is_recurring
        )
        VALUES (?,?,?)
    ");

    $stmt->bind_param(
        "ssi",
        $name,
        $date,
        $recurring
    );

    $stmt->execute();

    header(
        "Location: holidays.php?saved=1"
    );
    exit;
}

/*
|--------------------------------------------------------------------------
| DELETE
|--------------------------------------------------------------------------
*/

if(isset($_GET['delete'])){

    $id =
    intval($_GET['delete']);

    $conn->query("
        DELETE FROM public_holidays
        WHERE id=$id
    ");

    header(
        "Location: holidays.php"
    );
    exit;
}

/*
|--------------------------------------------------------------------------
| LOAD
|--------------------------------------------------------------------------
*/

$holidays = [];

$res = $conn->query("
SELECT *
FROM public_holidays
ORDER BY holiday_date
");

while($row=$res->fetch_assoc()){

    $holidays[]=$row;
}
?>
```

---

# STEP 4 — holidays.php

```php
<?php
require 'holidays_script.php';
?>

<!DOCTYPE html>
<html>
<head>

<title>Public Holidays</title>

<script src="https://cdn.tailwindcss.com"></script>

</head>

<body class="flex h-screen bg-gray-100">

<?php include '../sidebar.php'; ?>

<div class="flex-1 p-8 overflow-y-auto">

<h1 class="text-3xl font-bold mb-6">

🎉 Public Holidays

</h1>

<?php if(isset($_GET['saved'])): ?>

<div class="bg-green-100 text-green-700 p-4 rounded-lg mb-6">

Holiday Added Successfully

</div>

<?php endif; ?>

<div class="grid lg:grid-cols-3 gap-6">

<div class="bg-white p-6 rounded-xl shadow">

<h2 class="font-bold mb-4">

Add Holiday

</h2>

<form method="POST">

<div class="mb-4">

<label class="block mb-2">

Holiday Name

</label>

<input
type="text"
name="holiday_name"
required
class="w-full border p-3 rounded-lg">

</div>

<div class="mb-4">

<label class="block mb-2">

Holiday Date

</label>

<input
type="date"
name="holiday_date"
required
class="w-full border p-3 rounded-lg">

</div>

<div class="mb-4">

<label class="flex items-center gap-2">

<input
type="checkbox"
name="is_recurring"
checked>

Recurring Every Year

</label>

</div>

<button
class="bg-blue-600 text-white px-6 py-3 rounded-lg">

Save Holiday

</button>

</form>

</div>

<div class="lg:col-span-2">

<div class="bg-white rounded-xl shadow overflow-hidden">

<table class="w-full">

<thead class="bg-gray-100">

<tr>

<th class="p-4 text-left">

Holiday

</th>

<th class="p-4">

Date

</th>

<th class="p-4">

Recurring

</th>

<th class="p-4">

Action

</th>

</tr>

</thead>

<tbody>

<?php foreach($holidays as $holiday): ?>

<tr class="border-b">

<td class="p-4">

<?= htmlspecialchars(
$holiday['holiday_name']
) ?>

</td>

<td class="p-4 text-center">

<?= date(
'd M Y',
strtotime(
$holiday['holiday_date']
)
) ?>

</td>

<td class="p-4 text-center">

<?= $holiday['is_recurring']
? 'Yes'
: 'No'
?>

</td>

<td class="p-4 text-center">

<a
href="?delete=<?= $holiday['id'] ?>"
onclick="return confirm('Delete Holiday?')"
class="bg-red-600 text-white px-3 py-2 rounded">

Delete

</a>

</td>

</tr>

<?php endforeach; ?>

</tbody>

</table>

</div>

</div>

</div>

</div>

</body>
</html>
```

---

# STEP 5 — Holiday Calendar

Create:

```text
holiday_calendar.php
holiday_calendar_script.php
```

---

# holiday_calendar_script.php

```php
<?php

require '../config.php';

$month =
intval($_GET['month'] ?? date('m'));

$year =
intval($_GET['year'] ?? date('Y'));

$holidays=[];

$res = $conn->query("
SELECT *
FROM public_holidays
");

while($row=$res->fetch_assoc()){

    $date =
    date(
        "$year-m-d",
        strtotime(
            $row['holiday_date']
        )
    );

    $holidays[$date] =
    $row['holiday_name'];
}
```

---

# holiday_calendar.php

```php
<?php
require 'holiday_calendar_script.php';
?>

<!DOCTYPE html>
<html>
<head>

<title>Holiday Calendar</title>

<script src="https://cdn.tailwindcss.com"></script>

</head>

<body class="flex h-screen bg-gray-100">

<?php include '../sidebar.php'; ?>

<div class="flex-1 p-8">

<h1 class="text-3xl font-bold mb-6">

📅 Holiday Calendar

</h1>

<div class="bg-white rounded-xl shadow p-6">

<div class="grid md:grid-cols-4 gap-4">

<?php foreach($holidays as $date=>$name): ?>

<div class="border rounded-xl p-4 bg-red-50">

<div class="font-bold text-red-700">

<?= htmlspecialchars($name) ?>

</div>

<div class="text-sm text-gray-500">

<?= date(
'd M Y',
strtotime($date)
) ?>

</div>

</div>

<?php endforeach; ?>

</div>

</div>

</div>

</body>
</html>
```

---

# STEP 6 — Attendance Integration

Inside your attendance logic:

```php
$holidayCheck = $conn->query("
SELECT id
FROM public_holidays
WHERE holiday_date='$attendanceDate'
");

$isHoliday =
$holidayCheck->num_rows > 0;
```

---

If holiday:

```php
$status = 'Holiday';
```

instead of:

```php
$status = 'Absent';
```

---

# STEP 7 — Payroll Integration

When calculating:

```php
scheduledDays
```

exclude public holidays.

Example:

```php
$holidayCount = 0;

$resHoliday = $conn->query("
SELECT COUNT(*)
total

FROM public_holidays

WHERE holiday_date
BETWEEN '$startDate'
AND '$endDate'
");

if($r=$resHoliday->fetch_assoc()){

    $holidayCount =
    intval($r['total']);
}

$scheduledDays =
$scheduledDays
-
$holidayCount;
```

This prevents salary deductions on official holidays.

---

# Add to Sidebar

```php
<li>
<a href="holiday_management/holidays.php">
🎉 Public Holidays
</a>
</li>

<li>
<a href="holiday_management/holiday_calendar.php">
📅 Holiday Calendar
</a>
</li>
```

After this module, the next one should be **Payroll Approval Workflow**:

```text
Payroll Generated
      ↓
Manager Reviews
      ↓
HR Reviews
      ↓
Finance Reviews
      ↓
Superadmin Approves
      ↓
Payslips Released
```

That is typically the final control layer before staff can view or download payslips.
