I want to display a database driven Multilevel menu and below is what I have tried so far, but I am not getting the result as desired. Can any one help me to fix this. the output I am getting is only the main menu with parent id as 0, but not the sub menu items.
<?php
include('system/connection.php');
?>
<?php
//select all rows from the main_menu table
$q = "SELECT * FROM catelogue WHERE cat_visibility = '1'";
$r = mysqli_query($dbc, $q);
echo "<ul class='dropdown'>";
while ($rows = mysqli_fetch_assoc($r)) {
if ($rows['cat_parentid'] == 0) {
echo "<li><a href='#'>" . $rows['cat_name'] . "</a>";
echo "<ul>";
foreach ($rows as $item) {
if ($item['cat_parentid'] == $rows['cat_id']) {
echo "<li><a href='#'>" . $item['cat_name'] . "</a>";
echo "</li>";
}
}
echo "</ul>";
echo "</li>";
}
}
echo "</ul>";
?>
My Database structure is
-----------------------------------------
| cat_id | cat_name | cat_parentid |
-----------------------------------------
| 1 | Home | 0 |
| 2 | About | 0 |
| 3 | Contact | 0 |
| 4 | History | 2 |
| 5 | Services | 2 |
-----------------------------------------
Desired Output I want:
<ul class="dropdown">
<li><a href='#'>Home</a></li>
<li><a href='#'>About</a>
<ul>
<li><a href='#'>History</a></li>
<li><a href='#'>Services</a></li>
</ul>
</li>
<li><a href='#'>Contact</a></li>
</ul>
Here is a recursive solution.
The code is fully commented.
There are two useful checks in the processMenuEntry routine that can conveniently be done so that you can decide if you want different actions to happen.
Check whether the 'current' 'entry' is the 'root' node.
$isRoot = $currentEntry['cat_id'] == 0; // do 'First time' processing
Check whether the current 'entry' has a 'submenu'.
if (!empty($subMenu)) { ...
Q29910284-display-multilevel-database-driven-menu.php
The code:
Database connection:
$DB_HOST = "localhost";
$DB_USER = "test";
$DB_PASSWORD = "test";
$DB_TO_USE = "testmysql";
$dbc = new mysqli($DB_HOST, $DB_USER, $DB_PASSWORD, $DB_TO_USE);
Submenu Query:
/** -----------------------------------------------------------------
* Select all the menu entries for a given entry Id
*
* Note: it is safe to do 'parameter substitution' rather than using
* 'prepared queries' with placeholders as this 'entry Id' never
* comes from an external source.
*
* #param mysqli $dbc
* #param integer $currentEntryId
* #return array of menu entries
*/
function selectSubMenu($currentEntryId, $dbc)
{
$sql = "SELECT cat_id, cat_name, cat_parent_id
FROM catalogue
WHERE cat_parent_id = {$currentEntryId}
ORDER BY cat_id";
$resultSet = mysqli_query($dbc, $sql);
return $resultSet->fetch_all(MYSQLI_ASSOC);
}
Process Current Menu Entry:
/** --------------------------------------------------------------------------
* Process the current menu enty - it will return a complete menu as HTML
*
* These needs to know whether the current entry has a submenu and
* will therefore need to generate an 'unordered list' for the current entry.
*
* Alas, it also has to not display the 'list item text' for the 'root' entry
* but process the 'submenu'.
* This complicates the <li> current entry text generation slightly.
*
* #param array $currentEntry - one row
* #param array $subMenu - many rows - may be empty
* #param mysqli $dbc - database connection
* #return string - the HTML for the menu
*/
function processMenuEntry($currentEntry, array $subMenu, $dbc) {
$outMenu = '';
$isRoot = $currentEntry['cat_id'] == 0; // do 'First time' processing
// display the current entry text as a 'list item'
$outMenu .= !$isRoot ? "<li><a href='#'>" . $currentEntry['cat_name'] . "</a>" : '';
// does it have a submenu...
if (!empty($subMenu)) { // we need to add a complete submenu of <ul> ... </ul>
// Start of the submenu as an unordered list -- decide what is required
if ($isRoot) {
$outMenu .= '<ul class="dropdown">';
}
else {
$outMenu .= '<ul>';
}
// Display each entry of the submenu as a 'list item'
foreach ($subMenu as $submenuEntry) {
$outMenu .= processMenuEntry($submenuEntry,
selectSubMenu($submenuEntry['cat_id'], $dbc),
$dbc);
}
// close the current submenu - terminate the unordered list
$outMenu .= '</ul>';
}
// terminate the current list item
$outMenu .= !$isRoot ? '</li>' : '';
return $outMenu;
};
Process all the menu entries:
/* -------------------------------------------------------------------
* Process all the menu entries
*
* We need a complete menu 'tree' that includes a 'root' which is not provided
* in the database. I think it should be. Whatever, i need one.
*
* Initializing a 'tree walk' i always find 'interesting' ;-/
*/
$root = array('cat_id' => 0, 'cat_name' => '', 'cat_parent_id' => 0);
// build the output menu
$outMenu = processMenuEntry($root,
selectSubMenu($root['cat_id'], $dbc),
$dbc);
// wrap it in a <div>
$htmlMenu = '<div style="border: 1px solid red">'
. $outMenu
.'</div>';
?>
Output the generated HTML:
<!DOCTYPE html>
<html>
<head>
<title>Test Recursive Menu Builder</title>
</head>
<body>
<?= $htmlMenu ?>
</body>
</html>
The generated HTML
<!DOCTYPE html>
<html>
<head>
<title>Test Recursive Menu Builder
</title>
</head>
<body>
<div style="border: 1px solid red">
<ul class="dropdown">
<li>
<a href='#'>Home</a>
</li>
<li>
<a href='#'>About</a>
<ul>
<li>
<a href='#'>History</a>
</li>
<li>
<a href='#'>Services</a>
</li>
</ul>
</li>
<li>
<a href='#'>Contact</a>
</li>
</ul>
</div>
</body>
</html>
What you call $rows is actually one row. Then, in the foreach ($rows as $item) loop, it iterates through the columns of this row. So, there is no $item['cat_parentid']. Try to see the output of the $rows and $item with var_dump().
A draft idea of one possible solution that comes to my mind is to first iterate through the result rows and save the sub items in a parent item (note: some array initializations would have to be added here):
while ($row = mysqli_fetch_assoc($r)) {
$menuItems[$row['cat_id']] = $row;
$parentId = $row['cat_parentid'];
$menuItems[$parentId]['sub_items'][] = $row['cat_id'];
}
And then iterate through the $menuItems array generating output, recursion would be great for this.
Also, ordering the sql results would be beneficial, to be sure that top menu items come first:
"SELECT * FROM catelogue WHERE cat_visibility = '1' ORDER BY cat_parentid ASC";
Related
Good day :)
I have 2 tables - one containing the main headings and another which contains the subheadings and related paragraphs, which are related with a foreign key on TitleID and LinkID as shown here:
The idea is that I create a number of divs containing the main titles - from sectionamain with the related subcontent from sectiona, linked thru LinkID and TitleID.
<?php
function confirm_query($result_set) {
if (!$result_set) {
die("Database query failed.");
}
}
function get_practices() {
global $connection;
$query = "SELECT * FROM sectionamain ";
$query .= "LEFT JOIN sectiona ";
$query .= "ON sectiona.HeadingID = sectionamain.TitleID ";
$query .= "ORDER BY sectionamain.TitleID ASC";
$A_list = mysqli_query($connection, $query);
confirm_query($A_list);
return $A_list;
}
function display_practices() {
$output = "<div class=\"container inner\">\n";
$A_set = get_practices();
while ($list_A = mysqli_fetch_assoc($A_set)) {
$output .= "<div class=\"info\">\n";
$output .= "<div class=\"wrap\">\n";
$output .= "<h1 class=\"showcontent\" id=";
$output .= "". htmlentities($list_A["TitleID"]) ."";
$output .= ">";
$output .= htmlentities($list_A["MainTitle"]);
$output .= "</h1>\n";
$output .= "<div class=\"content\" id=\"content".htmlentities($list_A["TitleID"]) ."\">\n";
*** code would go here -
put items from sectiona with LinkID = 1 where TitleID = 1, etc until all data is sorted
$output .="</div>\n</div>\n</div>\n";
};
mysqli_free_result($A_set);
$output .= "</div>\n";
return $output;
}
?>
The end result would be something as shown below:
<h1>Main Title 1</h1>
<h3>Sub 1 with LinkID 1<h1>
<h3> ... </h3>
<h3>Sub n with LinkID 1</h3>
...
<h1>Main Title n</h1>
<h3>Sub 1 with LinkID n<h1>
<h3> ... </h3>
<h3>Sub n with LinkID n</h3>
Thank you in advance
xx
To solve your grouping issue, it's a matter of creating a data structure in an array. Since the database will give rows with repeating information, use this repeated information as a key in an array.
<?php
function get_practices() {
global $connection;
// It's good practice to specify which fields you want to get from the database.
// for clarity, I'm using heredoc format.
$query = >>>SECTIONAQUERY
SELECT am.TitleID, am.MainTitle, a.HeadingID, a.title, a.content
FROM sectionamain am
LEFT JOIN sectiona a
ON a.HeadingID = am.TitleID
ORDER BY sectionamain.TitleID ASC
SECTIONAQUERY;
$A_list = mysqli_query($connection, $query);
confirm_query($A_list);
return $A_list;
}
/**
* group_items
*
* takes database results and groups them by ID
*
* #param mysqli_result
* #return array
*/
function group_items($db_results) {
$data = array();
while($row = mysqli_fetch_assoc($db_results)) {
$title_id = htmlentities($row['TitleID']);
// group Main Title by title id
$data[$title_id]['title'] = htmlentities($row['MainTitle']);
// group data by title id
$data[$title_id]['data'][] = array(
'HeadingID' => htmlentities($row['HeadingID']),
'title' => htmlentities($row['title']),
'content' => htmlentities($row['content'])
);
}
return $data;
}
Then in your view, you could have something like this:
<?php
$A_list = get_practices();
$data = group_items($A_list);
// or, alternatively, $data = group_items(get_practices());
// now, go into "html mode" instead of in PHP,
// using PHP only for looping and variable substitution:
?>
<html>
<head>
...
</head>
<body>
<div>Your header stuff</div>
<div class="info">
<div class="wrap">
<?php foreach($data as $row): ?>
<h1 class="showcontent" id="<?= $row['title'] ?>"></h1>
<?php foreach($row['data'] as $sub_row): ?>
<h3><?= $sub_row['title'] ?></h3>
<div class="content"><?= $sub_row['content'] ?></div>
<!-- bonus: link to a new page? -->
<div><?= $sub_row['title'] ?></div>
<?php endforeach; ?>
<?php endforeach; ?>
</div>
</div>
</body>
</html>
Note, I personally would not stick output into a function; that's mixing logic and presentation. By using PHP's built-in templating, you don't have to worry about escaping quotes. Just use the <?= ?> syntax to drop in PHP variables. Use an include statement instead of calling the function. (or, you could always have the function include a partial view.)
Hope this addressed your question!
I am want to make a navigation menu with a sub menu on hover. I want to get this data from my database (to make it dynamic if data in database changes menu bar changes). In my database I have a table with the the following fields:
ID, Name, Level, Parent_id. Level can be 0 or 1. 0 for main menu 1 for sub menu the id of a main menu is tied to the parent_id field.
So for instance:
ID Name Level Parent_id
1 Test 0
2 Test2 0
3 Test_sub 1 1
4 Test_sub2 2 2
I have managed to get the main menu items from the db but now I am a little bit stuck. This is my code any help would be appriciated.
<?php
$q2= "SELECT * from menu where level = 0 ";
$q2result = $db->query($q2);
while($a2 = $q2result->fetch(PDO::FETCH_ASSOC)){
echo "
<ul>
<li><a href='#' ><span> " . $a2['name'] . " </span></a>
<ul>
<li><a href='#' ><span> test </span></a></li>
</ul>
</ul>
";
}
?>
First load all your datas into variables. Never print/echo while in SQL statement.
<?php
$q2= "SELECT * FROM menu ORDER BY Level ASC";
$q2result = $db->query($q2);
$nodes=array();
while($a2 = $q2result->fetch(PDO::FETCH_ASSOC)){
// assuming one parent node has already been assigned, due do level order into the SQL
if($node['Level']>0 && isset($nodes[$a2['id']])) {
$nodes[$a2['id']]['nodes'][]=$a2;
} else {
// parent node
$nodes[$a2['id']]=$a2;
$nodes[$a2['id']]['nodes']=array();
}
}
print "<ul>";
foreach($nodes as $node) {
print "<li>";
print "<a href='#'>".$node['Name']."</a>";
if(sizeof($node['nodes'])>0) {
print "<ul>";
foreach($node['nodes'] as $subnode) {
print "<li><a href='#'>".$subnode['Name']."</a></li>";
}
print "</ul>";
}
print "</li>";
}
print "</ul>";
?>
This may be much more improved, but with this, you can do what you ask, and improve it.
I have two tables in a database, sight_country and sightseeing. I am inserting the ID of the country field from the sight_country table to s_country field of the table sightseeing. In php I am showing country field values from sight_country in a CSS drop-down menubar.
the code is
<li class="menu-item-has-children">Sightseeing
<ul class="sub-menu">
<?php
$qry_st = "select * from `sight_country` limit 5";
$rec_st = mysql_query($qry_st );
if( mysql_num_rows($rec_st) > 0)
{
while($res_st = mysql_fetch_array($rec_st))
{
echo "<li><a href='sightseeing.php?id=$res_st[id]'>".$res_st['country']."</a></li>";
}
}
?>
</ul>
</li>
When click on link of county value then I am showing all sightseeing data from the table sightseeing in php page.
the code is
$sql = "select * from `sightseeing` where `s_country` ='$id'";
$res = mysql_query($sql);
$rec = mysql_fetch_array($res);
the country may have two or more related sightseeing data, so I am displaying sightseeing titles from the sightseeing table in a sidebar menu in my PHP page.
the code is
<ul class="st_lnks">
<?php
$qry_st = "select * from `sightseeing` where s_country = '$id'";
$rec_st = mysql_query($qry_st );
if( mysql_num_rows($rec_st) > 0)
{
while($res_st = mysql_fetch_array($rec_st))
{
echo "<li><a href='sightseeing.php?id=$res_st[s_country]'>".$res_st['stitle']."</a></li>";
}
}
?>
</ul>
when I click link of stitle I want to show it's related sightseeing data in same page. How it can be done?
I am assuming that;
The whole script is on one page (sightseeing.php), which varies depending on any GET variables (variables in the URL).
Originally the page just displays the first menu. Then when u click a country, you are sent again to sightseeing.php. Now also with ?id=* which shows also a second list, containing the list of sightseeing relevant to the country selected.
You have a field called 'id' in your sightseeing table that has the unique sightseeing id.
To now additionally show details of the sightseeing selected (clicked by user);
Modify the links in the second list. rather than:
echo "<li><a href='sightseeing.php?id=$res_st[s_country]'>".$res_st['stitle']."</a></li>";
Write:
echo "<li><a href='sightseeing.php?id=$res_st[s_country]&ss_id=$res_st[id]'>".$res_st['stitle']."</a></li>";
Now when u click one of the links and are sent back to to sightseeing.php you will also have another get variable GET['ss_id'] (which has the id of the sightseeing that you want to view).
You can use this variable to pull the relevant details of the sightseeing.
$sightSeeingId = $_GET['ss_id'];
$sql3 = "select * from `sightseeing` where `id` ='$sightSeeingId' LIMIT 1";
$res3 = mysql_query($sql3);
$sightSeeingData = mysql_fetch_array($res3);
check that it has data and print it out
if(!$res3) die(mysql_error());
if(mysql_num_rows($res3) > 0){
echo "Sight Seeing id:" . $sightSeeingData['id'];
}
As a side note you should be aware that mysql_* functions are outdated and your code is vunerable to sql injection, see here;
GET parameters vulnerable to SQL Injection - PHP
You could give your second link a second parameter. Give the first parameter a unique name
<ul class="sub-menu">
<?php
$qry_st = "select * from `sight_country` limit 5";
$rec_st = mysql_query($qry_st );
if ( mysql_num_rows($rec_st) > 0) {
while ($res_st = mysql_fetch_array($rec_st)) {
echo "<li><a href='sightseeing.php?idCountry=$res_st[id]'>".$res_st['country']."</a></li>";
}
}
?>
</ul>
Then add a second parameter when generating the second link:
<ul class="st_lnks">
<?php
$qry_st = "select * from `sightseeing` where s_country = '$id'";
$rec_st = mysql_query($qry_st );
if ( mysql_num_rows($rec_st) > 0) {
while($res_st = mysql_fetch_array($rec_st)) {
echo "<li><a href='sightseeing.php?idCountry=$idCountry&idSightseeing=res_st['id']'>".$res_st['stitle']."</a></li>";
}
}
?>
</ul>
I need some help with PHP. I have a multilevel css menu that works fine, but now I want to generate according to the records from a database.
The menu Code:
<div id="page-wrap">
<ul class="dropdown">
<li>Link 1 </li>
<li>Link 2 </li>
<li>Link 3 </li>
<li>Link 4
<ul class="sub_menu">
<li>Link 4 - 1</li>
<li>Link 4 - 2</li>
<li>Link 4 - 3</li>
</ul>
</li>
<li>Link 5</li>
<li>Link 6 </li>
</ul>
</div>
In the database every record has a field called main_manu which makes it a main link if the value of this field is Yes, and if the value is No then it has another field (sub_menu) which says the parent menu in which this link should be placed.! See the screenshot.
DB Fields
SO, now I don't know how to do the php piece that will get the records and if the value of the main_menu is yes, it will create a top level menu, and if the value of main_menu is no, it will create a sub level menu according to the value of sub_menu field.
Thanks a lot
UPDATE
This is the code I have so far and it works. It would be nice if I could use a single query instead of multiple nested queries.
<div id='page-wrap'>
<ul class='dropdown'>
<?
$sql_menu = "SELECT * FROM content WHERE visible = '1' and main_menu='yes' ";
$result_menu = mysql_query($sql_menu);
while($row = mysql_fetch_assoc($result_menu))
{
$id=$row['id'];
$menu_top=$row['menu_name'];
$menu_url=$row['menu_url'];
print "<li><a href='$menu_url'>$menu_top</a>";
$sql_sub = "SELECT * FROM content WHERE sub_menu = '$menu_url' ";
$result_sub = mysql_query($sql_sub);
$num_rows = mysql_num_rows($result_sub);
while($row = mysql_fetch_assoc($result_sub))
{
$id=$row['id'];
$menu_sub=$row['menu_name'];
$sub_url=$row['menu_url'];
If ($num_rows != 0)
{
print "<ul class='sub_menu'>
<li><a href='$sub_url'>$menu_sub</a></li>
</ul>";
}
}
print "</li>";
}
?>
</ul>
</div>
The code for this would be something like the following (This will need to be changed for whatever way you interact with the database etc.):
// Here we do a query to get all the rows from the table
$db_result = db_execute_query('SELECT * FROM `menu_table` ORDER BY `order_no`');
// Here we take the rows and put it into a structured array
$items = array();
$hierarchy = array('' => array());
while ($row = db_fetch_row($db_result)) {
$items[$row['menu_name']] = $row['menu_name_en'];
if ($row['main_menu'] == 'yes') {
$hierarchy[''][] = $row['menu_name'];
} else {
if (!isset($hierarchy[$row['sub_menu']]) {
$hierarchy[$row['sub_menu']] = array();
}
$hierarchy[$row['sub_menu']][] = $row['menu_name'];
}
}
// Here we define a recursive function to run through our $hierarchy array;
function show_menu($name = '') {
if (isset($hierarchy[$name])) {
if ($name == '') {
echo '<ul class="dropdown">';
} else {
echo '<ul class="sub_menu">';
}
foreach ($hierarchy[$name] as $sub) {
echo '<li>' . $items[$sub] . '';
show_menu($sub);
echo '</li>';
}
echo '</ul>';
}
}
// Here we execute the recursive function on the main menu
show_menu('');
Try to understand what I'm doing here instead of just implementing it verbatim. Once you get to know recursive functions, a whole new world can open for you.
Also note that your db table could be changed to make this code simpler
I think these link will help you out. if not please let me know i will give you the code
http://board.phpbuilder.com/showthread.php?10337808-how-to-create-menu-submenu-subsubmenu-using-php-mysql
http://www.sitepoint.com/forums/showthread.php?718237-how-to-create-dynamic-menu-and-submenu-using-php-and-mysql
I've just purchased a great little HTML5 video player, but the way to add files is by editing the actual html of the page.
This sucks, so what I'm trying to do is populate the UL when the page loads with the help of a MySQL table that holds appropriate data.
The list this page has looks like this:
<ul id='playlist1' data-address="playlist1">
<li data-address="local1" class='playlistItem' data-type='local' data-mp4Path='data/media/video/big_buck_bunny_trailer.mp4' data-ogvPath='data/media/video/big_buck_bunny_trailer.ogv' data-imagePath='data/media/video/big_buck_bunny_trailer.jpg' data-thumbPath='data/media/thumb/big_buck_bunny_trailer.jpg' data-aspectRatio='2'></li>
<li data-address="local2" class='playlistItem' data-type='local' data-mp4Path='data/media/video/big_buck_bunny_trailer.mp4' data-ogvPath='data/media/video/big_buck_bunny_trailer.ogv' data-imagePath='data/media/video/big_buck_bunny_trailer.jpg' data-thumbPath='data/media/thumb/big_buck_bunny_trailer.jpg' data-aspectRatio='2'></li>
<li data-address="local3" class='playlistItem' data-type='local' data-mp4Path='data/media/video/big_buck_bunny_trailer.mp4' data-ogvPath='data/media/video/big_buck_bunny_trailer.ogv' data-imagePath='data/media/video/big_buck_bunny_trailer.jpg' data-thumbPath='data/media/thumb/big_buck_bunny_trailer.jpg' data-aspectRatio='2'></li>
</ul>
Pretty basic list. So this is probably a basic thing I just can't seem to find the right answer for.
I'd like to 'GET' the values I have in a database table that read like this (these are collumn titles, the data would be in rows below):
id | data-address | data-imagePath | data-thumbPath | data-mp4Path | data-ogvPath | data-webmPath | title | desc | ord
My knowledge is growing for php and javascript, but making calls to MySQL tables is something I'm just trying to grasp.
What I'm trying below is declaring the following variable in a header script:
(taken from http://www.php.net/manual/en/function.mysql-fetch-object.php )
$data-mp4Path = mysql_query("select * from mytable");
while ($row = mysql_fetch_object($data-mp4Path)) {
echo $row->data-mp4Path;
}
mysql_free_result($data-mp4Path);
Then with a php call in the appropriate list field like so:
data-mp4Path='<? $data-mp4Path ?>'
The output however, doesn't parse the table cell data like I think the script should store into the $data-mp4Path variable...
Any help would be hugely appreciated!
_ Update _
With help from #peterm I've tried to use the code provided with the appropriate database fields and respective calls as they should be.
This is what browser output ends up being:
<ul id="playlist1" data-address="playlist1">
<!--?php
$db = new PDO('mysql:host=localhost;dbname=wordpress;charset=UTF-8', 'root', 'root');
$sql = "SELECT * FROM `wp_localTestinglbg_vp2_html5_rightside_videoplaylist`";
foreach ($db--->query($sql) as $row) {
$li = '<li data-address="local' .$row['id']. '" ';="" $li="" .=" class="playlistItem" data-type="local"" ;="" .$row['mp4'].="" '"';="" .$row['ogv'].="" .$row['data-imagepath'].="" .$row['data-thumbpath'].="" echo="" $li;="" }="" $db="null;" ?="">
</li></ul>
The dream of this working to act as a loop and output new LI items to the playlist would be great, but it isn't working yet.
__ Update __
After cleaning up the code, the output between UL tags is now blank. The output is as shown:
<ul id="playlist1">
</ul>
I removed the 'data-address=playlist1' within the tag.
Your code to generate <li>'s using PDO instead of mysql_* might look like this
... your preceding html
<ul>
<?php
$db = new PDO('mysql:host=localhost;dbname=yourdb;charset=UTF-8', 'user', 'password');
$sql = "SELECT * FROM `mytable`";
foreach ($db->query($sql) as $row) {
$li = '<li data-address="' .$row['data-address']. '"';
$li .= ' class="playlistItem" data-type="local"';
$li .= ' data-mp4Path="' .$row['data-mp4Path']. '"';
$li .= ' data-ogvPath="' .$row['data-ogvPath']. '"';
$li .= ' data-imagePath="' .$row['data-imagePath']. '"';
$li .= ' data-thumbPath="' .$row['data-thumbPath']. '"';
$li .= ' data-aspectRatio="2"></li>';
echo $li;
}
$db = null;
?>
</ul>
... your html continues here