query("SELECT value FROM settings WHERE `key` = 'active_theme'"); $res =$stmt->fetchColumn(); if ($res) { $active_theme =$res; } } catch (Exception $e) {} $theme_dir = __DIR__ . '/themes/' .$active_theme; if (!is_dir($theme_dir)) { $active_theme = 'default';$theme_dir = __DIR__ . '/themes/default'; } // --- Αρχικοποίηση Twig --- $loader = new \Twig\Loader\FilesystemLoader($theme_dir); $twig = new \Twig\Environment($loader, ['cache' => false]); $twig->addGlobal('session',$_SESSION); $twig->addGlobal('current_lang',$current_lang); // --- Φόρτωση Δυναμικών Κειμένων Site --- $siteTexts = []; try { $text_column = ($current_lang === 'en') ? 'text_value_en' : 'text_value_el'; $textsStmt =$pdo->query("SELECT text_key, {$text_column} as text_value FROM site_texts"); while ($row = $textsStmt->fetch(PDO::FETCH_ASSOC)) {$siteTexts[$row['text_key']] =$row['text_value']; } } catch (Exception $e) {} $twig->addGlobal('text',$siteTexts); // --- Φόρτωση Logo Site --- $site_logo = ''; try { $logoStmt =$pdo->prepare("SELECT value FROM settings WHERE `key` = 'site_logo'"); $logoStmt->execute(); $site_logo =$logoStmt->fetchColumn(); } catch (Exception $e) {} $twig->addGlobal('site_logo',$site_logo); try { // --- Φόρτωση Κατηγοριών --- $categoriesRaw =$pdo->query("SELECT * FROM categories ORDER BY sort_order ASC, name_el ASC")->fetchAll(PDO::FETCH_ASSOC); $categories = []; foreach ($categoriesRaw as $cat) {$cat['display_name'] = ($current_lang === 'en' && !empty($cat['name_en'])) ? $cat['name_en'] :$cat['name_el']; $categories[] =$cat; } // --- Λήψη Παραμέτρων Φίλτρων & ΣΕΛΙΔΟΠΟΙΗΣΗΣ --- $category_id = isset($_GET['category_id']) ? (int)$_GET['category_id'] : 0; $sort = isset($_GET['sort']) ?$_GET['sort'] : 'newest'; $min_price = (isset($_GET['min_price']) && is_numeric($_GET['min_price'])) ? (float)$_GET['min_price'] : null; $max_price = (isset($_GET['max_price']) && is_numeric($_GET['max_price'])) ? (float)$_GET['max_price'] : null; $search_query = isset($_GET['q']) ? trim($_GET['q']) : ''; // Παράμετροι Σελιδοποίησης $limit = isset($_GET['limit']) ? (int)$_GET['limit'] : 30; if (!in_array($limit, [30, 50, 100])) { $limit = 30; } // Default & Safety$page = isset($_GET['page']) ? (int)$_GET['page'] : 1; if ($page < 1) {$page = 1; } $current_category_name = null; $category_attributes = []; // --- ΔΙΑΣΠΑΣΗ ΤΟΥ SQL QUERY (Για να μετράμε και το σύνολο) --- $sql_select = "SELECT p.id, p.sku, p.title, p.price, p.created_at, pi.image_path"; $sql_from = " FROM products p LEFT JOIN product_images pi ON (p.id = pi.product_id AND pi.is_primary = 1)"; $sql_where = " WHERE p.status = 'available'"; $params = []; // 1. Φίλτρο Κατηγορίας if ($category_id > 0) { $catStmt =$pdo->prepare("SELECT name_el, name_en, attribute_group_id FROM categories WHERE id = ?"); $catStmt->execute([$category_id]); $catData =$catStmt->fetch(PDO::FETCH_ASSOC); if ($catData) { $current_category_name = ($current_lang === 'en' && !empty($catData['name_en'])) ?$catData['name_en'] : $catData['name_el'];$sql_where .= " AND (p.category_id = ? OR p.category_id IN (SELECT id FROM categories WHERE parent_id = ?))"; $params[] =$category_id; $params[] =$category_id; if ($catData['attribute_group_id']) { $attrStmt =$pdo->prepare(" SELECT a.id, a.name as name_el, a.name_en, a.unit, (SELECT GROUP_CONCAT(DISTINCT value SEPARATOR '||') FROM product_attribute_values WHERE attribute_id = a.id) as distinct_values FROM attributes a WHERE a.group_id = ? "); $attrStmt->execute([$catData['attribute_group_id']]); $catAttrsRaw =$attrStmt->fetchAll(PDO::FETCH_ASSOC); foreach ($catAttrsRaw as $a) {$a['display_name'] = ($current_lang === 'en' && !empty($a['name_en'])) ? $a['name_en'] :$a['name_el']; $category_attributes[] =$a; } } } } // 2. Έξυπνο Φίλτρο Αναζήτησης (Βελτιωμένο) if ($search_query !== '') { $clean_query = preg_replace('/[^\p{L}\p{N}\s\-]/u', ' ',$search_query); $words = preg_split('/\s+/', mb_strtolower($clean_query, 'UTF-8')); $words = array_filter($words, function($w) { return mb_strlen(trim($w)) > 1; }); if (!empty($words)) {$whereClauses = []; foreach ($words as $word) {$whereClauses[] = "(LOWER(COALESCE(p.sku, '')) LIKE CONCAT('%', ?, '%') OR LOWER(COALESCE(p.title, '')) LIKE CONCAT('%', ?, '%') OR LOWER(COALESCE(p.description, '')) LIKE CONCAT('%', ?, '%') OR LOWER(COALESCE(p.search_tags, '')) LIKE CONCAT('%', ?, '%'))"; array_push($params, $word,$word, $word,$word); } $sql_where .= " AND (" . implode(" AND ", $whereClauses) . ")"; } } // 3. Φίλτρο Τιμής if ($min_price !== null) {$sql_where .= " AND p.price >= ?"; $params[] =$min_price; } if ($max_price !== null) {$sql_where .= " AND p.price <= ?"; $params[] =$max_price; } // 4. Φίλτρο Δυναμικών Χαρακτηριστικών if (isset($_GET['attr']) && is_array($_GET['attr'])) { foreach ($_GET['attr'] as $attr_id =>$attr_val) { if (!empty($attr_val)) {$sql_where .= " AND EXISTS (SELECT 1 FROM product_attribute_values pav WHERE pav.product_id = p.id AND pav.attribute_id = ? AND pav.value = ?)"; $params[] = (int)$attr_id; $params[] =$attr_val; } } } // --- ΜΕΤΡΗΣΗ ΣΥΝΟΛΙΚΩΝ ΠΡΟΪΟΝΤΩΝ ΓΙΑ ΣΕΛΙΔΟΠΟΙΗΣΗ --- $countSql = "SELECT COUNT(p.id)" . $sql_from .$sql_where; $stmtCount = $pdo->prepare($countSql); $stmtCount->execute($params); $total_products = (int)$stmtCount->fetchColumn(); $total_pages = ceil($total_products / $limit); if ($page >$total_pages && $total_pages > 0) {$page = $total_pages; }$offset = ($page - 1) *$limit; // --- ΤΕΛΙΚΟ QUERY ΠΡΟΪΟΝΤΩΝ ΜΕ ΟΡΙΑ --- $sql =$sql_select . $sql_from .$sql_where; // 5. Ταξινόμηση if ($sort === 'price_asc') {$sql .= " ORDER BY p.price ASC"; } elseif ($sort === 'price_desc') {$sql .= " ORDER BY p.price DESC"; } else { $sql .= " ORDER BY p.id DESC"; } // 6. Προσθήκη Ορίων (Pagination) $sql .= " LIMIT " . $limit . " OFFSET " . $offset; // Εκτέλεση $stmt = $pdo->prepare($sql); $stmt->execute($params); $products =$stmt->fetchAll(PDO::FETCH_ASSOC); // --- ΕΝΣΩΜΑΤΩΣΗ ΧΑΡΑΚΤΗΡΙΣΤΙΚΩΝ ΣΤΑ ΠΡΟΪΟΝΤΑ --- if (!empty($products)) { $product_ids = array_column($products, 'id'); $inQuery = implode(',', array_fill(0, count($product_ids), '?')); $attrValsStmt =$pdo->prepare(" SELECT pav.product_id, a.name as name_el, a.name_en, a.unit, pav.value FROM product_attribute_values pav JOIN attributes a ON pav.attribute_id = a.id WHERE pav.product_id IN ($inQuery) "); $attrValsStmt->execute($product_ids); $all_attrs =$attrValsStmt->fetchAll(PDO::FETCH_ASSOC); $attrs_by_pid = []; foreach ($all_attrs as $attr) {$attr_name = ($current_lang === 'en' && !empty($attr['name_en'])) ? $attr['name_en'] :$attr['name_el']; $attrs_by_pid[$attr['product_id']][] = [ 'name' => $attr_name, 'value' => $attr['value'], 'unit' => $attr['unit'] ]; } foreach ($products as &$prod) {$prod['attributes'] = $attrs_by_pid[$prod['id']] ?? []; } unset($prod); } // --- ΔΗΜΙΟΥΡΓΙΑ BASE URL ΓΙΑ ΤΑ ΚΟΥΜΠΙΑ ΣΕΛΙΔΟΠΟΙΗΣΗΣ --- $qs =$_GET; unset($qs['page']); // Αφαιρούμε το page για να το βάλει δυναμικά το Twig $base_qs = http_build_query($qs);$pagination_url = 'index.php?' . ($base_qs ? $base_qs . '&' : '') . 'page='; } catch (Exception $e) { die("Σφάλμα ανάγνωσης δεδομένων: " . $e->getMessage()); } echo $twig->render('index.html.twig', [ 'site_title' => 'Hockey Gear CMS', 'categories' => $categories, 'products' => $products, 'current_category_name' => $current_category_name, 'category_id' => $category_id, 'category_attributes' => $category_attributes, 'search_query' => $search_query, 'filters' => $_GET, // Νέες μεταβλητές Σελιδοποίησης 'current_page' => $page, 'total_pages' => $total_pages, 'limit' => $limit, 'total_products' => $total_products, 'pagination_url' => $pagination_url ]);