Reputation: 322
I have built a search (https://brawlins.com/oer/index.php) and I want to enable user to be able to select filters to limit the search results after their initial search. I have the filters populated in a dropdown menu on my search page (https://brawlins.com/oer/search.php?term=) but I am not sure how to filter down the results once a user clicks on them. I want the users to be able to select multiple options as well. I create a class to store the filters. Below is the code from my filter class:
<?php
class filterContentProvider {
private $conn;
public function __construct($conn) {
$this->conn = $conn;
}
public function getType ($conn) {
$query = $this->conn->prepare("SELECT type, COUNT(*) as total FROM oer_search GROUP BY type");
$query->execute();
$filterHTML .= "<h3 class='filterTitle'>Type</h3>";
$filterHTML .= "<div class'dropdown'>";
$filterHTML .= "<button class='btn btn-filter dropdown-toggle' type='button' id='dropdownMenuButton' data-toggle='dropdown' aria-haspopup='true' aria-expanded='false'>Select - Type</button>";
$filterHTML .= "<div class='dropdown-menu scrollable-menu' aria-labelledby='dropdownMenuButton'>";
//$filterHTML .= "<option value=''>- Type -</option>";
while($row = $query->fetch(PDO::FETCH_ASSOC)) {
$type = $row["type"];
$total = number_format($row["total"]);
$filterHTML .= "<a class='dropdown-item' href='search.php?type=$type'>$type ($total)</a>";
}
$filterHTML .= "</div>";
$filterHTML .= "</div>"; //end of dropdown
return $filterHTML;
}
public function getSubject ($conn) {
$query = $this->conn->prepare("SELECT subject, COUNT(*) as total FROM oer_search GROUP BY subject");
$query->execute();
$filterHTML .= "<h3 class='filterTitle'>Subject</h3>";
$filterHTML .= "<div class'dropdown'>";
$filterHTML .= "<button class='btn btn-filter dropdown-toggle' type='button' id='dropdownMenuButton' data-toggle='dropdown' aria-haspopup='true' aria-expanded='false'>Select - Subject</button>";
$filterHTML .= "<div class='dropdown-menu scrollable-menu' aria-labelledby='dropdownMenuButton'>";
while($row = $query->fetch(PDO::FETCH_ASSOC)) {
$subject = $row["subject"];
$total = number_format($row["total"]);
if ($subject != "") {
$filterHTML .= "<a class='dropdown-item' href='search.php?subject=$subject'>$subject ($total)</a>";
}
}
$filterHTML .= "</div>";
$filterHTML .= "</div>"; //end of dropdown
return $filterHTML;
}
public function getLicense ($conn) {
$query = $this->conn->prepare("SELECT license, COUNT(*) as total FROM oer_search GROUP BY license");
$query->execute();
$filterHTML .= "<h3 class='filterTitle'>License</h3>";
$filterHTML .= "<div class'dropdown'>";
$filterHTML .= "<button class='btn btn-filter dropdown-toggle' type='button' id='dropdownMenuButton' data-toggle='dropdown' aria-haspopup='true' aria-expanded='false'>Select - License</button>";
$filterHTML .= "<div class='dropdown-menu scrollable-menu' aria-labelledby='dropdownMenuButton'>";
while($row = $query->fetch(PDO::FETCH_ASSOC)) {
$license = $row["license"];
$total = number_format($row["total"]);
if ($license != "") {
$filterHTML .= "<a class='dropdown-item' href='index-test.php?license=$license'>$license ($total)</a>";
}
}
$filterHTML .= "</div>";
$filterHTML .= "</div>"; //end of dropdown
return $filterHTML;
}
public function getReviewed ($conn) {
$query = $this->conn->prepare("SELECT review, COUNT(*) as total FROM oer_search GROUP BY review");
$query->execute();
$filterHTML .= "<h3 class='filterTitle'>Reviewed</h3>";
$filterHTML .= "<div class'dropdown'>";
$filterHTML .= "<button class='btn btn-filter dropdown-toggle' type='button' id='dropdownMenuButton' data-toggle='dropdown' aria-haspopup='true' aria-expanded='false'>Select - Reviewed</button>";
$filterHTML .= "<div class='dropdown-menu scrollable-menu' aria-labelledby='dropdownMenuButton'>";
while($row = $query->fetch(PDO::FETCH_ASSOC)) {
$review = $row["review"];
$total = number_format($row["total"]);
if ($review != "") {
$filterHTML .= "<a class='dropdown-item' href='index-test.php?review=$review'>$review ($total)</a>";
}
}
$filterHTML .= "</div>";
$filterHTML .= "</div>"; //end of dropdown
return $filterHTML;
}
public function getOrigin ($conn) {
$query = $this->conn->prepare("SELECT source, COUNT(*) as total FROM oer_search GROUP BY source");
$query->execute();
$filterHTML .= "<h3 class='filterTitle'>Source</h3>";
$filterHTML .= "<div class'dropdown'>";
$filterHTML .= "<button class='btn btn-filter dropdown-toggle' type='button' id='dropdownMenuButton' data-toggle='dropdown' aria-haspopup='true' aria-expanded='false'>Select - Source</button>";
$filterHTML .= "<div class='dropdown-menu scrollable-menu' aria-labelledby='dropdownMenuButton'>";
while($row = $query->fetch(PDO::FETCH_ASSOC)) {
$source = $row["source"];
$total = number_format($row["total"]);
if ($source != "") {
$filterHTML .= "<a class='dropdown-item' href='index-test.php?source=$source'>$source ($total)</a>";
}
}
$filterHTML .= "</div>";
$filterHTML .= "</div>"; //end of dropdown
return $filterHTML;
}
}
?>
Here is the code I am using on my search.php page. Any help would be much appreciated.
<?php
include("config.php");
include("classes/siteResultsProvider.php");
include("classes/imageResultsProvider.php");
include("classes/filterContentProvider.php");
include("classes/filterImageProvider.php");
if(isset($_GET["term"])){
$term = $_GET["term"];
}
if(isset($_GET["collection"])){
$collection = $_GET["collection"];
}
else {
$collection = "open_content";
}
$page = isset($_GET["page"]) ? $_GET["page"] : 1;
?>
<!DOCTYPE html>
<html lang="en">
<head>
<title>SOAR</title>
<?php
include("header.php");
?>
<div class="wrapper">
<div class="header">
<div class="headerContent">
<div class="searchContainer">
<form action="search.php" method="GET">
<div class="searchBarContainer">
<input type="hidden" name="collection" value="<?php echo $collection; ?>">
<input class="searchBox" type="text" name="term" value="<?php echo htmlspecialchars($term, ENT_QUOTES) ?>" aria-label="search box">
<button class="searchButton">
<img src="images/search-icon.png" alt="search icon">
</button>
</div>
</form>
</div>
</div><!--end of headerContent-->
<div class="tabsContainer">
<ul class="tabList">
<li class="<?php echo $collection == 'open_content' ? 'active' : '' ?>">
<a href='<?php echo "search.php?term=$term&collection=open_content"; ?>'><i class="fas fa-book-open"></i> Open Content</a>
</li>
<li class="<?php echo $collection == 'images' ? 'active' : '' ?>">
<a href='<?php echo "search.php?term=$term&collection=images"; ?>'><i class="fas fa-images"></i> Images</a>
</li>
</ul>
</div>
</div><!--end of header-->
<!-------------------------beginning of main section where seach results will display-------------------------->
<?php
if($collection == "open_content") {
$filters = new filterContentProvider($conn);
}
else {
$filters = new filterImageProvider($conn);
}
if($collection == "open_content") {
$filterType = $filters->getType($conn);
$filterSubject = $filters->getSubject($conn);
$filterOrigin = $filters->getOrigin($conn);
$fitlerLicense = $filters->getLicense($conn);
$filterReviewed = $filters->getReviewed($conn);
echo "<div class='filterContainer'>
<div class='filterContent'>
<div class='filter'>
$filterType
</div>
<div class='filter'>
$filterSubject
</div>
<div class='filter'>
$filterOrigin
</div>
<div class='filter'>
$fitlerLicense
</div>
<div class='filter'>
$filterReviewed
</div>
</div>
</div>";
}
else {
$imageFilterOrigin = $filters->getImageOrigin($conn);
$imageFilterLicense = $filters->getImageLicense($conn);
echo "<div class='filterContainer'>
<div class='filterContent'>
<div class='filter'>
$imageFilterOrigin
</div>
<div class='filter'>
$imageFilterLicense
</div>
</div>
</div>";
}
?>
<div class="mainResultsSection">
<?php
if($collection == "open_content") {
$resultsProvider = new siteResultsProvider($conn);
$pageSize = 25;
}
else {
$resultsProvider = new imageResultsProvider($conn);
$pageSize = 50;
}
$numResults = $resultsProvider->getNumResults($term);
echo "<p class='resultsCount'>" . number_format($numResults) . " results found</p>";
echo $resultsProvider->getResultsHTML($page, $pageSize, $term);
?>
</div>
<div class="paginationContainer">
<div class="pageButtons">
<div class="pageNumberContainer">
<img src="images/pageStart.png" alt="Start of page image">
</div>
<?php
$pagesToShow = 10;
$numPages = ceil($numResults / $pageSize);
$pagesLeft = min($pagesToShow, $numPages);
$currentPage = $page - floor($pagesToShow / 2);
if($currentPage < 1) {
$currentPage = 1;
}
if($currentPage + $pagesLeft > $numPages + 1) {
$currentPage = $numPages + 1 - $pagesLeft;
}
while($pagesLeft != 0 && $currentPage <= $numPages) {
if($currentPage == $page) {
echo "<div class='pageNumberContainer'>
<img src='images/pageSelected.png' alt='selected page page image'/>
<span class='pageNumber'>$currentPage</span>
</div>";
}
else {
echo "<div class='pageNumberContainer'>
<a href='search.php?term=$term&collection=$collection&page=$currentPage'>
<img src='images/page.png' alt='pages image'/>
<span class='pageNumber'>$currentPage</span>
</a>
</div>";
}
$currentPage++;
$pagesLeft--;
}
?>
<div class="pageNumberContainer">
<img src="images/pageEnd.png" alt="End of page image">
</div>
</div>
</div><!--end of pagination container-->
</div><!--end of wrapper-->
<script src="https://cdn.jsdelivr.net/gh/fancyapps/[email protected]/dist/jquery.fancybox.min.js"></script>
<script src="https://unpkg.com/masonry-layout@4/dist/masonry.pkgd.min.js"></script>
<script type="text/javascript" src="js/script.js"></script>
</body>
</html>
Upvotes: 2
Views: 1945
Reputation: 556
It seems like you'd want to do a couple of things to get this working.
If you want the results to be asynchronous:
onchange="addFilter('type', this.value)"
) See https://www.w3schools.com/jsref/event_onchange.aspaddFilter
) send the filters and query string back to your PHP script via an AJAX request. If you're using jQuery, the get
method would work for you. https://api.jquery.com/jquery.get/$('#myContainer').html(results);
in jQuery)Here's a really simple example:
test.php
<?php
// Look up the results here
// You'll probably want to do something more performant that this; it's just a lazy example. :)
// ...
$query = $this->conn->prepare("SELECT type, COUNT(*) as total FROM oer_search WHERE type LIKE :type AND subject LIKE :subject GROUP BY type");
$query->execute([
'type' => isset($_GET['type'] ? $_GET['type'] : '%',
'subject' => isset($_GET['subject'] ? $_GET['subject'] : '%',
]);
// ...
?>
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<script src="jquery-3.4.1.min.js"></script>
<script>
function addFilter(name, value) {
var url = '/test.php?';
var urlParams = new URLSearchParams(window.location.search);
var keys = urlParams.keys();
for(key of keys) {
if (key == name) {
continue;
}
url += key + '=' + urlParams.get(key) + '&';
}
url += name + '=' + value;
window.history.pushState({}, "", );
$.get(url, function(data) {
$('#results').html(data);
});
}
</script>
</head>
<body>
<select onchange="addFilter('type', this.value)">
<option></option>
<option>value 1</option>
<option>value 2</option>
</select>
<select onchange="addFilter('subject', this.value)">
<option></option>
<option>value 1</option>
<option>value 2</option>
</select>
<div id="results"></div>
</body>
</html>
If you don't care/want the page to reload:
Just make the onchange
event submit the form with the search parameters again. If you use jQuery, the submit
method would work. Be sure to select the options appropriately in the select inputs, or they'll clear out each time (making it impossible to set more than one).
Upvotes: 3