ONLINE FOOD ORDERING SYSTEM IN HTML CSS AND JAVASCRIPT WIHT PHP AND MY SWL

ONLINE FOOD ORDERING SYSTEM

Introduction

The Online Food Ordering System is a web-based application that allows customers to browse restaurant menus, select food items, add them to cart, and place orders online. The system has two main interfaces: Admin Panel for restaurant management and Client Side for customers. Administrators can manage food items, categories, view orders, and update order status, while customers can register, login, browse food, place orders, and track their order history.

Project Features

Client Side Features:

  • User Registration and Login System
  • Browse Food Items by Categories
  • Search Food Items
  • Add to Cart Functionality
  • Update Cart (Quantity, Remove Items)
  • Place Orders
  • View Order History
  • Track Order Status
  • User Profile Management
  • Secure Session Management

Admin Side Features:

  • Admin Login
  • Dashboard with Statistics
  • Manage Food Categories (Add, Edit, Delete)
  • Manage Food Items (Add, Edit, Delete)
  • View All Orders
  • Update Order Status (Pending, Processing, Completed, Cancelled)
  • View Registered Users
  • Admin Profile Management
  • Secure Admin Session

Project File Structure

online-food-ordering-system/
│
├── assets/
│   ├── css/
│   │   ├── style.css
│   │   ├── admin-style.css
│   │   └── responsive.css
│   ├── js/
│   │   ├── main.js
│   │   ├── cart.js
│   │   └── admin.js
│   └── images/
│       ├── foods/
│       └── uploads/
│
├── database/
│   └── food_ordering_system.sql
│
├── includes/
│   ├── config.php
│   ├── db_connection.php
│   ├── functions.php
│   └── session.php
│
├── admin/
│   ├── index.php
│   ├── login.php
│   ├── logout.php
│   ├── dashboard.php
│   ├── categories.php
│   ├── add-category.php
│   ├── edit-category.php
│   ├── delete-category.php
│   ├── foods.php
│   ├── add-food.php
│   ├── edit-food.php
│   ├── delete-food.php
│   ├── orders.php
│   ├── update-order.php
│   ├── users.php
│   └── profile.php
│
├── user/
│   ├── register.php
│   ├── login.php
│   ├── logout.php
│   ├── dashboard.php
│   ├── profile.php
│   └── orders.php
│
├── index.php
├── menu.php
├── cart.php
├── checkout.php
├── order-confirmation.php
├── search.php
├── contact.php
├── about.php
└── logout.php

Database Schema (food_ordering_system.sql)

-- Create Database
CREATE DATABASE IF NOT EXISTS food_ordering_system;
USE food_ordering_system;
-- Table: admin
CREATE TABLE admin (
admin_id INT PRIMARY KEY AUTO_INCREMENT,
username VARCHAR(50) UNIQUE NOT NULL,
password VARCHAR(255) NOT NULL,
email VARCHAR(100) UNIQUE NOT NULL,
full_name VARCHAR(100),
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
-- Insert default admin
INSERT INTO admin (username, password, email, full_name) 
VALUES ('admin', MD5('admin123'), '[email protected]', 'System Administrator');
-- Table: users
CREATE TABLE users (
user_id INT PRIMARY KEY AUTO_INCREMENT,
username VARCHAR(50) UNIQUE NOT NULL,
password VARCHAR(255) NOT NULL,
email VARCHAR(100) UNIQUE NOT NULL,
full_name VARCHAR(100) NOT NULL,
phone VARCHAR(20),
address TEXT,
city VARCHAR(50),
zip_code VARCHAR(20),
registered_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
-- Table: categories
CREATE TABLE categories (
category_id INT PRIMARY KEY AUTO_INCREMENT,
category_name VARCHAR(100) NOT NULL,
category_description TEXT,
category_image VARCHAR(255),
is_active BOOLEAN DEFAULT TRUE,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
-- Table: foods
CREATE TABLE foods (
food_id INT PRIMARY KEY AUTO_INCREMENT,
category_id INT,
food_name VARCHAR(100) NOT NULL,
food_description TEXT,
food_price DECIMAL(10,2) NOT NULL,
food_image VARCHAR(255),
is_available BOOLEAN DEFAULT TRUE,
is_recommended BOOLEAN DEFAULT FALSE,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (category_id) REFERENCES categories(category_id) ON DELETE SET NULL
);
-- Table: orders
CREATE TABLE orders (
order_id INT PRIMARY KEY AUTO_INCREMENT,
user_id INT,
order_number VARCHAR(50) UNIQUE NOT NULL,
order_date TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
total_amount DECIMAL(10,2) NOT NULL,
order_status ENUM('Pending', 'Processing', 'Completed', 'Cancelled') DEFAULT 'Pending',
payment_method ENUM('Cash', 'Card', 'Online') DEFAULT 'Cash',
payment_status ENUM('Pending', 'Paid') DEFAULT 'Pending',
delivery_address TEXT NOT NULL,
delivery_city VARCHAR(50),
delivery_zip VARCHAR(20),
delivery_phone VARCHAR(20),
special_instructions TEXT,
FOREIGN KEY (user_id) REFERENCES users(user_id) ON DELETE SET NULL
);
-- Table: order_items
CREATE TABLE order_items (
order_item_id INT PRIMARY KEY AUTO_INCREMENT,
order_id INT,
food_id INT,
quantity INT NOT NULL,
price DECIMAL(10,2) NOT NULL,
FOREIGN KEY (order_id) REFERENCES orders(order_id) ON DELETE CASCADE,
FOREIGN KEY (food_id) REFERENCES foods(food_id) ON DELETE SET NULL
);
-- Table: contact_messages
CREATE TABLE contact_messages (
message_id INT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(100) NOT NULL,
email VARCHAR(100) NOT NULL,
subject VARCHAR(200),
message TEXT NOT NULL,
submitted_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
is_read BOOLEAN DEFAULT FALSE
);

Core PHP Files

1. includes/config.php

<?php
// Database configuration
define('DB_HOST', 'localhost');
define('DB_USER', 'root');
define('DB_PASS', '');
define('DB_NAME', 'food_ordering_system');
// Application configuration
define('SITE_NAME', 'FoodieExpress');
define('SITE_URL', 'http://localhost/online-food-ordering-system/');
define('ADMIN_URL', SITE_URL . 'admin/');
define('UPLOAD_PATH', $_SERVER['DOCUMENT_ROOT'] . '/online-food-ordering-system/assets/uploads/');
define('UPLOAD_URL', SITE_URL . 'assets/uploads/');
// Start session if not started
if (session_status() == PHP_SESSION_NONE) {
session_start();
}
?>

2. includes/db_connection.php

<?php
require_once 'config.php';
class Database {
private $connection;
public function __construct() {
$this->connect();
}
private function connect() {
$this->connection = new mysqli(DB_HOST, DB_USER, DB_PASS, DB_NAME);
if ($this->connection->connect_error) {
die("Connection failed: " . $this->connection->connect_error);
}
$this->connection->set_charset("utf8");
}
public function getConnection() {
return $this->connection;
}
public function escapeString($string) {
return $this->connection->real_escape_string($string);
}
public function executeQuery($sql) {
return $this->connection->query($sql);
}
public function getLastInsertId() {
return $this->connection->insert_id;
}
public function __destruct() {
if ($this->connection) {
$this->connection->close();
}
}
}
// Create global database instance
$db = new Database();
$conn = $db->getConnection();
?>

3. includes/functions.php

<?php
require_once 'db_connection.php';
// Redirect to specified page
function redirect($url) {
header("Location: $url");
exit();
}
// Check if user is logged in
function isUserLoggedIn() {
return isset($_SESSION['user_id']) && !empty($_SESSION['user_id']);
}
// Check if admin is logged in
function isAdminLoggedIn() {
return isset($_SESSION['admin_id']) && !empty($_SESSION['admin_id']);
}
// Get all categories
function getCategories($limit = null) {
global $conn;
$sql = "SELECT * FROM categories WHERE is_active = 1 ORDER BY category_name";
if ($limit) {
$sql .= " LIMIT $limit";
}
$result = $conn->query($sql);
$categories = [];
if ($result->num_rows > 0) {
while ($row = $result->fetch_assoc()) {
$categories[] = $row;
}
}
return $categories;
}
// Get foods by category
function getFoodsByCategory($category_id, $limit = null) {
global $conn;
$sql = "SELECT * FROM foods WHERE category_id = $category_id AND is_available = 1 ORDER BY food_name";
if ($limit) {
$sql .= " LIMIT $limit";
}
$result = $conn->query($sql);
$foods = [];
if ($result->num_rows > 0) {
while ($row = $result->fetch_assoc()) {
$foods[] = $row;
}
}
return $foods;
}
// Get all foods
function getAllFoods($limit = null) {
global $conn;
$sql = "SELECT f.*, c.category_name FROM foods f 
LEFT JOIN categories c ON f.category_id = c.category_id 
WHERE f.is_available = 1 ORDER BY f.food_name";
if ($limit) {
$sql .= " LIMIT $limit";
}
$result = $conn->query($sql);
$foods = [];
if ($result->num_rows > 0) {
while ($row = $result->fetch_assoc()) {
$foods[] = $row;
}
}
return $foods;
}
// Get recommended foods
function getRecommendedFoods($limit = 6) {
global $conn;
$sql = "SELECT f.*, c.category_name FROM foods f 
LEFT JOIN categories c ON f.category_id = c.category_id 
WHERE f.is_available = 1 AND f.is_recommended = 1 
ORDER BY RAND() LIMIT $limit";
$result = $conn->query($sql);
$foods = [];
if ($result->num_rows > 0) {
while ($row = $result->fetch_assoc()) {
$foods[] = $row;
}
}
return $foods;
}
// Get food by ID
function getFoodById($food_id) {
global $conn;
$sql = "SELECT f.*, c.category_name FROM foods f 
LEFT JOIN categories c ON f.category_id = c.category_id 
WHERE f.food_id = $food_id";
$result = $conn->query($sql);
if ($result->num_rows > 0) {
return $result->fetch_assoc();
}
return null;
}
// Generate order number
function generateOrderNumber() {
return 'ORD-' . date('Ymd') . '-' . rand(1000, 9999);
}
// Calculate cart total
function calculateCartTotal($cart) {
$total = 0;
if (!empty($cart)) {
foreach ($cart as $item) {
$total += $item['price'] * $item['quantity'];
}
}
return $total;
}
// Upload image
function uploadImage($file, $target_dir) {
$target_file = $target_dir . basename($file["name"]);
$imageFileType = strtolower(pathinfo($target_file, PATHINFO_EXTENSION));
// Check if image file is actual image
$check = getimagesize($file["tmp_name"]);
if ($check === false) {
return ['success' => false, 'message' => 'File is not an image.'];
}
// Check file size (5MB max)
if ($file["size"] > 5000000) {
return ['success' => false, 'message' => 'File is too large. Maximum size is 5MB.'];
}
// Allow certain file formats
if ($imageFileType != "jpg" && $imageFileType != "png" && $imageFileType != "jpeg" && $imageFileType != "gif") {
return ['success' => false, 'message' => 'Only JPG, JPEG, PNG & GIF files are allowed.'];
}
// Generate unique filename
$new_filename = uniqid() . '.' . $imageFileType;
$target_file = $target_dir . $new_filename;
if (move_uploaded_file($file["tmp_name"], $target_file)) {
return ['success' => true, 'filename' => $new_filename];
} else {
return ['success' => false, 'message' => 'Error uploading file.'];
}
}
// Sanitize input
function sanitize($input) {
global $conn;
return $conn->real_escape_string(trim(htmlspecialchars($input, ENT_QUOTES, 'UTF-8')));
}
?>

4. index.php (Homepage)

<?php
require_once 'includes/config.php';
require_once 'includes/functions.php';
?>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>FoodieExpress - Online Food Ordering</title>
<link rel="stylesheet" href="assets/css/style.css">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css">
</head>
<body>
<!-- Navigation Bar -->
<nav class="navbar">
<div class="container">
<div class="nav-brand">
<a href="index.php">FoodieExpress</a>
</div>
<ul class="nav-menu">
<li><a href="index.php" class="active">Home</a></li>
<li><a href="menu.php">Menu</a></li>
<li><a href="about.php">About</a></li>
<li><a href="contact.php">Contact</a></li>
<?php if (isset($_SESSION['user_id'])): ?>
<li><a href="user/dashboard.php">Dashboard</a></li>
<li><a href="logout.php">Logout</a></li>
<?php else: ?>
<li><a href="user/login.php">Login</a></li>
<li><a href="user/register.php" class="btn-register">Register</a></li>
<?php endif; ?>
<li>
<a href="cart.php" class="cart-icon">
<i class="fas fa-shopping-cart"></i>
<span class="cart-count">0</span>
</a>
</li>
</ul>
</div>
</nav>
<!-- Hero Section -->
<section class="hero">
<div class="container">
<div class="hero-content">
<h1>Delicious Food Delivered To Your Doorstep</h1>
<p>Order your favorite meals from the best restaurants in town</p>
<a href="menu.php" class="btn btn-primary">Order Now</a>
</div>
</div>
</section>
<!-- Categories Section -->
<section class="categories">
<div class="container">
<h2 class="section-title">Popular Categories</h2>
<div class="category-grid">
<?php
$categories = getCategories(6);
foreach ($categories as $category):
?>
<div class="category-card">
<img src="assets/uploads/<?php echo $category['category_image'] ?? 'default-category.jpg'; ?>" 
alt="<?php echo $category['category_name']; ?>">
<h3><?php echo $category['category_name']; ?></h3>
<a href="menu.php?category=<?php echo $category['category_id']; ?>" class="btn-small">View Items</a>
</div>
<?php endforeach; ?>
</div>
</div>
</section>
<!-- Recommended Foods -->
<section class="recommended">
<div class="container">
<h2 class="section-title">Recommended For You</h2>
<div class="food-grid">
<?php
$recommended_foods = getRecommendedFoods(6);
foreach ($recommended_foods as $food):
?>
<div class="food-card">
<img src="assets/uploads/<?php echo $food['food_image'] ?? 'default-food.jpg'; ?>" 
alt="<?php echo $food['food_name']; ?>">
<div class="food-info">
<h3><?php echo $food['food_name']; ?></h3>
<p class="category"><?php echo $food['category_name']; ?></p>
<p class="description"><?php echo substr($food['food_description'], 0, 60) . '...'; ?></p>
<div class="food-footer">
<span class="price">$<?php echo number_format($food['food_price'], 2); ?></span>
<button class="btn-add-to-cart" data-food-id="<?php echo $food['food_id']; ?>">
<i class="fas fa-cart-plus"></i> Add
</button>
</div>
</div>
</div>
<?php endforeach; ?>
</div>
</div>
</section>
<!-- Footer -->
<footer class="footer">
<div class="container">
<div class="footer-content">
<div class="footer-section">
<h3>FoodieExpress</h3>
<p>Your favorite food delivery partner</p>
</div>
<div class="footer-section">
<h3>Quick Links</h3>
<ul>
<li><a href="about.php">About Us</a></li>
<li><a href="contact.php">Contact</a></li>
<li><a href="privacy.php">Privacy Policy</a></li>
<li><a href="terms.php">Terms & Conditions</a></li>
</ul>
</div>
<div class="footer-section">
<h3>Contact Info</h3>
<p><i class="fas fa-phone"></i> +1 234 567 890</p>
<p><i class="fas fa-envelope"></i> [email protected]</p>
<p><i class="fas fa-map-marker-alt"></i> 123 Food Street, Food City</p>
</div>
</div>
<div class="footer-bottom">
<p>&copy; 2024 FoodieExpress. All rights reserved.</p>
</div>
</div>
</footer>
<script src="assets/js/main.js"></script>
<script src="assets/js/cart.js"></script>
</body>
</html>

5. assets/css/style.css

/* Global Styles */
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
:root {
--primary-color: #ff6b6b;
--secondary-color: #4ecdc4;
--dark-color: #2c3e50;
--light-color: #f7f7f7;
--danger-color: #e74c3c;
--success-color: #2ecc71;
--warning-color: #f39c12;
}
body {
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
line-height: 1.6;
color: #333;
}
.container {
max-width: 1200px;
margin: 0 auto;
padding: 0 20px;
}
/* Navigation */
.navbar {
background: white;
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
position: sticky;
top: 0;
z-index: 1000;
}
.navbar .container {
display: flex;
justify-content: space-between;
align-items: center;
padding: 15px 20px;
}
.nav-brand a {
font-size: 24px;
font-weight: bold;
color: var(--primary-color);
text-decoration: none;
}
.nav-menu {
display: flex;
list-style: none;
align-items: center;
gap: 30px;
}
.nav-menu a {
color: var(--dark-color);
text-decoration: none;
font-weight: 500;
transition: color 0.3s;
}
.nav-menu a:hover,
.nav-menu a.active {
color: var(--primary-color);
}
.btn-register {
background: var(--primary-color);
color: white !important;
padding: 8px 20px;
border-radius: 5px;
transition: background 0.3s;
}
.btn-register:hover {
background: #ff5252;
}
.cart-icon {
position: relative;
font-size: 20px;
}
.cart-count {
position: absolute;
top: -8px;
right: -8px;
background: var(--primary-color);
color: white;
font-size: 12px;
padding: 2px 6px;
border-radius: 50%;
}
/* Hero Section */
.hero {
background: linear-gradient(135deg, var(--primary-color), var(--secondary-color));
color: white;
padding: 100px 0;
text-align: center;
}
.hero-content h1 {
font-size: 48px;
margin-bottom: 20px;
}
.hero-content p {
font-size: 18px;
margin-bottom: 30px;
}
/* Buttons */
.btn {
display: inline-block;
padding: 12px 30px;
border-radius: 5px;
text-decoration: none;
font-weight: 600;
transition: all 0.3s;
cursor: pointer;
border: none;
}
.btn-primary {
background: var(--dark-color);
color: white;
}
.btn-primary:hover {
background: #34495e;
transform: translateY(-2px);
}
.btn-small {
display: inline-block;
padding: 5px 15px;
background: var(--primary-color);
color: white;
text-decoration: none;
border-radius: 3px;
font-size: 14px;
}
.btn-add-to-cart {
background: var(--success-color);
color: white;
border: none;
padding: 8px 15px;
border-radius: 3px;
cursor: pointer;
transition: background 0.3s;
}
.btn-add-to-cart:hover {
background: #27ae60;
}
/* Sections */
section {
padding: 80px 0;
}
.section-title {
text-align: center;
font-size: 36px;
margin-bottom: 50px;
color: var(--dark-color);
position: relative;
}
.section-title:after {
content: '';
display: block;
width: 80px;
height: 3px;
background: var(--primary-color);
margin: 15px auto 0;
}
/* Category Grid */
.category-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
gap: 30px;
}
.category-card {
background: white;
border-radius: 10px;
overflow: hidden;
box-shadow: 0 5px 15px rgba(0,0,0,0.1);
transition: transform 0.3s;
text-align: center;
}
.category-card:hover {
transform: translateY(-5px);
}
.category-card img {
width: 100%;
height: 200px;
object-fit: cover;
}
.category-card h3 {
padding: 15px 0 10px;
color: var(--dark-color);
}
.category-card .btn-small {
margin-bottom: 20px;
}
/* Food Grid */
.food-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
gap: 30px;
}
.food-card {
background: white;
border-radius: 10px;
overflow: hidden;
box-shadow: 0 5px 15px rgba(0,0,0,0.1);
transition: transform 0.3s;
}
.food-card:hover {
transform: translateY(-5px);
}
.food-card img {
width: 100%;
height: 200px;
object-fit: cover;
}
.food-info {
padding: 20px;
}
.food-info h3 {
margin-bottom: 5px;
color: var(--dark-color);
}
.food-info .category {
color: var(--primary-color);
font-size: 14px;
margin-bottom: 10px;
}
.food-info .description {
color: #666;
font-size: 14px;
margin-bottom: 15px;
line-height: 1.4;
}
.food-footer {
display: flex;
justify-content: space-between;
align-items: center;
}
.price {
font-size: 20px;
font-weight: bold;
color: var(--dark-color);
}
/* Footer */
.footer {
background: var(--dark-color);
color: white;
padding: 50px 0 0;
}
.footer-content {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
gap: 30px;
margin-bottom: 30px;
}
.footer-section h3 {
margin-bottom: 20px;
position: relative;
}
.footer-section h3:after {
content: '';
display: block;
width: 50px;
height: 2px;
background: var(--primary-color);
margin-top: 10px;
}
.footer-section ul {
list-style: none;
}
.footer-section ul li {
margin-bottom: 10px;
}
.footer-section a {
color: #ccc;
text-decoration: none;
transition: color 0.3s;
}
.footer-section a:hover {
color: var(--primary-color);
}
.footer-section p {
margin-bottom: 10px;
color: #ccc;
}
.footer-section i {
margin-right: 10px;
color: var(--primary-color);
}
.footer-bottom {
text-align: center;
padding: 20px 0;
border-top: 1px solid #444;
color: #ccc;
}
/* Responsive Design */
@media (max-width: 768px) {
.nav-menu {
display: none;
}
.hero-content h1 {
font-size: 36px;
}
.section-title {
font-size: 28px;
}
.category-grid,
.food-grid {
grid-template-columns: 1fr;
}
}
/* Forms */
.form-container {
max-width: 500px;
margin: 50px auto;
padding: 30px;
background: white;
border-radius: 10px;
box-shadow: 0 5px 20px rgba(0,0,0,0.1);
}
.form-group {
margin-bottom: 20px;
}
.form-group label {
display: block;
margin-bottom: 5px;
font-weight: 500;
color: var(--dark-color);
}
.form-group input,
.form-group textarea,
.form-group select {
width: 100%;
padding: 10px;
border: 1px solid #ddd;
border-radius: 5px;
font-size: 16px;
transition: border-color 0.3s;
}
.form-group input:focus,
.form-group textarea:focus,
.form-group select:focus {
outline: none;
border-color: var(--primary-color);
}
/* Alerts */
.alert {
padding: 15px;
margin-bottom: 20px;
border-radius: 5px;
}
.alert-success {
background: #d4edda;
color: #155724;
border: 1px solid #c3e6cb;
}
.alert-danger {
background: #f8d7da;
color: #721c24;
border: 1px solid #f5c6cb;
}
.alert-warning {
background: #fff3cd;
color: #856404;
border: 1px solid #ffeeba;
}
/* Cart Page */
.cart-container {
max-width: 1000px;
margin: 50px auto;
padding: 20px;
}
.cart-table {
width: 100%;
border-collapse: collapse;
margin-bottom: 30px;
}
.cart-table th,
.cart-table td {
padding: 15px;
text-align: left;
border-bottom: 1px solid #ddd;
}
.cart-table th {
background: var(--light-color);
font-weight: 600;
}
.cart-item-image {
width: 80px;
height: 80px;
object-fit: cover;
border-radius: 5px;
}
.quantity-input {
width: 60px;
padding: 5px;
border: 1px solid #ddd;
border-radius: 3px;
text-align: center;
}
.btn-remove {
color: var(--danger-color);
background: none;
border: none;
cursor: pointer;
font-size: 18px;
}
.cart-summary {
background: var(--light-color);
padding: 20px;
border-radius: 10px;
text-align: right;
}
.cart-summary h3 {
margin-bottom: 15px;
}
.summary-item {
display: flex;
justify-content: space-between;
margin-bottom: 10px;
padding: 5px 0;
}
.summary-total {
font-size: 20px;
font-weight: bold;
color: var(--primary-color);
border-top: 2px solid #ddd;
padding-top: 10px;
margin-top: 10px;
}
/* Admin Dashboard */
.admin-container {
display: flex;
min-height: 100vh;
}
.admin-sidebar {
width: 250px;
background: var(--dark-color);
color: white;
padding: 20px;
}
.admin-sidebar h2 {
margin-bottom: 30px;
padding-bottom: 10px;
border-bottom: 2px solid var(--primary-color);
}
.admin-sidebar ul {
list-style: none;
}
.admin-sidebar li {
margin-bottom: 10px;
}
.admin-sidebar a {
color: #ccc;
text-decoration: none;
display: block;
padding: 10px;
border-radius: 5px;
transition: all 0.3s;
}
.admin-sidebar a:hover,
.admin-sidebar a.active {
background: var(--primary-color);
color: white;
}
.admin-main {
flex: 1;
padding: 20px;
background: #f5f5f5;
}
.admin-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 30px;
padding-bottom: 20px;
border-bottom: 1px solid #ddd;
}
.stats-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
gap: 20px;
margin-bottom: 30px;
}
.stat-card {
background: white;
padding: 20px;
border-radius: 10px;
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
}
.stat-card h3 {
color: #666;
font-size: 14px;
margin-bottom: 10px;
}
.stat-card .stat-number {
font-size: 32px;
font-weight: bold;
color: var(--dark-color);
}
.stat-card .stat-icon {
font-size: 40px;
color: var(--primary-color);
}

6. assets/js/cart.js

// Cart functionality
class ShoppingCart {
constructor() {
this.cart = this.getCart();
this.updateCartCount();
}
getCart() {
const cart = localStorage.getItem('cart');
return cart ? JSON.parse(cart) : [];
}
saveCart() {
localStorage.setItem('cart', JSON.stringify(this.cart));
this.updateCartCount();
}
addToCart(foodId, foodName, price, quantity = 1) {
const existingItem = this.cart.find(item => item.food_id === foodId);
if (existingItem) {
existingItem.quantity += quantity;
} else {
this.cart.push({
food_id: foodId,
food_name: foodName,
price: price,
quantity: quantity
});
}
this.saveCart();
this.showNotification('Item added to cart!');
}
removeFromCart(foodId) {
this.cart = this.cart.filter(item => item.food_id !== foodId);
this.saveCart();
this.renderCart();
}
updateQuantity(foodId, quantity) {
const item = this.cart.find(item => item.food_id === foodId);
if (item) {
if (quantity <= 0) {
this.removeFromCart(foodId);
} else {
item.quantity = quantity;
this.saveCart();
}
}
this.renderCart();
}
getCartTotal() {
return this.cart.reduce((total, item) => total + (item.price * item.quantity), 0);
}
getCartCount() {
return this.cart.reduce((count, item) => count + item.quantity, 0);
}
updateCartCount() {
const cartCountElements = document.querySelectorAll('.cart-count');
const count = this.getCartCount();
cartCountElements.forEach(element => {
element.textContent = count;
if (count > 0) {
element.style.display = 'inline';
} else {
element.style.display = 'none';
}
});
}
clearCart() {
this.cart = [];
this.saveCart();
}
renderCart() {
const cartTable = document.querySelector('.cart-table tbody');
const cartSummary = document.querySelector('.cart-summary');
if (!cartTable) return;
if (this.cart.length === 0) {
cartTable.innerHTML = '<tr><td colspan="6" style="text-align: center;">Your cart is empty</td></tr>';
if (cartSummary) {
cartSummary.innerHTML = '<h3>Cart Summary</h3><p>Your cart is empty</p>';
}
return;
}
let html = '';
this.cart.forEach(item => {
html += `
<tr>
<td><img src="assets/uploads/${item.image || 'default-food.jpg'}" alt="${item.food_name}" class="cart-item-image"></td>
<td>${item.food_name}</td>
<td>$${item.price.toFixed(2)}</td>
<td>
<input type="number" class="quantity-input" value="${item.quantity}" 
min="1" data-food-id="${item.food_id}">
</td>
<td>$${(item.price * item.quantity).toFixed(2)}</td>
<td>
<button class="btn-remove" data-food-id="${item.food_id}">
<i class="fas fa-trash"></i>
</button>
</td>
</tr>
`;
});
cartTable.innerHTML = html;
if (cartSummary) {
const subtotal = this.getCartTotal();
const tax = subtotal * 0.1; // 10% tax
const total = subtotal + tax;
cartSummary.innerHTML = `
<h3>Cart Summary</h3>
<div class="summary-item">
<span>Subtotal:</span>
<span>$${subtotal.toFixed(2)}</span>
</div>
<div class="summary-item">
<span>Tax (10%):</span>
<span>$${tax.toFixed(2)}</span>
</div>
<div class="summary-item summary-total">
<span>Total:</span>
<span>$${total.toFixed(2)}</span>
</div>
<a href="checkout.php" class="btn btn-primary" style="width: 100%; margin-top: 20px;">Proceed to Checkout</a>
`;
}
// Add event listeners
this.addCartEventListeners();
}
addCartEventListeners() {
// Quantity change
document.querySelectorAll('.quantity-input').forEach(input => {
input.addEventListener('change', (e) => {
const foodId = parseInt(e.target.dataset.foodId);
const quantity = parseInt(e.target.value);
this.updateQuantity(foodId, quantity);
});
});
// Remove buttons
document.querySelectorAll('.btn-remove').forEach(button => {
button.addEventListener('click', (e) => {
const foodId = parseInt(e.target.closest('.btn-remove').dataset.foodId);
this.removeFromCart(foodId);
});
});
}
showNotification(message) {
// Create notification element
const notification = document.createElement('div');
notification.className = 'notification';
notification.textContent = message;
notification.style.cssText = `
position: fixed;
top: 20px;
right: 20px;
background: var(--success-color);
color: white;
padding: 15px 25px;
border-radius: 5px;
z-index: 9999;
animation: slideIn 0.3s ease;
`;
document.body.appendChild(notification);
// Remove after 3 seconds
setTimeout(() => {
notification.remove();
}, 3000);
}
}
// Initialize cart
const cart = new ShoppingCart();
// Add to cart buttons
document.addEventListener('DOMContentLoaded', () => {
document.querySelectorAll('.btn-add-to-cart').forEach(button => {
button.addEventListener('click', (e) => {
const foodId = parseInt(e.target.dataset.foodId);
const foodName = e.target.closest('.food-card')?.querySelector('h3')?.textContent || 'Food Item';
const priceElement = e.target.closest('.food-card')?.querySelector('.price');
const price = parseFloat(priceElement?.textContent.replace('$', '') || '0');
cart.addToCart(foodId, foodName, price);
});
});
});

7. admin/login.php

<?php
require_once '../includes/config.php';
require_once '../includes/functions.php';
// Redirect if already logged in
if (isAdminLoggedIn()) {
redirect('dashboard.php');
}
$error = '';
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
$username = sanitize($_POST['username']);
$password = md5($_POST['password']);
$sql = "SELECT * FROM admin WHERE username = '$username' AND password = '$password'";
$result = $conn->query($sql);
if ($result->num_rows == 1) {
$admin = $result->fetch_assoc();
$_SESSION['admin_id'] = $admin['admin_id'];
$_SESSION['admin_username'] = $admin['username'];
$_SESSION['admin_name'] = $admin['full_name'];
redirect('dashboard.php');
} else {
$error = 'Invalid username or password';
}
}
?>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Admin Login - FoodieExpress</title>
<link rel="stylesheet" href="../assets/css/style.css">
<link rel="stylesheet" href="../assets/css/admin-style.css">
</head>
<body class="admin-login">
<div class="login-container">
<div class="login-box">
<h1>Admin Login</h1>
<p>FoodieExpress Administration</p>
<?php if ($error): ?>
<div class="alert alert-danger"><?php echo $error; ?></div>
<?php endif; ?>
<form method="POST" action="">
<div class="form-group">
<label for="username">Username</label>
<input type="text" id="username" name="username" required>
</div>
<div class="form-group">
<label for="password">Password</label>
<input type="password" id="password" name="password" required>
</div>
<button type="submit" class="btn btn-primary" style="width: 100%;">Login</button>
</form>
<div class="login-footer">
<a href="../index.php">Back to Website</a>
</div>
</div>
</div>
</body>
</html>

8. admin/dashboard.php

<?php
require_once '../includes/config.php';
require_once '../includes/functions.php';
// Check admin login
if (!isAdminLoggedIn()) {
redirect('login.php');
}
// Get statistics
$total_users = $conn->query("SELECT COUNT(*) as count FROM users")->fetch_assoc()['count'];
$total_orders = $conn->query("SELECT COUNT(*) as count FROM orders")->fetch_assoc()['count'];
$total_foods = $conn->query("SELECT COUNT(*) as count FROM foods")->fetch_assoc()['count'];
$total_categories = $conn->query("SELECT COUNT(*) as count FROM categories")->fetch_assoc()['count'];
// Get recent orders
$recent_orders = $conn->query("
SELECT o.*, u.full_name as customer_name 
FROM orders o 
LEFT JOIN users u ON o.user_id = u.user_id 
ORDER BY o.order_date DESC 
LIMIT 5
");
?>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Admin Dashboard - FoodieExpress</title>
<link rel="stylesheet" href="../assets/css/style.css">
<link rel="stylesheet" href="../assets/css/admin-style.css">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css">
</head>
<body>
<div class="admin-container">
<!-- Sidebar -->
<div class="admin-sidebar">
<h2>FoodieExpress Admin</h2>
<ul>
<li><a href="dashboard.php" class="active"><i class="fas fa-dashboard"></i> Dashboard</a></li>
<li><a href="categories.php"><i class="fas fa-list"></i> Categories</a></li>
<li><a href="foods.php"><i class="fas fa-utensils"></i> Food Items</a></li>
<li><a href="orders.php"><i class="fas fa-shopping-cart"></i> Orders</a></li>
<li><a href="users.php"><i class="fas fa-users"></i> Users</a></li>
<li><a href="profile.php"><i class="fas fa-user"></i> Profile</a></li>
<li><a href="logout.php"><i class="fas fa-sign-out"></i> Logout</a></li>
</ul>
</div>
<!-- Main Content -->
<div class="admin-main">
<div class="admin-header">
<h1>Dashboard</h1>
<div class="admin-user">
Welcome, <?php echo $_SESSION['admin_name']; ?>
</div>
</div>
<!-- Statistics Cards -->
<div class="stats-grid">
<div class="stat-card">
<div class="stat-icon"><i class="fas fa-users"></i></div>
<h3>Total Users</h3>
<div class="stat-number"><?php echo $total_users; ?></div>
</div>
<div class="stat-card">
<div class="stat-icon"><i class="fas fa-shopping-cart"></i></div>
<h3>Total Orders</h3>
<div class="stat-number"><?php echo $total_orders; ?></div>
</div>
<div class="stat-card">
<div class="stat-icon"><i class="fas fa-utensils"></i></div>
<h3>Food Items</h3>
<div class="stat-number"><?php echo $total_foods; ?></div>
</div>
<div class="stat-card">
<div class="stat-icon"><i class="fas fa-list"></i></div>
<h3>Categories</h3>
<div class="stat-number"><?php echo $total_categories; ?></div>
</div>
</div>
<!-- Recent Orders -->
<div class="admin-section">
<h2>Recent Orders</h2>
<table class="admin-table">
<thead>
<tr>
<th>Order #</th>
<th>Customer</th>
<th>Total</th>
<th>Status</th>
<th>Date</th>
<th>Action</th>
</tr>
</thead>
<tbody>
<?php if ($recent_orders->num_rows > 0): ?>
<?php while($order = $recent_orders->fetch_assoc()): ?>
<tr>
<td><?php echo $order['order_number']; ?></td>
<td><?php echo $order['customer_name']; ?></td>
<td>$<?php echo number_format($order['total_amount'], 2); ?></td>
<td>
<span class="status-badge status-<?php echo strtolower($order['order_status']); ?>">
<?php echo $order['order_status']; ?>
</span>
</td>
<td><?php echo date('M d, Y', strtotime($order['order_date'])); ?></td>
<td>
<a href="update-order.php?id=<?php echo $order['order_id']; ?>" class="btn-small">View</a>
</td>
</tr>
<?php endwhile; ?>
<?php else: ?>
<tr>
<td colspan="6" style="text-align: center;">No orders found</td>
</tr>
<?php endif; ?>
</tbody>
</table>
</div>
</div>
</div>
</body>
</html>

9. cart.php

<?php
require_once 'includes/config.php';
require_once 'includes/functions.php';
?>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Shopping Cart - FoodieExpress</title>
<link rel="stylesheet" href="assets/css/style.css">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css">
</head>
<body>
<!-- Navigation (same as index.php) -->
<nav class="navbar">
<!-- ... same navigation code ... -->
</nav>
<div class="cart-container">
<h1>Your Shopping Cart</h1>
<table class="cart-table">
<thead>
<tr>
<th>Image</th>
<th>Food Item</th>
<th>Price</th>
<th>Quantity</th>
<th>Subtotal</th>
<th>Action</th>
</tr>
</thead>
<tbody>
<!-- Cart items will be populated by JavaScript -->
</tbody>
</table>
<div class="cart-summary">
<!-- Cart summary will be populated by JavaScript -->
</div>
</div>
<!-- Footer (same as index.php) -->
<footer class="footer">
<!-- ... same footer code ... -->
</footer>
<script src="assets/js/main.js"></script>
<script src="assets/js/cart.js"></script>
<script>
document.addEventListener('DOMContentLoaded', () => {
cart.renderCart();
});
</script>
</body>
</html>

How to Use This Project - Step by Step Guide

Step 1: Setup Development Environment

  1. Install XAMPP/WAMP/MAMP on your computer
  2. Start Apache and MySQL services
  3. Create a folder named online-food-ordering-system in htdocs (for XAMPP) or www (for WAMP)

Step 2: Database Setup

  1. Open phpMyAdmin (http://localhost/phpmyadmin)
  2. Create a new database named food_ordering_system
  3. Import the SQL file from database/food_ordering_system.sql
  4. Verify tables are created successfully

Step 3: Configure Project

  1. Navigate to includes/config.php
  2. Update database credentials if different from default:
  • DB_HOST: localhost
  • DB_USER: root
  • DB_PASS: (empty for XAMPP)
  • DB_NAME: food_ordering_system
  1. Create upload folders:
  • assets/uploads/
  • assets/uploads/foods/
  • Set write permissions (755 or 777) for upload folders

Step 4: Access the Website

  1. Open browser and go to: http://localhost/online-food-ordering-system/
  2. You'll see the homepage with categories and recommended foods

Step 5: Test Client Side Features

  1. Register as a User:
  • Click on "Register" in navigation
  • Fill registration form with your details
  • Submit to create account
  1. Login:
  • Click on "Login"
  • Enter username and password
  • Access user dashboard
  1. Browse Menu:
  • Click on "Menu" in navigation
  • Browse food items by category
  • Use search functionality
  1. Add to Cart:
  • Click "Add to Cart" on any food item
  • View cart by clicking cart icon
  • Update quantities or remove items
  1. Place Order:
  • Go to cart page
  • Click "Proceed to Checkout"
  • Enter delivery details
  • Confirm order
  1. View Orders:
  • Go to user dashboard
  • Click on "My Orders"
  • View order history and status

Step 6: Test Admin Side Features

  1. Admin Login:
  • Go to: http://localhost/online-food-ordering-system/admin/login.php
  • Username: admin
  • Password: admin123
  1. Manage Categories:
  • Click on "Categories" in sidebar
  • Add new categories with images
  • Edit or delete existing categories
  1. Manage Food Items:
  • Click on "Food Items" in sidebar
  • Add new food items with details
  • Upload food images
  • Set prices and availability
  1. Manage Orders:
  • Click on "Orders" in sidebar
  • View all customer orders
  • Update order status
  • Process orders
  1. View Users:
  • Click on "Users" in sidebar
  • View registered customers
  • Monitor user activity

Step 7: Customize the Project

  1. Change Site Name: Update SITE_NAME in includes/config.php
  2. Modify Colors: Edit CSS variables in assets/css/style.css
  3. Add Logo: Replace logo in navigation
  4. Update Content: Modify text in HTML files
  5. Add Payment Gateway: Integrate PayPal/Stripe in checkout

Step 8: Deploy to Live Server (Optional)

  1. Purchase domain and hosting
  2. Upload all files to server
  3. Create MySQL database on server
  4. Import SQL file
  5. Update database credentials in config.php
  6. Test all functionality

Security Features Implemented

  • Password hashing using MD5 (consider using password_hash() for production)
  • SQL injection prevention through mysqli real_escape_string
  • Session management for user/admin authentication
  • Input sanitization
  • File upload validation
  • Protected admin pages

Future Enhancements Possible

  1. Online payment integration
  2. Email notifications for orders
  3. SMS alerts for order status
  4. Restaurant rating and reviews
  5. Multiple restaurant support
  6. Coupon and discount system
  7. Real-time order tracking
  8. Mobile app development
  9. Advanced analytics dashboard
  10. Multi-language support

This complete Online Food Ordering System provides a solid foundation for a food delivery platform. The code is modular, well-structured, and can be easily extended based on specific requirements. Both admin and client interfaces are fully functional with all core features implemented.

Leave a Reply

Your email address will not be published. Required fields are marked *


Macro Nepal Helper