query("SHOW COLUMNS FROM games")->fetchAll(PDO::FETCH_COLUMN); $cols = array_map('strtolower', $cols); $hasFeatured = in_array('is_featured', $cols, true); } catch (Throwable $e) {} /* ensure column hint */ $featuredHint = ''; if (!$hasFeatured) { $featuredHint = "Heads up: your games table has no is_featured column. Run: ALTER TABLE `games` ADD COLUMN `is_featured` TINYINT(1) NOT NULL DEFAULT 0 AFTER `is_published`;"; } /* ------------------------------------------------- EXPORT ALL GAMES (ignores filters & pagination) ------------------------------------------------- */ if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['export_all']) && $_POST['export_all'] === '1') { csrf_check(); try { // Determine game columns (excluding id + category_id) $colStmt = $pdo->query("SHOW COLUMNS FROM games"); $gameCols = []; while ($c = $colStmt->fetch(PDO::FETCH_ASSOC)) { $name = (string)$c['Field']; if ($name === 'id' || $name === 'category_id') { continue; } $gameCols[] = $name; } // Fetch ALL games with category name $st = $pdo->query(" SELECT g.*, c.name AS category_name FROM games g LEFT JOIN categories c ON c.id = g.category_id ORDER BY g.id ASC "); $games = []; while ($row = $st->fetch(PDO::FETCH_ASSOC)) { $fields = []; foreach ($gameCols as $col) { if (array_key_exists($col, $row)) { $fields[$col] = $row[$col]; } } $games[] = [ 'fields' => $fields, 'category_name' => $row['category_name'] ?? '', ]; } $payload = [ 'export_type' => 'games', 'scope' => 'all', 'exported_at' => gmdate('c'), 'source_host' => $_SERVER['HTTP_HOST'] ?? '', 'games_count' => count($games), 'games' => $games, ]; header('Content-Type: application/json; charset=utf-8'); header('Content-Disposition: attachment; filename="games-export-ALL-' . date('Ymd-His') . '.json"'); echo json_encode($payload, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT); exit; } catch (Throwable $e) { $err = 'Export ALL failed: ' . $e->getMessage(); } } /* ------------------------------------------------- BULK ACTIONS (selected rows) ------------------------------------------------- */ if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['bulk_action'])) { csrf_check(); $ids = array_filter(array_map('intval', $_POST['ids'] ?? [])); $act = $_POST['bulk_action'] ?? ''; if ($ids) { $ph = implode(',', array_fill(0, count($ids), '?')); /* Export selected games as JSON for import on another installation */ if ($act === 'export_json') { try { // Determine game columns (excluding id + category_id) $colStmt = $pdo->query("SHOW COLUMNS FROM games"); $gameCols = []; while ($c = $colStmt->fetch(PDO::FETCH_ASSOC)) { $name = (string)$c['Field']; if ($name === 'id' || $name === 'category_id') { continue; } $gameCols[] = $name; } // Fetch selected games with category name $st = $pdo->prepare(" SELECT g.*, c.name AS category_name FROM games g LEFT JOIN categories c ON c.id = g.category_id WHERE g.id IN ($ph) "); $st->execute($ids); $games = []; while ($row = $st->fetch(PDO::FETCH_ASSOC)) { $fields = []; foreach ($gameCols as $col) { if (array_key_exists($col, $row)) { $fields[$col] = $row[$col]; } } $games[] = [ 'fields' => $fields, 'category_name' => $row['category_name'] ?? '', ]; } $payload = [ 'export_type' => 'games', 'scope' => 'selected', 'exported_at' => gmdate('c'), 'source_host' => $_SERVER['HTTP_HOST'] ?? '', 'games_count' => count($games), 'games' => $games, ]; header('Content-Type: application/json; charset=utf-8'); header('Content-Disposition: attachment; filename="games-export-' . date('Ymd-His') . '.json"'); echo json_encode($payload, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT); exit; } catch (Throwable $e) { $err = 'Export failed: ' . $e->getMessage(); } } // Normal bulk actions try { if ($act === 'publish') { $st = $pdo->prepare("UPDATE games SET is_published=1,updated_at=NOW() WHERE id IN ($ph)"); $st->execute($ids); $msg = "Published " . $st->rowCount() . " game(s)."; } elseif ($act === 'unpublish') { $st = $pdo->prepare("UPDATE games SET is_published=0,updated_at=NOW() WHERE id IN ($ph)"); $st->execute($ids); $msg = "Unpublished " . $st->rowCount() . " game(s)."; } elseif ($act === 'delete') { $st = $pdo->prepare("DELETE FROM games WHERE id IN ($ph)"); $st->execute($ids); $msg = "Deleted " . $st->rowCount() . " game(s)."; } elseif ($act === 'feature_on' && $hasFeatured) { $st = $pdo->prepare("UPDATE games SET is_featured=1,updated_at=NOW() WHERE id IN ($ph)"); $st->execute($ids); $msg = "Set Featured on " . $st->rowCount() . " game(s)."; } elseif ($act === 'feature_off' && $hasFeatured) { $st = $pdo->prepare("UPDATE games SET is_featured=0,updated_at=NOW() WHERE id IN ($ph)"); $st->execute($ids); $msg = "Removed Featured on " . $st->rowCount() . " game(s)."; } else { if ($act !== 'export_json') { $err = 'Unknown action or missing is_featured column.'; } } } catch (Throwable $e) { $err = $e->getMessage(); } } else { $err = 'No rows selected.'; } } /* single-row feature toggle (legacy POST: feature_id + feature_set) Kept for backward-compatibility (non-JS). The UI below now uses AJAX. */ if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['feature_id']) && $hasFeatured) { csrf_check(); $gid = (int)($_POST['feature_id'] ?? 0); $set = (int)($_POST['feature_set'] ?? 0); if ($gid > 0) { $st = $pdo->prepare("UPDATE games SET is_featured=:s,updated_at=NOW() WHERE id=:id"); $st->execute([':s' => $set, ':id' => $gid]); $msg = $set ? 'Marked as featured.' : 'Removed from featured.'; } } /* FILTERS */ $q = trim((string)($_GET['q'] ?? '')); $cat = (int)($_GET['cat'] ?? 0); $prov = trim((string)($_GET['provider'] ?? '')); $status = $_GET['status'] ?? 'any'; // any|1|0 $feat = $_GET['feat'] ?? 'any'; // any|1|0 $sort = $_GET['sort'] ?? 'new'; // new|name|popular|featured $page = max(1, (int)($_GET['page'] ?? 1)); $perPage = min(100, max(10, (int)($_GET['per'] ?? 30))); $where = ['1=1']; $args = []; /* SAFE SEARCH (unique placeholders per column to avoid PDO duplicate-name issue) */ if ($q !== '') { $like = "%{$q}%"; $searchCols = ['g.name', 'g.slug', 'g.description', 'g.external_id']; $ors = []; $i = 0; foreach ($searchCols as $col) { $i++; $ph = ":q{$i}"; $ors[] = "$col LIKE $ph"; $args[$ph] = $like; } $where[] = '(' . implode(' OR ', $ors) . ')'; } if ($cat > 0) { $where[] = 'g.category_id=:cat'; $args[':cat'] = $cat; } if ($prov !== '') { $where[] = 'g.provider=:prov'; $args[':prov'] = $prov; } if ($status === '1' || $status === '0') { $where[] = 'g.is_published=:st'; $args[':st'] = (int)$status; } if ($hasFeatured && ($feat === '1' || $feat === '0')) { $where[] = 'g.is_featured=:ft'; $args[':ft'] = (int)$feat; } $orderSql = 'g.created_at DESC'; switch ($sort) { case 'name': $orderSql = 'g.name ASC'; break; case 'popular': $orderSql = 'g.plays DESC, g.created_at DESC'; break; case 'featured': $orderSql = $hasFeatured ? 'g.is_featured DESC, g.created_at DESC' : 'g.created_at DESC'; break; default: $orderSql = 'g.created_at DESC'; } $whereSql = 'WHERE ' . implode(' AND ', $where); /* COUNT */ $st = $pdo->prepare("SELECT COUNT(*) FROM games g $whereSql"); $st->execute($args); $total = (int)$st->fetchColumn(); $pages = max(1, (int)ceil($total / $perPage)); $offset = ($page - 1) * $perPage; /* FETCH */ $selectFeatured = $hasFeatured ? ', g.is_featured' : ''; $sql = "SELECT g.id,g.name,g.slug,g.provider,g.external_id,g.is_published$selectFeatured, g.thumb_url,g.category_id,c.name AS category_name,g.created_at,g.updated_at,g.plays FROM games g LEFT JOIN categories c ON c.id=g.category_id $whereSql ORDER BY $orderSql LIMIT :lim OFFSET :off"; $st = $pdo->prepare($sql); foreach ($args as $k => $v) { $st->bindValue($k, $v); } $st->bindValue(':lim', $perPage, PDO::PARAM_INT); $st->bindValue(':off', $offset, PDO::PARAM_INT); $st->execute(); $rows = $st->fetchAll(PDO::FETCH_ASSOC); /* FILTER DATA */ $cats = $pdo->query("SELECT id,name FROM categories ORDER BY name ASC")->fetchAll(PDO::FETCH_ASSOC); $providers = $pdo->query("SELECT DISTINCT provider FROM games WHERE provider IS NOT NULL AND provider<>'' ORDER BY provider ASC")->fetchAll(PDO::FETCH_COLUMN); require __DIR__ . '/../inc/header.php'; ?>

Manage Games

Add Game External Import
Reset Found result(s)
Game Provider / Ext.ID Category Featured Status Plays Created Actions
No games.


Published Hidden
1): ?>