Thursday 21 October 2021

PHP Project | How to Create eCommerce Product Filter with Pagination using Vanilla JavaScript


How to Add Multiple Search Filter in PHP with pagination for eCommerce Website Products filters using pure Vanilla JavaScript. If you are also looking for How can we implement search filters with pagination in eCommerce website then you have come on the right place because here we have share PHP Project tutorial on How to Create filter in PHP with MySQL, JavaScript and Bootstrap 5 library. Under this tutorial, we have latest web technology like Vanilla JavaScript and Bootstrap 5 library for build eCommerce website product filter with pagination.

Now we have come on the right topic and here we will show you how to filter product which has been come under price range, brand or gender filter. The main benefits of eCommerce Website product filter is for filter product from large number of product by price range filter, brand filter or gender filter. So most of the Online eCommerce website has put product filter on their website and with the help of that filter customer product from large number of product and found the specific product within their price range or brands. If you have seen any Online Shopping website, so on that website there are large number of product has been listed on that website, so when we have come on e-commerce website for buy product then we have to face difficulty for find product, so at that time product filter will help to user for search product on website and it has reduces user time for found product with the help of price range filter or brand filter.

PHP Project | How to Create eCommerce Product Filter with Pagination using Vanilla JavaScript

In this post you, we will learn you how to filter product on eCommerce website using PHP with pure JavaScript, Bootstrap 5 and MySQL. If you have build Product filter for Online Shopping website then good User interface (UI) is required for product filter so customer can easily search product with multiple filter. Under this tutorial, we will use Radio Button filter, Price Range filter and Checkbox filter using JavaScript. When user click on Radio Button or price filter or Checkbox filter then JavaScript will trigger fetch API and it will fetch data from MySQL database and display on web page without refresh of web page. So here for Ajax operation we have use JavaScript Fetch API. Under this tutorial we will put multiple search filter at the left sidebar, and here we have will make brand filter using radio button, price range filter and brand filter using checkbox. This is live product filter which has been run based on JavaScript Fetch API Ajax request and most of the e-commerce website use Ajax for search filter. Below you can find the source code which will help you to build product filter with multiple search filter and pagination for you ecommerce website project using PHP with JavaScript, Bootstrap 5 and MySQL Database.









Source Code


Create MySQL Table


For build product filter, first we have to create MySQL table for store product data. So for create table in MySQL database, you have to run following SQL script which will create sample_data table in your MySQL Database.


--
-- Table structure for table `sample_data`
--

CREATE TABLE `sample_data` (
  `sample_id` int(11) NOT NULL,
  `name` text NOT NULL,
  `sku` int(11) NOT NULL,
  `mpn` int(11) NOT NULL,
  `price` int(11) NOT NULL,
  `in_stock` varchar(20) NOT NULL,
  `currency` varchar(10) NOT NULL,
  `brand` varchar(255) NOT NULL,
  `description` text NOT NULL,
  `images` text NOT NULL,
  `gender` varchar(30) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1;

--
-- Indexes for table `sample_data`
--
ALTER TABLE `sample_data`
  ADD PRIMARY KEY (`sample_id`);

--
-- AUTO_INCREMENT for dumped tables
--

--
-- AUTO_INCREMENT for table `sample_data`
--
ALTER TABLE `sample_data`
  MODIFY `sample_id` int(11) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=1;


index.html


Under this tutorial, we have use pure JavaScript for create product filter with pagination. So here we have use .html file as our index file. Under this file we have only include Bootstrap 5 Stylesheet library for create layout for product filter and for pagination. Under this file you can also find JavaScript code for display all product with pagination link.

For display all product with pagination, here we have create one load_product(page) function. This function will be called when page has been load in browser, then it will send AJAX request using JavaScript Fetch API to process.php file for fetch product data from database. So this function will receive product data with pagination link data from server in JSON format and convert that data into HTML format and display all product with pagination link on web page.

Under this Product Filter tutorial, we have also add Skeleton Loading Effect with Bootstrap 5 stylesheet and JavaScript. So when page will load it will first load Product Skeleton and then after it will display product on web page with pagination link. Here skeleton effect will also work when we have click on pagination link also.

In this Product Filter Tutoral, we have cover following type of filter for search product from large amount of product.

  1. Radio Button Filter - In this tutorial, we have use Radio Button filter for load or display or filter product according to particular Gender product only. e.g. Suppose user want to see only "Male" gender product, then user can select "Male" Gender Radio button, then user can only view "Male" Gender product on web page without refresh of web page.
  2. Price Range Filter - Under this PHP Project on Advance product filter and here we have also include one more filter option like price range filter. So by this price ranger filter, user on ecommerce website can filter product based on price. So user can product list which comes under particular price range. In this tutorial for implement price range filter, here we have use pure JavaScript with Bootstrap 5 library PHP script and MySQL database.
  3. Checkbox Filter - Checkbox filter is mainly used for filter data with multiple condition, so here in Advance Product Filter with Pagination tutorial, we have also implement Checkbox filter for list product of Multiple brand on web page without refresh of web page. Here we have use pure javascript with PHP for add Multiple Checkbox filter under this product filter tutorial.
  4. Search Filter - Search Filter is used for search product data from database according to search query. By using this Search filter Customer can search product by type their query in search textbox and they can get filter data on web page by using JavaScript. Here for search live data we have use PHP script with pure JavaScript.

After apply all filter, suppose we want to remove fiter, so we have to refresh page, but in this tutorial, we have also add feature for clear all filter or reset filter. So by click on button all applied filter will be removed and it will load all product data on web page without refresh of web page by using pure JavaScript.


<!doctype html>
<html lang="en">
    <head>
        <meta charset="utf-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <meta name="description" content="">
        <meta name="author" content="">
        <meta name="generator" content="">
        <title>Product Filter in PHP using Vanilla JavaScript</title>

        <link rel="canonical" href="">

        <!-- CSS only -->
        <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3" crossorigin="anonymous">


        <style>
          .bd-placeholder-img {
            font-size: 1.125rem;
            text-anchor: middle;
            -webkit-user-select: none;
            -moz-user-select: none;
            user-select: none;
          }

          @media (min-width: 768px) {
            .bd-placeholder-img-lg {
              font-size: 3.5rem;
            }
          }

        </style>
    </head>
  
    <body>
    
        <div class="col-lg-8 mx-auto">

            <main>
                <h1 class="text-center mt-3 mb-3">Product Filter in PHP using Vanilla JavaScript - Live Data Search - 8</h1>

                <div class="row">

                    <div class="col-sm-3 p-3 bg-light">

                        <button type="button" name="clear_filter" class="btn btn-warning btn-sm form-control mb-2" id="clear_filter">Clear Filter</button>

                        <p class="fs-4 text-center border-bottom text-bold">Gender</p>

                        <div id="gender_filter" class="mb-2"></div>

                        <p class="fs-4 text-center border-bottom text-bold">Price</p>

                        <div id="price_filter" class="mb-2"></div>

                        <p class="fs-4 text-center border-bottom text-bold">Brand</p>

                        <div id="brand_filter" class="overflow-auto mb-3" style="height:350px;"></div>

                    </div>

                    <div class="col-sm-9">

                        <div class="input-group mt-3 mb-3">
                            <input type="text" class="form-control" id="search_textbox" placeholder="Search Product" aria-label="Search Product" aria-describedby="search_button" />
                            <button type="button" class="btn btn-primary" id="search_button">Search</button>
                        </div>
                        
                        <div id="product_area"></div>

                        <div id="skeleton_area"></div>

                        <div id="pagination_area" class="mt-2 mb-5" ></div>
                    </div>

                </div>
                
                
            </main>
        </div>

    </body>
</html>

<script>

function $(selector){

    return document.querySelector(selector);

}

load_product(1);

function load_product(page = 1, query = '')
{
    $('#product_area').style.display = 'none';

    $('#skeleton_area').style.display = 'block';

    $('#skeleton_area').innerHTML = make_skeleton();

    fetch('process.php?page='+page+query+'').then(function(response){

        return response.json();

    }).then(function(responseData){

        var html = '';

        if(responseData.data)
        {
            if(responseData.data.length > 0)
            {
                html += '<p class="h6">'+responseData.total_data+' Products Found</p>';

                html += '<div class="row">';

                for(var i = 0; i < responseData.data.length; i++)
                {
                    html += '<div class="col-md-3 mb-2 p-3">';

                    html += '<img src ="'+responseData.data[i].image+'" class="img-fluid border mb-3 p-3" />';

                    html += '<p class="fs-6 text-center">'+responseData.data[i].name+'&nbsp;&nbsp;&nbsp;<span class="badge bg-info text-dark">'+responseData.data[i].brand+'</span><br />';

                    html += '<span class="fw-bold text-danger"><span>&#8377;</span> '+responseData.data[i].price+'</span>';

                    html += '</div>';
                }

                html += '</div>';

                $('#product_area').innerHTML = html;
            }
            else
            {
                $('#product_area').innerHTML = '<p class="h6">No Product Found</p>';
            }
        }

        if(responseData.pagination)
        {
            $('#pagination_area').innerHTML = responseData.pagination;
        }

        setTimeout(function(){

            $('#product_area').style.display = 'block';

            $('#skeleton_area').style.display = 'none';

        }, 3000);

    });
}

function make_skeleton()
{
    var output = '<div class="row">';

    for(var count = 0; count < 8; count++)
    {
        output += '<div class="col-md-3 mb-3 p-4">';

        output += '<div class="mb-2 bg-light text-dark" style="height:240px;"></div>';

        output += '<div class="mb-2 bg-light text-dark" style="height:50px;"></div>';

        output += '<div class="mb-2 bg-light text-dark" style="height:25px;"></div>';

        output += '</div>';
    }

    output += '</div>';

    return output;
}

load_filter();

function load_filter()
{
    fetch('process.php?action=filter').then(function(response){

        return response.json();

    }).then(function(responseData){

        if(responseData.gender)
        {

            if(responseData.gender.length > 0)            
            {
                var html = '<div class="list-group">';

                for(var i = 0; i < responseData.gender.length; i++)
                {
                    html += '<label class="list-group-item">';

                    html += '<input type="radio" class="form-check-input me-1 gender_filter" name="gender_filter" value="'+responseData.gender[i].name+'" >';

                    html += responseData.gender[i].name+' <span class="text-muted">('+responseData.gender[i].total+')</span>';

                    html += '</label>';
                }

                html += '</div>';

                $('#gender_filter').innerHTML = html;

                var gender_elements = document.getElementsByClassName('gender_filter');

                for(var i = 0; i < gender_elements.length; i++)
                {
                    gender_elements[i].onclick = function(){

                        load_product(page = 1, make_query());

                    }
                }
            }

        }

        if(responseData.price)
        {
            if(responseData.price.length > 0)
            {
                var html = '<div class="list-group">';

                for(var i = 0; i < responseData.price.length; i++)
                {
                    html += '<a href="#" class="list-group-item list-group-item-action price_filter" id="'+responseData.price[i].condition+'"><span>&#8377;</span> '+responseData.price[i].name+' <span class="text-muted">('+responseData.price[i].total+')</a>';
                }

                html += '</div>';

                $('#price_filter').innerHTML = html;

                var price_elements = document.getElementsByClassName('price_filter');

                for(var i = 0; i < price_elements.length; i++)
                {
                    price_elements[i].onclick = function()
                    {
                        remove_active_class(price_elements);

                        this.classList.add('active');

                        load_product(page = 1, make_query());
                    }
                }
            }
        }

        if(responseData.brand)
        {
            if(responseData.brand.length > 0)
            {
                var html = '<div class="list-group">';

                for(var i = 0; i < responseData.brand.length; i++)
                {
                    html += '<label class="list-group-item">';

                    html += '<input type="checkbox" class="form-check-input me-1 brand_filter" value="'+responseData.brand[i].name+'" />';

                    html += responseData.brand[i].name + ' <span class="text-muted">('+responseData.brand[i].total+')</span>';

                    html += '</label>';
                }

                html += '</div>';

                $('#brand_filter').innerHTML = html;

                var brand_elements = document.getElementsByClassName("brand_filter");

                for(var i = 0; i < brand_elements.length; i++)
                {
                    brand_elements[i].onclick = function(){

                        load_product(page = 1, make_query());

                    }
                }
            }
        }

    });
}

function make_query()
{
    var query = '';

    var gender_elements = document.getElementsByClassName('gender_filter');

    for(var i = 0; i < gender_elements.length; i++)
    {
        if(gender_elements[i].checked)
        {
            query += '&gender_filter='+gender_elements[i].value+'';
        }
    }

    var price_elements = document.getElementsByClassName('price_filter');

    for(var i = 0; i < price_elements.length; i++)
    {
        if(price_elements[i].matches('.active'))
        {
            query += '&price_filter='+price_elements[i].getAttribute('id')+'';
        }
    }

    var brand_elements = document.getElementsByClassName('brand_filter');

    var brandlist = '';

    for(var i = 0; i < brand_elements.length; i++)
    {
        if(brand_elements[i].checked)
        {
            brandlist += brand_elements[i].value +',';
        }
    }

    if(brandlist != '')
    {
        query += '&brand_filter='+brandlist+'';
    }

    var search_query = $('#search_textbox').value;

    query += '&search_filter='+search_query+'';

    return query;
}

function remove_active_class(element)
{
    for(var i = 0; i < element.length; i++)
    {
        if(element[i].matches('.active'))
        {
            element[i].classList.remove("active");
        }
    }
}

$('#clear_filter').onclick = function(){

    var gender_elements = document.getElementsByClassName('gender_filter');

    for(var count = 0; count < gender_elements.length; count++)
    {
        gender_elements[count].checked = false;
    }

    var price_elements = document.getElementsByClassName('price_filter');

    remove_active_class(price_elements);

    var brand_elements = document.getElementsByClassName('brand_filter');

    for(var count = 0; count < brand_elements.length; count++)
    {
        brand_elements[count].checked = false;
    }

    $('#search_textbox').value = '';

    load_product(1, '');

}

$('#search_button').onclick = function(){

    var search_query = $('#search_textbox').value;

    if(search_query != '')
    {
        load_product(page = 1, make_query());
    }

}

</script>


process.php


This file has been use for perform server side operation. Under this file we have use PHP script for process server side data. In this file first we have make database connection using PHP PDO() class.

This file has been receive Ajax request for fetch product data from database and make pagination link. So based on $page number variable value which has been get from url and based on that value it has been fetch product data from database for display particular page product on web page.

This file also fetch data for different type of filter like gender filter, price range filter, search filter and brand filter from Mysql table.


<?php

//process.php

$connect = new PDO("mysql:host=localhost; dbname=test", "root", "");

if(isset($_GET["page"]))
{
	$data = array();

	$limit = 8;

	$page = 1;

	if($_GET["page"] > 1)
	{
		$start = (($_GET["page"] - 1) * $limit);

		$page = $_GET["page"];
	}
	else
	{
		$start = 0;
	}

	$where = '';

	$search_query = '';

	if(isset($_GET["gender_filter"]))
	{
		$where .= ' gender = "'.trim($_GET["gender_filter"]).'" ';

		$search_query .= '&gender_filter='.trim($_GET["gender_filter"]);
	}

	if(isset($_GET["price_filter"]))
	{
		if($where != '')
		{
			$where .= ' AND '. $_GET["price_filter"];
		}
		else
		{
			$where .= $_GET["price_filter"];
		}

		$search_query .= '&price_filter='.$_GET["price_filter"];
	}

	if(isset($_GET["brand_filter"]))
	{
		$brand_array = explode(",", $_GET["brand_filter"]);

		$brand_condition = '';

		foreach($brand_array as $brand)
		{
			$brand_condition .= 'brand = "' .$brand . '" OR ';
		}

		$brand_condition = substr($brand_condition, 0, -4);

		if($where != '')
		{
			$where .= ' AND ('.$brand_condition.')';
		}
		else
		{
			$where .= $brand_condition;
		}

		$search_query .= '&brand_filter='.$_GET["brand_filter"];
	}

	if(isset($_GET["search_filter"]))
	{
		$search_string = str_replace(" ", "%", $_GET["search_filter"]);

		if($where != '')
		{
			$where .= ' AND ( name LIKE "%'.$search_string.'%" ) ';
		}
		else
		{
			$where .= 'name LIKE "%'.$search_string.'%" ';
		}
		$search_query .= '&search_filter='.$_GET["search_filter"].'';
	}

	if($where != '')
	{
		$where = 'WHERE ' . $where;
	}

	$query = "
	SELECT name, price, images, brand 
	FROM sample_data 
	".$where."
	ORDER BY sample_id ASC
	";

	$filter_query = $query . ' LIMIT ' . $start . ', ' . $limit . '';

	$statement = $connect->prepare($query);

	$statement->execute();

	$total_data = $statement->rowCount();

	$result = $connect->query($filter_query);

	foreach($result as $row)
	{
		$image_array = explode(" ~ ", $row["images"]);

		$data[] = array(
			'name'		=>	$row['name'],
			'price'		=>	$row['price'],
			'brand'		=>	$row['brand'],
			'image'		=>	$image_array[0]
		);
	}

	$pagination_html = '
	<nav aria-label="Page navigation example">
  		<ul class="pagination justify-content-center">
	';

	$total_links = ceil($total_data/$limit);

	$previous_link = '';

	$next_link = '';

	$page_link = '';

	$page_array = '';

	if($total_links > 4)
	{
		if($page < 5)
		{
			for($count = 1; $count <= 5; $count++)
			{
				$page_array[] = $count;
			}

			$page_array[] = '...';

			$page_array[] = $total_links;
		}
		else
		{
			$end_limit = $total_links - 5;

			if($page > $end_limit)
			{
				$page_array[] = 1;

				$page_array[] = '...';

				for($count = $end_limit; $count <= $total_links; $count++)
				{
					$page_array[] = $count;
				}
			}
			else
			{
				$page_array[] = 1;

				$page_array[] = '...';

				for($count = $page - 1; $count <= $page + 1; $count++)
				{
					$page_array[] = $count;
				}

				$page_array[] = '...';

				$page_array[] = $total_links;
			}
		}
	}
	else
	{
		for($count = 1; $count <= $total_links; $count++)
		{
			$page_array[] = $count;
		}
	}

	for($count = 0; $count < count($page_array); $count++)
	{
		if($page == $page_array[$count])
		{
			$page_link .= '
				<li class="page-item active">
		      		<a class="page-link" href="#">'.$page_array[$count].'</a>
		    	</li>
			';

			$previous_id = $page_array[$count] - 1;

			if($previous_id > 0)
			{
				$previous_link = '<li class="page-item"><a class="page-link" href="javascript:load_product('.$previous_id.', `'.$search_query.'`)">Previous</a></li>';
			}
			else
			{
				$previous_link = '
					<li class="page-item disabled">
				        <a class="page-link" href="#">Previous</a>
				    </li>
				';
			}

			$next_id = $page_array[$count] + 1;

			if($next_id > $total_links)
			{
				$next_link = '
					<li class="page-item disabled">
		        		<a class="page-link" href="#">Next</a>
		      		</li>
				';
			}
			else
			{
				$next_link = '
				<li class="page-item"><a class="page-link" href="javascript:load_product('.$next_id.', `'.$search_query.'`)">Next</a></li>
				';
			}
		}
		else
		{
			if($page_array[$count] == '...')
			{
				$page_link .= '
					<li class="page-item disabled">
		          		<a class="page-link" href="#">...</a>
		      		</li>
				';
			}
			else
			{
				$page_link .= '
					<li class="page-item">
						<a class="page-link" href="javascript:load_product('.$page_array[$count].', `'.$search_query.'`)">'.$page_array[$count].'</a>
					</li>
				';
			}
		}
	}

	$pagination_html .= $previous_link . $page_link . $next_link;


	$pagination_html .= '
		</ul>
	</nav>
	';

	$output = array(
		'data'		=>	$data,
		'pagination'=>	$pagination_html,
		'total_data'=>	$total_data
	);

	echo json_encode($output);
}

if(isset($_GET["action"]))
{
	$data = array();

	$query = "
	SELECT gender, COUNT(sample_id) AS Total 
	FROM sample_data 
	GROUP BY gender
	";

	foreach($connect->query($query) as $row)
	{
		$sub_data = array();
		$sub_data['name'] = $row['gender'];
		$sub_data['total'] = $row['Total'];
		$data['gender'][] = $sub_data;
	}

	$price_range = array(
		'price < 1000'					=>	'Under 1000',
		'price > 1000 && price < 5000'	=>	'1000 - 5000',
		'price > 5000 && price < 10000'	=>	'5000 - 10000',
		'price > 10000 && price < 20000'=>	'10000 - 20000',
		'price > 20000'					=>	'Over 20000'
	);

	foreach($price_range as $key => $value)
	{
		$query = "
		SELECT COUNT(sample_id) AS Total 
		FROM sample_data 
		WHERE ".$key." 
		";

		$sub_data = array();

		foreach($connect->query($query) as $row)
		{
			$sub_data['name'] = $value;
			$sub_data['total'] = $row['Total'];
			$sub_data['condition'] = $key;
		}
		$data['price'][] = $sub_data;
	}

	$query = "
	SELECT brand, COUNT(sample_id) AS Total 
	FROM sample_data 
	GROUP BY brand
	";

	foreach($connect->query($query) as $row)
	{
		$sub_data = array();
		$sub_data['name'] = $row['brand'];
		$sub_data['total'] = $row['Total'];
		$data['brand'][] = $sub_data;
	}

	echo json_encode($data);
}

?>









10 comments:

  1. i think it will help if the filter sidebar could hide on mobile view so users wouldnt't have to scroll for long before accessing the results.

    ReplyDelete
    Replies
    1. add @media screen and (max-width: 600px){.classfilter {display:none}}
      this will hide the filter with screen size of less than 600px.
      then add a filter button with full screen overlay for filter

      Delete
  2. Hi,

    Image, name, brand and price not showing in product area.
    Filter sidebar oke

    Any idea what's wrong?

    ReplyDelete
  3. Hi,

    Is it possible to provide source code?

    ReplyDelete
  4. Hi,

    Image, name, brand and price not showing in product area.
    Filter sidebar oke

    Any idea what's wrong?

    ReplyDelete
  5. Hi,

    Image, name, brand and price not showing in product area.
    Filter sidebar oke

    Any idea what's wrong?

    ReplyDelete
  6. please tell me why images, name, etc not showing in main display

    ReplyDelete
  7. Incomplete tutorial. Files and data missing.

    ReplyDelete