Logic for displaying infinite category tree in nested <ul>s

Hi there,

I’m struggling with the logic for displaying a category tree as standard compliant nested <ul> tags and I was hoping someone could offer me a solution :slight_smile:

It is a tree of product categories which can be infinitely deep. I have a function which will get the full category tree in the correct order. For each row it will also tell me how many levels deep that category is. For example, if retrieving just the category name and level it would look something like this:

Clothing 1
Trousers 2
Mens trousers 3
Ladies trousers 3
Jackets 2
Shirts 2
Shoes 2
Mens shoes 3
Mens formal shoes 4
Mens casual shoes 4
Kids shoes 3
Ladies shows 3
Cars 1
Small cars 2
etc etc

If put a space before each category name foreach level then it looks like a tree:

Clothing 1
 Trousers 2
   Mens trousers 3
   Ladies trousers 3
 Jackets 2
 Shirts 2
 Shoes 2
  Mens shoes 3
   Mens formal shoes 4
   Mens casual shoes 4
  Kids shoes 3
  Ladies shoes 3
Cars 1
 Small cars 2

I want to use a good coding structure though and the tree will be best presented as a <ul>. So something like this:

<ul>
  <li>Clothing 1
    <ul>
      <li>Trousers 2
        <ul>
          <li>Mens trousers 3</li>
          <li>Ladies trousers 3</li>
        </ul>
      </li>
      <li>Jackets 2</li>
      <li>Shirts 2</li>
      <li>Shoes
        <ul>
          <li>Mens shoes 3
            <ul>
              <li>Mens formal shoes 4</li>
              <li>Mens casual shoes 4</li>
            </ul>
          </li>
          <li>Kids shoes 3</li>
          <li>Ladies shoes 3</li>
        </ul>
      </li>
    </ul>
   </li>
  <li>Cars 1
   <ul>
     <li>Small cars 2</i>
   </ul>
  </li>
</ul>

I think I’ve just got that right :wink: So is that possible just through using the value of the level number. I’ve been trying to echo tags based on the value of level changing but I just can’t get it right.

Many thanks :slight_smile:

PS. It may be worth noting that I’m using The Nested Set Model. So other values I can retrieve with each row are:

parent_id, nleft and nright.

Thanks!

Hey, looks like I’ve got this sorted now. Using something like this:

if(!is_array($categories)) {
	echo '<p class="error">Unable to retrieve categories, please bear with us.</p>';	
} else {
	
	echo '<ul id="menu_category">', "\
";
	$count = count($categories);
	if ($count == 1) {
		echo '<li>', $categories[0]['name'], '</li>', "\
";
	} else {
		$i = 0;
		while (isset($categories[$i])) {
			
			echo '<li><a href="'.$href.'">'.$categories[$i]['name'].'</a>';
			
			if ($i < $count - 1) {
				
				if ($categories[$i + 1]['nlevel'] > $categories[$i]['nlevel']) {
					echo '<ul>', "\
";
				} else {
					echo '</li>', "\
";
				}
				
				if ($categories[$i + 1]['nlevel'] < $categories[$i]['nlevel']) {
					echo str_repeat('</ul></li>' . "\
", ($categories[$i]['nlevel']-1) - ($categories[$i + 1]['nlevel']-1));
				}
				
			} else {
				echo '<li>', "\
";
				echo str_repeat('</ul></li>' . "\
", $categories[$i]['nlevel']-1);
			}
			$i++;
		} // END while
	} // END else
	echo '</ul>', "\
";	
}

I just need to change now so that it only show Descendants beyond level 2 if that level 2 is selected.

Cheers :slight_smile:

Use MySQL and PHP with javascript for xhtml output

http://www.codeassembly.com/How-to-display-infinite-depth-expandable-categories-using-php-and-javascript/

CREATE TABLE categories (

id int(11) NOT NULL auto_increment,

name varchar(100) NOT NULL,

parent int(11) NOT NULL,

PRIMARY KEY (id)

) ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=13 ;

– Dumping data for table categories

INSERT INTO categories (id, name, parent) VALUES

(1, ‘Web development’, 0),

(2, ‘Application development’, 0),

(3, ‘Linux’, 0),

(4, ‘Misc’, 0),

(5, ‘Php’, 1),

(6, ‘Mysql’, 1),

(7, ‘Javascript’, 1),

(8, ‘CSS’, 1),

(9, ‘C plus plus’, 2),

(10, ‘wxWidgets’, 2),

(11, ‘Tutorials’, 3),

(12, ‘My thoughts’, 4);
e are using a single table to hold together categories and subcategories. Each subcategory can have a parent to show which category it belongs to, and they can be linked recursively

n this example, we have only 1 level subcategories, but you can add how many levels you would like to. For example category ‘Web development’ has 4 subcategories: Php, Mysql, Javascript and CSS

sing data from this table we will generate a nested html unordered list using the php code below

<?php

//connect to database

$link = mysqli_connect(‘localhost’,‘root’,‘’);

mysqli_select_db($link,‘your_database_name’);

//get all rows

$query = mysqli_query($link,‘SELECT * FROM categories’);

while ( $row = mysqli_fetch_assoc($query) )

{

    $menu_array[$row['id']] = array('name' =&gt; $row['name'],'parent' =&gt; $row['parent']);

}

//recursive function that prints categories as a nested html unorderd list

function generate_menu($parent)

{

    $has_childs = false;

    //this prevents printing 'ul' if we don't have subcategories for this category



    global $menu_array;

    //use global array variable instead of a local variable to lower stack memory requierment



    foreach($menu_array as $key =&gt; $value)

    {

            if ($value['parent'] == $parent) 

            {       

                    //if this is the first child print '&lt;ul&gt;'                       

                    if ($has_childs === false)

                    {

                            //don't print '&lt;ul&gt;' multiple times                             

                            $has_childs = true;

                            echo '&lt;ul&gt;';

                    }

                    echo '&lt;li&gt;&lt;a href="/category/' . $value['name'] . '/"&gt;' . $value['name'] . '&lt;/a&gt;';

                    generate_menu($key);

                    //call function again to generate nested list for subcategories belonging to this category

                    echo '&lt;/li&gt;';

            }

    }

    if ($has_childs === true) echo '&lt;/ul&gt;';

}

//generate menu starting with parent categories (that have a 0 parent)

generate_menu(0);
nd the resulting html unordered list looks like this

<ul id=“categories”>

    &lt;li&gt;Web development

            &lt;ul&gt;

                    &lt;li&gt;&lt;a href="/category/Php/"&gt;Php&lt;/a&gt;&lt;/li&gt;

                    &lt;li&gt;&lt;a href="/category/Mysql/"&gt;Mysql&lt;/a&gt;

                    &lt;/li&gt;&lt;li&gt;&lt;a href="/category/Javascript/"&gt;Javascript&lt;/a&gt;&lt;/li&gt;

                    &lt;li&gt;&lt;a href="/category/CSS/"&gt;CSS&lt;/a&gt;&lt;/li&gt;

            &lt;/ul&gt;

    &lt;/li&gt;

    &lt;li&gt;Application development

            &lt;ul&gt;

                    &lt;li&gt;&lt;a href="/category/C-plus-plus/"&gt;C plus plus&lt;/a&gt;&lt;/li

                    &gt;&lt;li&gt;&lt;a href="/category/wxWidgets/"&gt;wxWidgets&lt;/a&gt;&lt;/li&gt;

            &lt;/ul&gt;

    &lt;/li&gt;

    &lt;li&gt;Linux

            &lt;ul&gt;

                    &lt;li&gt;&lt;a href="/category/Tutorials/"&gt;Tutorials&lt;/a&gt;&lt;/li&gt;

            &lt;/ul&gt;

    &lt;/li&gt;

    &lt;li&gt;Misc

            &lt;ul&gt;

                    &lt;li&gt;&lt;a href="/category/My-thoughts/"&gt;My thoughts&lt;/a&gt;&lt;/li&gt;

            &lt;/ul&gt;

    &lt;/li&gt;

</ul>

Hi cloudtap,

Thanks for your reply. That’s an interesting alternative which I’ll look in to.

Cheers :slight_smile:

I have a function which will get the full category tree in the correct order. For each row it will also tell me how many levels deep that category is.

Hey sxtrail,

Instead of being of help to you can I ask for your help instead… I have trouble displaying my category w/c is also can be infinitely deep…

can you show me your database table setup for that…

and can you show me the function which will get the full category tree in the correct order…

heres my current database set up

thanks, hope you can help me w/ this :slight_smile:

search for recursive function in this forums. you definitely get the answer.

Hi there,

I followed this article to get mine working: http://www.phpriot.com/articles/nested-trees-2

My database is pretty much as described in that article but in MySQL. I also used the same functions for retrieving and managing the category tree but customised them slightly for my own needs.

Works well for me!

Hope that helps.