PHP Nested foreach loop, how to affect (parent?) - php

I have a nested foreach loop running through categories in a database. When the user is viewing a category the category ID is set and that menu item gets it's class set as "active".
The issue I'm having is when a user is viewing a subcategory, I still need it's PARENT to be set to active.
// Run through category ID's and output info
foreach ($GLOBALS['AKB_CLASS_HELPER']->tree->nodesByPid[$catid] as $rowid) {
$row = $GLOBALS['AKB_CLASS_HELPER']->catsById[$rowid];
//Check to see if user has access
if (($accessible_cats !== false) && (!in_array($row['categoryid'],$accessible_cats)) && ($row['security'] == "private")) {
continue;
}
// If we're viewing a category, output "active" as a class in the menu
if (isset($GLOBALS['CategoryId'])
&& ($GLOBALS['CategoryId']) == $row['categoryid']) {
$activeCat = "active";
} else {
$activeCat = "";
}
//Pass through global variables
$GLOBALS['Link'] = GetUrl('category', $row['categoryid']);
$GLOBALS['Text'] = $GLOBALS['AKB_CLASS_TEMPLATE']->DisablePlaceholders(strip_tags($row['name']));
$GLOBALS['Active'] = $activeCat;
$output .= $GLOBALS['AKB_CLASS_TEMPLATE']->GetSnippet('CategoryRowCell');
//If subcategories exist
if (isset($GLOBALS['AKB_CLASS_HELPER']->tree->nodesByPid[$rowid])
&& is_array($GLOBALS['AKB_CLASS_HELPER']->tree->nodesByPid[$rowid])
&& !empty($GLOBALS['AKB_CLASS_HELPER']->tree->nodesByPid[$rowid])) {
$output .= $GLOBALS['AKB_CLASS_TEMPLATE']->GetSnippet('CategoryGridHeaderSub');
//For every subcategory, output data
foreach ($GLOBALS['AKB_CLASS_HELPER']->tree->nodesByPid[$rowid] as $subrowid) {
$subrow = $GLOBALS['AKB_CLASS_HELPER']->catsById[$subrowid];
//Here's the part I can't get working. Need to output "active" to the PARENT id($row I believe)
if (isset($GLOBALS['CategoryId'])
&& ($GLOBALS['CategoryId']) == $subrow['categoryid']) {
$activeCat = "active";
} else {
$activeCat = "";
}
//Set Global Variables
$GLOBALS['Link'] = GetUrl('category', $subrow['categoryid']);
$GLOBALS['Text'] = $GLOBALS['AKB_CLASS_TEMPLATE']->DisablePlaceholders(strip_tags($subrow['name']));
$GLOBALS['Active'] = $activeCat;
$output .= $GLOBALS['AKB_CLASS_TEMPLATE']->GetSnippet('CategoryRowCellSub');
}
}
$output .= $GLOBALS['AKB_CLASS_TEMPLATE']->GetSnippet('CategoryGridFooterSub');
}
So the part I need to figure out is in the nested foreach loop, how can I affect the parent ID or something of the like.
Current Output when viewing parents(Working perfectly)
<li class="categoryItem active">Parent 1
<ul class="categorySubList">
<li class="categorySubItem"><a class="categorylink" href="/categories/Parent+1/Subcategory+1/">Subcategory 1</a></li>
<li class="categorySubItem "><a class="categorylink" href="/categories/Parent+1/Subcategory+2/">Subcategory 2</a></li>
</ul>
Current Output when viewing children(not working)
<li class="categoryItem">Parent 1<!--this list item needs to be active-->
<ul class="categorySubList">
<li class="categorySubItem active"><a class="categorylink" href="/categories/Parent+1/Subcategory+1/">Subcategory 1</a></li>
<li class="categorySubItem "><a class="categorylink" href="/categories/Parent+1/Subcategory+2/">Subcategory 2</a></li>
</ul>

Related

Split menu list in two every 7 items

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>

Hierarchical tree menu - PHP / MySQL

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>";
?>

Using recursion to build navigation

I'm building navigation for a site and for the life of me I can't figure out recursion. I have all my data stored via MySQL using this design:
I've read several links on how recursion works and I must be slow because it's difficult for me to grasp. I've tried to write something and I know it is not even close to what I really need, but it's a start:
PDO
public function viewCategories()
{
$viewSQL = "SELECT * FROM categories";
try
{
$pdo = new PDO('mysql:host=localhost;dbname=store','root','');
$pdo->setAttribute(PDO::ATTR_ERRMODE,PDO::ERRMODE_EXCEPTION);
$categoryVIEW = $pdo->prepare($viewSQL);
$categoryVIEW->execute();
$array = $categoryVIEW->fetchAll(PDO::FETCH_ASSOC);
$categoryVIEW->closeCursor();
$json = json_encode($array);
return $json;
}
catch(PDOexception $e)
{
return $e->getMessage();
exit();
}
}
Recursion
$return = json_decode($category->viewCategories(),true);
function buildNavigation($json)
{
foreach($json as $item)
{
if($item['category_id'] === $item['parent'])
{
print('<li>'.$item['category_name'].'</li>');
if($item['category_id'] === $item['parent'])
{
print('<li>match'.$item['category_name'].'</li>');
buildNavigation($json);
}
}
}
buildNavigation($return);
as expected this will never enter the condition. I did try to figure this out on my own since this is a good thing to have knowledge of, but I guess it's beyond my mental capacity :(
Thanks for having a look :)
UPDATE
I know this has been answered already, but is there a way I can do this to build an associative array? I have been playing around with a function that ALMOST works for me that I got from HERE, but it adds an extra array that I do NOT want.
Method
private function buildCategories($array,$parent)
{
$result = array();
foreach($array as $row)
{
if($row['parent'] == $parent)
{
$result[$row['category_name']] = $this->buildCategories($array,$row['category_id']);
}
}
return $result;
}
$json = json_encode($this->buildCategories($array,NULL));
return $json;
I want this:
{"reloading":{"components","presses and dies","tumblers & scales","tools & accessories","shotshell reloading"}
but what I get is this:
{"reloading":{"components":[],"presses and dies":[],"tumblers & scales":[],"tools & accessories":[],"shotshell reloading":[]}
Here's an example with recursion.
function buildNavigation($items, $parent = NULL)
{
$hasChildren = false;
$outputHtml = '<ul>%s</ul>';
$childrenHtml = '';
foreach($items as $item)
{
if ($item['parent'] == $parent) {
$hasChildren = true;
$childrenHtml .= '<li>'.$item['category_name'];
$childrenHtml .= buildNavigation($items, $item['category_id']);
$childrenHtml .= '</li>';
}
}
// Without children, we do not need the <ul> tag.
if (!$hasChildren) {
$outputHtml = '';
}
// Returns the HTML
return sprintf($outputHtml, $childrenHtml);
}
print buildNavigation($items);
That script produces the following output :
<ul>
<li>Menu 1</li>
<li>Menu 2
<ul>
<li>Sub Menu 2.1</li>
<li>Sub Menu 2.2</li>
<li>Sub Menu 2.3
<ul>
<li>Sub Menu 2.2.1</li>
<li>Sub Menu 2.2.2</li>
<li>Sub Menu 2.2.3</li>
</ul>
</li>
</ul>
</li>
<li>Menu 3</li>
</ul>
I have the same above code with little bit modification, so that a user can apply different css on each level of menu, now its showing classes of sub menu like child-class1 when its in 1st sub menu , and it will show child-class2 when its in 2nd sub menu and so on...
<?php
function buildNavigation($items, $parent = NULL, $n=NULL)
{
$hasChildren = false;
if ($parent == NULL)
{
$level=0;
$outputHtml = '<ul class="parent-class">%s</ul>';
}
else
{
if($n==NULL)
{
$level=1;
}
else
{
$level=$n;
}
$outputHtml = '<ul class="child-class'.$level.'">%s</ul>';
}
$childrenHtml = '';
foreach($items as $item)
{
if ($item['parent'] == $parent) {
$hasChildren = true;
$childrenHtml .= '<li>'.$item['ptitle'].'';
$next = ++$level;
$childrenHtml .= buildNavigation($items, $item['pageid'],$next);
$childrenHtml .= '</li>';
}
}
// Without children, we do not need the <ul> tag.
if (!$hasChildren) {
$outputHtml = '';
}
// Returns the HTML
return sprintf($outputHtml, $childrenHtml);
}
echo buildNavigation($ppages);
?>
it will show out put like this
<ul class="parent-class">
<li>
page 1
<ul class="child-class1">
<li>
this is child page
<ul class="child-class2">
<li>
child of child </li>
</ul>
</li>
</ul>
</li>
</ul>
I would like to thanks Mr #Maxime Morin.

Wrap anchor tag content with SPAN using PHP

I need to take some simple UL tag generated in PHP (Joomla 1.5) and wrap each anchor tag's text content with a SPAN tag. The incoming HTML looks like this:
<ul>
<li>
Home
</li>
<li>
Watch UNC-TV
</li>
<li>
<a href="#" >Contact</a>
</li>
</ul>
The output needs to look like this:
<ul id="top-nav" class="flatList">
<li class="selected">
<a href="#"><span class="embed embed-top-nav">Home</span>
<p >news, highlights</p></a>
</li>
<li>
<a href="#"><span class="embed embed-top-nav">Watch UNC-TV</span>
<p>schedule, local programs</p></a>
</li>
<li id="nav-last">
<a href="#"><span class="embed embed-top-nav">Contact</span>
<p>feedback, connect, share</p></a>
</li>
</ul>
Also note the class added to the active LI tag ("selected") and the class added to the last one in the list ("nav-last"). This is in Joomla 1.5, where I'm overriding the mod_mainmenu module used by the Main Menu. The code uses the SimpleXML library to read and write the HTML in the modMainMenuXMLCallback(&$node, $args):
<?php
defined('_JEXEC') or die('Restricted access');
if ( ! defined('fancyMenuPatch') )
{
function fancyMenuPatch($result,$tag){
// Replace UL tag with ours.
// Replace LI tag with ours.
// Add to the start of the UL tag.
$begin_ul = "<ul id=\"top-nav\" class=\"flatList\">";
$begin_li = "<li>"; //not sure what to do with this.
// do the replacement
$result = str_replace("<ul>",$begin_ul, $result);
$result = str_replace("<li>", $begin_li, $result);
return $result;
}
define('fancyMenuPatch', true);
}
if ( ! defined('modMainMenuXMLCallbackDefined') )
{
function modMainMenuXMLCallback(&$node, $args)
{
$user = &JFactory::getUser();
$menu = &JSite::getMenu();
$active = $menu->getActive();
$path = isset($active) ? array_reverse($active->tree) : null;
if (($args['end']) && ($node->attributes('level') >= $args['end']))
{
$children = $node->children();
foreach ($node->children() as $child)
{
if ($child->name() == 'ul') {
$node->removeChild($child);
}
}
}
if ($node->name() == 'ul') {
foreach ($node->children() as $child)
{
if ($child->attributes('access') > $user->get('aid', 0)) {
$node->removeChild($child);
}
}
}
if (($node->name() == 'li') && isset($node->ul)) {
$node->addAttribute('class', 'parent');
}
if (isset($path) && (in_array($node->attributes('id'), $path) || in_array($node->attributes('rel'), $path)))
{
if ($node->attributes('class')) {
$node->addAttribute('class', $node->attributes('class').' active');
} else {
$node->addAttribute('class', 'active');
}
}
else
{
if (isset($args['children']) && !$args['children'])
{
$children = $node->children();
foreach ($node->children() as $child)
{
if ($child->name() == 'ul') {
$node->removeChild($child);
}
}
}
}
if (($node->name() == 'li') && ($id = $node->attributes('id'))) {
if ($node->attributes('class')) {
$node->addAttribute('class', $node->attributes('class').' item'.$id);
} else {
$node->addAttribute('class', 'item'.$id);
}
}
if (isset($path) && $node->attributes('id') == $path[0]) {
$node->addAttribute('id', 'current');
} else {
$node->removeAttribute('id');
}
$node->removeAttribute('rel');
$node->removeAttribute('level');
$node->removeAttribute('access');
}
define('modMainMenuXMLCallbackDefined', true);
}
ob_start();
modMainMenuHelper::render($params, 'modMyMainMenuXMLCallback');
$menu_html = ob_get_contents();
ob_end_clean();
if($params->get('menutype')=="primarynav"){
$tag = $params->get('tag_id');
}
//output the menu!
echo fancyMenuPatch($menu_html,$tag);
?>
Thank you.
Ok so here is how you want to do this. Jump out of the default.php script you posted above. As Joomla! uses the core mainmenu module for all menus and trees down from that you will need to edit the helper script. This should stick regardless of any 3rd party menu extension you may be using.
rootdirectory/modules/mod_mainmenu/helper.php
Now jump down to the switch statement at line 358. Specifically we want to edit line 363. It looks like this:
$data = ''.$image.$tmp->name.'';
Now edit it to be this:
$data = '<span class="embed embed-top-nav">'.$image.$tmp->name.'</span>';
there you go, now menus utilized by the Joomla! getMenu class will add this span tag around the links.
Note that you may also want to do this to line 375 for links that will open in a new window et cetra. Also note Louis' funny comment " // hrm...this is a bit dickey".
cheers

How to create a nested menu from MySQL with PHP?

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.

Categories