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): ?>