exec("CREATE TABLE IF NOT EXISTS `projects` ( `id` int(11) NOT NULL AUTO_INCREMENT, `title` varchar(200) NOT NULL, `description` text NOT NULL, `client_name` varchar(150) DEFAULT '', `location` varchar(255) DEFAULT '', `budget` decimal(12,2) DEFAULT 0, `materials` varchar(500) DEFAULT '', `completion_date` date DEFAULT NULL, `thumbnail` varchar(255) DEFAULT '', `gallery_images` text DEFAULT NULL, `is_featured` tinyint(1) DEFAULT 0, `is_active` tinyint(1) DEFAULT 1, `created_at` timestamp NOT NULL DEFAULT current_timestamp(), PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4"); $pdo->exec("CREATE TABLE IF NOT EXISTS `project_images` ( `id` int(11) NOT NULL AUTO_INCREMENT, `project_id` int(11) NOT NULL, `image` varchar(255) NOT NULL, `sort_order` int(11) DEFAULT 0, `created_at` timestamp NOT NULL DEFAULT current_timestamp(), PRIMARY KEY (`id`), KEY `project_id` (`project_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4"); } catch(Exception $e) {} $upload_dir = '../uploads/projects/'; if (!is_dir($upload_dir)) { @mkdir($upload_dir, 0777, true); } $upload_ok = is_writable($upload_dir); // Handle Delete Single Image if (isset($_GET['del_img']) && isset($_GET['pid'])) { $img_id = (int)$_GET['del_img']; $pid = (int)$_GET['pid']; try { $stmt = $pdo->prepare("SELECT image FROM project_images WHERE id=? AND project_id=?"); $stmt->execute([$img_id, $pid]); $img = $stmt->fetch(); if ($img) { @unlink($upload_dir . $img['image']); $pdo->prepare("DELETE FROM project_images WHERE id=?")->execute([$img_id]); $msg = "
Image deleted successfully.
"; } } catch(Exception $e) {} } // Handle Delete Project if (isset($_GET['delete'])) { $id = (int)$_GET['delete']; try { // Remove project images files $stmt = $pdo->prepare("SELECT image FROM project_images WHERE project_id=?"); $stmt->execute([$id]); foreach($stmt->fetchAll() as $img) @unlink($upload_dir . $img['image']); // Remove thumbnail $stmt2 = $pdo->prepare("SELECT thumbnail FROM projects WHERE id=?"); $stmt2->execute([$id]); $proj = $stmt2->fetch(); if ($proj) @unlink($upload_dir . $proj['thumbnail']); // DB delete (cascades project_images) $pdo->prepare("DELETE FROM projects WHERE id=?")->execute([$id]); $msg = "
Project deleted successfully.
"; } catch(Exception $e) { $msg = "
Error deleting project.
"; } } // Handle Add Project if ($_SERVER['REQUEST_METHOD'] == 'POST' && isset($_POST['action']) && $_POST['action'] == 'add') { $title = trim($_POST['title'] ?? ''); $desc = trim($_POST['description'] ?? ''); $client = trim($_POST['client_name'] ?? ''); $location = trim($_POST['location'] ?? ''); $budget = (float)($_POST['budget'] ?? 0); $materials = trim($_POST['materials'] ?? ''); $date = !empty($_POST['completion_date']) ? $_POST['completion_date'] : null; if (empty($title) || empty($desc)) { $msg = "
Please fill in the Title and Description fields.
"; } else { $thumbnail = ''; $all_images = []; $upload_errors = []; // Handle image uploads if (!empty($_FILES['images']['name'][0])) { if (!$upload_ok) { $upload_errors[] = 'Upload directory is not writable on the server.'; } else { foreach ($_FILES['images']['name'] as $k => $name) { if ($name && $_FILES['images']['error'][$k] == UPLOAD_ERR_OK) { $ext = strtolower(pathinfo($name, PATHINFO_EXTENSION)); $allowed = ['jpg','jpeg','png','gif','webp']; if (!in_array($ext, $allowed)) { $upload_errors[] = "File '$name' is not an allowed image type."; continue; } $fname = time() . '_' . $k . '_' . preg_replace('/[^a-zA-Z0-9._-]/', '_', $name); if (move_uploaded_file($_FILES['images']['tmp_name'][$k], $upload_dir . $fname)) { $all_images[] = $fname; if (empty($thumbnail)) $thumbnail = $fname; } else { $upload_errors[] = "Failed to upload '$name'."; } } elseif ($_FILES['images']['error'][$k] != UPLOAD_ERR_NO_FILE) { $upload_errors[] = "Upload error code " . $_FILES['images']['error'][$k] . " for file '$name'."; } } } } try { $stmt = $pdo->prepare("INSERT INTO projects (title, description, client_name, location, budget, materials, completion_date, thumbnail, gallery_images) VALUES (?,?,?,?,?,?,?,?,?)"); $stmt->execute([$title, $desc, $client, $location, $budget, $materials, $date, $thumbnail, json_encode($all_images)]); $project_id = $pdo->lastInsertId(); // Insert images into project_images table foreach ($all_images as $idx => $img) { $pdo->prepare("INSERT INTO project_images (project_id, image, sort_order) VALUES (?,?,?)")->execute([$project_id, $img, $idx]); } $flash = 'Project added successfully!'; if (!empty($upload_errors)) { $flash .= ' (Some images had issues: ' . implode(', ', $upload_errors) . ')'; } $msg = "
$flash
"; } catch(Exception $e) { $msg = "
Database Error: " . e($e->getMessage()) . "
"; } } } // Handle Edit Project if ($_SERVER['REQUEST_METHOD'] == 'POST' && isset($_POST['action']) && $_POST['action'] == 'edit') { $id = (int)$_POST['id']; $title = $_POST['title']; $desc = $_POST['description']; $client = $_POST['client_name']; $location = $_POST['location']; $budget = (float)$_POST['budget']; $materials= $_POST['materials']; $date = $_POST['completion_date'] ?: null; $new_images = []; if (!empty($_FILES['images']['name'][0])) { foreach ($_FILES['images']['name'] as $k => $name) { if ($name && $_FILES['images']['error'][$k] == 0) { $fname = time() . '_' . $k . '_' . preg_replace('/[^a-zA-Z0-9._-]/', '_', $name); move_uploaded_file($_FILES['images']['tmp_name'][$k], $upload_dir . $fname); $new_images[] = $fname; } } } try { // Get current thumbnail $stmt = $pdo->prepare("SELECT thumbnail FROM projects WHERE id=?"); $stmt->execute([$id]); $existing = $stmt->fetch(); // Get current images $stmt2 = $pdo->prepare("SELECT image FROM project_images WHERE project_id=? ORDER BY sort_order"); $stmt2->execute([$id]); $current_imgs = array_column($stmt2->fetchAll(), 'image'); // Insert new images $start_order = count($current_imgs); foreach ($new_images as $idx => $img) { $pdo->prepare("INSERT INTO project_images (project_id, image, sort_order) VALUES (?,?,?)")->execute([$id, $img, $start_order + $idx]); } // Get updated image list for gallery_images $all_imgs = array_merge($current_imgs, $new_images); $thumbnail = $existing['thumbnail'] ?: ($all_imgs[0] ?? ''); $pdo->prepare("UPDATE projects SET title=?, description=?, client_name=?, location=?, budget=?, materials=?, completion_date=?, thumbnail=?, gallery_images=? WHERE id=?") ->execute([$title, $desc, $client, $location, $budget, $materials, $date, $thumbnail, json_encode($all_imgs), $id]); $msg = "
Project updated successfully!
"; } catch(Exception $e) { $msg = "
Error: " . e($e->getMessage()) . "
"; } } // Fetch all projects $projects = []; try { $stmt = $pdo->query("SELECT p.*, (SELECT COUNT(*) FROM project_images WHERE project_id=p.id) as img_count FROM projects p ORDER BY p.created_at DESC"); $projects = $stmt->fetchAll(); } catch(Exception $e) {} // If editing, fetch edit data $edit_project = null; $edit_images = []; if (isset($_GET['edit'])) { $edit_id = (int)$_GET['edit']; try { $stmt = $pdo->prepare("SELECT * FROM projects WHERE id=?"); $stmt->execute([$edit_id]); $edit_project = $stmt->fetch(); $stmt2 = $pdo->prepare("SELECT * FROM project_images WHERE project_id=? ORDER BY sort_order"); $stmt2->execute([$edit_id]); $edit_images = $stmt2->fetchAll(); } catch(Exception $e) {} } ?>

Our Projects

Editing: Cancel
Hold Ctrl/Cmd to select multiple images
Cancel
>
Photo Title Location Budget Photos Date Actions
No projects added yet. Click Add Project to get started.
photos