| Server IP : 188.114.96.3 / Your IP : 216.73.216.143 Web Server : Apache System : Linux sv058.home.net.pl 6.8.2 husak_dirty_pages_fix #1 SMP PREEMPT_DYNAMIC Tue Apr 2 22:06:51 CEST 2024 x86_64 User : ( 3194769) PHP Version : 8.5.12 Disable Function : NONE MySQL : OFF | cURL : ON | WGET : ON | Perl : ON | Python : ON | Sudo : ON | Pkexec : OFF Directory : /polana/admin/ |
Upload File : |
<?php
declare(strict_types=1);
require_once dirname(__DIR__) . '/includes/import_menu.php';
require_login();
ensure_import_schema();
$mediaLibrary = media_library(120);
$id = (int)($_GET['id'] ?? 0);
$categoryId = (int)($_GET['category_id'] ?? 0);
$item = null;
if ($id > 0) {
$stmt = db()->prepare(
'SELECT i.*, c.menu_id, c.name AS category_name
FROM menu_items i
JOIN menu_categories c ON c.id=i.category_id
WHERE i.id=?'
);
$stmt->execute([$id]);
$item = $stmt->fetch();
if (!$item) {
http_response_code(404);
exit('Nie znaleziono pozycji.');
}
$categoryId = (int)$item['category_id'];
} else {
$stmt = db()->prepare('SELECT * FROM menu_categories WHERE id=?');
$stmt->execute([$categoryId]);
$category = $stmt->fetch();
if (!$category) {
http_response_code(404);
exit('Nie znaleziono kategorii.');
}
$item = [
'id' => 0,
'category_id' => $categoryId,
'menu_id' => (int)$category['menu_id'],
'category_name' => $category['name'],
'name' => '',
'name_en' => '',
'name_es' => '', 'name_de' => '',
'description_es' => '', 'description_de' => '',
'ingredients_es' => '', 'ingredients_de' => '',
'allergens_es' => '', 'allergens_de' => '',
'description_en' => '',
'ingredients_en' => '',
'allergens_en' => '',
'description' => '',
'ingredients' => '',
'price' => '',
'price_text' => '',
'weight' => '',
'allergens' => '',
'image_path' => '',
'available' => 1,
'active' => 1,
'featured' => 0,
'sort_order' => 0,
];
}
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
verify_csrf();
$action = (string)($_POST['action'] ?? 'save');
if ($action === 'delete' && $id > 0) {
$stmt = db()->prepare('DELETE FROM menu_items WHERE id=?');
$stmt->execute([$id]);
admin_log('item_delete', 'Usunięto pozycję #' . $id);
flash('success', 'Pozycja została usunięta.');
redirect('/admin/menu.php?id=' . (int)$item['menu_id']);
}
try {
$imagePath = $item['image_path'] ?: null;
if (!empty($_FILES['image']['name'])) {
$newPath = upload_file(
$_FILES['image'],
'uploads/dishes',
['image/jpeg', 'image/png', 'image/webp'],
8 * 1024 * 1024
);
if ($newPath) {
$imagePath = $newPath;
}
}
$libraryImageId = (int)($_POST['library_image_id'] ?? 0);
if ($libraryImageId > 0) {
$stmtMedia = db()->prepare('SELECT file_path FROM media_library WHERE id=? LIMIT 1');
$stmtMedia->execute([$libraryImageId]);
$libraryPath = $stmtMedia->fetchColumn();
if (is_string($libraryPath) && $libraryPath !== '') {
$imagePath = $libraryPath;
}
}
if (!empty($_POST['remove_image'])) {
$imagePath = null;
}
$priceRaw = str_replace(',', '.', trim((string)($_POST['price'] ?? '')));
$price = $priceRaw !== '' ? (float)$priceRaw : null;
$values = [
trim((string)$_POST['name']),
trim((string)($_POST['name_en'] ?? '')),
trim((string)($_POST['name_es'] ?? '')),
trim((string)($_POST['name_de'] ?? '')),
trim((string)($_POST['description'] ?? '')),
trim((string)($_POST['description_en'] ?? '')),
trim((string)($_POST['description_es'] ?? '')),
trim((string)($_POST['description_de'] ?? '')),
trim((string)($_POST['ingredients'] ?? '')),
trim((string)($_POST['ingredients_en'] ?? '')),
trim((string)($_POST['ingredients_es'] ?? '')),
trim((string)($_POST['ingredients_de'] ?? '')),
$price,
trim((string)($_POST['price_text'] ?? '')),
trim((string)($_POST['weight'] ?? '')),
trim((string)($_POST['allergens'] ?? '')),
trim((string)($_POST['allergens_en'] ?? '')),
trim((string)($_POST['allergens_es'] ?? '')),
trim((string)($_POST['allergens_de'] ?? '')),
$imagePath,
isset($_POST['available']) ? 1 : 0,
isset($_POST['active']) ? 1 : 0,
isset($_POST['featured']) ? 1 : 0,
(int)($_POST['sort_order'] ?? 0),
];
if ($id > 0) {
$stmt = db()->prepare(
'UPDATE menu_items SET
name=?, name_en=?, name_es=?, name_de=?, description=?, description_en=?, description_es=?, description_de=?, ingredients=?, ingredients_en=?, ingredients_es=?, ingredients_de=?, price=?, price_text=?, weight=?, allergens=?, allergens_en=?, allergens_es=?, allergens_de=?,
image_path=?, available=?, active=?, featured=?, sort_order=?
WHERE id=?'
);
$stmt->execute([...$values, $id]);
admin_log('item_update', 'Zapisano pozycję #' . $id);
} else {
$stmt = db()->prepare(
'INSERT INTO menu_items
(category_id, name, name_en, name_es, name_de, description, description_en, description_es, description_de, ingredients, ingredients_en, ingredients_es, ingredients_de, price, price_text, weight, allergens, allergens_en, allergens_es, allergens_de,
image_path, available, active, featured, sort_order)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)'
);
$stmt->execute([$categoryId, ...$values]);
$id = (int)db()->lastInsertId();
admin_log('item_create', 'Dodano pozycję #' . $id);
}
flash('success', 'Pozycja zapisana.');
redirect('/admin/menu.php?id=' . (int)$item['menu_id']);
} catch (Throwable $e) {
flash('error', $e->getMessage());
redirect($_SERVER['REQUEST_URI']);
}
}
$menuTypeStmt = db()->prepare('SELECT menu_type FROM menus WHERE id=? LIMIT 1');
$menuTypeStmt->execute([(int)$item['menu_id']]);
$menuType = polana_menu_type((string)($menuTypeStmt->fetchColumn() ?: 'food'));
$itemLabel = $menuType === 'wine' ? 'wina' : ($menuType === 'soft' ? 'napoju' : 'dania');
render_admin_header($id ? 'Edycja ' . $itemLabel : ($menuType === 'wine' ? 'Nowe wino' : ($menuType === 'soft' ? 'Nowy napój' : 'Nowe danie')));
?>
<div class="admin-title-row">
<div>
<h1><?= $id ? 'Edytuj pozycję' : 'Dodaj pozycję' ?></h1>
<p>Kategoria: <?= e($item['category_name']) ?></p>
</div>
<a class="btn btn-light" href="/admin/menu.php?id=<?= (int)$item['menu_id'] ?>">← Wróć</a>
</div>
<form class="form-card form-grid" method="post" enctype="multipart/form-data">
<?= csrf_field() ?>
<input type="hidden" name="action" value="save">
<label class="full">
Nazwa <?= e($itemLabel) ?>
<input name="name" value="<?= e($item['name']) ?>" required>
</label>
<label class="full">
Nazwa angielska (EN)
<input name="name_en" value="<?= e($item['name_en'] ?? '') ?>" placeholder="<?= e($menuType === 'wine' ? 'Wine name / grape / vintage' : 'English name of the dish or drink') ?>">
</label>
<?php foreach (['es'=>'Hiszpański (ES)','de'=>'Niemiecki (DE)'] as $language=>$languageLabel): ?>
<label class="full">
Nazwa: <?= e($languageLabel) ?> — ręczna edycja
<input name="name_<?= e($language) ?>" value="<?= e($item['name_'.$language] ?? '') ?>" maxlength="255">
</label>
<?php endforeach; ?>
<label class="full">
Opis
<textarea name="description"><?= e($item['description']) ?></textarea>
</label>
<label class="full">
Opis po angielsku (EN)
<textarea name="description_en"><?= e($item['description_en'] ?? '') ?></textarea>
</label>
<?php foreach (['es'=>'Hiszpański (ES)','de'=>'Niemiecki (DE)'] as $language=>$languageLabel): ?>
<label class="full">Opis: <?= e($languageLabel) ?>
<textarea name="description_<?= e($language) ?>" rows="3"><?= e($item['description_'.$language] ?? '') ?></textarea></label>
<?php endforeach; ?>
<label class="full">
Składniki
<textarea name="ingredients" rows="4" placeholder="np. wołowina, ogórek kiszony, ziemniak..."><?= e($item['ingredients'] ?? '') ?></textarea>
<span class="muted">Pełny wykaz składników dla informacji o daniu i alergenach.</span>
</label>
<label class="full">
Ingredients (EN)
<textarea name="ingredients_en" rows="3" placeholder="English translation – verify allergens carefully"><?= e($item['ingredients_en'] ?? '') ?></textarea>
</label>
<?php foreach (['es'=>'Hiszpański (ES)','de'=>'Niemiecki (DE)'] as $language=>$languageLabel): ?>
<label class="full">Składniki: <?= e($languageLabel) ?>
<textarea name="ingredients_<?= e($language) ?>" rows="3"><?= e($item['ingredients_'.$language] ?? '') ?></textarea></label>
<?php endforeach; ?>
<label>
Cena [zł]
<input name="price" inputmode="decimal"
value="<?= $item['price'] !== null && $item['price'] !== '' ? e(number_format((float)$item['price'], 2, '.', '')) : '' ?>"
placeholder="39.00">
</label>
<label>
Cena tekstowa – opcjonalnie
<input name="price_text" value="<?= e($item['price_text']) ?>" placeholder="<?= e($menuType === 'wine' ? 'np. 150 ml — 29 zł / 750 ml — 139 zł' : 'np. 15 zł / 100 g') ?>">
<?php if ($menuType === 'wine'): ?><span class="muted">Dla różnych cen kieliszka i butelki użyj ceny tekstowej. Jest wyświetlana w menu PL/EN i PDF.</span><?php endif; ?>
</label>
<label>
Gramatura / pojemność
<input name="weight" value="<?= e($item['weight']) ?>" placeholder="<?= e($menuType === 'wine' ? 'np. 150 ml / 750 ml' : 'np. 250 g') ?>">
</label>
<label>
Kolejność
<input type="number" name="sort_order" value="<?= (int)$item['sort_order'] ?>">
</label>
<label class="full">
Alergeny
<input name="allergens" value="<?= e($item['allergens']) ?>" placeholder="np. gluten (pszenica), mleko, jaja, gorczyca">
</label>
<label class="full">
Allergens (EN)
<input name="allergens_en" value="<?= e($item['allergens_en'] ?? '') ?>" placeholder="e.g. gluten, milk, eggs">
</label>
<?php foreach (['es'=>'Hiszpański (ES)','de'=>'Niemiecki (DE)'] as $language=>$languageLabel): ?>
<label class="full">Alergeny: <?= e($languageLabel) ?>
<input name="allergens_<?= e($language) ?>" value="<?= e($item['allergens_'.$language] ?? '') ?>" maxlength="500"></label>
<?php endforeach; ?>
<label class="full">
Zdjęcie JPG/PNG/WebP
<input type="file" name="image" accept="image/jpeg,image/png,image/webp">
</label>
<?php if ($mediaLibrary): ?>
<label class="full">
albo wybierz z biblioteki
<select name="library_image_id">
<option value="">— bez zmiany —</option>
<?php foreach ($mediaLibrary as $media): ?>
<option value="<?= (int)$media['id'] ?>">
<?= e($media['alt_text'] ?: $media['original_name'] ?: basename($media['file_path'])) ?>
</option>
<?php endforeach; ?>
</select>
</label>
<div class="full">
<a class="btn btn-light btn-small" href="/admin/media.php" target="_blank">Otwórz bibliotekę zdjęć ↗</a>
</div>
<?php endif; ?>
<?php if (!empty($item['image_path'])): ?>
<div class="full">
<img src="<?= e($item['image_path']) ?>" alt="" style="width:180px;border-radius:12px">
<label class="check-row">
<input type="checkbox" name="remove_image" value="1"> Usuń zdjęcie
</label>
</div>
<?php endif; ?>
<label class="check-row">
<input type="checkbox" name="available" value="1" <?= (int)$item['available'] ? 'checked' : '' ?>>
Dostępne
</label>
<label class="check-row">
<input type="checkbox" name="active" value="1" <?= (int)$item['active'] ? 'checked' : '' ?>>
Widoczne
</label>
<label class="check-row">
<input type="checkbox" name="featured" value="1" <?= (int)$item['featured'] ? 'checked' : '' ?>>
Wyróżnione
</label>
<div class="full">
<button class="btn btn-primary" type="submit">Zapisz</button>
</div>
</form>
<?php if ($id): ?>
<form method="post" class="form-card" onsubmit="return confirm('Na pewno usunąć tę pozycję?')">
<?= csrf_field() ?>
<input type="hidden" name="action" value="delete">
<button class="btn btn-danger" type="submit">Usuń pozycję</button>
</form>
<?php endif; ?>
<?php render_admin_footer(); ?>