Echo Menu Tree with Recursive Function

Echo menu tree with recursive function

How about:

function recurse($categories, $parent = null, $level = 0)
{
$ret = '<ul>';
foreach($categories as $index => $category)
{
if($category['root'] == $parent)
{
$ret .= '<li><a href="#"><p class="Tier' . $level . '">' . $category['name'] . '</p></a>';
$ret .= $this->recurse($categories, $category['id'], $level+1);
$ret .= '</li>';
}
}
return $ret . '</ul>';
}

This function requires that you first query your database for the entire list of available categories and assumes that your root categories have a value of null, but the function can be changed to accept -1 or 0 depending on how your current schema works.

$categories = { get from database into an multi-dimensional array };
$Tree = $this->recurse($categories);
echo $Tree;

You may consider doing the following to prevent any empty UL's appearing when no children exist for the parent:

function recurse($categories, $parent = null, $level = 0)
{
$ret = '<ul>';
foreach($categories as $index => $category)
{
if($category['root'] == $parent)
{
$ret .= '<li><a href="#"><p class="Tier' . $level . '">' . $category['name'] . '</p></a>';
$sub = $this->recurse($categories, $category['id'], $level+1);
if($sub != '<ul></ul>')
$ret .= $sub;
$ret .= '</li>';
}
}
return $ret . '</ul>';
}

However, the best solution, would be to select your data to include a column containing how many child categories each category has.

select Category.*, (select count(distinct c1.id) from Category as c1 where c1.root = Category.id) as ChildCount from Category

In which your function would be:

function recurse($categories, $parent = null, $level = 0)
{
$ret = '<ul>';
foreach($categories as $index => $category)
{
if($category['root'] == $parent)
{
$ret .= '<li><a href="#"><p class="Tier' . $level . '">' . $category['name'] . '</p></a>';
if($category['ChildCount'] > 0)
$ret .= $this->recurse($categories, $category['id'], $level+1);
$ret .= '</li>';
}
}
return $ret . '</ul>';
}

Hope that helps?

Recursive menu tree from array

You can try with this one - if you want the indentations as well you can just add some int parameter to the recursive function that defines how many spaces to add as prefix to the echoed lines...:

function buildTree($arr, $parent = 0, $indent = 0)
{
foreach($arr as $item)
{
if ($item["parent"] == $parent)
{
if ($indent != 0)
{
echo str_repeat(" ", $indent) . "- ";
}
echo $item['name'] . '<br/>';
buildTree($arr, $item['term_id'], $indent + 2);
}
}
}

buildTree($categories);

recursive function menu tree , no DB

Almost there! You just need to make a recursive call to createList() in the first version of your code, appending its result to $html.

public function createList()
{
$html = "";
foreach ($this->children as $child) {
$html .= "<ul><li>" . $child->id;
if ($child->children) {
$html .= $child->createList();
}
$html .= "</li></ul>";
}
return $html;
}

Dynamic menu tree using recursion

Here is what I have used finally,

function menuBuilder($menu_array, $is_sub = false)
{
if(!$is_sub) {
$menu = '<ul id="side-menu" class="nav"><li class="top-li"></li>';
} else {
$menu = '<ul class="nav side-submenu">';
}

$sub = '';
foreach ($menu_array as $child) {
foreach ($child as $key => $val) {
if (is_array($val)) {
$sub = menuBuilder($val, true);
} else {
$sub = null;
$$key = $val;
}
}

$menu .= "<li>".((trim($child['name'])!=null)?("<a>".$child['name']."</a>"):"")."$sub</li>";
unset($url, $display, $sub);

}
return $menu . "</ul>";
}

$array = json_decode($json, true);
echo $list = menuBuilder($array['data']['parentNode']['children']);

PHP: nested menu with a recursive function, expand only some nodes (not all the tree)

At last that's what I did, it works very fine:

// create array of ancestors' ID from current page
function path($page = 0) {
global $database_connApp, $connApp;
// let's create arrays
do {
mysql_select_db($database_connApp, $connApp);
$query_rsPage = "SELECT pages.pag_id FROM pages WHERE pages.pag_id = " . $page;
$rsPage = mysql_query($query_rsPage, $connApp) or die(mysql_error());
$row_rsPage = mysql_fetch_assoc($rsPage);
$bid[] = $row_rsPage['pag_id'];
$page = $row_rsPage['pag_parent'];
} while ($page > 0);

// move to the last array index
end($bid);
$output = $bid;
return $output;
}

// create the menu
function fmenu($parent, $array, $path) {
$has_children = false;
foreach($array as $key => $value) {
if (in_array($value['parent'], $path)) {
if ($value['parent'] == $parent) {
if ($has_children === false && $parent) {
$has_children = true;
echo '<ul>' ."\n";
}
$active = ($_GET['iData'] == $value['id']) ? ' class="active"' : '';
echo '<li' . $active . '>' . "\n";
echo '<a href="../pagine/' . $value['id'] . '/' . slugify($value['title']) . '.htm">' . html($value['title']) . '</a>' . " \n";
echo "\n";
fmenu($key, $array, $path);
echo "</li>\n";
}
}
}
if ($has_children === true && $parent) echo "</ul>\n";
}

echo fmenu(0, $nested, path($row_rsEdit['pag_id']));

PHP Recursive menu function

As I agree with @Tim Withers I start to solve problem from preparing current array:

function prepareMenu($array)
{
$return = array();
//1
krsort($array);
foreach ($array as $k => &$item)
{
if (is_numeric($item['Parent']))
{
$parent = $item['Parent'];
if (empty($array[$parent]['Childs']))
{
$array[$parent]['Childs'] = array();
}
//2
array_unshift($array[$parent]['Childs'],$item);
unset($array[$k]);
}
}
//3
ksort($array);
return $array;
}

Some explanation.

  1. This is a weak point as I assumed that order of your menu array will be constant. Assumed order is:
    • top elements first
    • after that children
    • after that children of children
    • so on..
  2. Here is a place where I add a child at beginning of array to save original order.
  3. Rollback to original order.

Then function to build menu:

function buildMenu($array)
{
echo '<ul>';
foreach ($array as $item)
{
echo '<li>';
echo $item['Name'];
if (!empty($item['Childs']))
{
buildMenu($item['Childs']);
}
echo '</li>';
}
echo '</ul>';
}

With this and proper array order, no matter how deep rabbit hole is - you have your tree.

Usage:

$menu = prepareMenu($menu);
buildMenu($menu);

Of course... There must be better way... :-P


EDIT:

For array (a little midification [next child]):

$menu = array(
array(
'Menu_IDX' => '1',
'Order' => '1',
'Name' => 'History',
'Parent' => '',
'Path' => 'History',
'Link' => '',
),
array
(
'Menu_IDX' => '2',
'Order' => '25',
'Name' => 'Review',
'Parent' => '',
'Path' => 'Review',
'Link' => 'Review',
),
array
(
'Menu_IDX' => '3',
'Order' => '35',
'Name' => 'Past Medical History',
'Parent' => '',
'Path' => 'Past Medical History',
'Link' => 'Past Medical History',
),
array
(
'Menu_IDX' => '4',
'Order' => '45',
'Name' => 'Item 1',
'Parent' => '0',
'Path' => 'Item 1',
'Link' => 'Item 1',
),
array
(
'Menu_IDX' => '5',
'Order' => '55',
'Name' => 'Item 2',
'Parent' => '0',
'Path' => 'Item 2',
'Link' => 'Item 2',
),
array
(
'Menu_IDX' => '6',
'Order' => '65',
'Name' => 'Item 3',
'Parent' => '0',
'Path' => 'Item 3',
'Link' => 'Item 3',
),
array
(
'Menu_IDX' => '7',
'Order' => '65',
'Name' => 'Item 31',
'Parent' => '5',
'Path' => 'Item 31',
'Link' => 'Item 31',
)
);

Output will be:

  • History
    • Item 1
    • Item 2
    • Item 3
      • Item 31
    • Review
    • Past Medical History

Recursion functions, To Display dynamic menus with parent, children and siblings only

Since you have said that you want the code to be in php rather than JS Jquery. I have tried this. It iterates your array thrice, within which it built's a nested tree ie., what you needed.

Define your array $menuItems here and go on with the code below

<ul>
<?php
foreach($menuItems as $menu)
{
if($menu['main'] == 1)
{
?>
<li>
<a href='<?= '?activeMenu='.$menu['id'] ?>'><?php echo $menu['name']; ?></a>
<?php
if(isset($_GET['activeMenu']) && $_GET['activeMenu'] == $menu['id'])
{
?>
<ul>
<?php
foreach($menuItems as $submenu_level1)
{
if($submenu_level1['parent_id'] == $_GET['activeMenu'])
{
?>
<li>
<a href='<?= '?activeMenu='.$_GET['activeMenu'].'&activeSubMenu='.$submenu_level1['id'] ?>'><?php echo $submenu_level1['name']; ?>
<?php
if(isset($_GET['activeMenu']) && isset($_GET['activeSubMenu']) && $_GET['activeMenu'] == $menu['id'] && $_GET['activeSubMenu'] == $submenu_level1['id'])
{
foreach($menuItems as $submenu_level2)
{
?>
<ul>
<?php
if($submenu_level2['parent_id'] == $_GET['activeSubMenu'])
{
?>
<li><a href='<?= $_SERVER['PHP_SELF'] ?>'><?php echo $submenu_level2['name']; ?></li>
<?php
}
?>
</ul>
<?php
}
}
?>
</li>
<?php
}
}
?>
</ul>
<?php
}
?>
</li>
<?php
}
}
?>
</ul>


Related Topics



Leave a reply



Submit