Jump to content


Corporate Sponsors


Latest News: (loading..)

- - - - -

[Contribution] Category Box as Nested Unordered List v1.0


98 replies to this topic

#1 nate_02631

  • Community Member
  • 279 posts
  • Real Name:Nate
  • Gender:Male
  • Location:Brewster, MA

Posted 30 April 2006, 22:26

WHAT IS IT?
This contribution is an alternate category box which will output your store's categories as a proper nested unordered list, instead of a collection of non-breaking spaces, quasi-bullets and break tags.

What's the big deal about that you ask? With the categories now output as an unordered list, you can now more easily apply a lot of nifty CSS to turn your category list into a horizontal drop-down or vertical fly-out menu, make it a collapsible menu, easily attach bullets, add cool mouseover effects, or just about anything you can dream up!

The advantage of this technique over pure javascript solutions is that it is much more flexible, easier to apply CSS trickery to, is more search-engine friendly and makes just one query to the database.

Output includes optional CSS class tags to mark categories as selected or as parent cats. You can also choose to render all of your categories (useful for dynamic menus) or to render only the root cats and the selected category tree. Note that this contribution merely provides a foundation for you to construct a more attractive/functional menu by providing a more semantically-correct output. A little CSS-magic is required on your end, though I have included a sample vertical flyout menu CSS. I have included some resources in the readme.

The download is available in the Contributions: http://www.oscommerce.com/community/contributions,4201

Any feedback, bug reports are welcome, or if you just want to post some cool unordered list menu resources or show off what you've done below...

Edited by Johnson, 01 May 2006, 07:12.

** Please do not PM with personal support requests (even if offering "payment"). Thank you.

#2 Micke

  • Community Member
  • 191 posts
  • Real Name:Micke

Posted 01 May 2006, 09:46

Thanks for this great contribution, this is exactly what I want! The other dynamic category enhancement I have run into I never got right...
I have had a look at Suckerfish and this contributions looks very promising!
If I have gotten the instructions right, doing a clean "to-start-with" install of this contribution is just a matter of putting ul_categories.php in the boxes directory and adding the example css to the stylesheet.
I run into trouble though, because the menu only shows the first four main categories and no sub levels fly out...
Running it without stylesheet renders an unorderd list (as promised) with the four first main categories and all their sub levels.
Hmm.
Have I missed something?

#3 Micke

  • Community Member
  • 191 posts
  • Real Name:Micke

Posted 01 May 2006, 10:50

Here's more...
I have 22 main categories in total and three levels at maximum...

Firefox:
The webpage in Swedish shows the first four main categories and all four fly-out!
The webpage in English shows the first three main categories and all three fly-out!

IE:
The webpage in Swedish shows the first four main categories and none of them fly-out!
The webpage in English shows the first three main categories and none of them fly-out!

We have to fix this to be able to use this contrib, of course...I'm not sure how.

#4 Micke

  • Community Member
  • 191 posts
  • Real Name:Micke

Posted 01 May 2006, 10:52

This reply was posted by mistake, and I could not figure out how to delete it...

Edited by Micke, 01 May 2006, 10:54.


#5 nate_02631

  • Community Member
  • 279 posts
  • Real Name:Nate
  • Gender:Male
  • Location:Brewster, MA

Posted 01 May 2006, 13:51

Hi,

Yes, with the contrib I included the CSS from the "suckerfish" menus, it also makes use of some Javascript, which I did not include as part of the distribution. This JS I believe is to make browsers work that don't recognize the "hover" state for elements other than <A> anchor tags (such as older versions of Explorer). I am using a suckerfish style menu with the JS and am having no Explorer problems. See the son of suckerfish for details...

Also, when you are doing CSS based styles, you need to allow for the # of submenus you intend to have. I think the included example only allows for two sublevels...

The included CSS is not meant to be a starting point, but rather just an illustration of what's possible. There's plenty of people smarter than me doing stuff with CSS and lists (some resource links included in readme)...

Interesting point about the different languages... I did use the lang in the query - pretty sure it's being sucked in correctly... Will check it again...
** Please do not PM with personal support requests (even if offering "payment"). Thank you.

#6 EidolonNight

  • Community Member
  • 68 posts
  • Real Name:James Tomasello
  • Location:Florida

Posted 01 May 2006, 15:28

This contrib seems to be what I am looking for... I was wondering if you could direct me to a working live example, I would like to see this in action before I install it on my store.

Thank you
James Tomasello

#7 nate_02631

  • Community Member
  • 279 posts
  • Real Name:Nate
  • Gender:Male
  • Location:Brewster, MA

Posted 01 May 2006, 15:49

Hi - nothing to see really ;). It simply outputs your category tree (either the whole thing or just the roots and selected subcat tree, as the default osc cat box) as a bulleted list (with subbullets for categories).

The sample CSS supplied makes it resemble a fly-out menu (which of course you've seen), but the idea is that it generates a bullet list *framework* where you can more easily use CSS to style as desired...

I am in the process of redoing my dad's photography site and wanted to include a category dropdown embedded in the header, which I why I came up with this little contrib. I plan to use the technique described in "Suckerfish dropdowns" - which uses CSS and just a *teeny* bit of javascript to bring older MSIE's in line... but that is not completely represented in the included sample CSS...

I've included some resources for styling list-menus, but you can do a ton with them, like having expandable/collapsable menus, fly-out/drop-down menus, menus with mouseover effects, or whatever else you can dream up! Heck, the drop-downs at the top of this forum are just a gussied-up unordered list (with maybe a little JS thrown in!)...

Give it a try! The one script file in the package will not override any other so it won't mess up your site! (goes in includes/boxes)
** Please do not PM with personal support requests (even if offering "payment"). Thank you.

#8 EidolonNight

  • Community Member
  • 68 posts
  • Real Name:James Tomasello
  • Location:Florida

Posted 01 May 2006, 16:01

Thank you for such a quick response. I believe this is exactly what I am looking for. I will play with it a bit and let you know if there are any suggstions or problems. Again, thank you!
James Tomasello

#9 Micke

  • Community Member
  • 191 posts
  • Real Name:Micke

Posted 02 May 2006, 07:14

Hi!
I still have the problem I posted earlier... I believe it's something that has to be fixed in ul_categories.php.
Here's what happens if I set the "show_full_tree" to "true":
The menu has 3 or 4 top level categories, depending on language. In the last top level categoriy there is a tangled up version of the rest of the categories. It seems like the script does not find it's way back to the "root". The UL-list drifts deeper into new levels.
(Without CSS, this contribution makes a very nice site map by the way...)
Setting the "show_full_tree" to "false" renders all 22 top level categories perfectly!
But that's what you get with the standard menu... Since I have 840 products in 22 top level categories with sometimes as much as 4(or 5?) sub levels, rendering the full tree with all the fly-outs will give customers a fair chance to get an overview of the products...

#10 Micke

  • Community Member
  • 191 posts
  • Real Name:Micke

Posted 02 May 2006, 11:55

Between lines 122-130 there's this piece of code:
if ($GLOBALS['this_level'] != $level) {

				if ($GLOBALS['this_level'] < $level)
						$output .= "\n".'<ul>';
					else
						$output .= '</ul></li>'."\n";		
		
				$GLOBALS['this_level'] = $level;
		}
I believe that there has to be some code here checking if were back att root level or not... and if were not keep on </ul>'ing until we are... Anybody knows how to fix that?

#11 eurabia

  • Community Member
  • 3 posts
  • Real Name:Klaus-Dieter Asmussen

Posted 02 May 2006, 15:29

View PostMicke, on May 2 2006, 11:55 AM, said:

Between lines 122-130 there's this piece of code:
if ($GLOBALS['this_level'] != $level) {

				if ($GLOBALS['this_level'] < $level)
						$output .= "\n".'<ul>';
					else
						$output .= '</ul></li>'."\n";		
		
				$GLOBALS['this_level'] = $level;
		}
I believe that there has to be some code here checking if were back att root level or not... and if were not keep on </ul>'ing until we are... Anybody knows how to fix that?


Hello from Germany. Try this. For me it works fine now (normal Osc-looking). Thanks at the coder of this contribution.


<?php
/*
  $Id: ul_categories.php,v 1.00 2006/04/30 01:13:58 nate_02631 Exp $
	
	Outputs the store category list as a proper unordered list, opening up
	possibilities to use CSS to style as drop-down/flyout, collapsable or 
	other menu types.

  osCommerce, Open Source E-Commerce Solutions
  http://www.oscommerce.com

  Copyright (c) 2006 Nate Welch http://www.natewelch.com

  Released under the GNU General Public License
*/

// BEGIN Configuration options

  // Set to false to display the unordered list only. Set to true to display in
	// a regular box. The former is useful for better integrating the menu with your layout.
	$show_ulcats_as_box = true;
	
	// Indicates whether or not to render your entire category list or just the root categories
	// and the currently selected submenu tree. Rendering the full list is useful for dynamic menu
	// generation where you want the user to have instant access to all categories. The other option
	// is the default oSC behaviour, when the subcats aren't available until the parent is clicked. 
	$show_full_tree = true;	
  
	// This is the CSS *ID* you want to assign to the UL (unordered list) containing
	// your category menu. Used in conjuction with the CSS list you create for the menu.
	// This value cannot be blank.
	$idname_for_menu = 'nav';
  
	// This is the *CLASSNAME* you want to tag a LI to indicate the selected category.
	// The currently selected category (and its parents, if any) will be tagged with
	// this class. Modify your stylesheet as appropriate. Leave blank or set to false to not assign a class. 
	$classname_for_selected = 'selected';
  
	// This is the *CLASSNAME* you want to tag a LI to indicate a category has subcategores.
	// Modify your stylesheet to draw an indicator to show the users that subcategories are
	// available. Leave blank or set to false to not assign a class. 	
	$classname_for_parent = 'daddy';

// END Configuration options

// Global Variables
$GLOBALS['this_level'] = 0;

// Initialize HTML and info_box class if displaying inside a box
if ($show_ulcats_as_box) {
	echo '<tr><td>';
	$info_box_contents = array();
	$info_box_contents[] = array('text' => BOX_HEADING_CATEGORIES);
	new infoBoxHeading($info_box_contents, true, false);					
}

// Generate a bulleted list (uses configuration options above)
$categories_string = tep_make_cat_ullist();

// Output list inside a box if specified, otherwise just output unordered list
if ($show_ulcats_as_box) {
	$info_box_contents = array();
	$info_box_contents[] = array('text' => $categories_string);
	new infoBox($info_box_contents);
		echo '</td></tr>';	
} else {
	echo $categories_string;	
}


// Create the root unordered list
function tep_make_cat_ullist($rootcatid = 0, $maxlevel = 0){

	global $idname_for_menu, $cPath_array, $show_full_tree, $languages_id;

	// Modify category query if not fetching all categories (limit to root cats and selected subcat tree)
		if (!$show_full_tree) {
		$parent_query	= 'AND (c.parent_id = "0"';	
				
				if (isset($cPath_array)) {
				
					$cPath_array_temp = $cPath_array;
				
					foreach($cPath_array_temp AS $key => $value) {
							$parent_query	.= ' OR c.parent_id = "'.$value.'"';
						}
						
						unset($cPath_array_temp);
				}	
				
		$parent_query .= ')';				
		} else {
		$parent_query	= '';	
		}
		
		$result = tep_db_query('select c.categories_id, cd.categories_name, c.parent_id from ' . TABLE_CATEGORIES . ' c, ' . TABLE_CATEGORIES_DESCRIPTION . ' cd where c.categories_id = cd.categories_id and cd.language_id="' . (int)$languages_id .'" '.$parent_query.' order by sort_order, cd.categories_name');
	
		while ($row = tep_db_fetch_array($result)) {				
		$table[$row['parent_id']][$row['categories_id']] = $row['categories_name'];
	}

	$output .= '<ul id="'.$idname_for_menu.'">';
	$output .= tep_make_cat_ulbranch($rootcatid, $table, 0, $maxlevel);

		// Close off nested lists
	for ($nest = 0; $nest <= $GLOBALS['this_level']; $nest++) {
		$output .= '</ul>';		
		}
			 
	return $output;
}

// Create the branches of the unordered list
function tep_make_cat_ulbranch($parcat, $table, $level, $maxlevel) {

	global $cPath_array, $classname_for_selected, $classname_for_parent;
		
	$list = $table[$parcat];
	
	while(list($key,$val) = each($list)){
			 
		if ($GLOBALS['this_level'] != $level) {

						// BoF changed by asmus
				if ($GLOBALS['this_level'] < $level)
						$output .= "\n".'<li><ul>';
					else
						$output .= '</ul></li>'."\n";		
						// EoF changed by asmus		
				$GLOBALS['this_level'] = $level;
		}

		if (isset($cPath_array) && in_array($key, $cPath_array) && $classname_for_selected) {
			$this_cat_class = ' class="'.$classname_for_selected.'"';
		} else {
			$this_cat_class = '';		
			}	
		
		$output .= '<li'.$this_cat_class.'><a href="';

		if (!$level) {
					unset($GLOBALS['cPath_set']);
						$GLOBALS['cPath_set'][0] = $key;
			$cPath_new = 'cPath=' . $key;

		} else {
						$GLOBALS['cPath_set'][$level] = $key;		
			$cPath_new = 'cPath=' . implode("_", array_slice($GLOBALS['cPath_set'], 0, ($level+1)));
		}
	
		if (tep_has_category_subcategories($key) && $classname_for_parent) {
			$this_parent_class = ' class="'.$classname_for_parent.'"';
		} else {
			$this_parent_class = '';		
			}				

		$output .= tep_href_link(FILENAME_DEFAULT, $cPath_new) . '"'.$this_parent_class.'>'.$val;		

		if (SHOW_COUNTS == 'true') {
			$products_in_category = tep_count_products_in_category($key);
			if ($products_in_category > 0) {
				$output .= '&nbsp;(' . $products_in_category . ')';
			}
		}

		// BoF changed by asmus		
		$output .= '</a></li>."\n"';	

		if (!tep_has_category_subcategories($key)) {
			$output .= '';	
		}						 
		// EoF changed by asmus									

		if ((isset($table[$key])) AND (($maxlevel > $level + 1) OR ($maxlevel == '0'))) {
			$output .= tep_make_cat_ulbranch($key,$table,$level + 1,$maxlevel);
		}
	
		} // End while loop

	return $output;
}	

?>


#12 EidolonNight

  • Community Member
  • 68 posts
  • Real Name:James Tomasello
  • Location:Florida

Posted 02 May 2006, 17:44

The code does not recognize category depth properly on my store. The last post was no help to me, and actually contains two bugs. I don't know how you got it to work perfectly for you...

The original code sees the first category and lists everything under that category properly. Then the next top level category get listed under the deepest category from the first list and continues to "step in" very far for each additional top level category. Does this make sense? What is happening?
James Tomasello

#13 nate_02631

  • Community Member
  • 279 posts
  • Real Name:Nate
  • Gender:Male
  • Location:Brewster, MA

Posted 02 May 2006, 18:29

Don't suppose you have an example to look at? I can do some further testing, but it seemed to work O.K. with the different menus I tried...

Does the category tree render as expected without CSS? (proper nesting, etc...)
** Please do not PM with personal support requests (even if offering "payment"). Thank you.

#14 EidolonNight

  • Community Member
  • 68 posts
  • Real Name:James Tomasello
  • Location:Florida

Posted 02 May 2006, 18:58

I have taken the css away for now untill the list is generated properly. I have a screen shot.... It's very large, sorry folks.

[img]http://bcpframeshop.com/catalog/images/shot.gif[/img]
James Tomasello

#15 nate_02631

  • Community Member
  • 279 posts
  • Real Name:Nate
  • Gender:Male
  • Location:Brewster, MA

Posted 02 May 2006, 19:01

SPEAKING OF EXAMPLES...

Take a look at http://www.seelily.com/fec/ - which has the default CSS applied... I directed him to add the simple JS on this page:

http://www.htmldog.com/articles/suckerfish/

(specifically for the "Suckerfish" technique whose CSS is included in the package) which gets some versions of MSIE to recognize the :hover event for other elements other than anchor tags...

EidionNight, if you can get back to me with answers on previous post, and/or provide me with an .sql dump of your categories & categories_description tables, I would be happy to test it out on my test setup...
** Please do not PM with personal support requests (even if offering "payment"). Thank you.

#16 nate_02631

  • Community Member
  • 279 posts
  • Real Name:Nate
  • Gender:Male
  • Location:Brewster, MA

Posted 02 May 2006, 19:04

Looks like we cross-posted, EidolonNight ;)

That is quite a list! Do you think your could PM me the HTML of that unordered list and I can see what's going on - and/or the sql dump would be helpful... Looks like is missing *one* </UL> to close off, although I don't know if the language thing is possibly interfering?
** Please do not PM with personal support requests (even if offering "payment"). Thank you.

#17 Micke

  • Community Member
  • 191 posts
  • Real Name:Micke

Posted 02 May 2006, 19:17

I've got the problem solved the caveman way.
Paste this over the stuff at line 120 and on...
while(list($key,$val) = each($list)){
			
		if ($GLOBALS['this_level'] != $level) {

				if ($GLOBALS['this_level'] < $level)
						$output .= "\n".'<ul>';
				elseif ($GLOBALS['this_level'] -1 == $level)
						$output .= '</ul></li>'."\n";		
				elseif ($GLOBALS['this_level'] -2 == $level)
						$output .= '</ul></li></ul></li>'."\n";	
				elseif ($GLOBALS['this_level'] -3 == $level)
						$output .= '</ul></li></ul></li></ul></li>'."\n";	
				elseif ($GLOBALS['this_level'] -4 == $level)
						$output .= '</ul></li></ul></li></ul></li></ul></li>'."\n";					
		
				$GLOBALS['this_level'] = $level;
		}
This takes care of the depth in my categories...

#18 nate_02631

  • Community Member
  • 279 posts
  • Real Name:Nate
  • Gender:Male
  • Location:Brewster, MA

Posted 02 May 2006, 19:42

Me cavemen - me code HTML ;)

Thanks for the post Micke, it reflects just what I suspected the problem was after EidolonNight sent me his HTML...

The top categories of his list (Baseball, Football, Basketball Hockey) goes down to four levels but only steps back one (to level three) when it should go back *two* to level two... This is causing the progressive nesting effect seen in these categories.

The latter half of the list (NASCAR, Golf Tennis) renders correctly (albiet at the wrong level) because it doesn't jump levels like that.

Awful sorry as I thought I accounted for this in the package. Micke's "brute force" approach should work, though I'll see if I can come up with something less "barbaric" ;-) and I'll add it to the package in the contribs section - maybe I'll include another CSS example or two, and include the JS for the suckerfish technique while I'm at it...

Will post back here when I've added it...
** Please do not PM with personal support requests (even if offering "payment"). Thank you.

#19 nate_02631

  • Community Member
  • 279 posts
  • Real Name:Nate
  • Gender:Male
  • Location:Brewster, MA

Posted 02 May 2006, 23:04

A version 1.1 update has been uploaded to the contributions which should fix the aforementioned glitch (regardless of # of levels) and also adds a couple extra config options to render optional HTML before and after the menu (if not rendering in a box). Thought it could be useful in certain situations to better jibe with layouts, if needed.

I have included updated vertical fly-out and horiz drop downs based on the Suckerfish menus as well their JS which brings MSIE in line. The examples are somewhat lame and just included to give you an idea of what's possible. I encourage readers of this thread to post more interesting examples/resources below...
** Please do not PM with personal support requests (even if offering "payment"). Thank you.

#20 drunknbass

  • Community Member
  • 118 posts
  • Real Name:Aaron
  • Location:Orange County California

Posted 03 May 2006, 04:04

ok i got a question... ok questions haha
what can i change in the code if i dont want the categories to expand at all. i might want to just have the parent categories diplay, even if it has sub cats i dont want that part of the menu..

and if i decide against that i have another question..
i changed this code area and inserted my own code to ditch the lame categories textand the little half circle thing at the top and put my graphic. this is where i put it
// Initialize HTML and info_box class if displaying inside a box
if ($show_ulcats_as_box) {
	echo '<tr><td>';
	$info_box_contents = array();
   echo  '' . tep_image(DIR_WS_IMAGES . 'shopnav.gif', 'Categories') . '';				
}

// Generate a bulleted list (uses configuration options above)
its the echo line.
but theres is a gap between this image and the first parent category and i want it to be seamless like a <br> tag.
also i dont want my parent category names to have the offset spacing before it, and i dont want the children to be offset either. cause it doesnt go with my layout. im sure youll understand when you lok at my page..
http://www.enveamerica.com

and im in the middle of the facelift so dont mind the mess :P
Check out my fully customized oscommerce site by viewing my profile.