Great question, Kahnu! You're saying:
You have a single PHP file (like
category.php) that displays all categories and their nested children, and you want to manage clean URLs like:
example.com/category/parent-category/child-category/grandchild-category/
So now, you need to handle this with .htaccess routing, and have PHP parse the category slugs dynamically from the URL.
✅ Step-by-Step Setup
🔁 1. Folder Structure Assumption
Your app is in:
/var/www/html/
├── .htaccess
├── category.php
└── other files...
🧾 2. Sample URLs to Support
-
example.com/category/parent/ -
example.com/category/parent/child/ -
example.com/category/parent/child/grandchild/
All handled by category.php.
⚙️ 3. .htaccess Rules
RewriteEngine On
RewriteBase /
# Redirect category slug path to category.php
RewriteRule ^category/(.*)$ category.php?path=$1 [L,QSA]
-
This will pass the entire slug path as
$_GET['path'] -
Example:
-
URL:
/category/parent/child/grandchild -
PHP gets:
$_GET['path'] = "parent/child/grandchild"
-
🧑💻 4. In category.php, Parse the Path
<?php
// Get the slug path
$path = isset($_GET['path']) ? $_GET['path'] : '';
// Split the slugs into an array
$slugs = array_filter(explode('/', $path));
// Example: ['parent', 'child', 'grandchild']
// You can now loop through these slugs to fetch each category level from your DB
$parent_id = 0;
$category = null;
foreach ($slugs as $slug) {
$stmt = $db->prepare("SELECT * FROM categories WHERE slug = ? AND parent_id = ?");
$stmt->execute([$slug, $parent_id]);
$category = $stmt->fetch(PDO::FETCH_ASSOC);
if (!$category) {
echo "Category not found!";
exit;
}
$parent_id = $category['id']; // Update for next level
}
// Now $category holds the last matched category
echo "<h1>{$category['name']}</h1>";
// You can also list its child categories or posts now
?>
📌 Example Use Case
URL:
example.com/category/electronics/mobile/smartphones
-
Parsed as:
['electronics', 'mobile', 'smartphones'] -
Final
$categorywill besmartphones, and its parent chain can be fetched for breadcrumbs.
✅ Summary
| Feature | Description |
|---|---|
.htaccess |
Pass nested slugs to one PHP file |
category.php |
Split path, recursively find categories |
| URL-friendly | Clean, SEO-friendly structure |
| Dynamic | Works for any depth of nesting |
Would you like a full example database structure with slugs + a working breadcrumb loop for this too?
Absolutely, Kahnu! Here's a complete working version of the same breadcrumb system using MySQLi instead of PDO.
✅ Full Working Example using mysqli
🧩 Database Table: categories
CREATE TABLE categories (
id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(255) NOT NULL,
slug VARCHAR(255) NOT NULL,
parent_id INT DEFAULT 0
);
🧪 Sample Data:
INSERT INTO categories (name, slug, parent_id) VALUES
('Electronics', 'electronics', 0),
('Mobile', 'mobile', 1),
('Smartphones', 'smartphones', 2),
('Feature Phones', 'feature-phones', 2),
('Accessories', 'accessories', 1);
⚙️ .htaccess Rewrite Rules
RewriteEngine On
RewriteBase /
# Route all /category/ paths to category.php
RewriteRule ^category/(.*)$ category.php?path=$1 [L,QSA]
🧑💻 category.php using mysqli
<?php
// Database connection
$mysqli = new mysqli("localhost", "your_user", "your_pass", "your_db");
if ($mysqli->connect_error) {
die("Connection failed: " . $mysqli->connect_error);
}
// Get slug path from URL
$path = isset($_GET['path']) ? $_GET['path'] : '';
$slugs = array_filter(explode('/', $path));
$breadcrumbs = [];
$parent_id = 0;
$current_category = null;
foreach ($slugs as $slug) {
$stmt = $mysqli->prepare("SELECT * FROM categories WHERE slug = ? AND parent_id = ?");
$stmt->bind_param("si", $slug, $parent_id);
$stmt->execute();
$result = $stmt->get_result();
if ($result->num_rows == 0) {
http_response_code(404);
echo "Category not found.";
exit;
}
$category = $result->fetch_assoc();
$breadcrumbs[] = $category;
$parent_id = $category['id'];
$current_category = $category;
$stmt->close();
}
// Output breadcrumbs
echo '<nav>';
echo '<a href="/">Home</a> > ';
foreach ($breadcrumbs as $i => $cat) {
$url = '/category/' . implode('/', array_slice($slugs, 0, $i + 1));
if ($i < count($breadcrumbs) - 1) {
echo "<a href=\"$url\">" . htmlspecialchars($cat['name']) . "</a> > ";
} else {
echo '<span>' . htmlspecialchars($cat['name']) . '</span>';
}
}
echo '</nav>';
// Output current category title
echo "<h1>" . htmlspecialchars($current_category['name']) . "</h1>";
// Optional: Show child categories
$stmt = $mysqli->prepare("SELECT * FROM categories WHERE parent_id = ?");
$stmt->bind_param("i", $current_category['id']);
$stmt->execute();
$children = $stmt->get_result();
if ($children->num_rows > 0) {
echo "<ul>";
while ($child = $children->fetch_assoc()) {
$child_path = $path . '/' . $child['slug'];
echo "<li><a href=\"/category/$child_path\">" . htmlspecialchars($child['name']) . "</a></li>";
}
echo "</ul>";
}
$stmt->close();
$mysqli->close();
?>
✅ Example URLs
| URL Path | Output Breadcrumb |
|---|---|
/category/electronics |
Home > Electronics |
/category/electronics/mobile |
Home > Electronics > Mobile |
/category/electronics/mobile/smartphones |
Home > Electronics > Mobile > Smartphones |
Would you like me to also generate a zip or GitHub-ready structure with this setup?
Yes, Kahnu — it's definitely possible and a great idea ✅
You can write a reusable function that takes either:
-
A category ID, or
-
A category slug
…and returns the full breadcrumb trail, climbing up the parent_id chain recursively or in a loop.
✅ PHP Function using MySQLi (Pass category id or slug)
function get_category_breadcrumbs($mysqli, $category_input, $type = 'id') {
$breadcrumbs = [];
// 1. Fetch the starting category
if ($type === 'id') {
$stmt = $mysqli->prepare("SELECT * FROM categories WHERE id = ?");
$stmt->bind_param("i", $category_input);
} else {
$stmt = $mysqli->prepare("SELECT * FROM categories WHERE slug = ?");
$stmt->bind_param("s", $category_input);
}
$stmt->execute();
$result = $stmt->get_result();
$category = $result->fetch_assoc();
$stmt->close();
if (!$category) {
return false; // not found
}
// 2. Climb up the parent tree
while ($category) {
array_unshift($breadcrumbs, $category); // add to beginning
if ($category['parent_id'] == 0) break;
$stmt = $mysqli->prepare("SELECT * FROM categories WHERE id = ?");
$stmt->bind_param("i", $category['parent_id']);
$stmt->execute();
$result = $stmt->get_result();
$category = $result->fetch_assoc();
$stmt->close();
}
return $breadcrumbs;
}
✅ Example Usage:
$mysqli = new mysqli("localhost", "your_user", "your_pass", "your_db");
// By ID
$breadcrumbs = get_category_breadcrumbs($mysqli, 3); // ID of "Smartphones"
// Or by Slug
// $breadcrumbs = get_category_breadcrumbs($mysqli, 'smartphones', 'slug');
if ($breadcrumbs) {
echo '<nav>';
echo '<a href="/">Home</a> > ';
foreach ($breadcrumbs as $i => $cat) {
$slug_parts = array_column(array_slice($breadcrumbs, 0, $i + 1), 'slug');
$path = '/category/' . implode('/', $slug_parts);
if ($i < count($breadcrumbs) - 1) {
echo "<a href=\"$path\">" . htmlspecialchars($cat['name']) . "</a> > ";
} else {
echo '<span>' . htmlspecialchars($cat['name']) . '</span>';
}
}
echo '</nav>';
} else {
echo "Category not found.";
}
✅ Output Example (for ID 3 → smartphones)
Home > Electronics > Mobile > Smartphones
✅ Summary
| Feature | Description |
|---|---|
| Flexible input | Accepts category id or slug |
| Clean output | Returns full hierarchy as array |
| SEO-friendly | Works with /category/slug/... format |
| Reusable | Can be used anywhere (post page, archive…) |
Would you like a similar function for posts, where it fetches the category → full breadcrumb trail from that?
0 Comments
Post a Comment