Add attribute filter bar to product listing with dynamic selection
This commit is contained in:
parent
6132472b62
commit
1ef0f7c8bf
@ -132,3 +132,68 @@
|
||||
min-height: 36px;
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 1024px) {
|
||||
.home-nav__item a {
|
||||
font-size: 1rem;
|
||||
padding: 5px 24px;
|
||||
}
|
||||
}
|
||||
|
||||
/* ==========================================================
|
||||
ATTRIBUTE FILTER BAR
|
||||
========================================================== */
|
||||
|
||||
.attrbar {
|
||||
width: 100%;
|
||||
background-color: #f8f9fa;
|
||||
border-bottom: 1px solid #ddd;
|
||||
padding: 10px 0;
|
||||
}
|
||||
|
||||
.attrbar__inner {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.attr-filter-form {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 15px;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.attr-filter-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 5px;
|
||||
font-size: 0.9rem;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.attr-filter-item select {
|
||||
padding: 4px 8px;
|
||||
border: 1px solid #ccc;
|
||||
border-radius: 4px;
|
||||
background-color: #fff;
|
||||
cursor: pointer;
|
||||
font-size: 0.85rem;
|
||||
}
|
||||
|
||||
.attr-filter-reset {
|
||||
font-size: 0.85rem;
|
||||
color: #e63946;
|
||||
text-decoration: none;
|
||||
padding: 4px 8px;
|
||||
border: 1px solid #e63946;
|
||||
border-radius: 4px;
|
||||
background-color: transparent;
|
||||
transition: all 0.2s ease;
|
||||
}
|
||||
|
||||
.attr-filter-reset:hover {
|
||||
background-color: #e63946;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
137
attrbar.php
Normal file
137
attrbar.php
Normal file
@ -0,0 +1,137 @@
|
||||
<?php
|
||||
// attrbar.php
|
||||
require_once __DIR__ . '/lib/bootstrap.php';
|
||||
$conn = db_connect();
|
||||
$currentCategory = isset($_GET['category']) ? $_GET['category'] : 'all';
|
||||
|
||||
$catId = null;
|
||||
$categoriesConfig = [
|
||||
'iphone' => 20,
|
||||
'ipad' => 21,
|
||||
'macbook' => 22,
|
||||
'airpods' => 23,
|
||||
'accessories' => 24,
|
||||
];
|
||||
|
||||
if (isset($categoriesConfig[$currentCategory])) {
|
||||
$catId = $categoriesConfig[$currentCategory];
|
||||
}
|
||||
|
||||
// Fetch available attributes for the category if selected
|
||||
$attributes = [];
|
||||
if ($catId) {
|
||||
// Only show attributes related to the products in the active category
|
||||
$stmtAttr = $conn->prepare("
|
||||
SELECT DISTINCT a.attributeID, a.name, a.unit
|
||||
FROM attributes a
|
||||
JOIN productAttributes pa ON a.attributeID = pa.attributeID
|
||||
JOIN products p ON pa.productID = p.productID
|
||||
WHERE p.categoryID = ?
|
||||
ORDER BY a.name
|
||||
");
|
||||
$stmtAttr->bind_param("i", $catId);
|
||||
$stmtAttr->execute();
|
||||
$resAttr = $stmtAttr->get_result();
|
||||
while ($row = $resAttr->fetch_assoc()) {
|
||||
$attributes[] = $row;
|
||||
}
|
||||
$stmtAttr->close();
|
||||
} else {
|
||||
// Or all active across any product?
|
||||
// User typically filters by category first. But if 'all', maybe just get top attributes.
|
||||
$resAttr = $conn->query("
|
||||
SELECT DISTINCT a.attributeID, a.name, a.unit
|
||||
FROM attributes a
|
||||
JOIN productAttributes pa ON a.attributeID = pa.attributeID
|
||||
ORDER BY a.name LIMIT 5
|
||||
");
|
||||
if ($resAttr) {
|
||||
while ($row = $resAttr->fetch_assoc()) {
|
||||
$attributes[] = $row;
|
||||
}
|
||||
}
|
||||
}
|
||||
?>
|
||||
|
||||
<?php if (!empty($attributes)): ?>
|
||||
<div class="attrbar" aria-label="Attributfilter">
|
||||
<div class="attrbar__inner container">
|
||||
<form action="index.php" method="GET" class="attr-filter-form">
|
||||
<?php if (isset($_GET['category'])): ?>
|
||||
<input type="hidden" name="category" value="<?= htmlspecialchars($_GET['category']) ?>">
|
||||
<?php endif; ?>
|
||||
<?php if (isset($_GET['search'])): ?>
|
||||
<input type="hidden" name="search" value="<?= htmlspecialchars($_GET['search']) ?>">
|
||||
<?php endif; ?>
|
||||
|
||||
<?php foreach ($attributes as $attr):
|
||||
$attrId = $attr['attributeID'];
|
||||
$attrName = $attr['name'] . ($attr['unit'] ? ' (' . $attr['unit'] . ')' : '');
|
||||
|
||||
// Fetch distinct values for this attribute based on current category
|
||||
if ($catId) {
|
||||
$vStmt = $conn->prepare("
|
||||
SELECT DISTINCT pa.valueString, pa.valueNumber, pa.valueBool
|
||||
FROM productAttributes pa
|
||||
JOIN products p ON pa.productID = p.productID
|
||||
WHERE p.categoryID = ? AND pa.attributeID = ?
|
||||
ORDER BY pa.valueString, pa.valueNumber
|
||||
");
|
||||
$vStmt->bind_param("ii", $catId, $attrId);
|
||||
} else {
|
||||
$vStmt = $conn->prepare("
|
||||
SELECT DISTINCT valueString, valueNumber, valueBool
|
||||
FROM productAttributes
|
||||
WHERE attributeID = ?
|
||||
ORDER BY valueString, valueNumber
|
||||
");
|
||||
$vStmt->bind_param("i", $attrId);
|
||||
}
|
||||
$vStmt->execute();
|
||||
$vRes = $vStmt->get_result();
|
||||
$values = [];
|
||||
while ($vRow = $vRes->fetch_assoc()) {
|
||||
if ($vRow['valueString'] !== null) $values[] = $vRow['valueString'];
|
||||
elseif ($vRow['valueNumber'] !== null) $values[] = $vRow['valueNumber'];
|
||||
elseif ($vRow['valueBool'] !== null) $values[] = $vRow['valueBool'] ? 'Ja' : 'Nein';
|
||||
}
|
||||
$vStmt->close();
|
||||
|
||||
if (empty($values)) continue;
|
||||
$paramName = "attr_" . $attrId;
|
||||
$selectedValue = isset($_GET[$paramName]) ? $_GET[$paramName] : '';
|
||||
?>
|
||||
<div class="attr-filter-item">
|
||||
<label for="attr_<?= $attrId ?>"><?= htmlspecialchars($attrName) ?>:</label>
|
||||
<select name="<?= $paramName ?>" id="attr_<?= $attrId ?>" onchange="this.form.submit()">
|
||||
<option value="">Alle</option>
|
||||
<?php foreach ($values as $val): ?>
|
||||
<option value="<?= htmlspecialchars($val) ?>" <?= (string)$val === (string)$selectedValue ? 'selected' : '' ?>>
|
||||
<?= htmlspecialchars($val) ?>
|
||||
</option>
|
||||
<?php endforeach; ?>
|
||||
</select>
|
||||
</div>
|
||||
<?php endforeach; ?>
|
||||
|
||||
<noscript>
|
||||
<button type="submit">Filtern</button>
|
||||
</noscript>
|
||||
<?php
|
||||
// Show reset button only if at least one attr filter is active
|
||||
$hasActiveFilter = false;
|
||||
foreach ($_GET as $k => $v) {
|
||||
if (strpos($k, 'attr_') === 0 && $v !== '') {
|
||||
$hasActiveFilter = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ($hasActiveFilter): ?>
|
||||
<a href="index.php<?= isset($_GET['category']) ? '?category='.urlencode($_GET['category']) : '' ?>" class="attr-filter-reset">Filter zurücksetzen</a>
|
||||
<?php endif; ?>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
|
||||
@ -92,15 +92,39 @@ $categories = [
|
||||
<?php if ($activeCategory === 'all' || $activeCategory === $key): ?>
|
||||
|
||||
<?php
|
||||
$stmt = $conn->prepare("
|
||||
SELECT productID, model, description, imagePath
|
||||
FROM products
|
||||
WHERE categoryID = ?
|
||||
");
|
||||
$baseQuery = "SELECT DISTINCT p.productID, p.model, p.description, p.imagePath FROM products p ";
|
||||
$whereClauses = ["p.categoryID = ?"];
|
||||
$params = [$cat['id']];
|
||||
$types = "i";
|
||||
|
||||
// Find attribute filters from $_GET
|
||||
$attrIndex = 0;
|
||||
foreach ($_GET as $k => $v) {
|
||||
if ($v !== '' && strpos($k, 'attr_') === 0) {
|
||||
$attrId = (int)substr($k, 5);
|
||||
$attrAlias = "pa" . $attrIndex;
|
||||
$baseQuery .= " JOIN productAttributes $attrAlias ON p.productID = $attrAlias.productID ";
|
||||
|
||||
// Assume string or number comparison. For simplicity, check string or number.
|
||||
// In DB, valueString, valueNumber, valueBool can be checked.
|
||||
$whereClauses[] = "($attrAlias.attributeID = ? AND ($attrAlias.valueString = ? OR $attrAlias.valueNumber = ? OR ($attrAlias.valueBool = 1 AND ? = 'Ja') OR ($attrAlias.valueBool = 0 AND ? = 'Nein')))";
|
||||
|
||||
$stmt->bind_param("i", $cat['id']); // i = integer
|
||||
$params[] = $attrId;
|
||||
$params[] = $v;
|
||||
$params[] = is_numeric($v) ? (float)$v : 0;
|
||||
$params[] = $v;
|
||||
$params[] = $v;
|
||||
$types .= "isdss";
|
||||
|
||||
$attrIndex++;
|
||||
}
|
||||
}
|
||||
|
||||
$sql = $baseQuery . " WHERE " . implode(" AND ", $whereClauses);
|
||||
|
||||
$stmt = $conn->prepare($sql);
|
||||
$stmt->bind_param($types, ...$params);
|
||||
$stmt->execute();
|
||||
|
||||
$result = $stmt->get_result();
|
||||
?>
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user