Solved

Category/Sub-Category Menu Tree

Posted on 2009-05-12
18
4,310 Views
Last Modified: 2013-12-12
Hey Everyone,
I need help with a categories/subcategories menu tree for an online store I'm working on. I want to be able to list the menu in the left column of the online store with links to MAIN CATEGORIES as well as showing SUB-CATEGORIES (Infinite level) when a MAIN CATEGORY is selected. Like this:

MAIN CATEGORY 1
  > Sub Category
  > Sub Category
  > Sub Category
    > Sub Sub Category
    > Sub Sub Category
MAIN CATEGORY 2
MAIN CATEGORY 3
etc....

So my problem is that I can get the 1st level child sub-categories but when you try to click the link of the sub-category...it only displays the root categories. I want the user to be able to see the MAIN CATEGORIES first and once they click a MAIN CATEGORY any sub-categories will show up. And when you click those sub-category links...any sub sub categories can show up.

NOTES:
- I want the root categories to always show
- All sub-categories are in <ul>/<li> format
- the GET variable is "cid" when a user clicks a link
- I'd also like to minimize the MYSQL queries so that it doesn't clog it up (if I were to have an infinite number of sub-categories)

DATABASE SET UP
DB: shop_category
cat_id
parent_id
cat_name

Here's the code for my work so far...HELP:
<ul>

<?php

// FYI the $conn class is just to simplify the MYSQL QUERIES
 

$catID = $_GET['cid'];

$getroot = $conn->dbQuery("SELECT * FROM shop_category WHERE parent_id='0' ORDER BY cat_sort ASC");

while ($rootcat = $conn->dbFetchArray($getroot)) {

echo "<li><a href=\"index.php?cid=$rootcat[cat_id]\">$rootcat[cat_name]</a>";

if($catID !=0) { getSubCategory($catID,$rootcat['cat_id']);}

echo "</li>\n";

}//END while 

$conn->dbFreeResult($getroot);

mysql_close();
 

function getSubCategory($catid,$parentid) {

global $conn;

if($catid == $parentid) {

$getdata = $conn->dbQuery("SELECT * FROM shop_category WHERE parent_id='$catid' ORDER BY cat_sort ASC");

$numrows = $conn->dbNumRows($getdata);

if ($numrows > 0) {

$count = 1;

while ($subcat = $conn->dbFetchArray($getdata)) {

$startlist = ($count ==1) ? "<ul>" : "";

$endlist = ($count ==$numrows) ? "</ul>\n" : "";

echo "$startlist<li>&raquo;&nbsp;&nbsp;<a href=\"index.php?cid=$subcat[cat_id]\">$subcat[cat_name]</a>";

getSubCategory($subcat['cat_id'], $subcat['parent_id']);

echo "</li>$endlist\n";

$count++;

}//END while

} //END numrows >0

}//END if catid = parentid

}//END function
 

?>

</ul>

Open in new window

0
Comment
Question by:timrauter
  • 9
  • 9
18 Comments
 
LVL 8

Expert Comment

by:Bobaran98
Comment Utility
Hello, I'd like to point you to a solution I coded in response to an EE post last week.  It's not exactly what you're looking for-- it uses tables instead of <ul>/<li> lists-- but it does allow you to expand and collapse categories, subcategories, etc.  You'll see in my concept code that it was designed with the intent that a person could implement while looping through a database resultset.  As far as the user would ever see, the menu could be styled to look the same whether you used tables or lists.

As for your MySQL resultset, I would think it'd be best to load the entire menu structure at the start and display collapsed.  You could always think about an AJAX solution for loading submenus, but there will always be the potential for delay there, and I'm not sure you'd gain anything.  Just how many menu items are you likely to have?

Okay, here's the link:  http://www.experts-exchange.com/Web_Development/Web_Languages-Standards/PHP/PHP_Databases/Q_24393259.html
0
 

Author Comment

by:timrauter
Comment Utility
I think what I'm looking for is a more dynamic menu..I like the idea of  expand/collapse and I tried that before but it just seemed to clumsy after awhile. I'll look into this though
0
 
LVL 8

Expert Comment

by:Bobaran98
Comment Utility
What do you mean by dynamic?  Do you mean dramatic?  With flair? :-)  Or do you mean dynamic in a programming sense, where data is loaded dynamically?  In my mind, it's the user's experience that matters most.  Behavior and appearance are important... I don't know that it matters whether you accomplish that great experience for the user by preloading all of your data at initial loadtime or by using, say, AJAX to load menu items dynamically as needed.  What matters is whether the user notices a difference.

As for clumsy, I honestly believe that what's most likely to cause clumsiness in the look-and-feel of your menu is if you're having to dynamically load entries.  There's bound to be a slight lag at times.

However, whether you use lists or tables to actually display your results, I don't think that will make much difference.  I'm simply offering you something that's already done and optimized for looping through a resultset.  It's cross-browser compatible, and the movement is smooth.  Remember, it may not look great graphically at the moment, but that's a matter of styling.  Just look at the behavior.  I'm sure there are ways of doing this exact same thing with <ul><li> lists.

Ok, one last caveat about your table data (I'm going back to the dynamically loading data question).  If you're talking about a huge list of options... say, 300 main categories with a combined total of 10,000 submenus and subsubmenu items... well, something more dynamic (in a programming sense) definitely would be called for.  In that case, I would suggest preloading options to a certain point, say 1 or 2 levels deep, then any time the user clicks within a level or two of an unloaded submenu, your AJAX or whatever calls out and grabs those submenu items so that they'll be ready by the time the user gets there.  I think that might be a way to mitigate the lag factor.

Thoughts?
0
 

Author Comment

by:timrauter
Comment Utility
Thanks for your comments bobaran98.
I'm really not looking for anything crazy here. I really only have a 3 level deep menu...but I want it to be expandable in case more levels are necessary.

I'm actually pulling the categories DYNAMICALLY from a database so I just need to figure out how to pull the proper PARENT-CHILD function to display the proper category and it's sub-categories. Am I just over-thinking this? I've been playing with my function (see code above) over and over again and I can't seem to figure this out. I've been stumped on this for days. I'm just looking for someone who can say...LOOK YOU IDIOT...you do this and here's why.

The user experience is supposed to be simple. Click on a ROOT CATEGORY and the page refreshes with both PRODUCTS from that category (which will display in the right column) and the menu in the left column which will display any sub-categories within the category that the user selected.

Make sense? If you can give me some sample code...that would help too. I'm a better learner by viewing code and breaking it down.
0
 
LVL 8

Expert Comment

by:Bobaran98
Comment Utility
You know, I think I've misunderstood form the beginning what you meant by "dynamic."  You simply meant that when the page loads, it queries the database and gets the latest category/subcategory/item data, then creates its menu based on that.  You meant that you didn't want to hardcode the whole solution in HTML.  I thought you meant you wanted to load the page, then load additional menu items periodically (and dynamically) depending on what the user did.  And I couldn't understand why you would possibly want to do it that way.

You'll have to forgive me.  It was several hours after my bed time when I first responded. :-)

So, let's start over.

Have you tried the code from the link I posted above?  Scroll down to the bottom, copy/paste the entire block of code, and save it as an HTML file.  Run it.  See if you like the feel of it.  That code doesn't have any MySQL references in it, but it was designed with the express intention of making it easy to spit out your menu categories from a database.

Here's that link again:  http://www.experts-exchange.com/Web_Development/Web_Languages-Standards/PHP/PHP_Databases/Q_24393259.html

So that's part of your sample code.  Give me an hour or so, and I'll take your SQL code from above and integrate it with my expand/collapse code.  If at that point you still don't think that's what you want, we'll go from there.
0
 

Author Comment

by:timrauter
Comment Utility
We're getting there...Now I just need the PHP code to display all of the categories and sub-categories and then we can implement the Javascript to show/hide. If you can help me out that would be great...my brain is FRIED
0
 
LVL 8

Expert Comment

by:Bobaran98
Comment Utility
Okay, I've got the following code for you.  I even created a table in my database just so I can test it, so I know this code should work perfectly if you just copy paste it into a brand new PHP file, upload it, and go.

A few quick notes:
  • You need to change your MySQL credentials on lines 28 and 29
  • Your shop_category table need to be set up already, or else this won't run
  • I've assumed for this example that you have no more than three levels... anything more than that in the database just won't display right now
  • You can do any number of things with the displayCatData() function (javascript).  Right now I simply have it writing a value to a div tag when a category gets clicked, but you could also set things up to load a separate document into an iframe, or into a separate frame, OR this could be an opportunity to actually use that AJAX (to actually load a separate page using javascript, but have it appear in a div tag somewhere.
Hopefully these SQL queries should run a lot faster than what you had before... this particular SQL query design is such that you'll need to run a query for each level in the database.

Note that there is definitely room for some optimization of the code... not to make it run faster, but to make it capable of displaying menu levels as far deep as the database entries warrant.  It would take a bit of rewriting on the code, in essence creating a few functions that would run recursively.  But that would take a bit more time and thought, and I decided to show it to you as is and discover whether you liked it before throwing any more time into it!

Hope you do indeed like it! :-)  If any of the code doesn't make sense, just let me know!

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">

<HTML>

 <HEAD>

  <TITLE> Dynamic Expand / Collapse v1 </TITLE>
 

        <script language="javascript1.2">

			function expandCollapse(objID,dbID) {

                var kids = document.getElementById(objID+"kids");

                if(kids) {

					if(kids.style.display != "") { kids.style.display = ""; }

					else { kids.style.display = "none"; }

				}

				displayCatData(dbID);

			}
 

			function displayCatData(dbID) {

				document.getElementById("catData").innerHTML = "Tada! We are now displaying data specific to the shop_category table entry with <b>cat_id="+dbID+"</b>!!";

			}

        </script>
 

 </HEAD>
 

 <BODY>

  

<?php
 
 

$db = mysql_connect($db_location, $db_username, $db_password);

mysql_select_db($db_name,$db) or die( "Unable to select database"); 
 

$level0sql = "SELECT * FROM shop_category WHERE parent_id='0' ORDER BY cat_sort ASC";

$level0 = mysql_query($level0sql);

$num0cats = mysql_numrows($level0);

$string0 = ""; $comma = "";

for($i=0;$i<$num0cats;$i++) { $string0 .= $comma.mysql_result($level0,$i,"cat_id"); $comma = ","; }
 

$level1sql = "SELECT B.* FROM shop_category B, shop_category A WHERE B.parent_id=A.cat_id AND A.cat_id IN ($string0) ORDER BY A.cat_sort ASC, B.cat_sort ASC";

$level1 = mysql_query($level1sql);

$num1cats = mysql_numrows($level1);

$string1 = ""; $comma = "";

for($i=0;$i<$num1cats;$i++) { $string1 .= $comma.mysql_result($level1,$i,"cat_id"); $comma = ","; }
 

$level2sql = "SELECT C.* FROM shop_category C, shop_category B, shop_category A WHERE C.parent_id=B.cat_id AND B.cat_id IN ($string1) AND B.parent_id=A.cat_id ORDER BY A.cat_sort, B.cat_sort ASC, C.cat_sort ASC";

$level2 = mysql_query($level2sql);

$num2cats = mysql_numrows($level2);
 

mysql_close();
 
 

echo "<table border='1' width='400'>";
 

$b = 0; $c = 0;
 

for($a=0;$a<$num0cats;$a++) {
 

	$id0 = mysql_result($level0,$a,"cat_id");

	$name0 = mysql_result($level0,$a,"cat_name");
 

	$aID = "row$a";

	echo "<tr id='$aID'><td><a href='javascript:expandCollapse(\"$aID\",$id0);'>$name0</a></td></tr>\n";
 

	$firstB = true;
 

	while(mysql_result($level1,$b,"parent_id")==$id0) {
 

		if($firstB) {

			echo "<tr id='$aID"."kids' style='display:none'><td align='right'>\n";

			echo "	<table border='1' width='90%'>\n";

			$firstB = false;

		}
 

		$id1 = mysql_result($level1,$b,"cat_id");

		$name1 = mysql_result($level1,$b,"cat_name");
 

		$bID = $aID."_".$b;

		echo "<tr id='$bID'><td><a href='javascript:expandCollapse(\"$bID\",$id1);'>$name1</a></td></tr>\n";
 

		$firstC = true;
 

		while(mysql_result($level2,$c,"parent_id")==$id1) {
 

			if($firstC) {

				echo "<tr id='$bID"."kids' style='display:none'><td align='right'>\n";

				echo "	<table border='1' width='90%'>\n";

				$firstC = false;

			}
 

			$id2 = mysql_result($level2,$c,"cat_id");

			$name2 = mysql_result($level2,$c,"cat_name");
 

			$cID = $bID."_".$c;

			echo "<tr id='$cID'><td><a href='javascript:expandCollapse(\"$cID\",$id2);'>$name2</a></td></tr>\n";
 

			$c++;

			if($c==$num2cats || mysql_result($level2,$c,"parent_id")<>$id1) {

				echo "	</table>\n";

				echo "</td></tr>\n";

			}
 

		}
 

		$b++;

		if($b==$num1cats || mysql_result($level1,$b,"parent_id")<>$id0) {

			echo "	</table>\n";

			echo "</td></tr>\n";

		}
 

	}
 

}
 

?>
 

<p>
 

<div id="catData" style="width:400px;height:200px;padding:20px;border:solid 1px #000000;background-color:#AAAAAA;vertical-align:middle;text-align:center;"> Default Message </div>
 
 

 </BODY>

</HTML>

Open in new window

0
 

Author Comment

by:timrauter
Comment Utility
Thanks for this code. I'm still not sure that this is the proper method to use. There seems to be quite a few SQL queries and what happens if a client has 5-6 sub-categories instead?

Let me give you some visuals of what I'm trying to do so maybe you can point me in the right direction.

Here is the full menu structure (so you know what's where):
http://rockpaperscissor.com/myshop/index_test2.php

The ROOT (parent_id = 0) categories are images all the rest are <ul>/<li>
Here's the code for this:
#######################
<ul class="menu">
<?php
$getroot = $conn->dbQuery("SELECT * FROM shop_category WHERE parent_id='0' ORDER BY cat_sort ASC");
while ($rootcat = $conn->dbFetchArray($getroot)) {
echo "<li><a href=\"index_test2.php?cid=$rootcat[cat_id]\" onMouseOver=\"rollOn('cat$rootcat[cat_id]'); return true;\" onMouseOut=\"rollOff('cat$rootcat[cat_id]'); return true;\"><img src=\"_images/_cat/cat$rootcat[cat_id].gif\" width=\"151\" height=\"15\" border=\"0\" name=\"cat$rootcat[cat_id]\" alt=\"$rootcat[cat_name]\" title=\"$rootcat[cat_name]\"></a>";
getSubCategory($rootcat['cat_id']);
echo "</li>\n";
}//END while
$conn->dbFreeResult($getroot);
mysql_close();

function getSubCategory($parentid) {
global $conn;
$getdata = $conn->dbQuery("SELECT * FROM shop_category WHERE parent_id='$parentid' ORDER BY cat_sort ASC");
$numrows = $conn->dbNumRows($getdata);
if ($numrows > 0) {
$count = 1;
while ($subcat = $conn->dbFetchArray($getdata)) {
$startlist = ($count ==1) ? "<ul>" : "";
$endlist = ($count ==$numrows) ? "</ul>\n" : "";
echo "$startlist<li>&raquo;&nbsp;&nbsp;<a href=\"index_test2.php?cid=$subcat[cat_id]\">$subcat[cat_name]</a>";
getSubCategory($subcat['cat_id']);
echo "</li>$endlist\n";
$count++;
}//END while
} //END numrows >0
}//END function

?>
</ul>
#######################


WHAT I WANT TO DO IS HAVE THE ROOT CATEGORIES EXPAND WHEN A USER CLICKS IT.


Here's a working example of what I'm working on. It will return the FIRST LEVEL of sub-categories but it won't return anything beyond that.
http://rockpaperscissor.com/myshop/index_test1.php

Here's the code for this:
#######################
<ul class="menu">
<?php
$getroot = $conn->dbQuery("SELECT * FROM shop_category WHERE parent_id='0' ORDER BY cat_sort ASC");
while ($rootcat = $conn->dbFetchArray($getroot)) {
echo "<li><a href=\"index_test1.php?cid=$rootcat[cat_id]\" onMouseOver=\"rollOn('cat$rootcat[cat_id]'); return true;\" onMouseOut=\"rollOff('cat$rootcat[cat_id]'); return true;\"><img src=\"_images/_cat/cat$rootcat[cat_id].gif\" width=\"151\" height=\"15\" border=\"0\" name=\"cat$rootcat[cat_id]\" alt=\"$rootcat[cat_name]\" title=\"$rootcat[cat_name]\"></a>";
if($catID !=0) { getSubCategory($catID, $rootcat['cat_id']);}
echo "</li>\n";
}//END while
$conn->dbFreeResult($getroot);
mysql_close();

function getSubCategory($catid, $parentid) {
global $conn;
if($catid == $parentid) {
$getdata = $conn->dbQuery("SELECT * FROM shop_category WHERE parent_id='$catid' ORDER BY cat_sort ASC");
$numrows = $conn->dbNumRows($getdata);
if ($numrows > 0) {
$count = 1;
while ($subcat = $conn->dbFetchArray($getdata)) {
$startlist = ($count ==1) ? "<ul>" : "";
$endlist = ($count ==$numrows) ? "</ul>\n" : "";
echo "$startlist<li>&raquo;&nbsp;&nbsp;<a href=\"index_test1.php?cid=$subcat[cat_id]\">$subcat[cat_name]</a>";
getSubCategory($subcat['cat_id'], $parentid);
echo "</li>$endlist\n";
$count++;
}//END while
}//END numrows >0
}
}//END function

?>
</ul>
#######################


Help!!!!
0
 
LVL 8

Expert Comment

by:Bobaran98
Comment Utility
timrauter... before I work my way through your code, simple question:  did you try running the code I posted?  All you need to do is put in your database credentials, and it should run fine.
  1. It does exactly what you're looking for.
  2. It can be configured to look exactly how you want it.
  3. It's completely cross-browser compatible.
  4. It expands and collapses the menu without ever reloading the page.
I don't understand why you're so set on the lists.  I'm not sure there's a way to implement that that doesn't require the page to reload every time you click something, which is wildly and unnecessarily inefficient.  If all you're looking for is a certain look to the list, you can do it just fine with the solution I've provided you.  Please don't be distracted by the ugly table borders in my example.  We can change the look and no one would ever know it was a table.

As for that link you gave me... is that how you want your menu to appear?  Do you want to take that exact menu-- data, fonts, color, bullet points-- and simply make it collapsible?  Easy.  Peanuts.  It's all been written in the code I gave you.  All you have to do is remove the table borders, play with the fonts, and add your cute little bullet points.

And even if you do favor lists as opposed to the tables, that has nothing to do with my PHP/MySQL solution.  I think the flow of the process is about as efficient as you're going to get unless you upgrade to a professional database product.

But if you haven't tried the code, please do that.  I've not yet gotten any indication that you've even test-driven this code that I've put so much time into for you.  If you have, that's fine... but please let me know!  I just don't want to feel that you're dismissing the option out of hand after all my work! :-)

I'm not sure what your concern is about the number of queries in my code.  There are only three (six if you count subqueries too).  MySQL may not be a database powerhouse, but it can handle a lot more queries than that without even thinking about having an issue.

You asked about if the client has 5-6 subcategories... I assume you mean levels of categories?  As I mentioned in my notes, this code is nothing more than a proof of the process.  It can be adapted to a pair of recursive functions to make it entirely extensible.  And even then, the number of queries is low, always equal to the number of levels-- irrespective of how many category entries exist at each level.  Most solutions to a problem like this, as you already noted above, would be hitting the database for each entry, looking to see if it had subcategories.  The number of queries in that kind of solution grows exponentially with the number of category entries.

In short, if you implement my code in the form of a recursive function, you would have a very efficient solution for what you're trying to accomplish.
0
What Is Threat Intelligence?

Threat intelligence is often discussed, but rarely understood. Starting with a precise definition, along with clear business goals, is essential.

 

Author Comment

by:timrauter
Comment Utility
bobaran98...I'm in no way discrediting what you've provided me at all. I need to run through your code and test it out more thoroughly I've just been frustrated because I've been trying to find this solution for a while and I guess I have my head stuck on a certain way of doing it.

Let me know go through everything with a clear head and I'll get back to you.
0
 
LVL 8

Expert Comment

by:Bobaran98
Comment Utility
No problem.  And I'm sorry if I came across short.  I stayed up entirely too late last night playing with code for various questions on this site. :-)  Forgive me!  It's your project and you're the one that needs to be happy with it! :-)
0
 

Author Comment

by:timrauter
Comment Utility
Bobaran98,
Thanks for the code. I've run a test on it and I hate to say this...but it's still not what I need. Here's the URL:

http://rockpaperscissor.com/myshop/test.php

The way my shopping cart template system is set up is not really compatible with just "onclick" Javascript functions or Ajax right now. So the problem still remains that the menu does not expand when the proper link is selected. If I wasn't refreshing the page...it would be great.

I'm really at my wits end here and I know this can't be too complicated. I've just been working on it for so long that I've lost direction....PLEASE HELP ANYONE AND EVERYONE!
0
 
LVL 8

Expert Comment

by:Bobaran98
Comment Utility
I apologize for wasting your time.  I completely missed the fact that you needed to reload the entire page with each category chosen.  I never would have pushed the smooth-flowing expandable/collapsible menus otherwise.

Ok, timrauter.  Here we go.  Brand new approach, brand new fresh code.  This time, we're using <ul>/<li> lists, like you originally asked... because if you don't need tables, this is definitely easier! ;-)

In terms of querying cost, I still don't think it's too bad.  For every level of the menu that the user has drilled down into, there will be two queries.

Rather than explain more here, I've carefully commented the following code.  If you have any questions, let me know!

P.S.  There's no longer any need for JavaScript!

P.P.S.  Somewhere along the line, I picked up this assumption that your parent_id/cat_id values where strings and needed quotation marks... Usually these values would be integers, so if that's the case, just go through and remove the apostrophes or quotation marks around cat_id and parent_id values in the SQL, and around value assignments/comparisons for $nextParent and $lastParent in the PHP.

<?php
 

//open database connection

$db = mysql_connect($db_location, $db_username, $db_password);

mysql_select_db($db_name,$db) or die( "Unable to select database"); 
 

//assign variables

$currentParent = $_REQUEST['cid'];

$lastParent = -1;

$menu = "";
 

//loop through menu levels, starting with the kids of the chosen cid, if they exist

while($currentParent <> "-1") {
 

	//get categories whose parent category is $currentParent

	$query = "SELECT * FROM shop_category WHERE parent_id='$currentParent' ORDER BY cat_sort ASC";

	$result = mysql_query($query);

	$numResults = mysql_numrows($result);

	

	$temp = "";
 

	//loop through the kids of $currentParent

	for($i=0;$i<$numResults;$i++) {
 

		$myID = mysql_result($result,$i,"cat_id");

		$myName = mysql_result($result,$i,"cat_name");

		$temp .= "<li><a href='test.php?cid=$myID'>$myName</a></li>\n";
 

		//if/when you reach the cat_id for whom we've already pulled

		//	the menu structure, prepend our $temp categories and erase $temp

		if($myID==$lastParent) {

			$menu = $temp.$menu;

			$temp = "";

		}

	}
 

	//append $temp to the menu structure we've already created; at this point,

	//	$temp only includes categories that appear after the subcategory structure

	//	previously created

	$menu .= $temp;
 

	//add outer list tags, but only if there were any options at this level (on the

	//	first run through this while loop, there may not be any child options

	if($menu<>"") { $temp = "<ul>\n".$menu."</ul>"; }

	

	//save id of the current parent before overwriting $currentParent

	$lastParent = $currentParent;
 

	//if $currentParent is 0, then we've just finished outputting the top level and 

	//	need to exit the while loop; otherwise, assign value of $currentParent for the

	//	next level up

	if($currentParent=="0") {

		$currentParent = "-1";

	} else {

		//we can use the last $myID (cat_id) to determine the next parent_id... it doesn't matter,

		//	because all cat_id's in this resultset will share the same parent_id

		$currentParentResult = mysql_query("SELECT parent_id FROM shop_category WHERE cat_id='$myID'");

		$currentParent = mysql_result($currentParentResult,0,"parent_id");

	}
 

}
 

//close database connection

mysql_close();
 

//print the <ul>/<li> menu to screen!

echo $menu;
 

?>

Open in new window

0
 

Author Comment

by:timrauter
Comment Utility
Bobaran98,
OK...I think we're getting close but a few errors:
http://rockpaperscissor.com/myshop/test.php

1.
If you go to the test page (and since "cid" is not initiated) the root categories show up (GREAT). When you click one of the links that has sub-categories (ex. Personalized Stationery)...the page reloads, stalls, and displays nothing. Can you help me troubleshoot this?

2.
How would I display all the root categories (parent_id =0) as the images that I used in the previous example. So it would be IMAGE MENU FOR TOP LEVEL CATS....then <ul>/<li> for the sub-cats.

I've attached the code for test.php for you to view.
Let me know and thanks for all of your hard work on this.
<?php

require("_inc/db_class.php");
 

$_SESSION['shop_return_url'] = $_SERVER['REQUEST_URI'];

$catID  = (isset($_GET['cid']) && $_GET['cid'] != '1') ? $_GET['cid'] : 0;

$prodID   = (isset($_GET['pid']) && $_GET['pid'] != '') ? $_GET['pid'] : 0; 

?>

<?php

// set the default page title

$pageTitle = "Shop At Rock Paper Scissors";
 

/*if (isset($_GET['pid']) && (int)$_GET['pid'] > 0) {

   $prodID = (int)$_GET['pid'];

   $sql = "SELECT pd_name

           FROM tbl_product

           WHERE pd_id = $prodID";
 

   $result    = dbQuery($sql);

   $row       = dbFetchAssoc($result);

   $pageTitle = $row['pd_name'];
 

} else */if (isset($_GET['cid']) && (int)$_GET['cid'] > 0) {

   $catID = (int)$_GET['cid'];

   $result = $conn->dbQuery("SELECT cat_name FROM shop_category WHERE cat_id='$catID'");

   $row = $conn->dbFetchArray($result);

   $pageTitle = $row['cat_name'];

}
 
 
 

?>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml">

<head>

<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />

<title><?php echo $pageTitle?></title>

<meta name="description" content="The official website of Rock Paper Scissors stationery store"/>

<meta name="keywords" content="rock paper scissors, franklin, tennessee, stationery, lauren, note cards, greeting cards, blank cards, custom, personalized, calling cards, invitations, customized, custom, save the dates, children, family, Holiday, special occasions, fun"/>

<meta name="author" content="Milk Money Promotions"/>

<meta name="robots" content="Index, Follow"/>

<link rel="shortcut icon" href="favicon.ico"/>

<link rel="icon" href="favicon_anim.gif" type="image/gif" />

<link rel="stylesheet" href="_css/rps.css"/>

<script type="text/javascript" src="_js/rps.js"></script>

<script type="text/javascript" src="_js/jquery.js"></script>

</head>

<body>

 <img src="_images/toplogo.gif" alt="toplogo" width="442" height="105" /><br />

<a href="index.php" onmouseover="rollOn('nav1'); return true;" onmouseout="rollOff('nav1'); return true;"><img src="_images/menu_home.gif" alt="home" name="nav1" width="61" height="28" border="0"/></a><a href="http://www.rockpaperscissor.com/shop" target="_blank" onmouseover="rollOn('nav2'); return true;" onmouseout="rollOff('nav2'); return true;"><img src="_images/menu_shop.gif" alt="shop" name="nav2" width="60" height="28" border="0"/></a><a href="press.php" onmouseover="rollOn('nav3'); return true;" onmouseout="rollOff('nav3'); return true;"><img src="_images/menu_press.gif" alt="press" name="nav3" width="62" height="28" border="0"/></a><a href="http://www.rockpaperscissor.com/blog" target="_blank" onmouseover="rollOn('nav4'); return true;" onmouseout="rollOff('nav4'); return true;"><img src="_images/menu_blog.gif" alt="blog" name="nav4" width="60" height="28" border="0"/></a><a href="ourstory.php" onmouseover="rollOn('nav5'); return true;" onmouseout="rollOff('nav5'); return true;"><img src="_images/menu_story.gif" alt="our story" name="nav5" width="96" height="28" border="0"/></a><a href="contact.php" onmouseover="rollOn('nav6'); return true;" onmouseout="rollOff('nav6'); return true;"><img src="_images/menu_contact.gif" alt="home" name="nav6" width="103" height="28" border="0"/></a><br />

<img src="_images/curvetop.png" alt="topcurve" width="817" height="27" /><br />

<div id="content">

<div class="padit">

<table width="767" border="0" cellspacing="0" cellpadding="0">

<tr valign="middle" class="tbltile">

<td><a href="index.php"><img src="_images/title_shop.gif" alt="shop" width="253" height="75" border="0"></a></td>

<td align="right"><a href="account.php" onmouseover="rollOn('nav7'); return true;" onmouseout="rollOff('nav7'); return true;"><img src="_images/btn_myaccount.gif" alt="account" width="106" height="28" border="0" name="nav7"></a><a href="shopping_cart.php" onmouseover="rollOn('nav8'); return true;" onmouseout="rollOff('nav8'); return true;"><img src="_images/btn_viewcart.gif" alt="cart" width="101" height="28" border="0" name="nav8"></a><a href="checkout_shipping.php" onmouseover="rollOn('nav9'); return true;" onmouseout="rollOff('nav9'); return true;"><img src="_images/btn_checkout.gif" alt="checkout" width="100" height="28" border="0" name="nav9"></a></td>

</tr>

</table>

<table width="767" border="0" cellspacing="0" cellpadding="0">

<tr valign="top">

<td width="171">

<ul class="menu">

<?php

//assign variables

$lastParent = -1;

$menu = "";

 

//loop through menu levels, starting with the kids of the chosen cid, if they exist

while($catID <> "-1") {

 

        //get categories whose parent category is $currentParent

        $query = "SELECT * FROM shop_category WHERE parent_id='$catID' ORDER BY cat_sort ASC";

        $result = $conn->dbQuery($query);

        $numResults = $conn->dbNumRows($result);

        

        $temp = "";

 

        //loop through the kids of $currentParent

        for($i=0;$i<$numResults;$i++) {

 

                $myID = mysql_result($result,$i,"cat_id");

                $myName = mysql_result($result,$i,"cat_name");

                $temp .= "<li><a href='test.php?cid=$myID'>$myName</a></li>\n";

 

                //if/when you reach the cat_id for whom we've already pulled

                //      the menu structure, prepend our $temp categories and erase $temp

                if($myID==$lastParent) {

                        $menu = $temp.$menu;

                        $temp = "";

                }

        }

 

        //append $temp to the menu structure we've already created; at this point,

        //      $temp only includes categories that appear after the subcategory structure

        //      previously created

        $menu .= $temp;

 

        //add outer list tags, but only if there were any options at this level (on the

        //      first run through this while loop, there may not be any child options

        if($menu<>"") { $temp = "<ul>\n".$menu."</ul>"; }

        

        //save id of the current parent before overwriting $currentParent

        $lastParent = $catID;

 

        //if $currentParent is 0, then we've just finished outputting the top level and 

        //      need to exit the while loop; otherwise, assign value of $currentParent for the

        //      next level up

        if($catID=="0") {

                $catID = "-1";

        } else {

                //we can use the last $myID (cat_id) to determine the next parent_id... it doesn't matter,

                //      because all cat_id's in this resultset will share the same parent_id

                $currentParentResult = mysql_query("SELECT parent_id FROM shop_category WHERE cat_id='$myID'");

                $catID = mysql_result($currentParentResult,0,"parent_id");

        }

 

}

 

//close database connection

mysql_close();

 

//print the <ul>/<li> menu to screen!

echo $menu;

 

?>

</ul>

</td>

<td width="32" class="divvert"></td>

<td width="564">

<img src="_images/_banners/homebanner.gif" alt="banner" width="562" height="175" class="imgbrdr" border="0"/><br />
 

<img src="_images/title_featured.gif" alt="featured" width="275" height="22" class="spacer5"/><br />

<div class="prodthumb">

<a href="" class="fade"><img src="_images/_products/_thumbs/prod1.jpg" alt="prod1" width="175" height="175" class="imgprodbrdr"/></a><br />

Pink Suitcase - Eye Glasses<br />

$35.00

</div>

<div class="prodthumb">

<a href="" class="fade"><img src="_images/_products/_thumbs/prod1.jpg" alt="prod1" width="175" height="175" class="imgprodbrdr"/></a><br />

Pink Suitcase - Eye Glasses<br />

$35.00

</div>

<div class="prodthumb">

<a href="" class="fade"><img src="_images/_products/_thumbs/prod1.jpg" alt="prod1" width="175" height="175" class="imgprodbrdr"/></a><br />

Pink Suitcase - Eye Glasses<br />

$35.00

</div><br class="clearit" />

<div class="prodthumb">

<a href="" class="fade"><img src="_images/_products/_thumbs/prod1.jpg" alt="prod1" width="175" height="175" class="imgprodbrdr"/></a><br />

Pink Suitcase - Eye Glasses<br />

$35.00

</div>

<div class="prodthumb">

<a href="" class="fade"><img src="_images/_products/_thumbs/prod1.jpg" alt="prod1" width="175" height="175" class="imgprodbrdr"/></a><br />

Pink Suitcase - Eye Glasses<br />

$35.00

</div>

<div class="prodthumb">

<a href="" class="fade"><img src="_images/_products/_thumbs/prod1.jpg" alt="prod1" width="175" height="175" class="imgprodbrdr"/></a><br />

Pink Suitcase - Eye Glasses<br />

$35.00

</div><br class="clearit" />

<div class="prodthumb">

<a href="" class="fade"><img src="_images/_products/_thumbs/prod1.jpg" alt="prod1" width="175" height="175" class="imgprodbrdr"/></a><br />

Pink Suitcase - Eye Glasses<br />

$35.00

</div>

<div class="prodthumb">

<a href="" class="fade"><img src="_images/_products/_thumbs/prod1.jpg" alt="prod1" width="175" height="175" class="imgprodbrdr"/></a><br />

Pink Suitcase - Eye Glasses<br />

$35.00

</div>

<div class="prodthumb">

<a href="" class="fade"><img src="_images/_products/_thumbs/prod1.jpg" alt="prod1" width="175" height="175" class="imgprodbrdr"/></a><br />

Pink Suitcase - Eye Glasses<br />

$35.00

</div><br class="clearit" />

</td>

</tr>

</table>

<?php include("_inc/footer.php") ?>

Open in new window

0
 

Author Comment

by:timrauter
Comment Utility
Bobaran98,
I got the error fixed and it seems to be working. My question is this:

1.
How can I indent all sub-categories (and sub sub-categories)? I checked the source code and there is no additional <ul></ul> when a sub-category is found. I'd like it to be arranged like this:
<ul>
<li>ROOT CAT #1
     <ul>
     <li>SUB CATS</li>
     <li>SUB CATS</li>
     <li>SUB CATS</li>
             <ul>
              <li>SUB SUB CATS</li>
              <li>SUB SUB CATS</li>
              <li>SUB SUB CATS</li>
              </ul>
      </ul>
</li>
<li>ROOT CAT #2</li>
<li>ROOT CAT #3</li>
etc.


2.
When the parent_id=0 (root) I want to display images instead of text.

Let me know on this
Thanks my friend. We're so close and I'm excited.

I've attached the REVISED CODE that fixed the error
<?php

require("_inc/db_class.php");
 

$_SESSION['shop_return_url'] = $_SERVER['REQUEST_URI'];

$catID  = (isset($_GET['cid']) && $_GET['cid'] != '1') ? $_GET['cid'] : 0;

$prodID   = (isset($_GET['pid']) && $_GET['pid'] != '') ? $_GET['pid'] : 0; 

?>

<?php

// set the default page title

$pageTitle = "Shop At Rock Paper Scissors";
 

/*if (isset($_GET['pid']) && (int)$_GET['pid'] > 0) {

   $prodID = (int)$_GET['pid'];

   $sql = "SELECT pd_name

           FROM tbl_product

           WHERE pd_id = $prodID";
 

   $result    = dbQuery($sql);

   $row       = dbFetchAssoc($result);

   $pageTitle = $row['pd_name'];
 

} else */if (isset($_GET['cid']) && (int)$_GET['cid'] > 0) {

   $catID = (int)$_GET['cid'];

   $result = $conn->dbQuery("SELECT cat_name FROM shop_category WHERE cat_id='$catID'");

   $row = $conn->dbFetchArray($result);

   $pageTitle = $row['cat_name'];

}
 
 
 

?>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml">

<head>

<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />

<title><?php echo $pageTitle?></title>

<meta name="description" content="The official website of Rock Paper Scissors stationery store"/>

<meta name="keywords" content="rock paper scissors, franklin, tennessee, stationery, lauren, note cards, greeting cards, blank cards, custom, personalized, calling cards, invitations, customized, custom, save the dates, children, family, Holiday, special occasions, fun"/>

<meta name="author" content="Milk Money Promotions"/>

<meta name="robots" content="Index, Follow"/>

<link rel="shortcut icon" href="favicon.ico"/>

<link rel="icon" href="favicon_anim.gif" type="image/gif" />

<link rel="stylesheet" href="_css/rps.css"/>

<script type="text/javascript" src="_js/rps.js"></script>

<script type="text/javascript" src="_js/jquery.js"></script>

</head>

<body>

 <img src="_images/toplogo.gif" alt="toplogo" width="442" height="105" /><br />

<a href="index.php" onmouseover="rollOn('nav1'); return true;" onmouseout="rollOff('nav1'); return true;"><img src="_images/menu_home.gif" alt="home" name="nav1" width="61" height="28" border="0"/></a><a href="http://www.rockpaperscissor.com/shop" target="_blank" onmouseover="rollOn('nav2'); return true;" onmouseout="rollOff('nav2'); return true;"><img src="_images/menu_shop.gif" alt="shop" name="nav2" width="60" height="28" border="0"/></a><a href="press.php" onmouseover="rollOn('nav3'); return true;" onmouseout="rollOff('nav3'); return true;"><img src="_images/menu_press.gif" alt="press" name="nav3" width="62" height="28" border="0"/></a><a href="http://www.rockpaperscissor.com/blog" target="_blank" onmouseover="rollOn('nav4'); return true;" onmouseout="rollOff('nav4'); return true;"><img src="_images/menu_blog.gif" alt="blog" name="nav4" width="60" height="28" border="0"/></a><a href="ourstory.php" onmouseover="rollOn('nav5'); return true;" onmouseout="rollOff('nav5'); return true;"><img src="_images/menu_story.gif" alt="our story" name="nav5" width="96" height="28" border="0"/></a><a href="contact.php" onmouseover="rollOn('nav6'); return true;" onmouseout="rollOff('nav6'); return true;"><img src="_images/menu_contact.gif" alt="home" name="nav6" width="103" height="28" border="0"/></a><br />

<img src="_images/curvetop.png" alt="topcurve" width="817" height="27" /><br />

<div id="content">

<div class="padit">

<table width="767" border="0" cellspacing="0" cellpadding="0">

<tr valign="middle" class="tbltile">

<td><a href="index.php"><img src="_images/title_shop.gif" alt="shop" width="253" height="75" border="0"></a></td>

<td align="right"><a href="account.php" onmouseover="rollOn('nav7'); return true;" onmouseout="rollOff('nav7'); return true;"><img src="_images/btn_myaccount.gif" alt="account" width="106" height="28" border="0" name="nav7"></a><a href="shopping_cart.php" onmouseover="rollOn('nav8'); return true;" onmouseout="rollOff('nav8'); return true;"><img src="_images/btn_viewcart.gif" alt="cart" width="101" height="28" border="0" name="nav8"></a><a href="checkout_shipping.php" onmouseover="rollOn('nav9'); return true;" onmouseout="rollOff('nav9'); return true;"><img src="_images/btn_checkout.gif" alt="checkout" width="100" height="28" border="0" name="nav9"></a></td>

</tr>

</table>

<table width="767" border="0" cellspacing="0" cellpadding="0">

<tr valign="top">

<td width="171">

<ul class="menu">

<?php

//assign variables

$lastParent = -1;

$menu = "";

 

//loop through menu levels, starting with the kids of the chosen cid, if they exist

while($catID <> "-1") {

 

        //get categories whose parent category is $currentParent

        $query = "SELECT * FROM shop_category WHERE parent_id='$catID' ORDER BY cat_sort ASC";

        $result = $conn->dbQuery($query);

        $numResults = $conn->dbNumRows($result);

        

        $temp = "";

 

        //loop through the kids of $currentParent

        for($i=0;$i<$numResults;$i++) {

 

                $myID = mysql_result($result,$i,"cat_id");

                $myName = mysql_result($result,$i,"cat_name");

                $temp .= "<li><a href='test.php?cid=$myID'>$myName</a></li>\n";

 

                //if/when you reach the cat_id for whom we've already pulled

                //      the menu structure, prepend our $temp categories and erase $temp

                if($myID==$lastParent) {

                        $menu = $temp.$menu;

                        $temp = "";

                }

        }

 

        //append $temp to the menu structure we've already created; at this point,

        //      $temp only includes categories that appear after the subcategory structure

        //      previously created

        $menu .= $temp;

 

        //add outer list tags, but only if there were any options at this level (on the

        //      first run through this while loop, there may not be any child options

        if($menu<>"") { $temp = "<ul>\n".$menu."</ul>"; }

        

        //save id of the current parent before overwriting $currentParent

        $lastParent = $catID;

 

        //if $currentParent is 0, then we've just finished outputting the top level and 

        //      need to exit the while loop; otherwise, assign value of $currentParent for the

        //      next level up

        if($catID=="0") {

                $catID = "-1";

        } else {

                //we can use the last $myID (cat_id) to determine the next parent_id... it doesn't matter,

                //      because all cat_id's in this resultset will share the same parent_id

                $currentParentResult = $conn->dbQuery("SELECT parent_id FROM shop_category WHERE cat_id='$catID'");

                $catID = mysql_result($currentParentResult,0,"parent_id");

        }

 

}

 

//close database connection

mysql_close();

 

//print the <ul>/<li> menu to screen!

echo $menu;

 

?>

</ul>

</td>

<td width="32" class="divvert"></td>

<td width="564">

<img src="_images/_banners/homebanner.gif" alt="banner" width="562" height="175" class="imgbrdr" border="0"/><br />
 

<img src="_images/title_featured.gif" alt="featured" width="275" height="22" class="spacer5"/><br />

<div class="prodthumb">

<a href="" class="fade"><img src="_images/_products/_thumbs/prod1.jpg" alt="prod1" width="175" height="175" class="imgprodbrdr"/></a><br />

Pink Suitcase - Eye Glasses<br />

$35.00

</div>

<div class="prodthumb">

<a href="" class="fade"><img src="_images/_products/_thumbs/prod1.jpg" alt="prod1" width="175" height="175" class="imgprodbrdr"/></a><br />

Pink Suitcase - Eye Glasses<br />

$35.00

</div>

<div class="prodthumb">

<a href="" class="fade"><img src="_images/_products/_thumbs/prod1.jpg" alt="prod1" width="175" height="175" class="imgprodbrdr"/></a><br />

Pink Suitcase - Eye Glasses<br />

$35.00

</div><br class="clearit" />

<div class="prodthumb">

<a href="" class="fade"><img src="_images/_products/_thumbs/prod1.jpg" alt="prod1" width="175" height="175" class="imgprodbrdr"/></a><br />

Pink Suitcase - Eye Glasses<br />

$35.00

</div>

<div class="prodthumb">

<a href="" class="fade"><img src="_images/_products/_thumbs/prod1.jpg" alt="prod1" width="175" height="175" class="imgprodbrdr"/></a><br />

Pink Suitcase - Eye Glasses<br />

$35.00

</div>

<div class="prodthumb">

<a href="" class="fade"><img src="_images/_products/_thumbs/prod1.jpg" alt="prod1" width="175" height="175" class="imgprodbrdr"/></a><br />

Pink Suitcase - Eye Glasses<br />

$35.00

</div><br class="clearit" />

<div class="prodthumb">

<a href="" class="fade"><img src="_images/_products/_thumbs/prod1.jpg" alt="prod1" width="175" height="175" class="imgprodbrdr"/></a><br />

Pink Suitcase - Eye Glasses<br />

$35.00

</div>

<div class="prodthumb">

<a href="" class="fade"><img src="_images/_products/_thumbs/prod1.jpg" alt="prod1" width="175" height="175" class="imgprodbrdr"/></a><br />

Pink Suitcase - Eye Glasses<br />

$35.00

</div>

<div class="prodthumb">

<a href="" class="fade"><img src="_images/_products/_thumbs/prod1.jpg" alt="prod1" width="175" height="175" class="imgprodbrdr"/></a><br />

Pink Suitcase - Eye Glasses<br />

$35.00

</div><br class="clearit" />

</td>

</tr>

</table>

<?php include("_inc/footer.php") ?>

Open in new window

0
 
LVL 8

Expert Comment

by:Bobaran98
Comment Utility
Okay, about your indenting issue, I did address that in my code... look at line 100 the last time you posted it.  The problem is I made a slight error! :-)  Change the assignment so it adds the <ul></ul> to the $menu variable instead, like so:



   if($menu<>"") { $menu = "<ul>\n".$menu."</ul>"; }

Open in new window

0
 
LVL 8

Accepted Solution

by:
Bobaran98 earned 500 total points
Comment Utility
As far as images go, I suggest you just add code that changes the value of $myName to an image tag rather than text when you're at the top level.  Then you would just need to rename the appropriate images in such a way that they have their id numbers embedded in their file name.  For example, right after $myName is assigned and before the entry is added to $temp, you could do:


if($catID=="0") { $myName = "<img src='imgName$myID"."jpg' border='0'>"; }

Just make sure you've got your your images named imgName1.jpg and so on if you do something like that.

Take a look below for the code in context.



for($i=0;$i<$numResults;$i++) {
 

		$myID = mysql_result($result,$i,"cat_id");

		$myName = mysql_result($result,$i,"cat_name");

		if($catID=="0") { $myName = "<img src='imgName$myID' border='0'>"; }

		$temp .= "<li><a href='test.php?cid=$myID'>$myName</a></li>\n";
 

		//if/when you reach the cat_id for whom we've already pulled

		//      the menu structure, prepend our $temp categories and erase $temp

		if($myID==$lastParent) {

				$menu = $temp.$menu;

				$temp = "";

		}

}
 

?>

Open in new window

0
 

Author Closing Comment

by:timrauter
Comment Utility
Bobaran98,
I apologize for not getting back to you sooner. IT WORKS IT WORKS IT WORKS! Thank you SOOO much for your help. I've been working on this for 3 weeks now and your simple code is FANTASTIC. Thank you!
0

Featured Post

How to run any project with ease

Manage projects of all sizes how you want. Great for personal to-do lists, project milestones, team priorities and launch plans.
- Combine task lists, docs, spreadsheets, and chat in one
- View and edit from mobile/offline
- Cut down on emails

Join & Write a Comment

Suggested Solutions

Consider the following scenario: You are working on a website and make something great - something that lets the server work with information submitted by your users. This could be anything, from a simple guestbook to a e-Money solution. But what…
Since pre-biblical times, humans have sought ways to keep secrets, and share the secrets selectively.  This article explores the ways PHP can be used to hide and encrypt information.
This tutorial will teach you the core code needed to finalize the addition of a watermark to your image. The viewer will use a small PHP class to learn and create a watermark.
The viewer will learn how to create a basic form using some HTML5 and PHP for later processing. Set up your basic HTML file. Open your form tag and set the method and action attributes.: (CODE) Set up your first few inputs one for the name and …

771 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

12 Experts available now in Live!

Get 1:1 Help Now