I have the below code for my CSS menu, it gets all the links from a database using PHP.
I have set active/current links for selected items which works fine for top level links but where i have sub menus it doesnt work.
for example, i have the following:
Services
- Service 1
-- Sub Service 1
If Service 1 is selected, the Services link is active/current but if the Sub Service 1 link is selected, i want the Services link to be active/current but its not
how can i fix this using the below code?
<ul class="nav">
<?php
//select all the top row items
$sql="SELECT * from website_menu where parent_top = '' and parent = '' order by sequence ASC ";
$rs=mysql_query($sql,$conn) or die(mysql_error());
while($result=mysql_fetch_array($rs))
{
//then select all the next rows down (parent_top)
$current = false;
$subMenu = '';
$sql2="SELECT * from website_menu where parent_top = '".$result["sequence"]."' order by sequence ASC ";
$rs2=mysql_query($sql2,$conn) or die(mysql_error());
if(mysql_num_rows($rs2) > 0)
{
$subMenu = '<ul>';
while($result2=mysql_fetch_array($rs2))
{
if($_GET["id"] == $result2["link"])
{
$current = true;
}
$subMenu .= '<li><span>'.$result2["title"].'</span>';
//
$sql3="SELECT * from website_menu where parent = '".$result2["sequence"]."' ";
$rs3=mysql_query($sql3,$conn) or die(mysql_error());
if(mysql_num_rows($rs3) > 0)
{
$subMenu .='<ul>';
while($result3=mysql_fetch_array($rs3))
{
$subMenu .='<li><span>'.$result3["title"].'</span></li>';
}
$subMenu .='</ul>';
$subMenu .='</li>';
}
else
{
$subMenu .='</li>';
}
}
$subMenu .= '</ul>';
}
echo '<li';
if($_GET["id"] == $result["link"] || $current)
{
echo ' class="active"';
}
echo '><span>'.$result["title"].'</span>', $subMenu, '</li>';
}
?>
</ul>
You might want to try this
In your following while loop make this change
while($result3=mysql_fetch_array($rs3))
{
$subMenu .='<li><span>'.$result3["title"].'</span></li>';
// add this if block
if($_GET["id"] == $result3["link"])
{
$current = true;
}
}
Related
I'm querying a category table id, parent_id, name to generate list view of all the categories and sub-categories. What I have so far is:
HP
Laptops
PC
Sports
Sunglasses
Food
House
The function that I use to generate the output is:
public function get_category($parent_id = NULL)
{
$query = $this->db->get_where('category', array('parent_id' => $parent_id))->result();
$result = '';
foreach ($query as $row)
{
$i = 0;
if ($i == 0)
{
$result .= '<ul>';
}
$result .= '<li><a href="'.base_url().'category/edit/'.$row->id.'">' . $row->name;
$result .= $this->get_category($row->id);
$result .= '</li>';
$i++;
if ($i > 0)
{
$result .= '</ul>';
}
}
return $result;
}
This is what I want to achieve:
HP
HP > Laptops
HP > PC
Sports
Sports > Sunglasses
Food
House
Try following
public function get_category($parent_id = NULL,$level, $prev = "")
{
$query = $this->db->get_where('category', array('parent_id' => $parent_id))->result();
$result = '';
foreach ($query as $row)
{
$temp = $prev;
if($level == 0){
$temp .= '' . $row->name.'';
}else{
$temp .= ' > ' . $row->name.'';
}
$result .= $temp;
$result .= "<br />";
$result .= $this->get_category($row->id, $level + 1, $temp);
}
return $result;
}
First run of this function should be
get_category(NULL, 0, "");
Here
NULL is parent id (you can use a loop to dynamicaly pass id)
level should be 0
prev should be empty
I've created a demo according to your needs and it worked for me. I'm sharing the code below, I've done explaining in the comments wherever necessary. See if it helps you.
Controller
public function get_category($parent_id = NULL){
// get the {category}, {sub_category} from the table, if {sub_category} stored in different table use {JOIN}
$data['category'] = $this->db->get_where('category', array('parent_id' => $parent_id))->result();
$this->load->view('your-view', $data);
}
View
<?php
if(!empty($category)){ // check if {$category} has value; if not, do nothing
$catArr = array(); // initialize array to store category id
?>
<ul> <!-- Start ul -->
<?php
foreach($category as $cat){ //loop through all the {category} array
// check if the {cat_id} already exists in array; if not, do so where {cat_id} is category id(change your value here)
if( ! in_array( $cat->cat_id, $catArr ) ){
$catArr[] = $cat->event_id;
?>
<li><?php echo $cat->cat_name; ?></li> <!-- show {cat_name} in list -- your category name here -->
<?php
}
?>
<!-- Show {cat_name} and {subcat_name} both -- (your values here). Give links or whatever here(your styling)-->
<li><?php echo $cat->cat_name; ?> > <?php echo $cat->subcat_name; ?></li>
<?php
}
?>
</ul>
<?php
}
?>
OUTPUT
Honda
Honda > Car
Honda > Bike
Philips
Philips > Electricals
Philips > Electronics
My function is duplicating some nodes on the tree. When I am calling that function in a recursive way. I have a database table of all father, mother, wife, husband, child ids. I am taking all persons from their father id only. I don't know from where these extra nodes are coming and how should I handle ie it. Output image
<?php
function categoryTree($parent_id = 0,&$alreadyThereArr=array())
{
$ci =& get_instance();
//$query = $ci->db->query("SELECT * FROM tbl_user WHERE father_id = $parent_id ORDER BY id ASC");
$sql="SELECT * FROM `tbl_user` WHERE father_id = '$parent_id' ORDER BY id ASC";
$query=$ci->db->query($sql);
$result=$query->result();
if(count($result) > 0)
{
echo '<ul>';
foreach($result as $key)
{
if(!in_array($key->id,$alreadyThereArr))
{
//echo 'In';
if($key->wife_id != 0)
{
//echo 'wife';
$wife=$ci->Main_M->getSingleRow('tbl_user','id',$key->wife_id);
$start='<div>
<span class="male">'.$key->name.'</span>
<span class="spacer"></span>
<span class="female">'.$wife->name.'</span>
</div>';
}
else
{
$gender=($key->gender == 'M') ? 'male' : 'female';
$start='<div><span class="'.$gender.'">'.$key->name.'</span></div>';
}
$alreadyThereArr[]=&$key->id;
echo '<li>';
echo $start;
echo '<ul>';
categoryTree($key->id, $alreadyThereArr);
echo '</ul>';
echo '</li>';
}
}
echo '</ul>';
}
//print_r($alreadyThereArr);
}
?>
I got a dynamic menu that uses bootstrap, but one menu button has about 14 child items. Way too long for a website, so I want to split it in half.
This is the code that I'm trying to replicate:
<ul class="dropdown-menu dropdown-menu-large row" role="menu">
<li class="col-sm-6">
<ul>
<li>Life Insurance</li>
<li>Home Insurance</li>
<li>Travel Insurance</li>
<li>Pet Insurance</li>
</ul>
</li>
<li class="col-sm-6">
<ul>
<li>Boat Insurance</li>
<li>Auto Insurance</li>
<li>Bike Insurance</li>
<li>Business Insurance</li>
</ul>
</li>
</ul>
This is what I tried:
$tel = 1;
foreach ( $nmenuccr as $cmenu ) {
// If id matches and category id is 11 (services) split in half
if ( $cmenu['id'] && $cmenu['catid'] == '11' ){
if($tel == 1) {
$hmenu .= '<li class="col-sm-6"><ul>';
}
$hmenu.= '
<li>'.$cmenu['title'].'</li>
';
if(($tel % 7) == 0){
$hmenu .= '</ul></li> <li class="col-sm-6"><ul>';
}
$tel++;
if(($tel % 7) != 0){
$menu .= '</li>';
}
//Else use the normal dropdown layout
}else{
if (strlen($cmenu['title']) > 25){
$shortstrmen = substr($cmenu['title'], 0, 25) . '...';
$hmenu.= '
<li>'.$shortstrmen.'
';
}else{
$hmenu.= '
<li>'.$cmenu['title'].'
';
}
}
}
However this returns the following code:
https://jsfiddle.net/sms16v44/
Does anyone see what I am doing wrong?
Instead of trying to alter your code, I came up with the following. This allows you to automatically create sub menu's out of a menu. I hope it helps out.
It creates it like the following screenshot:
and the other function/way:
<?php
// recreating dummy menu data
function createDummyList() {
$nmenuccr = array();
for($i=0;$i<24;$i++) {
$a = array();
$a['id']=$i;
$a['catid']=$i;
$a['alias']="alias $i";
$a['title']="title $i";
array_push($nmenuccr, $a);
}
return $nmenuccr;
}
/**
* Parse a menu into smaller menu's
* #param type $menu the main menu
* #param type $class html class
* #param type $max_sub_items max items before creating a new submenu
* #param type $submenu (used for recursion)
* #return string
*/
function createMenuList(&$menu, $class, $max_sub_items) {
$out = "<ul class='$class'><li>";
// shift items
$submenu = array();
$i=0;
$loop=0;
while(count($menu) > 0) {
array_push($submenu, array_shift($menu));
$i++;
if ($i == $max_sub_items || count($menu) == 0) {
$out .= createList($submenu, $loop);
$out .= '<li>In between</li>';
$i=0;
$submenu = array();
$loop++;
}
}
$out .= "</li></ul>";
return $out;
}
/**
*
* #param type $list
* #param type $submenu_label
* #return string
*/
function createList(&$list, $loop) {
$out = '<ul>';
foreach($list as $l) {
$out .= '<li>'.$l['title'].'</li>';
}
$out .= '</ul>';
return $out;
}
/**
* Parse a menu into smaller menu's
* #param type $menu the main menu
* #param type $class html class
* #param type $max_sub_items max items before creating a new submenu
* #param type $submenu (used for recursion)
* #return string
*/
function createSubMenuList(&$menu, $class, $max_sub_items, $submenu = 0) {
// create new list
$out = "<ul class='$class'>";
// shift items
for($i=0;$i<$max_sub_items;$i++) {
$item = array_shift($menu);
// add item to list
if (isset($item)) {
$out .= '<li>'.$item['title'].'</li>';
}
}
// check if we're done
if (count($menu) > 0) {
$submenu++;
$out .= "<li class='submenu_$submenu'>";
// create submenu in parent menu
$out .= createSubMenuList($menu, $class, $max_sub_items, $submenu);
$out .= "</li>";
}
$out .= "</ul>";
return $out;
}
// call menu creation function
$list1=createDummyList();
$list2=createDummyList();
echo createSubMenuList($list1, 'hoofdmenu', 7);
echo "<hr />";
echo createMenuList($list2, 'hoofdmenu', 7);
?>
It would be easier to help if you could include the output array as comment too.
However, try this. Change this:
if(($tel % 7) != 0){
$menu .= '</li>';
}
to:
if(($tel % 7) != 0){
$menu .= '</ul></li>';
}
Hopefully it will work
Keepin it a junky piece of code, you can just quick-fix it this way:
$tel = 0;
/* .. */
// If id matches and category id is 11 (services) split in half
if ( $cmenu['id'] && $cmenu['catid'] == '11' ){
if(++$tel == 1) {
$hmenu .= '<li class="col-sm-6"><ul>';
}
$hmenu.= '<li>'.$cmenu['title'].'</li>';
if(($tel % 7) == 0){
if ($tel == 7) {
$hmenu .= '</ul></li><li class="col-sm-6"><ul>';
} else {
$hmenu .= '</ul></li>';
}
}
//Else use the normal dropdown layout
} // ..
Working example (updated):
http://sandbox.onlinephpfunctions.com/code/13fd6974cd66c847747f44a4be9b892aa47e4979
But you should refactor your $nmenuccr through a function, which will make it an array reflecting the target structure of menu to KISS the view-generating part of code.
Edit: updated operations on $tel.
Try this for any length of menu.....
<ul class="dropdown-menu dropdown-menu-large row" role="menu">
<?php
$counter = 1;
foreach ($nmenuccr as $cmenu ) {
if($counter == 1){
echo '<li class="col-sm-6"><ul>';
}//.... end of if() .....//
echo '<li>'.$cmenu['title'].'</li>';
$counter ++;
if($counter == 5){
echo "</ul></li>";
$counter = 1;
}//.... end of if() .....//
}//.... end of foreach() .....//
?>
</ul>
Your check for category ID 11 didn't seem pertinent to your question, so I didn't include that logic in there. Things become a lot simpler when you leave the opening and closing parts outside the loop. Then, you're only outputting your repeated item, and checking for the one case ($tel % 4) where you put a divider in.
<?php
$nmenuccr = [ // sample data
["alias"=>"life-insurance", "title"=>"Life Insurance"],
["alias"=>"life-insurance", "title"=>"Home Insurance"],
["alias"=>"life-insurance", "title"=>"Travel Insurance"],
["alias"=>"life-insurance", "title"=>"Pet Insurance"],
["alias"=>"life-insurance", "title"=>"Boat Insurance"],
["alias"=>"life-insurance", "title"=>"Auto Insurance"],
["alias"=>"life-insurance", "title"=>"Bike Insurance"],
["alias"=>"life-insurance", "title"=>"Business Insurance"],
];
$hmenu = "<li class=\"col-sm-6\">\n\t<ul>\n";
foreach ($nmenuccr as $tel=>$cmenu) {
if ($tel % 4 == 0 && $tel > 0) {
$hmenu .= "\t</ul>\n</li>\n<li class=\"col-sm-6\">\n\t<ul>\n";
}
$hmenu.= "\t\t<li>$cmenu[title]</li>\n";
}
$hmenu .= "\t</ul>\n</li>";
echo $hmenu;
Output:
<li class="col-sm-6">
<ul>
<li>Life Insurance</li>
<li>Home Insurance</li>
<li>Travel Insurance</li>
<li>Pet Insurance</li>
</ul>
</li>
<li class="col-sm-6">
<ul>
<li>Boat Insurance</li>
<li>Auto Insurance</li>
<li>Bike Insurance</li>
<li>Business Insurance</li>
</ul>
</li>
In working on a dynamic menu w/ CRUD I have been having some trouble with the finishing touches. It works, but there are some extra tags getting inserted where there shouldn't be and can't figure out how to clean it up before I share it with the world. I used this as a starting point, then changed it to work with an accordion menu (http://www.phpro.org/tutorials/Simple-Mysql-PHP-Menu.html).
Below is the data from the table (I changed the names on the first 2 fields to get it to fit in the SO format from menu_item_id to id, and from menu_parent_id to pid).
id pid menu_item_name menu_url sortorder status
1 0 Settings 0 ACTIVE
2 5 Grid Demo grid.php ACTIVE
3 5 setGridOptions gridoptions.php ACTIVE
4 1 Menu Items adminmenu.php 1 ACTIVE
5 0 Grid Settings 100 ACTIVE
6 1 General Settings settings.php 100 ACTIVE
Here is the PHP that connects to the mysql database and creates the hierarchical tree array to make it work:
include 'db.php';
$sql = "SELECT * FROM menu_items WHERE status = \"ACTIVE\" ORDER BY sortorder, menu_item_name";
$query = $db->query($sql);
while($data = $query->fetch(PDO::FETCH_ASSOC))
// loop over the results
{
// Assign by reference
$thisref = &$refs[ $data['menu_item_id'] ];
// add the the menu parent
$thisref['menu_item_id'] = $data['menu_item_id'];
$thisref['menu_parent_id'] = $data['menu_parent_id'];
$thisref['menu_item_name'] = $data['menu_item_name'];
$thisref['menu_url'] = $data['menu_url'];
// if there is no parent id
if ($data['menu_parent_id'] == 0)
{
$list[ $data['menu_item_id'] ] = &$thisref;
}
else
{
$refs[ $data['menu_parent_id'] ]['children'][ $data['menu_item_id'] ] = &$thisref;
}
}
function create_list( $arr )
{
$html = "";
foreach ($arr as $key=>$v)
{
if ($v['menu_parent_id'] == '0')
{
$html .= '<a class="menuitem submenuheader" href="'. $v['menu_url'] .'">'.$v['menu_item_name']."</a>\n";
$html .= "<div class=\"submenu\">\n<ul>\n";
$html .= "<li>" . create_list($v['children']) . "</li>";
$html .= "</ul>\n";
}
else{
$html .= '<li><a id="' . $v['menu_item_id'] . '">'.$v['menu_item_name']."</a></li>\n";
}
}
$html .= "</div>\n";
return $html;
}
echo "<div class=\"glossymenu\">";
echo create_list( $list );
echo "</div>";
When I run it, it outputs the following:
<div class="glossymenu"><a class="menuitem submenuheader">Settings</a>
<div class="submenu">
<ul>
<li><li><a id="4">Menu Items</a></li>
<li><a id="6">General Settings</a></li>
</div>
</li></ul>
<a class="menuitem submenuheader" href="">Grid Settings</a>
<div class="submenu">
<ul>
<li><li><a id="2">Grid Demo</a></li>
<li><a id="3">setGridOptions</a></li>
</div>
</li></ul>
</div>
</div>
As you can see there are extra <li> tags, the </ul> is in the wrong
spot (should be after the </div>) Other than that, it is working great.
The other thing I can't figure out is if I have a root menu item with no children, I would love it to have a different output like
<a id="8">No Children Menu Item</a>
Instead of:
<a class="menuitem submenuheader">No Children Menu Item</a>
The second example would create the make it show up the little (+/-) for expanding and contracting and wouldn't allow me to click on it. For clarification on the <a> tags, I am using javascript to do a .get() based off the id which is why there is no href or url shown.
UPDATE
It is working correctly and I posted it on Github for anyone that wants it.
https://github.com/ajhalls/php-accordian-menu
Try this :
<?php
include 'db.php';
$sql = "SELECT * FROM menu_items WHERE status = 'ACTIVE' ORDER BY pid ASC, sortorder ASC, menu_item_name ASC";
$query = $db->query($sql);
$menu_items = array();
while($data = $query->fetch(PDO::FETCH_ASSOC)) {
if($data['pid'] == 0) {
$menu_items[$data['id']] = array();
$menu_items[$data['id']]['id'] = $data['id'];
$menu_items[$data['id']]['name'] = $data['menu_item_name'];
$menu_items[$data['id']]['url'] = $data['menu_url'];
$menu_items[$data['id']]['children'] = array();
} else if($data['pid'] != 0) {
$tmp = array();
$tmp['id'] = $data['id'];
$tmp['name'] = $data['menu_item_name'];
$tmp['url'] = $data['menu_url'];
array_push($menu_items[$data['pid']]['children'],$tmp);
unset($tmp);
}
}
function create_list($arr)
{
$html = "";
foreach($arr as $key => $value) {
if(count($value['children']) > 0) {
$html .= ' <a class="menuitem submenuheader" href="'. $value['url'] .'">'.$value['name'].'</a>
<div class="submenu">
<ul>';
foreach($value['children'] AS $child) {
$html .= ' <li>
<a id="'.$child['id'].'">'.$child['name'].'</a>
</li>';
}
$html .= ' </ul>
</div>';
} else{
$html .= ' <a id="'.$value['id'].'">'.$value['name'].'</a>';
}
}
return $html;
}
echo "<div class=\"glossymenu\">";
echo create_list($menu_items);
echo "</div>";
?>
I need to create a menu with PHP from a MySQL database.
Table called categories has id, name, parent_id, shortdesc, etc.
The output need to have parent list and children list under the partent list as follows.
If you can show me codes or website, I will appreciate it.
<ul id="catmenu">
<li class="menulist">Cars
<ul>
<li>Ford</li>
<li>Honda</li>
<li>Toyota</li>
</ul>
</li>
<li class="menulist">Food
<ul>
<li>Pasta</li>
<li>Pizza</li>
...
</ul>
</li>
...
...
</ul>
This is specifically for two levels deep. Recommended approach should it be more is to use an optimized table structure for traversal, like http://articles.sitepoint.com/article/hierarchical-data-database/2 (pointed out elsewhere) or to pull the data you need and push it into a dictionary (associative array) and query it that way.
<?php
$query = <<<EOT
SELECT
parent.name as parent_name,
child.name as child_name,
FROM
items child
INNER JOIN
items parent
ON
child.parent_id = parent.id
ORDER BY
parent.name
EOT;
$result = mysql_query($query) or die('Failure!');
echo "<ul id=\"catmenu\">";
$last_parent = '';
while($row = mysql_fetch_array($result)){
// If this is a new category, start a new one
if($last_parent != $row['parent_name']){
// Unless this is the first item, close the last category
if($last_parent != ''){
echo "</ul></li>";
}
$last_parent = $row['parent_name'];
echo "<li class=\"menulist\">{$row['parent_name']}<ul>";
}
echo "<li>{$row['child_name']}</li>";
}
// If we actually had items, close the "category"
if($last_parent != ''){
echo "</ul></li>";
}
echo "</ul>";
?>
If you have only two levels then, you could just display them :
echo '<ul id="catmenu">';
foreach($menu as $element) {
echo '<li><ul class="menulist">';
foreach($element['submenu'] as $submenu) {
echo '<li>' . $submenu['name'] . '</li>';
}
echo '</ul></li>';
}
echo '</ul>
If you have an undefined number of submenus however you should use a Recursive Function.
function menu($item) {
$ret = '<li>' . $item['name'];
if (!empty($item['submenu'])) {
foreach($item['submenu'] as $submenu) {
$ret .= menu($submenu);
}
}
return $ret;
}
echo menu($menu);
So every of your subcategories, whatever their number is will be displayed.
You make database like this.
ID NAME PARENT
0 Cars -1
1 Foods -1
2 Ford 0
3 Honda 0
4 Toyota 0
5 Pasta 1
6 Pizza 1
...
You query them all up and put it in an array.
$Menus = array();
// In a read MySQL loop
$Menus[$i]['ID']
$Menus[$i]['NAME']
$Menus[$i]['PARENT']
// Sorry, lazy to write. I think you know what I mean.
Then you loop all menu looking for PARENT == -1. Generate all UL and IL then sub it with another nested menu.
You can simply create a function like this.
var $MenuLevelClass = array("menulist");
function CreateMenu($Menus, $Tab = 0, $Parent = -1, $Level = 0) {
global $MenuLevelClass;
$CatClass = ($Level != 0) ? '' : ' class="catmenu"';
$MenuClass = $MenuLevelClass[$Level];
if ($MenuClass != '')
$MenuClass = ' class="'.$MenuClass.'"';
$TabCount = $Level + $Tab;
$TabUL = "";
for ($t = 0; $t < $TabCount; $t++)
$TabUL = $TabUL."\t";
$TabLI = $TabUL."\t";
?>
<?=$TabUL?><ul<?=$CatClass?>>
<?php
$MenuCount = count($Menus);
for ($m = 0; $m < $MenuCount; $m++) {
$Menu = $Menu[$m];
$ID = $Menu['ID'];
if ($ID != $Parent)
continue;
?>
<?=$TabLI?><li<?=$MenuClass?>><?=$Menu['Name']?><?=CreateMenu($Menus, $Tab + 1, $ID, $Level + 1)?></li>
<?php
?>
<?=$TabUL?></ul>
<?php
}
}
And to use it just run 'CreateMenu($Menus);' or 'CreateMenu($Menus, $PrefixTabCount);'.
CreateMenu will recursively create the nested menu for you.
I have not test it so you may have to adjust it.
Hope this helps.