2026-03-22 22:16:44 +01:00
|
|
|
<?php
|
|
|
|
|
session_start();
|
|
|
|
|
require __DIR__ . '/helpers.php';
|
|
|
|
|
|
2026-05-23 13:29:35 +02:00
|
|
|
$ADMIN_KEY = getenv('FLIXCOOKS_ADMIN_KEY') ?: '';
|
2026-03-22 22:16:44 +01:00
|
|
|
$authed = isset($_SESSION['fc_admin']) && $_SESSION['fc_admin'] === true;
|
|
|
|
|
|
2026-05-23 13:29:35 +02:00
|
|
|
if ($ADMIN_KEY === '') {
|
|
|
|
|
http_response_code(503);
|
|
|
|
|
?>
|
|
|
|
|
<!doctype html>
|
|
|
|
|
<html lang="en">
|
|
|
|
|
<head>
|
|
|
|
|
<meta charset="UTF-8">
|
|
|
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
|
|
|
<title>FlixCooks Admin Unavailable</title>
|
|
|
|
|
<link rel="stylesheet" href="/assets/style.css">
|
|
|
|
|
<style>
|
|
|
|
|
body { display: grid; place-items: center; min-height: 100vh; }
|
|
|
|
|
.login-card { background: #fff; padding: 24px; border-radius: 16px; box-shadow: var(--shadow); width: min(420px, 90vw); }
|
|
|
|
|
.error { color: #b00020; margin: 0; }
|
|
|
|
|
</style>
|
|
|
|
|
</head>
|
|
|
|
|
<body>
|
|
|
|
|
<div class="login-card">
|
|
|
|
|
<h1>Admin unavailable</h1>
|
|
|
|
|
<p class="error">FLIXCOOKS_ADMIN_KEY is not configured.</p>
|
|
|
|
|
</div>
|
|
|
|
|
</body>
|
|
|
|
|
</html>
|
|
|
|
|
<?php
|
|
|
|
|
exit;
|
|
|
|
|
}
|
|
|
|
|
|
2026-03-22 22:16:44 +01:00
|
|
|
if (!$authed && isset($_POST['password'])) {
|
|
|
|
|
if (hash_equals($ADMIN_KEY, $_POST['password'])) {
|
|
|
|
|
$_SESSION['fc_admin'] = true;
|
|
|
|
|
$authed = true;
|
|
|
|
|
} else {
|
|
|
|
|
$error = 'Wrong password';
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!$authed) {
|
|
|
|
|
?>
|
|
|
|
|
<!doctype html>
|
|
|
|
|
<html lang="en">
|
|
|
|
|
<head>
|
|
|
|
|
<meta charset="UTF-8">
|
|
|
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
|
|
|
<title>FlixCooks Admin Login</title>
|
|
|
|
|
<link rel="stylesheet" href="/assets/style.css">
|
|
|
|
|
<style>
|
|
|
|
|
body { display: grid; place-items: center; min-height: 100vh; }
|
|
|
|
|
.login-card { background: #fff; padding: 24px; border-radius: 16px; box-shadow: var(--shadow); width: min(360px, 90vw); }
|
|
|
|
|
.login-card h1 { margin: 0 0 12px; }
|
|
|
|
|
.login-card form { display: grid; gap: 12px; }
|
|
|
|
|
.login-card input { padding: 12px; border-radius: 10px; border: 1px solid rgba(0,0,0,0.1); }
|
|
|
|
|
.login-card button { padding: 12px; border-radius: 10px; border: none; background: var(--accent); color: #fff; font-weight: 700; cursor: pointer; }
|
|
|
|
|
.error { color: #b00020; margin: 0; }
|
|
|
|
|
</style>
|
|
|
|
|
</head>
|
|
|
|
|
<body>
|
|
|
|
|
<div class="login-card">
|
|
|
|
|
<h1>Admin</h1>
|
|
|
|
|
<p>Enter your password to manage recipes.</p>
|
|
|
|
|
<?php if (!empty($error)): ?><p class="error"><?php echo e($error); ?></p><?php endif; ?>
|
|
|
|
|
<form method="post">
|
|
|
|
|
<input type="password" name="password" placeholder="Password" required>
|
|
|
|
|
<button type="submit">Login</button>
|
|
|
|
|
</form>
|
|
|
|
|
</div>
|
|
|
|
|
</body>
|
|
|
|
|
</html>
|
|
|
|
|
<?php
|
|
|
|
|
exit;
|
|
|
|
|
}
|
|
|
|
|
|
2026-05-23 10:23:28 +02:00
|
|
|
try {
|
|
|
|
|
$allRecipes = load_recipes();
|
2026-06-18 09:53:39 +02:00
|
|
|
$siteSettings = load_site_settings();
|
2026-05-23 10:23:28 +02:00
|
|
|
} catch (DatabaseUnavailableException $e) {
|
|
|
|
|
handle_database_unavailable($e);
|
|
|
|
|
}
|
2026-03-22 22:16:44 +01:00
|
|
|
$message = null;
|
2026-03-23 16:26:45 +01:00
|
|
|
$errors = [];
|
2026-03-22 22:16:44 +01:00
|
|
|
$editing = null;
|
|
|
|
|
$editIndex = null;
|
|
|
|
|
$editingEn = [];
|
|
|
|
|
$editingDe = [];
|
2026-03-23 16:26:45 +01:00
|
|
|
$view = (isset($_GET['view']) && $_GET['view'] === 'settings') ? 'settings' : 'recipes';
|
|
|
|
|
|
|
|
|
|
if (empty($_SESSION['csrf_token'])) {
|
|
|
|
|
$_SESSION['csrf_token'] = bin2hex(random_bytes(16));
|
|
|
|
|
}
|
2026-03-22 22:16:44 +01:00
|
|
|
|
|
|
|
|
if (isset($_GET['edit'])) {
|
|
|
|
|
$slugEdit = trim($_GET['edit']);
|
|
|
|
|
foreach ($allRecipes as $idx => $r) {
|
|
|
|
|
if (($r['slug'] ?? '') === $slugEdit) {
|
|
|
|
|
$editing = $r;
|
|
|
|
|
$editIndex = $idx;
|
|
|
|
|
$editingEn = $r['i18n']['en'] ?? [];
|
|
|
|
|
$editingDe = $r['i18n']['de'] ?? [];
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2026-03-23 16:26:45 +01:00
|
|
|
if ($_SERVER['REQUEST_METHOD'] === 'POST' && ($_POST['action'] ?? '') === 'save_settings') {
|
|
|
|
|
if (!hash_equals($_SESSION['csrf_token'] ?? '', $_POST['token'] ?? '')) {
|
|
|
|
|
$errors[] = 'Invalid form token, please retry.';
|
|
|
|
|
} else {
|
|
|
|
|
$imprint = $siteSettings['imprint'];
|
|
|
|
|
$privacy = $siteSettings['privacy'];
|
|
|
|
|
|
|
|
|
|
$imprint['de']['owner_name'] = trim($_POST['owner_name_de'] ?? $imprint['de']['owner_name']);
|
|
|
|
|
$imprint['en']['owner_name'] = trim($_POST['owner_name_en'] ?? $imprint['en']['owner_name']);
|
|
|
|
|
$imprint['de']['address'] = trim($_POST['address_de'] ?? $imprint['de']['address']);
|
|
|
|
|
$imprint['en']['address'] = trim($_POST['address_en'] ?? $imprint['en']['address']);
|
|
|
|
|
$imprint['de']['email'] = trim($_POST['email_de'] ?? $imprint['de']['email']);
|
|
|
|
|
$imprint['en']['email'] = trim($_POST['email_en'] ?? $imprint['en']['email']);
|
|
|
|
|
$imprint['de']['phone'] = trim($_POST['phone_de'] ?? $imprint['de']['phone']);
|
|
|
|
|
$imprint['en']['phone'] = trim($_POST['phone_en'] ?? $imprint['en']['phone']);
|
|
|
|
|
$imprint['de']['legal_form'] = trim($_POST['legal_form_de'] ?? $imprint['de']['legal_form']);
|
|
|
|
|
$imprint['en']['legal_form'] = trim($_POST['legal_form_en'] ?? $imprint['en']['legal_form']);
|
|
|
|
|
$imprint['de']['business_purpose'] = trim($_POST['business_purpose_de'] ?? $imprint['de']['business_purpose']);
|
|
|
|
|
$imprint['en']['business_purpose'] = trim($_POST['business_purpose_en'] ?? $imprint['en']['business_purpose']);
|
|
|
|
|
$imprint['de']['wko_membership'] = trim($_POST['wko_de'] ?? $imprint['de']['wko_membership']);
|
|
|
|
|
$imprint['en']['wko_membership'] = trim($_POST['wko_en'] ?? $imprint['en']['wko_membership']);
|
|
|
|
|
$imprint['de']['authority'] = trim($_POST['authority_de'] ?? $imprint['de']['authority']);
|
|
|
|
|
$imprint['en']['authority'] = trim($_POST['authority_en'] ?? $imprint['en']['authority']);
|
|
|
|
|
$imprint['de']['uid'] = trim($_POST['uid_de'] ?? $imprint['de']['uid']);
|
|
|
|
|
$imprint['en']['uid'] = trim($_POST['uid_en'] ?? $imprint['en']['uid']);
|
|
|
|
|
$imprint['de']['odr'] = trim($_POST['odr_link'] ?? $imprint['de']['odr']);
|
|
|
|
|
$imprint['en']['odr'] = $imprint['de']['odr'];
|
|
|
|
|
$imprint['de']['last_updated'] = date('Y-m-d');
|
|
|
|
|
$imprint['en']['last_updated'] = date('Y-m-d');
|
|
|
|
|
|
|
|
|
|
$privacy['de']['controller'] = trim($_POST['controller_de'] ?? $privacy['de']['controller']);
|
|
|
|
|
$privacy['en']['controller'] = trim($_POST['controller_en'] ?? $privacy['en']['controller']);
|
|
|
|
|
$privacy['de']['address'] = trim($_POST['privacy_address_de'] ?? $privacy['de']['address']);
|
|
|
|
|
$privacy['en']['address'] = trim($_POST['privacy_address_en'] ?? $privacy['en']['address']);
|
|
|
|
|
$privacy['de']['contact_email'] = trim($_POST['privacy_email_de'] ?? $privacy['de']['contact_email']);
|
|
|
|
|
$privacy['en']['contact_email'] = trim($_POST['privacy_email_en'] ?? $privacy['en']['contact_email']);
|
|
|
|
|
$privacy['de']['contact_phone'] = trim($_POST['privacy_phone_de'] ?? $privacy['de']['contact_phone']);
|
|
|
|
|
$privacy['en']['contact_phone'] = trim($_POST['privacy_phone_en'] ?? $privacy['en']['contact_phone']);
|
|
|
|
|
$privacy['de']['hosting_provider'] = trim($_POST['hosting_de'] ?? $privacy['de']['hosting_provider']);
|
|
|
|
|
$privacy['en']['hosting_provider'] = trim($_POST['hosting_en'] ?? $privacy['en']['hosting_provider']);
|
|
|
|
|
$privacy['de']['cookie_statement'] = trim($_POST['cookie_de'] ?? $privacy['de']['cookie_statement']);
|
|
|
|
|
$privacy['en']['cookie_statement'] = trim($_POST['cookie_en'] ?? $privacy['en']['cookie_statement']);
|
|
|
|
|
$privacy['de']['purposes'] = trim($_POST['purposes_de'] ?? $privacy['de']['purposes']);
|
|
|
|
|
$privacy['en']['purposes'] = trim($_POST['purposes_en'] ?? $privacy['en']['purposes']);
|
|
|
|
|
$privacy['de']['log_retention_days'] = (int) ($_POST['log_retention'] ?? $privacy['de']['log_retention_days']);
|
|
|
|
|
$privacy['en']['log_retention_days'] = $privacy['de']['log_retention_days'];
|
|
|
|
|
$privacy['de']['last_updated'] = date('Y-m-d');
|
|
|
|
|
$privacy['en']['last_updated'] = date('Y-m-d');
|
|
|
|
|
|
|
|
|
|
// Require core fields
|
|
|
|
|
$requiredPairs = [
|
|
|
|
|
['imprint', 'owner_name', 'Owner name'],
|
|
|
|
|
['imprint', 'address', 'Address'],
|
|
|
|
|
['imprint', 'email', 'Email'],
|
|
|
|
|
['imprint', 'phone', 'Phone'],
|
|
|
|
|
['imprint', 'business_purpose', 'Business purpose'],
|
|
|
|
|
['privacy', 'controller', 'Controller'],
|
|
|
|
|
['privacy', 'contact_email', 'Privacy email'],
|
|
|
|
|
['privacy', 'contact_phone', 'Privacy phone'],
|
|
|
|
|
['privacy', 'hosting_provider', 'Hosting provider'],
|
|
|
|
|
['privacy', 'cookie_statement', 'Cookie statement'],
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
foreach ($requiredPairs as [$section, $key, $label]) {
|
|
|
|
|
$deVal = ${$section}['de'][$key] ?? '';
|
|
|
|
|
$enVal = ${$section}['en'][$key] ?? '';
|
|
|
|
|
if ($deVal === '' && $enVal !== '') {
|
|
|
|
|
${$section}['de'][$key] = $enVal;
|
|
|
|
|
} elseif ($enVal === '' && $deVal !== '') {
|
|
|
|
|
${$section}['en'][$key] = $deVal;
|
|
|
|
|
} elseif ($deVal === '' && $enVal === '') {
|
|
|
|
|
$errors[] = $label . ' is required (DE or EN).';
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (empty($errors)) {
|
|
|
|
|
$siteSettings['imprint'] = $imprint;
|
|
|
|
|
$siteSettings['privacy'] = $privacy;
|
|
|
|
|
if (save_site_settings($siteSettings)) {
|
2026-06-18 09:53:39 +02:00
|
|
|
$siteSettings = load_site_settings(true);
|
2026-03-23 16:26:45 +01:00
|
|
|
$message = 'Settings saved.';
|
|
|
|
|
} else {
|
2026-06-18 09:53:39 +02:00
|
|
|
$errors[] = 'Could not save settings. Check the database connection.';
|
2026-03-23 16:26:45 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ($_SERVER['REQUEST_METHOD'] === 'POST' && ($_POST['action'] ?? '') === 'delete') {
|
2026-07-03 10:46:54 +02:00
|
|
|
if (!hash_equals($_SESSION['csrf_token'] ?? '', $_POST['token'] ?? '')) {
|
|
|
|
|
$errors[] = 'Invalid form token, please retry.';
|
2026-03-22 22:16:44 +01:00
|
|
|
} else {
|
2026-07-03 10:46:54 +02:00
|
|
|
$slugDel = trim($_POST['slug'] ?? '');
|
|
|
|
|
if ($slugDel !== '' && delete_recipe($slugDel)) {
|
|
|
|
|
$message = 'Recipe deleted.';
|
|
|
|
|
$allRecipes = load_recipes();
|
|
|
|
|
} else {
|
|
|
|
|
$message = 'Could not delete recipe.';
|
|
|
|
|
}
|
|
|
|
|
$editing = null;
|
|
|
|
|
$editIndex = null;
|
2026-03-22 22:16:44 +01:00
|
|
|
}
|
2026-03-23 16:26:45 +01:00
|
|
|
} elseif ($_SERVER['REQUEST_METHOD'] === 'POST' && ($_POST['action'] ?? '') === 'save') {
|
2026-07-03 10:46:54 +02:00
|
|
|
if (!hash_equals($_SESSION['csrf_token'] ?? '', $_POST['token'] ?? '')) {
|
|
|
|
|
$errors[] = 'Invalid form token, please retry.';
|
|
|
|
|
} else {
|
2026-03-22 22:16:44 +01:00
|
|
|
// helpers
|
|
|
|
|
$parse_csv = fn($text) => array_values(array_filter(array_map('trim', explode(',', $text ?? '')), 'strlen'));
|
|
|
|
|
$parse_lines = fn($text) => array_values(array_filter(array_map('trim', preg_split('/\\r?\\n/', $text ?? '')), 'strlen'));
|
2026-05-21 14:50:06 +02:00
|
|
|
$parse_lines_exact = fn($text) => array_map('trim', preg_split('/\\r?\\n/', $text ?? ''));
|
2026-03-22 22:16:44 +01:00
|
|
|
|
|
|
|
|
$titleEn = trim($_POST['title_en'] ?? '');
|
|
|
|
|
$titleDe = trim($_POST['title_de'] ?? '');
|
|
|
|
|
$descriptionEn = trim($_POST['description_en'] ?? '');
|
|
|
|
|
$descriptionDe = trim($_POST['description_de'] ?? '');
|
|
|
|
|
$hero = trim($_POST['hero'] ?? '');
|
|
|
|
|
$categoryEn = trim($_POST['category_en'] ?? '');
|
|
|
|
|
$categoryDe = trim($_POST['category_de'] ?? '');
|
|
|
|
|
$tagsEn = $parse_csv($_POST['tags_en'] ?? '');
|
|
|
|
|
$tagsDe = $parse_csv($_POST['tags_de'] ?? '');
|
|
|
|
|
$prep = (int) ($_POST['prep_time'] ?? 0);
|
|
|
|
|
$cook = (int) ($_POST['cook_time'] ?? 0);
|
|
|
|
|
$total = (int) ($_POST['total_time'] ?? ($prep + $cook));
|
|
|
|
|
$servings = (int) ($_POST['servings'] ?? 0);
|
|
|
|
|
$difficultyEn = trim($_POST['difficulty_en'] ?? 'Easy');
|
|
|
|
|
$difficultyDe = trim($_POST['difficulty_de'] ?? 'Einfach');
|
|
|
|
|
$ingredientsEn = $parse_lines($_POST['ingredients_en'] ?? '');
|
|
|
|
|
$ingredientsDe = $parse_lines($_POST['ingredients_de'] ?? '');
|
|
|
|
|
$utensilsEn = $parse_lines($_POST['utensils_en'] ?? '');
|
|
|
|
|
$utensilsDe = $parse_lines($_POST['utensils_de'] ?? '');
|
|
|
|
|
$stepsEn = $parse_lines($_POST['steps_en'] ?? '');
|
|
|
|
|
$stepsDe = $parse_lines($_POST['steps_de'] ?? '');
|
2026-05-21 14:50:06 +02:00
|
|
|
$stepVideosEn = $parse_lines_exact($_POST['step_videos_en'] ?? '');
|
|
|
|
|
$stepVideosDe = $parse_lines_exact($_POST['step_videos_de'] ?? '');
|
|
|
|
|
$stepTimersEn = $parse_lines_exact($_POST['step_timers_en'] ?? '');
|
|
|
|
|
$stepTimersDe = $parse_lines_exact($_POST['step_timers_de'] ?? '');
|
2026-03-22 22:16:44 +01:00
|
|
|
$featured = isset($_POST['featured']) && $_POST['featured'] === '1';
|
|
|
|
|
$comingSoon = isset($_POST['coming_soon']) && $_POST['coming_soon'] === '1';
|
|
|
|
|
$slugOriginal = trim($_POST['slug_original'] ?? '');
|
|
|
|
|
|
2026-05-21 14:14:10 +02:00
|
|
|
$nutriCal = (int) ($_POST['nutrition_calories'] ?? 0);
|
|
|
|
|
$nutriProt = (int) ($_POST['nutrition_protein'] ?? 0);
|
|
|
|
|
$nutriCarb = (int) ($_POST['nutrition_carbs'] ?? 0);
|
|
|
|
|
$nutriFat = (int) ($_POST['nutrition_fat'] ?? 0);
|
|
|
|
|
|
2026-03-22 22:16:44 +01:00
|
|
|
// keep previous language data if fields left blank while editing
|
|
|
|
|
$prevEn = $editing['i18n']['en'] ?? [];
|
|
|
|
|
$prevDe = $editing['i18n']['de'] ?? [];
|
|
|
|
|
|
|
|
|
|
$titleEn = $titleEn !== '' ? $titleEn : ($prevEn['title'] ?? '');
|
|
|
|
|
$titleDe = $titleDe !== '' ? $titleDe : ($prevDe['title'] ?? '');
|
|
|
|
|
$descriptionEn = $descriptionEn !== '' ? $descriptionEn : ($prevEn['description'] ?? '');
|
|
|
|
|
$descriptionDe = $descriptionDe !== '' ? $descriptionDe : ($prevDe['description'] ?? '');
|
|
|
|
|
$categoryEn = $categoryEn !== '' ? $categoryEn : ($prevEn['category'] ?? '');
|
|
|
|
|
$categoryDe = $categoryDe !== '' ? $categoryDe : ($prevDe['category'] ?? '');
|
|
|
|
|
$difficultyEn = $difficultyEn !== '' ? $difficultyEn : ($prevEn['difficulty'] ?? 'Easy');
|
|
|
|
|
$difficultyDe = $difficultyDe !== '' ? $difficultyDe : ($prevDe['difficulty'] ?? 'Einfach');
|
|
|
|
|
$tagsEn = !empty($tagsEn) ? $tagsEn : ($prevEn['tags'] ?? []);
|
|
|
|
|
$tagsDe = !empty($tagsDe) ? $tagsDe : ($prevDe['tags'] ?? []);
|
|
|
|
|
$ingredientsEn = !empty($ingredientsEn) ? $ingredientsEn : ($prevEn['ingredients'] ?? []);
|
|
|
|
|
$ingredientsDe = !empty($ingredientsDe) ? $ingredientsDe : ($prevDe['ingredients'] ?? []);
|
|
|
|
|
$utensilsEn = !empty($utensilsEn) ? $utensilsEn : ($prevEn['utensils'] ?? []);
|
|
|
|
|
$utensilsDe = !empty($utensilsDe) ? $utensilsDe : ($prevDe['utensils'] ?? []);
|
|
|
|
|
$stepsEn = !empty($stepsEn) ? $stepsEn : ($prevEn['steps'] ?? []);
|
|
|
|
|
$stepsDe = !empty($stepsDe) ? $stepsDe : ($prevDe['steps'] ?? []);
|
2026-05-21 14:50:06 +02:00
|
|
|
$stepVideosEn = !empty($stepVideosEn) ? $stepVideosEn : ($prevEn['step_videos'] ?? []);
|
|
|
|
|
$stepVideosDe = !empty($stepVideosDe) ? $stepVideosDe : ($prevDe['step_videos'] ?? []);
|
|
|
|
|
$stepTimersEn = !empty($stepTimersEn) ? $stepTimersEn : ($prevEn['step_timers'] ?? []);
|
|
|
|
|
$stepTimersDe = !empty($stepTimersDe) ? $stepTimersDe : ($prevDe['step_timers'] ?? []);
|
2026-03-22 22:16:44 +01:00
|
|
|
|
|
|
|
|
if ($titleEn === '') {
|
|
|
|
|
$message = 'English title is required.';
|
|
|
|
|
} elseif (!$comingSoon && (empty($ingredientsEn) || empty($stepsEn))) {
|
|
|
|
|
$message = 'Ingredients and steps are required unless marked coming soon.';
|
|
|
|
|
} else {
|
|
|
|
|
// determine slug
|
|
|
|
|
if ($slugOriginal) {
|
|
|
|
|
$slug = $slugOriginal;
|
|
|
|
|
} else {
|
|
|
|
|
$slug = slugify($titleEn ?: $titleDe);
|
|
|
|
|
// ensure unique slug
|
|
|
|
|
$existingSlugs = array_map(fn($r) => $r['slug'] ?? '', $allRecipes);
|
|
|
|
|
$base = $slug;
|
|
|
|
|
$i = 1;
|
|
|
|
|
while (in_array($slug, $existingSlugs, true)) {
|
|
|
|
|
$slug = $base . '-' . $i;
|
|
|
|
|
$i++;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$record = [
|
|
|
|
|
'slug' => $slug,
|
|
|
|
|
'hero' => $hero,
|
|
|
|
|
'prep_time' => $prep,
|
|
|
|
|
'cook_time' => $cook,
|
|
|
|
|
'total_time' => $total,
|
|
|
|
|
'servings' => $servings,
|
|
|
|
|
'featured' => $featured,
|
|
|
|
|
'coming_soon' => $comingSoon,
|
2026-05-21 14:14:10 +02:00
|
|
|
'nutrition' => [
|
|
|
|
|
'calories' => $nutriCal,
|
|
|
|
|
'protein' => $nutriProt,
|
|
|
|
|
'carbs' => $nutriCarb,
|
|
|
|
|
'fat' => $nutriFat
|
|
|
|
|
],
|
2026-03-22 22:16:44 +01:00
|
|
|
'i18n' => [
|
|
|
|
|
'en' => [
|
|
|
|
|
'title' => $titleEn,
|
|
|
|
|
'description' => $descriptionEn,
|
|
|
|
|
'category' => $categoryEn,
|
|
|
|
|
'difficulty' => $difficultyEn,
|
|
|
|
|
'tags' => $tagsEn,
|
|
|
|
|
'ingredients' => $ingredientsEn,
|
|
|
|
|
'utensils' => $utensilsEn,
|
|
|
|
|
'steps' => $stepsEn,
|
2026-05-21 14:50:06 +02:00
|
|
|
'step_videos' => $stepVideosEn,
|
|
|
|
|
'step_timers' => $stepTimersEn,
|
2026-03-22 22:16:44 +01:00
|
|
|
],
|
|
|
|
|
'de' => [
|
|
|
|
|
'title' => $titleDe ?: $titleEn,
|
|
|
|
|
'description' => $descriptionDe ?: $descriptionEn,
|
|
|
|
|
'category' => $categoryDe ?: $categoryEn,
|
|
|
|
|
'difficulty' => $difficultyDe,
|
|
|
|
|
'tags' => !empty($tagsDe) ? $tagsDe : $tagsEn,
|
|
|
|
|
'ingredients' => !empty($ingredientsDe) ? $ingredientsDe : $ingredientsEn,
|
|
|
|
|
'utensils' => !empty($utensilsDe) ? $utensilsDe : $utensilsEn,
|
|
|
|
|
'steps' => !empty($stepsDe) ? $stepsDe : $stepsEn,
|
2026-05-21 14:50:06 +02:00
|
|
|
'step_videos' => !empty($stepVideosDe) ? $stepVideosDe : $stepVideosEn,
|
|
|
|
|
'step_timers' => !empty($stepTimersDe) ? $stepTimersDe : $stepTimersEn,
|
2026-03-22 22:16:44 +01:00
|
|
|
],
|
|
|
|
|
],
|
|
|
|
|
];
|
|
|
|
|
|
2026-05-23 10:23:28 +02:00
|
|
|
if ($slugOriginal && $slugOriginal !== $slug) {
|
|
|
|
|
delete_recipe($slugOriginal);
|
2026-03-22 22:16:44 +01:00
|
|
|
}
|
|
|
|
|
|
2026-05-23 10:23:28 +02:00
|
|
|
if (save_recipe($record)) {
|
2026-03-22 22:16:44 +01:00
|
|
|
$message = $slugOriginal ? 'Saved changes.' : 'Saved! New recipe added.';
|
2026-05-23 10:23:28 +02:00
|
|
|
$allRecipes = load_recipes();
|
2026-03-22 22:16:44 +01:00
|
|
|
} else {
|
2026-05-23 10:23:28 +02:00
|
|
|
$message = 'Could not save to database.';
|
2026-03-22 22:16:44 +01:00
|
|
|
}
|
|
|
|
|
}
|
2026-07-03 10:46:54 +02:00
|
|
|
} // end CSRF else
|
2026-03-22 22:16:44 +01:00
|
|
|
}
|
|
|
|
|
?>
|
|
|
|
|
<!doctype html>
|
|
|
|
|
<html lang="en">
|
|
|
|
|
<head>
|
|
|
|
|
<meta charset="UTF-8">
|
|
|
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
|
|
|
<title>FlixCooks Admin</title>
|
|
|
|
|
<link rel="stylesheet" href="/assets/style.css">
|
|
|
|
|
<style>
|
|
|
|
|
body { max-width: 1100px; margin: 24px auto 64px; padding: 0 16px; color: var(--ink); }
|
|
|
|
|
.admin-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 18px; }
|
2026-03-23 16:26:45 +01:00
|
|
|
.admin-tabs { display: flex; gap: 8px; }
|
|
|
|
|
.admin-tabs a { padding: 8px 12px; border-radius: 10px; border: 1px solid rgba(255,255,255,0.15); text-decoration: none; color: var(--ink); }
|
|
|
|
|
.admin-tabs a.active { background: var(--accent-soft); border-color: var(--accent); }
|
2026-03-22 22:16:44 +01:00
|
|
|
form.admin-form {
|
|
|
|
|
display: grid;
|
|
|
|
|
gap: 12px;
|
|
|
|
|
background: var(--surface-2);
|
|
|
|
|
padding: 18px;
|
|
|
|
|
border-radius: 16px;
|
|
|
|
|
box-shadow: var(--shadow);
|
2026-03-23 16:28:36 +01:00
|
|
|
border: 1px solid rgba(0,0,0,0.08);
|
|
|
|
|
color: #1b1b1b;
|
2026-03-22 22:16:44 +01:00
|
|
|
}
|
2026-03-23 16:28:36 +01:00
|
|
|
form.admin-form label { font-weight: 700; display: block; margin-bottom: 6px; color: #1b1b1b; }
|
2026-03-22 22:16:44 +01:00
|
|
|
form.admin-form input, form.admin-form textarea, form.admin-form select {
|
|
|
|
|
width: 100%;
|
|
|
|
|
padding: 12px;
|
|
|
|
|
border-radius: 12px;
|
2026-03-23 16:28:36 +01:00
|
|
|
border: 1px solid #c9cdd3;
|
|
|
|
|
background: #f8fafc;
|
|
|
|
|
color: #1b1b1b;
|
2026-03-22 22:16:44 +01:00
|
|
|
}
|
|
|
|
|
form.admin-form textarea { resize: vertical; }
|
|
|
|
|
form.admin-form input::placeholder,
|
|
|
|
|
form.admin-form textarea::placeholder {
|
2026-03-23 16:28:36 +01:00
|
|
|
color: #5c6672;
|
2026-03-22 22:16:44 +01:00
|
|
|
}
|
|
|
|
|
form.admin-form textarea { min-height: 120px; }
|
|
|
|
|
.row { display: grid; grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)); gap: 12px; }
|
|
|
|
|
.message { padding: 12px; border-radius: 12px; background: var(--accent-soft); color: var(--ink); }
|
|
|
|
|
.list { margin-top: 18px; }
|
|
|
|
|
.list-item { padding: 12px 0; border-bottom: 1px solid rgba(255,255,255,0.08); display: flex; justify-content: space-between; align-items: center; }
|
|
|
|
|
.pill { background: rgba(255,255,255,0.06); color: var(--ink); }
|
|
|
|
|
</style>
|
|
|
|
|
</head>
|
|
|
|
|
<body>
|
|
|
|
|
<div class="admin-header">
|
|
|
|
|
<h1>FlixCooks Admin</h1>
|
2026-03-23 16:26:45 +01:00
|
|
|
<div style="display:flex; gap:8px; align-items:center;">
|
|
|
|
|
<div class="admin-tabs">
|
|
|
|
|
<a href="/admin.php" class="<?php echo $view === 'recipes' ? 'active' : ''; ?>">Recipes</a>
|
|
|
|
|
<a href="/admin.php?view=settings" class="<?php echo $view === 'settings' ? 'active' : ''; ?>">Site settings</a>
|
|
|
|
|
</div>
|
2026-03-22 22:16:44 +01:00
|
|
|
<a class="button" href="/index.php" style="padding:10px 14px;">View site</a>
|
|
|
|
|
<?php if ($editing): ?>
|
|
|
|
|
<a class="button" href="/admin.php" style="padding:10px 14px;">Back</a>
|
|
|
|
|
<?php endif; ?>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<?php if ($message): ?>
|
|
|
|
|
<div class="message"><?php echo e($message); ?></div>
|
|
|
|
|
<?php endif; ?>
|
2026-03-23 16:26:45 +01:00
|
|
|
<?php if (!empty($errors)): ?>
|
|
|
|
|
<div class="message" style="background:#b00020; color:#fff;">
|
|
|
|
|
<?php echo e(implode(' ', $errors)); ?>
|
2026-03-22 22:16:44 +01:00
|
|
|
</div>
|
2026-03-23 16:26:45 +01:00
|
|
|
<?php endif; ?>
|
2026-03-22 22:16:44 +01:00
|
|
|
|
2026-03-23 16:26:45 +01:00
|
|
|
<?php if ($view === 'settings'): ?>
|
|
|
|
|
<?php $im = $siteSettings['imprint']; $pv = $siteSettings['privacy']; ?>
|
|
|
|
|
<form class="admin-form" method="post">
|
|
|
|
|
<input type="hidden" name="action" value="save_settings">
|
|
|
|
|
<input type="hidden" name="token" value="<?php echo e($_SESSION['csrf_token']); ?>">
|
|
|
|
|
<h2>Imprint (DE)</h2>
|
|
|
|
|
<div class="row">
|
|
|
|
|
<div><label>Name *</label><input type="text" name="owner_name_de" value="<?php echo e($im['de']['owner_name']); ?>" required></div>
|
|
|
|
|
<div><label>Adresse *</label><input type="text" name="address_de" value="<?php echo e($im['de']['address']); ?>" required></div>
|
2026-03-22 22:16:44 +01:00
|
|
|
</div>
|
2026-03-23 16:26:45 +01:00
|
|
|
<div class="row">
|
|
|
|
|
<div><label>E-Mail *</label><input type="email" name="email_de" value="<?php echo e($im['de']['email']); ?>" required></div>
|
|
|
|
|
<div><label>Telefon *</label><input type="text" name="phone_de" value="<?php echo e($im['de']['phone']); ?>" required></div>
|
2026-03-22 22:16:44 +01:00
|
|
|
</div>
|
2026-03-23 16:26:45 +01:00
|
|
|
<label>Rechtsform / Hinweis</label>
|
|
|
|
|
<input type="text" name="legal_form_de" value="<?php echo e($im['de']['legal_form']); ?>">
|
|
|
|
|
<label>Unternehmensgegenstand / Blattlinie *</label>
|
|
|
|
|
<input type="text" name="business_purpose_de" value="<?php echo e($im['de']['business_purpose']); ?>" required>
|
|
|
|
|
<div class="row">
|
|
|
|
|
<div><label>WKO-Mitgliedschaft</label><input type="text" name="wko_de" value="<?php echo e($im['de']['wko_membership']); ?>"></div>
|
|
|
|
|
<div><label>Aufsichts-/Gewerbebehörde</label><input type="text" name="authority_de" value="<?php echo e($im['de']['authority']); ?>"></div>
|
|
|
|
|
</div>
|
|
|
|
|
<div class="row">
|
|
|
|
|
<div><label>UID</label><input type="text" name="uid_de" value="<?php echo e($im['de']['uid']); ?>"></div>
|
|
|
|
|
<div><label>ODR-Link</label><input type="url" name="odr_link" value="<?php echo e($im['de']['odr']); ?>"></div>
|
2026-03-22 22:16:44 +01:00
|
|
|
</div>
|
|
|
|
|
|
2026-03-23 16:26:45 +01:00
|
|
|
<hr>
|
|
|
|
|
<h2>Imprint (EN)</h2>
|
|
|
|
|
<div class="row">
|
|
|
|
|
<div><label>Name *</label><input type="text" name="owner_name_en" value="<?php echo e($im['en']['owner_name']); ?>" required></div>
|
|
|
|
|
<div><label>Address *</label><input type="text" name="address_en" value="<?php echo e($im['en']['address']); ?>" required></div>
|
2026-03-22 22:16:44 +01:00
|
|
|
</div>
|
2026-03-23 16:26:45 +01:00
|
|
|
<div class="row">
|
|
|
|
|
<div><label>Email *</label><input type="email" name="email_en" value="<?php echo e($im['en']['email']); ?>" required></div>
|
|
|
|
|
<div><label>Phone *</label><input type="text" name="phone_en" value="<?php echo e($im['en']['phone']); ?>" required></div>
|
2026-03-22 22:16:44 +01:00
|
|
|
</div>
|
2026-03-23 16:26:45 +01:00
|
|
|
<label>Legal form / note</label>
|
|
|
|
|
<input type="text" name="legal_form_en" value="<?php echo e($im['en']['legal_form']); ?>">
|
|
|
|
|
<label>Business purpose / editorial line *</label>
|
|
|
|
|
<input type="text" name="business_purpose_en" value="<?php echo e($im['en']['business_purpose']); ?>" required>
|
|
|
|
|
<div class="row">
|
|
|
|
|
<div><label>Chamber membership</label><input type="text" name="wko_en" value="<?php echo e($im['en']['wko_membership']); ?>"></div>
|
|
|
|
|
<div><label>Supervisory authority</label><input type="text" name="authority_en" value="<?php echo e($im['en']['authority']); ?>"></div>
|
|
|
|
|
</div>
|
|
|
|
|
<div class="row">
|
|
|
|
|
<div><label>VAT ID</label><input type="text" name="uid_en" value="<?php echo e($im['en']['uid']); ?>"></div>
|
2026-03-22 22:16:44 +01:00
|
|
|
</div>
|
|
|
|
|
|
2026-03-23 16:26:45 +01:00
|
|
|
<hr>
|
|
|
|
|
<h2>Privacy (DE)</h2>
|
|
|
|
|
<div class="row">
|
|
|
|
|
<div><label>Verantwortlicher *</label><input type="text" name="controller_de" value="<?php echo e($pv['de']['controller']); ?>" required></div>
|
|
|
|
|
<div><label>Adresse *</label><input type="text" name="privacy_address_de" value="<?php echo e($pv['de']['address']); ?>" required></div>
|
|
|
|
|
</div>
|
|
|
|
|
<div class="row">
|
|
|
|
|
<div><label>E-Mail *</label><input type="email" name="privacy_email_de" value="<?php echo e($pv['de']['contact_email']); ?>" required></div>
|
|
|
|
|
<div><label>Telefon *</label><input type="text" name="privacy_phone_de" value="<?php echo e($pv['de']['contact_phone']); ?>" required></div>
|
|
|
|
|
</div>
|
|
|
|
|
<label>Hosting *</label>
|
|
|
|
|
<input type="text" name="hosting_de" value="<?php echo e($pv['de']['hosting_provider']); ?>" required>
|
|
|
|
|
<label>Zwecke *</label>
|
|
|
|
|
<textarea name="purposes_de" required><?php echo e($pv['de']['purposes']); ?></textarea>
|
|
|
|
|
<label>Cookies *</label>
|
|
|
|
|
<textarea name="cookie_de" required><?php echo e($pv['de']['cookie_statement']); ?></textarea>
|
2026-03-22 22:16:44 +01:00
|
|
|
|
2026-03-23 16:26:45 +01:00
|
|
|
<hr>
|
|
|
|
|
<h2>Privacy (EN)</h2>
|
|
|
|
|
<div class="row">
|
|
|
|
|
<div><label>Controller *</label><input type="text" name="controller_en" value="<?php echo e($pv['en']['controller']); ?>" required></div>
|
|
|
|
|
<div><label>Address *</label><input type="text" name="privacy_address_en" value="<?php echo e($pv['en']['address']); ?>" required></div>
|
|
|
|
|
</div>
|
|
|
|
|
<div class="row">
|
|
|
|
|
<div><label>Email *</label><input type="email" name="privacy_email_en" value="<?php echo e($pv['en']['contact_email']); ?>" required></div>
|
|
|
|
|
<div><label>Phone *</label><input type="text" name="privacy_phone_en" value="<?php echo e($pv['en']['contact_phone']); ?>" required></div>
|
|
|
|
|
</div>
|
|
|
|
|
<label>Hosting *</label>
|
|
|
|
|
<input type="text" name="hosting_en" value="<?php echo e($pv['en']['hosting_provider']); ?>" required>
|
|
|
|
|
<label>Purposes *</label>
|
|
|
|
|
<textarea name="purposes_en" required><?php echo e($pv['en']['purposes']); ?></textarea>
|
|
|
|
|
<label>Cookies *</label>
|
|
|
|
|
<textarea name="cookie_en" required><?php echo e($pv['en']['cookie_statement']); ?></textarea>
|
2026-03-22 22:16:44 +01:00
|
|
|
|
2026-03-23 16:26:45 +01:00
|
|
|
<div class="row">
|
|
|
|
|
<div>
|
|
|
|
|
<label>Log retention (days)</label>
|
|
|
|
|
<input type="number" name="log_retention" min="0" value="<?php echo e((int) $pv['de']['log_retention_days']); ?>">
|
2026-03-22 22:16:44 +01:00
|
|
|
</div>
|
2026-03-23 16:26:45 +01:00
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<button type="submit" class="button" style="width: fit-content;">Save settings</button>
|
|
|
|
|
</form>
|
|
|
|
|
<?php else: ?>
|
2026-03-23 16:30:19 +01:00
|
|
|
<div class="list">
|
|
|
|
|
<h2>Existing recipes (<?php echo count($allRecipes); ?>)</h2>
|
|
|
|
|
<?php if (empty($allRecipes)): ?>
|
|
|
|
|
<p>No recipes yet.</p>
|
|
|
|
|
<?php else: ?>
|
|
|
|
|
<?php foreach ($allRecipes as $r): ?>
|
|
|
|
|
<?php $display = localize_recipe($r, 'en'); ?>
|
|
|
|
|
<div class="list-item">
|
|
|
|
|
<div>
|
|
|
|
|
<strong><?php echo e($display['title'] ?? $r['slug']); ?></strong>
|
|
|
|
|
<span class="pill"><?php echo e($display['category'] ?? ''); ?></span>
|
|
|
|
|
<?php if (!empty($r['featured'])): ?><span class="pill">Featured</span><?php endif; ?>
|
|
|
|
|
<?php if (!empty($r['coming_soon'])): ?><span class="pill">Coming soon</span><?php endif; ?>
|
|
|
|
|
</div>
|
|
|
|
|
<div style="display:flex; gap:8px; align-items:center;">
|
|
|
|
|
<small><?php echo e($r['slug']); ?></small>
|
|
|
|
|
<a class="button" href="/admin.php?edit=<?php echo urlencode($r['slug']); ?>" style="padding:8px 12px;">Edit</a>
|
|
|
|
|
<form method="post" style="margin:0;" onsubmit="return confirm('Delete this recipe?');">
|
|
|
|
|
<input type="hidden" name="action" value="delete">
|
2026-07-03 10:46:54 +02:00
|
|
|
<input type="hidden" name="token" value="<?php echo e($_SESSION['csrf_token']); ?>">
|
2026-03-23 16:30:19 +01:00
|
|
|
<input type="hidden" name="slug" value="<?php echo e($r['slug']); ?>">
|
|
|
|
|
<button type="submit" class="button" style="padding:8px 12px;">Delete</button>
|
|
|
|
|
</form>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
<?php endforeach; ?>
|
|
|
|
|
<?php endif; ?>
|
|
|
|
|
</div>
|
|
|
|
|
|
2026-03-23 16:26:45 +01:00
|
|
|
<form class="admin-form" method="post">
|
|
|
|
|
<input type="hidden" name="action" value="save">
|
2026-07-03 10:46:54 +02:00
|
|
|
<input type="hidden" name="token" value="<?php echo e($_SESSION['csrf_token']); ?>">
|
2026-03-23 16:26:45 +01:00
|
|
|
<?php if ($editing): ?>
|
|
|
|
|
<input type="hidden" name="slug_original" value="<?php echo e($editing['slug']); ?>">
|
|
|
|
|
<?php endif; ?>
|
|
|
|
|
<label>Hero Image URL</label>
|
|
|
|
|
<input type="text" name="hero" placeholder="https://... or /assets/images/hero.jpg" value="<?php echo e($editing['hero'] ?? ''); ?>">
|
|
|
|
|
<p style="color: var(--muted); margin: 4px 0 8px; font-size: 13px;">Accepts full URLs or relative paths (e.g. /assets/images/hero.jpg).</p>
|
|
|
|
|
|
|
|
|
|
<div class="row">
|
|
|
|
|
<div>
|
|
|
|
|
<label>Prep time (minutes)</label>
|
|
|
|
|
<input type="number" name="prep_time" min="0" value="<?php echo e($editing['prep_time'] ?? 0); ?>">
|
|
|
|
|
</div>
|
|
|
|
|
<div>
|
|
|
|
|
<label>Cook time (minutes)</label>
|
|
|
|
|
<input type="number" name="cook_time" min="0" value="<?php echo e($editing['cook_time'] ?? 0); ?>">
|
|
|
|
|
</div>
|
|
|
|
|
<div>
|
|
|
|
|
<label>Total time (minutes)</label>
|
|
|
|
|
<input type="number" name="total_time" min="0" value="<?php echo e($editing['total_time'] ?? 0); ?>" placeholder="0 to auto-sum">
|
|
|
|
|
</div>
|
|
|
|
|
<div>
|
|
|
|
|
<label>Servings</label>
|
|
|
|
|
<input type="number" name="servings" min="1" value="<?php echo e($editing['servings'] ?? 2); ?>">
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
|
2026-05-21 14:14:10 +02:00
|
|
|
<div class="row">
|
|
|
|
|
<div>
|
|
|
|
|
<label>Calories (kcal)</label>
|
|
|
|
|
<input type="number" name="nutrition_calories" min="0" value="<?php echo e($editing['nutrition']['calories'] ?? 0); ?>">
|
|
|
|
|
</div>
|
|
|
|
|
<div>
|
|
|
|
|
<label>Protein (g)</label>
|
|
|
|
|
<input type="number" name="nutrition_protein" min="0" value="<?php echo e($editing['nutrition']['protein'] ?? 0); ?>">
|
|
|
|
|
</div>
|
|
|
|
|
<div>
|
|
|
|
|
<label>Carbs (g)</label>
|
|
|
|
|
<input type="number" name="nutrition_carbs" min="0" value="<?php echo e($editing['nutrition']['carbs'] ?? 0); ?>">
|
|
|
|
|
</div>
|
|
|
|
|
<div>
|
|
|
|
|
<label>Fat (g)</label>
|
|
|
|
|
<input type="number" name="nutrition_fat" min="0" value="<?php echo e($editing['nutrition']['fat'] ?? 0); ?>">
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
|
2026-03-23 16:26:45 +01:00
|
|
|
<hr>
|
|
|
|
|
<h3>English</h3>
|
|
|
|
|
<div class="row">
|
|
|
|
|
<div>
|
|
|
|
|
<label>Title (EN) *</label>
|
|
|
|
|
<input type="text" name="title_en" required value="<?php echo e($editingEn['title'] ?? ''); ?>">
|
|
|
|
|
</div>
|
|
|
|
|
<div>
|
|
|
|
|
<label>Category (EN)</label>
|
|
|
|
|
<input type="text" name="category_en" placeholder="Dinner, Dessert..." value="<?php echo e($editingEn['category'] ?? ''); ?>">
|
|
|
|
|
</div>
|
|
|
|
|
<div>
|
|
|
|
|
<label>Difficulty (EN)</label>
|
|
|
|
|
<?php $diffEn = $editingEn['difficulty'] ?? 'Easy'; ?>
|
|
|
|
|
<select name="difficulty_en">
|
|
|
|
|
<option <?php echo $diffEn==='Easy'?'selected':''; ?>>Easy</option>
|
|
|
|
|
<option <?php echo $diffEn==='Medium'?'selected':''; ?>>Medium</option>
|
|
|
|
|
<option <?php echo $diffEn==='Hard'?'selected':''; ?>>Hard</option>
|
|
|
|
|
</select>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
<label>Description (EN)</label>
|
|
|
|
|
<textarea name="description_en" placeholder="Short teaser"><?php echo e($editingEn['description'] ?? ''); ?></textarea>
|
|
|
|
|
<label>Tags (EN, comma separated)</label>
|
|
|
|
|
<input type="text" name="tags_en" placeholder="gluten-free, 30-minutes" value="<?php echo e(isset($editingEn['tags']) ? implode(', ', $editingEn['tags']) : ''); ?>">
|
|
|
|
|
<label>Ingredients (EN, one per line) *</label>
|
|
|
|
|
<textarea name="ingredients_en" placeholder="1 cup flour 2 eggs"><?php echo isset($editingEn['ingredients']) ? e(implode("\n", $editingEn['ingredients'])) : ''; ?></textarea>
|
|
|
|
|
<label>Utensils (EN, one per line)</label>
|
|
|
|
|
<textarea name="utensils_en" placeholder="12" skillet Sheet pan Rubber spatula"><?php echo isset($editingEn['utensils']) ? e(implode("\n", $editingEn['utensils'])) : ''; ?></textarea>
|
|
|
|
|
<label>Steps (EN, one per line) *</label>
|
|
|
|
|
<textarea name="steps_en" placeholder="Preheat oven... Mix dry ingredients..."><?php echo isset($editingEn['steps']) ? e(implode("\n", $editingEn['steps'])) : ''; ?></textarea>
|
2026-05-21 14:50:06 +02:00
|
|
|
<label>Step Videos (EN, matching steps line by line)</label>
|
|
|
|
|
<textarea name="step_videos_en" placeholder="https://...mp4 "><?php echo isset($editingEn['step_videos']) ? e(implode("\n", $editingEn['step_videos'])) : ''; ?></textarea>
|
|
|
|
|
<label>Step Timers (EN, matching steps line by line, in minutes)</label>
|
|
|
|
|
<textarea name="step_timers_en" placeholder="0 15"><?php echo isset($editingEn['step_timers']) ? e(implode("\n", $editingEn['step_timers'])) : ''; ?></textarea>
|
2026-03-23 16:26:45 +01:00
|
|
|
|
|
|
|
|
<hr>
|
|
|
|
|
<h3>Deutsch</h3>
|
|
|
|
|
<div class="row">
|
|
|
|
|
<div>
|
|
|
|
|
<label>Titel (DE)</label>
|
|
|
|
|
<input type="text" name="title_de" value="<?php echo e($editingDe['title'] ?? ''); ?>">
|
|
|
|
|
</div>
|
|
|
|
|
<div>
|
|
|
|
|
<label>Kategorie (DE)</label>
|
|
|
|
|
<input type="text" name="category_de" placeholder="Abendessen, Dessert..." value="<?php echo e($editingDe['category'] ?? ''); ?>">
|
|
|
|
|
</div>
|
|
|
|
|
<div>
|
|
|
|
|
<label>Schwierigkeitsgrad (DE)</label>
|
|
|
|
|
<?php $diffDe = $editingDe['difficulty'] ?? 'Einfach'; ?>
|
|
|
|
|
<select name="difficulty_de">
|
|
|
|
|
<option <?php echo strtolower($diffDe)==='einfach'?'selected':''; ?>>Einfach</option>
|
|
|
|
|
<option <?php echo strtolower($diffDe)==='mittel'?'selected':''; ?>>Mittel</option>
|
|
|
|
|
<option <?php echo strtolower($diffDe)==='schwer'?'selected':''; ?>>Schwer</option>
|
|
|
|
|
</select>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
<label>Beschreibung (DE)</label>
|
|
|
|
|
<textarea name="description_de" placeholder="Kurzer Teaser"><?php echo e($editingDe['description'] ?? ''); ?></textarea>
|
|
|
|
|
<label>Tags (DE, komma-getrennt)</label>
|
|
|
|
|
<input type="text" name="tags_de" placeholder="schnell, vegetarisch" value="<?php echo e(isset($editingDe['tags']) ? implode(', ', $editingDe['tags']) : ''); ?>">
|
|
|
|
|
<label>Zutaten (DE, eine pro Zeile)</label>
|
|
|
|
|
<textarea name="ingredients_de" placeholder="300 g Mehl 2 Eier"><?php echo isset($editingDe['ingredients']) ? e(implode("\n", $editingDe['ingredients'])) : ''; ?></textarea>
|
|
|
|
|
<label>Werkzeug (DE, eine pro Zeile)</label>
|
|
|
|
|
<textarea name="utensils_de" placeholder="Pfanne Kochtopf"><?php echo isset($editingDe['utensils']) ? e(implode("\n", $editingDe['utensils'])) : ''; ?></textarea>
|
|
|
|
|
<label>Schritte (DE, eine pro Zeile)</label>
|
|
|
|
|
<textarea name="steps_de" placeholder="Backofen vorheizen... Teig kneten..."><?php echo isset($editingDe['steps']) ? e(implode("\n", $editingDe['steps'])) : ''; ?></textarea>
|
2026-05-21 14:50:06 +02:00
|
|
|
<label>Step Videos (DE)</label>
|
|
|
|
|
<textarea name="step_videos_de"><?php echo isset($editingDe['step_videos']) ? e(implode("\n", $editingDe['step_videos'])) : ''; ?></textarea>
|
|
|
|
|
<label>Step Timers (DE)</label>
|
|
|
|
|
<textarea name="step_timers_de"><?php echo isset($editingDe['step_timers']) ? e(implode("\n", $editingDe['step_timers'])) : ''; ?></textarea>
|
2026-03-23 16:26:45 +01:00
|
|
|
|
|
|
|
|
<label><input type="checkbox" name="featured" value="1" <?php echo !empty($editing['featured']) ? 'checked' : ''; ?>> Mark as featured</label>
|
|
|
|
|
<label><input type="checkbox" name="coming_soon" value="1" <?php echo !empty($editing['coming_soon']) ? 'checked' : ''; ?>> Mark as coming soon (name & image only)</label>
|
|
|
|
|
|
|
|
|
|
<button type="submit" class="button" style="width: fit-content;"><?php echo $editing ? 'Save changes' : 'Save recipe'; ?></button>
|
|
|
|
|
</form>
|
|
|
|
|
<?php endif; ?>
|
2026-03-22 22:16:44 +01:00
|
|
|
</body>
|
|
|
|
|
</html>
|