Bootstrap eCommerce Product Category Subcategory Page with Filter and Navigation

Last modified on March 2nd, 2021.

Do not underestimate the presence of a category page in your eCommerce website. It will help to elevate your online shop. A category page in an eCommerce website describes the classification of your online shop products.

There are popular libraries to create eCommerce websites with a category navigation menu. If you already have an eCommerce shop, this article will help to integrate the category navigation functionality.

It magnifies the shopping cart’s potential availability, to users. It’s one of the best marketing strategies to show off a gallery of product categories. It impresses customers and leads to impulsive growth in the conversion rate.

View Demo

Bootstrap eCommerce Category Page Output

What is inside?

  1. Importance of a category page in an eCommerce application
  2. About this example
  3. Bootstrap eCommerce product category gallery in HTML
  4. jQuery AJAX script to filter product categories
  5. PHP code to browse and filter categories by keyword
  6. PHP services prepare requests and execute queries
  7. Database script
  8. Output: eCommerce product-subcategory

Importance of a category page in an eCommerce website

In a previous article, we have seen the necessity of a product gallery in an eCommerce website.

In this article, it tells the importance of an eCommerce product category page.

  1. It helps to check based on which the eCommerce products are classified.
  2. It reveals the variety or domain that the eCommerce application covers.
  3. Category page with search supports narrowing down the category result among the vast availability.
  4. A category page with proper navigation leads to easy category/product browsing in an eCommerce application.
  5. It will attract people by showing the wide classification of your products selling online.

About this example

An eCommerce website includes classified products. It has a variety of categories and subcategories on which the product classification made.

In the case of having a huge database of product categories, an interface must help to browse categories easily.

This example shows the product categories and subcategories in a gallery format.

It contains a search filter to browse product categories. It also fetches subcategories by clicking the main categories. The categories and the subcategories are from the database.

It uses Bootstrap to design the UI to display the product category gallery. It uses jQuery AJAX to get subcategories based on the selected category.

The following image shows the file structure created for this eCommerce website subcategory example.

eCommerce Product Category File Structure

This HTML code displays the gallery structure of the eCommerce website  product categories and subcategories using a Bootstrap template.

By default, it only displays the parent categories in a gallery format.

On clicking a parent category tile, it invokes an AJAX code to fetch the subcategory list.

The subcategories are shown in the same gallery format as the main category.

index.php

<html>
<head>
<title>Category-subcategory-gallery-with-search</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link href="./vendor/bootstrap/css/bootstrap.min.css" rel="stylesheet" />
<script src="./vendor/jquery/jquery.min.js" type="text/javascript"></script>
<script src="./vendor/bootstrap/js/bootstrap.min.js"></script>
</head>
<body>
<div class="container">
<div class="h2 font-weight-bold mt-3">Product Category</div>
<form name="cards" id="cards" action="" method="get">
<div class='form-row mt-5 mt-4'>
<div class='col-md-6 form-inline'>
<label class="px-3">Name </label><input type='text'
class='form-control' name='category' id='category' value="<?php echo $keyword; ?>">
<input class="btn btn-secondary ml-2" type="submit" value="Search"
name="search">
</div>
</div>
<div>
<?php
if (! empty($categoryResult)) {
$categoryArray = array_chunk($categoryResult, 4);
$i = 1;
foreach ($categoryArray as $column) {
?><div class="form-row mb-3" id="category-row-<?php echo $i;?>">
<?php
foreach ($column as $k => $v) {
?>
<div class="col-md-3 mt-3 rounded"
id="cat-id-<?php echo $column[$k]["id"];?>"
onclick="showSubcategory('<?php echo $column[$k]["id"];?>','<?php echo $i;?>','<?php echo $column[$k]["category_name"];?>')">
<div class="text-center">
<img src="data/image-bird.jpg" class="img-thumbnail mt-4">
<div class="text-center font-weight-bold mt-3 mb-3"><?php echo $column[$k]["category_name"];?></div>
</div>
</div>
<?php
}
?>
<div class="form-row bg-light mt-3 w-100 subcategory-row d-none"></div>
</div>
<?php
$i ++;
}
}
?>
</div>
</form>
</div>
<script src="./assets/js/category.js"></script>
</body>
</html>

jQuery AJAX script to filter product categories

This JavaScript code defines the showSubcategory() function. This function receives the selected parent category id.

It sends the selected category details to the server. In the success block, it will receive the subcategory gallery HTML as a response from the server.

On selecting the main category, the jQuery script will apply a sliding effect on displaying the subcategory panel.

assets/category.js

function showSubcategory(id, row, categoryName) {
	$(".col-md-3").removeClass("border border-success");
	$(".subcategory-row").hide();
	$.ajax({
				url : "ajax/get-subcategory.php",
				type : "POST",
				data : "category-id=" + id +"&name=" + categoryName,
				success : function(response) {
					$("#cat-id-" + id).addClass("border border-success");
					$(".subcategory-row").removeClass("d-none");
					$(".subcategory-row").html("");
					var parent = $("#category-row-" + row);
				    parent.find(".subcategory-row").append(response);					
					parent.find(".subcategory-row").slideToggle();
					$("#closeWindow").on('click', function() {
						$("#cat-id-" + id).removeClass("border border-success");
								$(".subcategory-row").slideUp();
							});
				}
			});
}

PHP code to browse and filter categories by keyword

In this section, it shows the PHP script to filter categories by entered keyword. This script will be at the beginning of the landing page.

index.php (Category search by keyword)

<?php
use Phppot\Category;

require_once __DIR__ . '/Model/Category.php';
$categoryModel = new Category();
$keyword = "";
if (! empty($_GET["category"])) {
    $keyword = $_GET["category"];
    $categoryResult = $categoryModel->getCategoryByName($keyword);
} else {
    $categoryResult = $categoryModel->getAllCategory();
}
?>

This is an AJAX endpoint called on selecting the main category tile. It builds the subcategory gallery in a HTML format.

This format is printed in this endpoint and sent as an AJAX response.

ajax/get-subcategory.php

<?php
use Phppot\Category;

if (! empty($_POST["category-id"])) {
    require_once __DIR__ . '/../Model/Category.php';
    $categoryModel = new Category();
    $subcategoryResult = $categoryModel->getAllSubcategory($_POST["category-id"]);
    $html = '<div class="h5 font-weight-bold w-75 px-3 p-2">' . $_POST["name"] . ' > Subcategories</div><div class="w-25 text-right px-3 p-2 close" id="closeWindow">X</div>';
    if (! empty($subcategoryResult)) {
        foreach ($subcategoryResult as $k => $v) {
            $html .= "<div class='col-md-3'><div class='text-center'><img src='" . $subcategoryResult[$k]["image_path"] . "' id='" . $subcategoryResult[$k]["id"] . "' class='rounded mt-3'><div class='text-center font-weight-bold mt-3 mb-3'>" . $subcategoryResult[$k]["sub_category_name"] . "</div></div></div>";
        }
    }
    print($html);
    exit();
}

PHP classes prepare requests and execute queries

This Category model has the PHP functions to read categories from the database.

The getCategoryByName() method appends the condition with the entered search keyword. This condition is optional and available if and only if the user uses the search box.

The getAllSubcategory() method receives the selected parent category id as its parameter. Based on this, it fetches data from the subcategory database.

Model/Category.php

<?php
namespace Phppot;

class Category
{

    private $ds;

    function __construct()
    {
        require_once __DIR__ . './../lib/DataSource.php';
        $this->ds = new DataSource();
    }

    function getAllSubcategory($categoryId)
    {
        $query = "SELECT * FROM tbl_sub_category WHERE category_id = ?";
        $paramType = 'i';
        $paramArray = array(
            $categoryId
        );
        $result = $this->ds->select($query, $paramType, $paramArray);
        return $result;
    }

    function getAllCategory()
    {
        $query = "SELECT * FROM tbl_category";
        $result = $this->ds->select($query);
        return $result;
    }

    function getCategoryByName($search)
    {
        $query = "SELECT * FROM tbl_category WHERE category_name LIKE  '%" . $search . "%'";
        $result = $this->ds->select($query);
        return $result;
    }
}

This is a routine DataSource I have created for many of my examples uses the database.

It uses MySQLi and prepared statements for executing database operations.

It connects the prepares query statements and binds the params into them.

lib/DataSource.php

<?php
namespace Phppot;

/**
 * Generic datasource class for handling DB operations.
 * Uses MySqli and PreparedStatements.
 *
 * @version 2.3
 */
class DataSource
{

    // PHP 7.1.0 visibility modifiers are allowed for class constants.
    // when using above 7.1.0, declare the below constants as private
    const HOST = 'localhost';

    const USERNAME = 'root';

    const PASSWORD = '';

    const DATABASENAME = 'category-example';

    private $conn;

    /**
     * PHP implicitly takes care of cleanup for default connection types.
     * So no need to worry about closing the connection.
     *
     * Singletons not required in PHP as there is no
     * concept of shared memory.
     * Every object lives only for a request.
     *
     * Keeping things simple and that works!
     */
    function __construct()
    {
        $this->conn = $this->getConnection();
    }

    /**
     * If connection object is needed use this method and get access to it.
     * Otherwise, use the below methods for insert / update / etc.
     *
     * @return \mysqli
     */
    public function getConnection()
    {
        $conn = new \mysqli(self::HOST, self::USERNAME, self::PASSWORD, self::DATABASENAME);

        if (mysqli_connect_errno()) {
            trigger_error("Problem with connecting to database.");
        }

        $conn->set_charset("utf8");
        return $conn;
    }

    /**
     * To get database results
     *
     * @param string $query
     * @param string $paramType
     * @param array $paramArray
     * @return array
     */
    public function select($query, $paramType = "", $paramArray = array())
    {
        $stmt = $this->conn->prepare($query);
        if (! empty($paramType) && ! empty($paramArray)) {
            $this->bindQueryParams($stmt, $paramType, $paramArray);
        }

        $stmt->execute();
        $result = $stmt->get_result();

        if ($result->num_rows > 0) {
            while ($row = $result->fetch_assoc()) {
                $resultset[] = $row;
            }
        }

        if (! empty($resultset)) {
            return $resultset;
        }
    }

    /**
     * To insert
     *
     * @param string $query
     * @param string $paramType
     * @param array $paramArray
     * @return int
     */

    /**
     * To execute query
     *
     * @param string $query
     * @param string $paramType
     * @param array $paramArray
     */
    public function execute($query, $paramType = "", $paramArray = array())
    {
        $stmt = $this->conn->prepare($query);

        if (! empty($paramType) && ! empty($paramArray)) {
            $this->bindQueryParams($stmt, $paramType = "", $paramArray = array());
        }
        $stmt->execute();
    }

    /**
     * 1.
     * Prepares parameter binding
     * 2. Bind prameters to the sql statement
     *
     * @param string $stmt
     * @param string $paramType
     * @param array $paramArray
     */
    public function bindQueryParams($stmt, $paramType, $paramArray = array())
    {
        $paramValueReference[] = & $paramType;
        for ($i = 0; $i < count($paramArray); $i ++) {
            $paramValueReference[] = & $paramArray[$i];
        }
        call_user_func_array(array(
            $stmt,
            'bind_param'
        ), $paramValueReference);
    }

    /**
     * To get database results
     *
     * @param string $query
     * @param string $paramType
     * @param array $paramArray
     * @return array
     */
    public function numRows($query, $paramType = "", $paramArray = array())
    {
        $stmt = $this->conn->prepare($query);

        if (! empty($paramType) && ! empty($paramArray)) {
            $this->bindQueryParams($stmt, $paramType, $paramArray);
        }

        $stmt->execute();
        $stmt->store_result();
        $recordCount = $stmt->num_rows;
        return $recordCount;
    }
}

Database script

This EOD diagram shows the relationship between the tbl_category and tbl_sub_category tables.

Database EOD

Import this database script before running this example on your server.

This script includes INSERT queries to load the sample data to run this example.

--
-- Database: `category-example`
--

-- --------------------------------------------------------

--
-- Table structure for table `tbl_category`
--

CREATE TABLE `tbl_category` (
  `id` int(11) NOT NULL,
  `category_name` varchar(255) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1;

--
-- Dumping data for table `tbl_category`
--

INSERT INTO `tbl_category` (`id`, `category_name`) VALUES
(1, 'Category1'),
(2, 'Category2'),
(3, 'Category3'),
(4, 'Category4'),
(5, 'Category5'),
(6, 'Category6'),
(7, 'Category10');

-- --------------------------------------------------------

--
-- Table structure for table `tbl_sub_category`
--

CREATE TABLE `tbl_sub_category` (
  `id` int(11) NOT NULL,
  `category_id` int(11) NOT NULL,
  `sub_category_name` varchar(255) NOT NULL,
  `image_path` varchar(255) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1;

--
-- Dumping data for table `tbl_sub_category`
--

INSERT INTO `tbl_sub_category` (`id`, `category_id`, `sub_category_name`, `image_path`) VALUES
(1, 1, 'Flat', 'data/images1.jpg'),
(2, 1, 'Round', 'data/images2.jpg'),
(3, 1, 'Square', 'data/images3.jpg'),
(4, 1, 'Oval', 'data/images4.jpg'),
(6, 2, 'Checker Plate', 'data/images1.jpg'),
(7, 2, 'Satin Sheets', 'data/images2.jpg'),
(8, 2, 'Hot & Cold Sheet', 'data/images3.jpg'),
(9, 3, 'Rectangular', 'data/images4.jpg'),
(10, 3, 'Square Tubing', 'data/images5.jpg'),
(11, 3, 'Round Tubing', 'data/images1.jpg'),
(12, 3, 'Black Pipe', 'data/images2.jpg'),
(13, 4, 'Sample1', 'data/images3.jpg'),
(14, 4, 'Sample2', 'data/images4.jpg\r\n'),
(15, 5, 'Sample3', 'data/images1.jpg');

--
-- Indexes for dumped tables
--

--
-- Indexes for table `tbl_category`
--
ALTER TABLE `tbl_category`
  ADD PRIMARY KEY (`id`);

--
-- Indexes for table `tbl_sub_category`
--
ALTER TABLE `tbl_sub_category`
  ADD PRIMARY KEY (`id`),
  ADD KEY `category_id_rel` (`category_id`) USING BTREE;

--
-- AUTO_INCREMENT for dumped tables
--

--
-- AUTO_INCREMENT for table `tbl_category`
--
ALTER TABLE `tbl_category`
  MODIFY `id` int(11) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=9;

--
-- AUTO_INCREMENT for table `tbl_sub_category`
--
ALTER TABLE `tbl_sub_category`
  MODIFY `id` int(11) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=16;

--
-- Constraints for dumped tables
--

--
-- Constraints for table `tbl_sub_category`
--
ALTER TABLE `tbl_sub_category`
  ADD CONSTRAINT `tbl_sub_category_ibfk_1` FOREIGN KEY (`category_id`) REFERENCES `tbl_category` (`id`);

Output: eCommerce product-subcategory

This screenshot shows the output on searching the eCommerce product categories by a keyword.

The figure shows the populated the entered keyword in the search form.

eCommerce Product Category Search Output

Conclusion

We have seen how to create the eCommerce website category subcategory gallery with a search option.

This article describes the importance of the category page in an eCommerce website.

This example shows the product category with an image preview. It adds more beauty to the category page compared to the text-based category card.

Thus, a simple example helps you to create category navigation with a search for your eCommerce website.

Download

Leave a Reply

Your email address will not be published. Required fields are marked *

↑ Back to Top