Submenus in php and mysql directory style database -
i've been trying make menu submenus on each main item , sub_sub_menus on each sub menu through php , mysql. feel i'm there i'm new php , mysql i've come here help. have been searching hours answer, i've found examples of dropdown menus none this.
not sure how add sql database here try add if requested.
my php code below far.
$result = mysqli_query($link, 'select * library parent_id =' . $parent_id = 0); $subresult = mysqli_query($link, 'select * library parent_id >'. $parent_id); if(mysqli_num_rows($result) > 0) { echo '<ul class="nav list">'; while($row = mysqli_fetch_array($result)) { echo '<li class="nav-item">'. '<a href="#">'.$row['mainfolder'] .'</a>'. '<ul class="dropdown-content nav">'; while($sub = mysqli_fetch_array($subresult)) { if($row['id']===$sub['parent_id']) { echo $sub['parent_id']; $submenuitems = mysqli_query($link, 'select mainfolder library parent_id ='. $sub['parent_id']); $items = mysqli_fetch_array($submenuitems); foreach ($items $eachitem){ echo' <li class="submenu">'.'<a class="sub" href="#">'.htmlspecialchars($eachitem, ent_quotes, 'utf-8').'</li>'.'</a>'.'</ul>'; } } } } echo '</ul>'.'</li>'; echo '</ul>'; }
because asked nicely, , because challenge of recursive functions decided go ahead , out.
my original answer getting bit out of hand, cleaned up. did ton of debugging, , fixed few "bugs" found in original post.
echo "<pre>"; //preserve whitespace //i mocked arrays ('canned data') make things easier show , test //order of parents matter ( should in order left right of menu ) $parents = [ ['id' => 1, 'title' => 'item1', 'link' => 'http://www.example.com/item1', 'parent_id' => 0], ['id' => 8, 'title' => 'item8', 'link' => 'http://www.example.com/item8', 'parent_id' => 0], ]; var_export( $parents ); echo "\n\n"; //you can order children way want, still grouped under right parent $children = [ ['id' => 2, 'title' => 'item2', 'link' => 'http://www.example.com/item2', 'parent_id' => 1], ['id' => 3, 'title' => 'item3', 'link' => 'http://www.example.com/item3', 'parent_id' => 2], ['id' => 4, 'title' => 'item4', 'link' => 'http://www.example.com/item4', 'parent_id' => 1], //not ordered ['id' => 5, 'title' => 'item5', 'link' => 'http://www.example.com/item5', 'parent_id' => 2, "target" => null, "css_class" => null], ['id' => 6, 'title' => 'item6', 'link' => 'http://www.example.com/item6', 'parent_id' => 1, "target" => "_blank"], ['id' => 7, 'title' => 'item7', 'link' => 'http://www.example.com/item7', 'parent_id' => 8, "css_class"=>"test"], ]; var_export($children); echo "\n\n"; $lv = 1; $html = "<ul class=\"menu menu_lv0\" >\n"; foreach( $parents &$parent ){ $html = buildmenutree( $parent, $children, $html, $lv, $lv ); //pass refrence no return needed } $html .= "</ul>\n"; var_export( $parents ); echo "\n\n"; echo htmlspecialchars( $html )."\n\n"; //htmlspecialchars display reasons //========================================= // define function //========================================= //$parent passed refrence function buildmenutree( &$parent, $children, $html='', $lv=0, $indent=0 ){ if( $lv == 1 || $lv == 2) $mode = true; if( !$children ) return; reset( $children ); //reset array $t0 = getindent( $indent ); $t1 = getindent( ($indent+1) ); //css class menu item $css_class = (isset($parent['css_class']) && $parent['css_class']) ? " {$parent['css_class']}" : ""; //link target $target = (isset($parent['target']) && $parent['target']) ? "target=\"{$parent['target']}\" " : ""; $id = $parent['id']; $html .= "{$t0}<li id=\"menu_item_{$id}\" class=\"menu_item item_lv{$lv}{$css_class}\">\n"; $html .= "{$t1}<a class=\"menu_link\" href=\"{$parent['link']}\" {$target}>{$parent['title']}</a>"; while( false !== ( $child = current( $children ) ) ){ //if parents id, matches childs parent id, add current child //as child of parent , check ( current child ) children may have // add if( ... && $limit == $lv) , pass in $limit param function limit depth if( $parent['id'] == $child['parent_id'] ){ $key = key( $children ); //remove - reduce array , our processing time, can remove current item //also current item parent in recusive function , therefore //know cannot child of , wont need in branch unset( $children[$key] ); //make recursive call ( call method again //&$parent, $children, $html='', $lv=1, $indent=1 $r_html = buildmenutree($child, $children, "", ($lv + 1), ($indent+2)); //creante children array if not exists if( !isset( $parent['children'] ) ){ $parent['children'] = []; $html .= "\n{$t1}<ul class=\"sub_menu menu_lv{$lv} parent_{$parent['id']}\" >\n"; $html .= $r_html; }else{ $html .= $r_html; } ///store child $parent['children'][] = $child; }else{ $next = next( $children ); }; } if( !isset( $parent['children'] ) ) $html .= "\n"; else $html .= "{$t1}</ul>\n"; $html .= "{$t0}</li>\n"; return $html; } function getindent( $indent, $pad = " " ){ return str_pad("", ( $indent * 4 ), $pad); } echo "</pre>";
i tested on apache/2.4.18 (win32) php/7.0.4) , 100% works.
output
array tree structure parent passed reference, it's modified not returned, need return html
$parent = array ( 0 => array ( 'id' => 1, 'title' => 'item1', 'link' => 'http://www.example.com/item1', 'parent_id' => 0, 'children' => array ( 0 => array ( 'id' => 2, 'title' => 'item2', 'link' => 'http://www.example.com/item2', 'parent_id' => 1, 'children' => array ( 0 => array ( 'id' => 3, 'title' => 'item3', 'link' => 'http://www.example.com/item3', 'parent_id' => 2, ), 1 => array ( 'id' => 5, 'title' => 'item5', 'link' => 'http://www.example.com/item5', 'parent_id' => 2, 'target' => null, 'css_class' => null, ), ), ), 1 => array ( 'id' => 4, 'title' => 'item4', 'link' => 'http://www.example.com/item4', 'parent_id' => 1, ), 2 => array ( 'id' => 6, 'title' => 'item6', 'link' => 'http://www.example.com/item6', 'parent_id' => 1, 'target' => '_blank', ), ), ), 1 => array ( 'id' => 8, 'title' => 'item8', 'link' => 'http://www.example.com/item8', 'parent_id' => 0, 'children' => array ( 0 => array ( 'id' => 7, 'title' => 'item7', 'link' => 'http://www.example.com/item7', 'parent_id' => 8, 'css_class' => 'test', ), ), ), )
html
<ul class="menu menu_lv0" > <li id="menu_item_1" class="menu_item item_lv1"> <a class="menu_link" href="http://www.example.com/item1" >item1</a> <ul class="sub_menu menu_lv1 parent_1" > <li id="menu_item_2" class="menu_item item_lv2"> <a class="menu_link" href="http://www.example.com/item2" >item2</a> <ul class="sub_menu menu_lv2 parent_2" > <li id="menu_item_3" class="menu_item item_lv3"> <a class="menu_link" href="http://www.example.com/item3" >item3</a> </li> <li id="menu_item_5" class="menu_item item_lv3"> <a class="menu_link" href="http://www.example.com/item5" >item5</a> </li> </ul> </li> <li id="menu_item_4" class="menu_item item_lv2"> <a class="menu_link" href="http://www.example.com/item4" >item4</a> </li> <li id="menu_item_6" class="menu_item item_lv2"> <a class="menu_link" href="http://www.example.com/item6" target="_blank" >item6</a> </li> </ul> </li> <li id="menu_item_8" class="menu_item item_lv1"> <a class="menu_link" href="http://www.example.com/item8" >item8</a> <ul class="sub_menu menu_lv1 parent_8" > <li id="menu_item_7" class="menu_item item_lv2 test"> <a class="menu_link" href="http://www.example.com/item7" >item7</a> </li> </ul> </li> </ul>
i took liberty add few things consider commonly implemented features of navigation menu.
- css class, if row contains
$row ['css_class']
<li>
add it's value it's classes, can setfalse|null
or not have it. - target, if item contains
$row ['target']
<a>
tag have target attribute it's value, can setfalse|null
or not have it.
you can see these test cases:
- most items omit
target
,css_class
don't use word class, because reserved word - item5 has both
target
,css_class
setnull
false
value omit these tags. - item6 has
target
value of_blank
, link<a target="_blank" ..
in output - item7 has
css_class
oftest
, has these classesmenu_item item_lv2 test
here list of classes added html
ul classes:
- top level
<ul>
have class ofmenu
- sub level
<ul>
have class ofsub_menu
- sub level
<ul>
have class ofparent_{id}
{id}
id of parent - every
<ul>
have class ofmenu_lv{lv}
{lv}
nesting level
ul classes & id:
- every
<li>
have id ofmenu_item_{id}
{id}
record id - every
<li>
have class ofmenu_item
- every
<li>
have class ofitem_lv{lv}
where{lv}
nesting level
a classes:
- every
<a>
tag have class ofmenu_link
the catch, not set children
key in record manually, $parent['children']
or $child['children']
. had use way detect if children had been added yet. ( although work refined, didn't seem important )
this took quite bit of work , time, on own css. but, have built many, many menus , html should close need (although, admit, has been few years sense made nav menu).
lastly can test online in phpsanbox link
good luck, , enjoy!
Comments
Post a Comment