ORIGINAL POST
I want to create a navigation menu in PHP with Bootstrap 4. Problem is that one of the \'s is not right (the on
I added menu
to the database and check if it's 0 or 1. I have dropped the sub-sub menu's, but I will update this post if I add them.
function menu_builder($pdo, $parent_id) {
$sql = $pdo->prepare("SELECT * FROM menus");
if ($sql->execute()) {
while ($row = $sql->fetch(PDO::FETCH_ASSOC)) {
$array[$row['parent_id']][] = $row;
}
main_menu($array);
}
}
function main_menu ($array, $parent_id = 0) {
if (!empty($array[$parent_id])) {
foreach ($array[$parent_id] as $item) {
if ($item['menu'] == '0') {
echo " <li class=\"nav-item\">" . PHP_EOL;
echo " <a class=\"nav-link\" href=\"#\">" . $item['menu_naam'] . "</a>" . PHP_EOL;
main_menu($array, $item['id']);
echo " </li>" . PHP_EOL;
}
elseif ($item['menu'] == '1') {
echo " <li class=\"nav-item dropdown\"><a class=\"nav-link dropdown-toggle\" href=\"#\" id=\"navbarDropdown\" role=\"button\" data-toggle=\"dropdown\" aria-haspopup=\"true\" aria-expanded=\"false\">" . $item['menu_naam'] . "</a>" . PHP_EOL;
sub_menu($array, $item['id']);
echo " </li>" . PHP_EOL;
}
}
//echo "</div>" . PHP_EOL;
echo "</li>" . PHP_EOL;
}
}
function sub_menu ($array, $parent_id) {
if (!empty($array[$parent_id])) {
echo " <div class=\"dropdown-menu\" aria-labelledby=\"navbarDropdown\">" . PHP_EOL;
foreach ($array[$parent_id] as $item) {
echo " <a class=\"dropdown-item\" href=\"" . $item['url'] . "\">" . $item['menu_naam'] . "</a>" . PHP_EOL;
}
echo " </div>" . PHP_EOL;
}
}
?>
<header class="navbar navbar-dark bg-dark fixed-top navbar-expand-sm">
<a class="navbar-brand" href="#">Webshop</a>
<button class="navbar-toggler" style="background: #000000" type="button" data-toggle="collapse" data-target="#navbar-header" aria-controls="navbar-header">
☰
</button>
<div class="navbar-collapse collapse show" id="navbar-header">
<?php
echo "<ul class=\"navbar-nav mr-auto\">";
echo menu_builder($pdo, 0);
echo "</ul>" . PHP_EOL;
?>
</div>
</header>
EDIT: To have sub-menu's the code looks like this and you need the following css
too.
function menu_builder($pdo, $parent_id) {
$sql = $pdo->prepare("SELECT * FROM menus");
if ($sql->execute()) {
while ($row = $sql->fetch(PDO::FETCH_ASSOC)) {
$array[$row['parent_id']][] = $row;
}
main_menu($array);
}
}
function main_menu ($array, $parent_id = 0) {
if (!empty($array[$parent_id])) {
foreach ($array[$parent_id] as $item) {
if ($item['menu'] == '0') {
echo " <li class=\"nav-item\">" . PHP_EOL;
echo " <a class=\"nav-link\" href=\"" . $item['url'] . "\">" . $item['menu_naam'] . "</a>" . PHP_EOL;
main_menu($array, $item['id']);
echo " </li>" . PHP_EOL;
}
elseif ($item['menu'] == '1') {
echo " <li class=\"nav-item dropdown\">". PHP_EOL;
echo " <a class=\"nav-link dropdown-toggle\" href=\"" . $item['url'] . "\" id=\"navbarDropdown\" role=\"button\" data-toggle=\"dropdown\" aria-haspopup=\"true\" aria-expanded=\"false\">" . $item['menu_naam'] . "</a>" . PHP_EOL;
sub_menu($array, $item['id']);
echo " </li>" . PHP_EOL;
}
}
}
}
function sub_menu ($array, $parent_id) {
if (!empty($array[$parent_id])) {
echo " <div class=\"dropdown-menu\" aria-labelledby=\"navbarDropdown\">" . PHP_EOL;
foreach ($array[$parent_id] as $item) {
if ($item['sub_menu'] == '0') {
echo " <a class=\"dropdown-item\" href=\"" . $item['url'] . "\">" . $item['menu_naam'] . "</a>" . PHP_EOL;
}
elseif ($item['sub_menu'] == '1') {
echo " <div class=\"dropdown-submenu\">" . PHP_EOL;
echo " <a class=\"dropdown-item dropdown-toggle\" href=\"" . $item['url'] . "\">" . $item['menu_naam'] . "</a>" . PHP_EOL;
sub_sub_menu($array, $item['id']);
echo " </div>" . PHP_EOL;
}
}
echo " </div>" . PHP_EOL;
}
}
function sub_sub_menu ($array, $parent_id) {
if (!empty($array[$parent_id])) {
echo " <div class=\"dropdown-menu\" aria-labelledby=\"navbarDropdown\">" . PHP_EOL;
foreach ($array[$parent_id] as $item) {
echo " <a class=\"dropdown-item\" href=\"" . $item['url'] . "\">" . $item['menu_naam'] . "</a>" . PHP_EOL;
}
}
echo " </div>" . PHP_EOL;
}
The CSS you need for the sub-menu's because bootstrap doesn't have support for it by default (https://stackoverflow.com/a/45755948/2877035):
.dropdown-submenu {
position: relative;
}
.dropdown-submenu a::after {
transform: rotate(-90deg);
position: absolute;
right: 6px;
top: .8em;
}
.dropdown-submenu .dropdown-menu {
top: 0;
left: 100%;
margin-left: .1rem;
margin-right: .1rem;
}
and the jQuery:
$('.dropdown-menu a.dropdown-toggle').on('click', function(e) {
if (!$(this).next().hasClass('show')) {
$(this).parents('.dropdown-menu').first().find('.show').removeClass("show");
}
var $subMenu = $(this).next(".dropdown-menu");
$subMenu.toggleClass('show');
$(this).parents('li.nav-item.dropdown.show').on('hidden.bs.dropdown', function(e) {
$('.dropdown-submenu .show').removeClass("show");
});
return false;
});
I have maked some changes for bootstrap 4.1
<style type="text/css">
.navbar .dropdown-toggle, .navbar .dropdown-menu a {
cursor: pointer;
}
.navbar .dropdown-item.active, .navbar .dropdown-item:active {
color: inherit;
text-decoration: none;
background-color: inherit;
}
.navbar .dropdown-item:focus, .navbar .dropdown-item:hover {
color: #16181b;
text-decoration: none;
background-color: #f8f9fa;
}
@media (min-width: 767px) {
.navbar .dropdown-toggle:not(.nav-link)::after {
display: inline-block;
width: 0;
height: 0;
margin-left: .5em;
vertical-align: 0;
border-bottom: .3em solid transparent;
border-top: .3em solid transparent;
border-left: .3em solid;
}
}
</style>
<script type="text/javascript">
$(document).ready(function () {
$('.navbar .dropdown-item').on('click', function (e) {
var $el = $(this).children('.dropdown-toggle');
var $parent = $el.offsetParent(".dropdown-menu");
$(this).parent("li").toggleClass('open');
if (!$parent.parent().hasClass('navbar-nav')) {
if ($parent.hasClass('show')) {
$parent.removeClass('show');
$el.next().removeClass('show');
$el.next().css({"top": -999, "left": -999});
} else {
$parent.parent().find('.show').removeClass('show');
$parent.addClass('show');
$el.next().addClass('show');
$el.next().css({"top": $el[0].offsetTop, "left": $parent.outerWidth() - 4});
}
e.preventDefault();
e.stopPropagation();
}
});
$('.navbar .dropdown').on('hidden.bs.dropdown', function () {
$(this).find('li.dropdown').removeClass('show open');
$(this).find('ul.dropdown-menu').removeClass('show open');
});
});
</script>
<?php function menu_builder1($db, $parent_id) {
$sql = $db->prepare("SELECT * FROM menu WHERE status = 1 ORDER BY position ASC");
if($sql->execute()) {
while ($row = $sql->fetch(PDO::FETCH_ASSOC)) {
$array[$row['menu_sub_id']][] = $row;
}
main_menu1($array);
}
}
function main_menu1($array, $parent_id = false) {
if(!empty($array[$parent_id])) {
foreach ($array[$parent_id] as $item) {
if ($item['dropdown'] == false) {
echo '<li class="nav-item active"><a class="nav-link" href="' . $item['href'] . '">' . $item['name'] . '</a></li>';
}
elseif ($item['dropdown'] == true) {
echo '<li class="nav-item dropdown"><a class="nav-link dropdown-toggle" id="dropdown2" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">' . $item['name'] . '</a>';
sub_menu1($array, $item['menu_id']);
echo '</li>';
}
}
}
}
function sub_menu1($array = array(), $parent_id = false) {
if(!empty($array[$parent_id])) {
echo '<ul class="dropdown-menu" aria-labelledby="dropdown2">';
foreach ($array[$parent_id] as $item) {
if ($item['dropdown'] == false) {
echo '<li class="dropdown-item"><a href="' . $item['href'] . '">' . $item['name'] . '</a></li>';
}
elseif ($item['dropdown'] == true) {
echo '<li class="dropdown-item dropdown"><a class="dropdown-toggle" id="dropdown2-1" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">' . $item['name'] . '</a>';
sub_sub_menu1($array, $item['menu_id']);
echo '</li>';
}
}
echo "</ul>";
}
}
function sub_sub_menu1($array = array(), $parent_id = false) {
if(!empty($array[$parent_id])) {
echo '<ul class="dropdown-menu" aria-labelledby="dropdown2-1">';
foreach ($array[$parent_id] as $item) {
if ($item['dropdown'] == false) {
echo '<li class="dropdown-item"><a href="' . $item['href'] . '">' . $item['name'] . '</a></li>';
}
}
echo "</ul>";
}
}
?>
<div class="navbar navbar-expand-md navbar-dark bg-dark mb-4" role="navigation">
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarCollapse" aria-controls="navbarCollapse" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarCollapse">
<ul class="navbar-nav mr-auto">
<?=menu_builder1($db, 0)?>
</ul>
</div>
</div>
also some SQL info
CREATE TABLE `menu` (
`menu_id` int(11) NOT NULL,
`menu_sub_id` int(11) NOT NULL,
`added` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
`status` int(1) NOT NULL DEFAULT '1',
`href` varchar(150) NOT NULL,
`class` varchar(150) NOT NULL,
`position` int(3) NOT NULL,
`name` varchar(150) NOT NULL,
`description` varchar(500) NOT NULL,
`dropdown` int(11) NOT NULL,
`sub_menu` int(1) NOT NULL,
`sub_sub_menu` int(1) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
ALTER TABLE `menu`
ADD PRIMARY KEY (`menu_id`);
ALTER TABLE `menu`
MODIFY `menu_id` int(11) NOT NULL AUTO_INCREMENT;
COMMIT;