Jump to content
Sign in to follow this  
uscetech

Multiple Category Drop-Downs When Filtered By MFG - WIP

Recommended Posts

I've searched high and low for something like this to no avail. If someone knows of a contrib that does this already, please, please let me know.

 

By default if you select a manufacturer, all of the categories with products by that manufacturer get inserted into a single drop-down. So if you have more than one level of categories/sub-categories, it gets hard to navigate. And if there are 2 or more sub-categories with the same name, it's down right frustrating.

 

What I want/am trying to do: Each level of categories gets its own drop-down. The 1st drop-down will be the root categories, the 2nd will be root's sub-categories, the 3rd with be the sub-categories sub-categories, and so on.

 

I've managed to get a working solution but it's pretty slow, I'm still learning php :P. The 1st drop-down is populated on page load, the rest are populated as previous drop-downs are selected using javascript. The amount of drop-downs is determined by the maximum level of categories/sub-categories. So if your store has 3 levels of categories, there will be 3 drop-downs, one for each level. When a category is selected that doesn't have any more sub-categories, it selects that category as the filter_id and submits the form.

 

I moved this into a separate module named mfg_categories.php in the modules folder so it would be easier to work with.

 

In the /catalog/index.php file (Backup the original), I replaced:

 

// optional Product List Filter
if (PRODUCT_LIST_FILTER > 0) {
  if (isset($HTTP_GET_VARS['manufacturers_id'])) {
	$filterlist_sql = "select distinct c.categories_id as id, cd.categories_name as name from " . TABLE_PRODUCTS . " p, " . TABLE_PRODUCTS_TO_CATEGORIES . " p2c, " . TABLE_CATEGORIES . " c, " . TABLE_CATEGORIES_DESCRIPTION . " cd where p.products_status = '1' and p.products_id = p2c.products_id and p2c.categories_id = c.categories_id and p2c.categories_id = cd.categories_id and cd.language_id = '" . (int)$languages_id . "' and p.manufacturers_id = '" . (int)$HTTP_GET_VARS['manufacturers_id'] . "' order by cd.categories_name";
  } else {
	$filterlist_sql= "select distinct m.manufacturers_id as id, m.manufacturers_name as name from " . TABLE_PRODUCTS . " p, " . TABLE_PRODUCTS_TO_CATEGORIES . " p2c, " . TABLE_MANUFACTURERS . " m where p.products_status = '1' and p.manufacturers_id = m.manufacturers_id and p.products_id = p2c.products_id and p2c.categories_id = '" . (int)$current_category_id . "' order by m.manufacturers_name";
  }
  $filterlist_query = tep_db_query($filterlist_sql);
  if (tep_db_num_rows($filterlist_query) > 1) {
	echo '			<td align="center" class="main">' . tep_draw_form('filter', FILENAME_DEFAULT, 'get') . TEXT_SHOW . ' ';
	if (isset($HTTP_GET_VARS['manufacturers_id'])) {
	  echo tep_draw_hidden_field('manufacturers_id', $HTTP_GET_VARS['manufacturers_id']);
	  $options = array(array('id' => '', 'text' => TEXT_ALL_CATEGORIES));
	} else {
	  echo tep_draw_hidden_field('cPath', $cPath);
	  $options = array(array('id' => '', 'text' => TEXT_ALL_MANUFACTURERS));
	}
	echo tep_draw_hidden_field('sort', $HTTP_GET_VARS['sort']);
	while ($filterlist = tep_db_fetch_array($filterlist_query)) {
	  $options[] = array('id' => $filterlist['id'], 'text' => $filterlist['name']);
	}
	echo tep_draw_pull_down_menu('filter_id', $options, (isset($HTTP_GET_VARS['filter_id']) ? $HTTP_GET_VARS['filter_id'] : ''), 'onchange="this.form.submit()"');
	echo '</form></td>' . "\n";
  }
}

 

with:

 

// optional Product List Filter
if (PRODUCT_LIST_FILTER > 0) {

// MODIFY START

  // IS CATEGORIES DROPDOWN
  if (isset($HTTP_GET_VARS['manufacturers_id'])) {
	include(DIR_WS_MODULES . 'mfg_categories.php');  
  } 
  // IS MANUFACTURERS DROPDOWN
  else {
	$filterlist_sql= "select distinct m.manufacturers_id as id, m.manufacturers_name as name from " . TABLE_PRODUCTS . " p, " . TABLE_PRODUCTS_TO_CATEGORIES . " p2c, " . TABLE_MANUFACTURERS . " m where p.products_status = '1' and p.manufacturers_id = m.manufacturers_id and p.products_id = p2c.products_id and p2c.categories_id = '" . (int)$current_category_id . "' order by m.manufacturers_name";

	  $filterlist_query = tep_db_query($filterlist_sql);
	  if (tep_db_num_rows($filterlist_query) > 1) {
		echo '			<td align="center" class="main" width="33%">' . tep_draw_form('filter', FILENAME_DEFAULT, 'get') . TEXT_SHOW . ' ';

	  echo tep_draw_hidden_field('cPath', $cPath);
	  $options = array(array('id' => '', 'text' => TEXT_ALL_MANUFACTURERS));

		echo tep_draw_hidden_field('sort', $HTTP_GET_VARS['sort']);
		while ($filterlist = tep_db_fetch_array($filterlist_query)) {
		  $options[] = array('id' => $filterlist['id'], 'text' => $filterlist['name']);
		}   

		echo tep_draw_pull_down_menu('filter_id', $options, (isset($HTTP_GET_VARS['filter_id']) ? $HTTP_GET_VARS['filter_id'] : ''), 'onchange="this.form.submit()"');
		echo '</form></td>' . "\n";
		}
		else {
			echo '			<td align="center" class="main" width="33%"> </td>';
		}
  }	 

// MODIFY STOP	  

} // PRODUCT_LIST FILTER END

 

That just separates the categories drop-down from the manufacturers drop-down. By default they both use the same drop-down.

 

Download mfg_categories-02-19-07.php.txt

And rename it to mfg_categories.php and put it in the /catalog/includes/modules folder.

 

I would appreciate any help on this, I have been working on this for far too long. My .bak files are getting out of hand.

 

Thanks in advance.

Share this post


Link to post
Share on other sites

Ok, I took this back to the drawing board. The one above took like 10-20 sec to load. This revised one takes 2 seconds to load. Also the last one had problems with redirecting if a drop-down only contained a single category, that is fixed. I'm pretty pleased with it now, if you would like to modify/use it, help yourself. It probably could use a little more tweaking, but work perfectly and it much faster.

 

mfg_categories.php.txt updated: 02-23-07

 

multiple_drop_downs.gif

 

<?php
/*
 $Id: mfg_categories.php,v 0.9 2007/02/23 12:00:00 hpdl Exp $

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

 Copyright (c) 2003 osCommerce

 Released under the GNU General Public License

By default when a customer selects to show products from a specific manufacturer, all the categories containing products by that manufacturer are displayed into a single drop-down box. 
This contribution displays multiple category drop-downs, one for each level of categories.
*/

define('FILTER_DROP_DOWN_DEVIDER', ' ›› '); 
define('FILTER_DEFAULT_TEXT', 'All Categories');
define('FILTER_DEFAULT_TEXT_NEXT', 'Choose Here Now');
define('FILTER_DEFAULT_TEXT_INACTIVE', '------');


$filterlist_sql = "select distinct c.categories_id as id, cd.categories_name as name, c.parent_id as parent_id from " . TABLE_PRODUCTS . " p, " . TABLE_PRODUCTS_TO_CATEGORIES . " p2c, " . TABLE_CATEGORIES . " c, " . TABLE_CATEGORIES_DESCRIPTION . " cd where p.products_status = '1' and p.products_id = p2c.products_id and p2c.categories_id = c.categories_id and p2c.categories_id = cd.categories_id and cd.language_id = '" . (int)$languages_id . "' and p.manufacturers_id = '" . (int)$HTTP_GET_VARS['manufacturers_id'] . "' and c.categories_id = cd.categories_id order by c.parent_id, c.sort_order, cd.categories_name";


$filterlist_query = tep_db_query($filterlist_sql);
if (tep_db_num_rows($filterlist_query) > 1) {
  echo '			<td align="left" class="main" width="100%" colspan="3">' . tep_draw_form('filter', FILENAME_DEFAULT, 'get') . TEXT_SHOW . ' ';	  

	$options = '';
	$num_max_cats = 0;
	$category_options = array();	
  while ($filterlist = tep_db_fetch_array($filterlist_query)) {

		$filter_id = $filterlist['id'];
	$categories = array();
	tep_get_parent_categories($categories, $filter_id);
	$categories = array_reverse($categories);
	$categories[] = $filter_id; //add this category to the end

		for ($i=0, $n=sizeof($categories); $i<$n; ++$i) { //FILTER_MAX_LEVELS //sizeof($categories)

			if (tep_not_null($categories[($i+1)]) && !in_arrayr($categories[($i+1)], $category_options)) {
				if ($i == 0 && !in_arrayr($categories[$i], $category_main)) {
					$category_options_name = tep_get_cat_name($categories[$i]);	
					$category_main[] = array('id' => $categories[$i], 'text' => $category_options_name);	

					$category_options_name = tep_get_cat_name($categories[($i+1)]);
			  $category_options[$categories[$i]][] = array('id' => $categories[($i+1)], 'text' => $category_options_name);	
				}
				else {
					$category_options_name = tep_get_cat_name($categories[($i+1)]);
			  $category_options[$categories[$i]][] = array('id' => $categories[($i+1)], 'text' => $category_options_name);				
				}

				$category_options[$categories[$i]] = tep_sort_array_names($category_options[$categories[$i]]);
			}
			if (($i+1) > $num_max_cats) $num_max_cats = ($i+1);
		}  
	}  

	while (list ($key, $val) = each ($category_options)) {
	  $this_level_option_names = '';
	  $this_level_option_values = '';

		foreach($category_options[$key] as $key2 => $val2) {
			$this_level_option_names .= '"' . $val2['text'] . '",';
			$this_level_option_values .= $val2['id'] . ',';
		}

		$this_level_option_names = substr_replace($this_level_option_names,"",-1);
		$this_level_option_values = substr_replace($this_level_option_values,"",-1);

  if (sizeof($category_options[$key]) == 1) { //add this for single category javascript redirect
	  $this_level_option_names = $this_level_option_names . ',""';
	  $this_level_option_values = $this_level_option_values . ',-1';
		}

		$options .= 'optionsArray[' . $key . '] = new Array(' . $this_level_option_names . ')' . "\n"; 
		$options .= 'valuesArray[' . $key . '] = new Array(' . $this_level_option_values . ')' . "\n";
	}

	$category_main = tep_sort_array_names($category_main);
	array_unshift($category_main, array('id' => '', 'text' => FILTER_DEFAULT_TEXT));

  //DRAW THE FIRST MAIN DROP DOWN
	echo tep_draw_pull_down_menu('Menu', $category_main, '', 'onChange="updateOptions(0,this.options[this.selectedIndex].value);"');

	$default_text = array(array('id' => '', 'text' => FILTER_DEFAULT_TEXT_INACTIVE));

	// DRAW THE REST OF THE DROP DOWNS - start at 1, 0 is already drawn
	for ($i=1, $n=$num_max_cats; $i<$n; ++$i) {
		$menu_number = $i;
		echo FILTER_DROP_DOWN_DEVIDER;
		echo tep_draw_pull_down_menu('Menu', $default_text, '', 'onChange="updateOptions(' . $menu_number . ',this.options[this.selectedIndex].value);"');
	}

	//DRAW DEFAULT HIDDEN FIELDS
	echo tep_draw_hidden_field('sort', $HTTP_GET_VARS['sort']);
	echo tep_draw_hidden_field('manufacturers_id', $HTTP_GET_VARS['manufacturers_id']);
  echo tep_draw_hidden_field('filter_id', '', 'value=""');	  

  echo '</form></td>' . "\n";
}
else { // NOTHING TO DISPLAY
	echo '			<td align="center" class="main" width="100%" colspan="3"> </td>';
}

// ###############################
// # FUNCTIONS START
// ###############################

function in_arrayr($needle, $haystack) {
if (is_array($haystack)) {
  foreach ($haystack as $v) {
   if ($needle == $v) return true;
   elseif (is_array($v)) {
	 if (in_arrayr($needle, $v) === true) return true;
   }
  }
 }
 return false;
}

function tep_sort_array_names($array)
{	
if (is_array($array)) {
	foreach($array as $key => $val) {
		$array_id[$key]  = $val['id'];
		$array_name[$key] = $val['text'];
	}
	array_multisort($array_name, SORT_ASC, $array);
}
return $array;
}

function tep_get_cat_name($category_id) {
global $languages_id;
$cName = '';

$category_sql = ("select distinct 
cd.categories_name
from " . TABLE_CATEGORIES_DESCRIPTION . " cd 
where cd.categories_id = '" . (int)$category_id . "' and 
cd.language_id = '" . (int)$languages_id . "'");

$category_query = tep_db_query($category_sql);
while ($category = tep_db_fetch_array($category_query)) {
	$cName = $category['categories_name'];
}

return $cName;
}		

// ###############################
// # FUNCTIONS STOP
// ###############################
?>

<script>
<!--

/*
########### START CASCADING DROP DOWNS SCRIPT ###########
*/

// Do Not Edit These Variables
var _F=document.filter;
var formMenu=_F.Menu;
var defaultFirst="<?php echo FILTER_DEFAULT_TEXT_NEXT; ?>";
var defaultNone="<?php echo FILTER_DEFAULT_TEXT_INACTIVE; ?>";
var optionsArray = new Array; 
var valuesArray = new Array; 
var arr; 
var varr; 

//This is the Option Array that will build your options

<?php
echo $options;
?>

//Do Not Edit Below Here - This is the actual function.

function updateOptions(menu,array) {
	arr = optionsArray[array]; 
	varr = valuesArray[array]; 

	if (varr==undefined && array!=0) {
		document.filter.filter_id.value = array;
		document.filter.submit();
	}
	else {
			var current = formMenu[menu + 1].options.length;
			var nextMenu = menu + 1;
			var allMenus = formMenu.length

			for (var j=current;j>0;j--) {
				formMenu[menu + 1].options[j] = null; 
			}
			for (int=nextMenu;int<allMenus;int++) {
				for (var y=formMenu[int].options.length;y>0;y--) {
					formMenu[int].options[y] = null; 
				}
				formMenu[int].options[0].text=defaultNone;
			}
			for (var i=0;i<arr.length;i++) {
				if (varr[i]!=-1) {
					formMenu[menu + 1].options[formMenu[menu + 1].options.length] = new Option(arr[i],varr[i]); 
				}
			}
			formMenu[menu + 1].options[0].text=defaultFirst;
	}
}
/*
########### END CASCADING DROP DOWNS SCRIPT ###########
*/
-->
</script>

</tr>
<tr>
<td align="center" class="main" width="33%"></td>

Share this post


Link to post
Share on other sites

You my sir, are a MIND READER.

 

With over 3000 products this type of tool/mod becomes extremely usefull.

 

Thank you for sharing this Awesome contribution.

 

Works like a dream on Current Version: osCMax v2.0 RC3 LIKE A DREAM!!!!

Share this post


Link to post
Share on other sites
This is a beautiful thing you've done here, friend.

 

Installed, working great.

 

 

Using RC1 / MySql 4.1...

 

Dropdown will show on manufactuer page and show categories.

When Category is selected, results are blank. Is there a variable that needs to be changed or initiated?

 

This is the URL from after selecting the 1st category in the respective manufacturer:

/osc/catalog/index.php?Menu=3&Menu=&Menu=&sort=2a&manufacturers_id=4&filter_id=3

 

-------------------Update

 

Files need to be defined? Searching for locations to edit now.

Edited by 1trackmind

Share this post


Link to post
Share on other sites
Using RC1 / MySql 4.1...

 

Dropdown will show on manufactuer page and show categories.

When Category is selected, results are blank. Is there a variable that needs to be changed or initiated?

 

This is the URL from after selecting the 1st category in the respective manufacturer:

/osc/catalog/index.php?Menu=3&Menu=&Menu=&sort=2a&manufacturers_id=4&filter_id=3

 

-------------------Update

 

Files need to be defined? Searching for locations to edit now.

 

 

Still Not Working... Is there a way to debug?

Share this post


Link to post
Share on other sites

Getting an Object Expected Error in IE on the mfg_categories.php 02-23-07.

 

----- Update

 

This is where I am at---

 

The mfg_categories.php 02-19-07 works**

The mfg_categories.php 02-23-07 Does not work.

 

**The orignial mfg_categories.php works when the Products from the Same Manufacturer have the Same Amount of Categories and/or Subcategories Only.

 

<<<<I think this was addressed in the 02-23-07 page?>>>>

 

Using PHP 5 / Mysql 4.1

Edited by 1trackmind

Share this post


Link to post
Share on other sites

I have finally figure it out why :D :D .

 

Here is what you need to change.

 

1. go to /includes/modules/mfg_categories.php

 

2. on about line 60 include this reset($category_options);

 

like so ...

 

this is the original code

 

while (list ($key, $val) = each ($category_options)) {
	  $this_level_option_names = '';
	  $this_level_option_values = '';

		foreach($category_options[$key] as $key2 => $val2) {
			$this_level_option_names .= '"' . $val2['text'] . '",';
			$this_level_option_values .= $val2['id'] . ',';

		}

		$this_level_option_names = substr_replace($this_level_option_names,"",-1);
		$this_level_option_values = substr_replace($this_level_option_values,"",-1);

     if (sizeof($category_options[$key]) == 1) { //add this for single category javascript redirect
     	$this_level_option_names = $this_level_option_names . ',""';
     	$this_level_option_values = $this_level_option_values . ',-1';
		}

		$options .= 'optionsArray[' . $key . '] = new Array(' . $this_level_option_names . ')' . "\n"; 
		$options .= 'valuesArray[' . $key . '] = new Array(' . $this_level_option_values . ')' . "\n";
	}

 

now replace with this

 

	reset($category_options);
	while (list ($key, $val) = each ($category_options)) {
	  $this_level_option_names = '';
	  $this_level_option_values = '';

		foreach($category_options[$key] as $key2 => $val2) {
			$this_level_option_names .= '"' . $val2['text'] . '",';
			$this_level_option_values .= $val2['id'] . ',';

		}

		$this_level_option_names = substr_replace($this_level_option_names,"",-1);
		$this_level_option_values = substr_replace($this_level_option_values,"",-1);

     if (sizeof($category_options[$key]) == 1) { //add this for single category javascript redirect
     	$this_level_option_names = $this_level_option_names . ',""';
     	$this_level_option_values = $this_level_option_values . ',-1';
		}

		$options .= 'optionsArray[' . $key . '] = new Array(' . $this_level_option_names . ')' . "\n"; 
		$options .= 'valuesArray[' . $key . '] = new Array(' . $this_level_option_values . ')' . "\n";
	}

 

The problem was that some servers will think that the array $category_options has already been traversed and it is at the end. with this you force it to be at the beginning every time

hope this helps.

Share this post


Link to post
Share on other sites
The problem was that some servers will think that the array $category_options has already been traversed and it is at the end. with this you force it to be at the beginning every time

hope this helps.

:thumbsup:

 

Hi, grat code, do you think i can do the same with customers? :-" I Mean, find customers searching them and ordering them by work they do, city in wich they live, and so on.

 

Can you give to me any suggestions? To me will be really useful . :lol:

 

I think I've just to put in your code different tables for the queries. Ist't right?

 

Thank you for your help!

 

Western

Edited by western

Share this post


Link to post
Share on other sites

I am having a hard time with this one...it keeps telling me that the first parameter of array_unshift needs to be an array??? I thought it already was?

 

$category_main = tep_sort_array_names($category_main);

array_unshift($category_main, array('id' => '', 'text' => FILTER_DEFAULT_TEXT));

Share this post


Link to post
Share on other sites

PLEASE PLEASE PLEASE is there any chance of getting a complete package/contribution on this...(installation/help etc)?

 

I've played around with it for a while now and "no go"... "no how"... but then again, I am not that good in PHP, so nothing surprising there...

 

Or it seems the orig. contrib. is done by MFG? Searched addons for MFG and found nothing of the sort, the preson exists, but not the contrib.

 

Any help, towards the final solution as seen couple of posts before me in the small .gif would be most appreciated...!

 

using 2.2 MS2

 

Thnks guys,

 

Sten

Edited by millend

Share this post


Link to post
Share on other sites

HI uscetech,

 

This contribution is one the best contributions I have added to my site. Thanks for the great effort.

 

I was wondering if you could guide to to make some modifications.

 

1. as each category is selected, I wish the category name to be displayed or at least retained in the drop-down box

2. when a manufacturer is selected, all products for this manufacturer are displayed. I wish not to display any products until the final category is selected.

 

I hope you will be able to guide me in this project.

 

Regards

Share this post


Link to post
Share on other sites
HI uscetech,

 

This contribution is one the best contributions I have added to my site. Thanks for the great effort.

 

I was wondering if you could guide to to make some modifications.

 

1. as each category is selected, I wish the category name to be displayed or at least retained in the drop-down box

2. when a manufacturer is selected, all products for this manufacturer are displayed. I wish not to display any products until the final category is selected.

 

I hope you will be able to guide me in this project.

 

Regards

 

Hi,

 

Does any1 have a working example of this tool?

Share this post


Link to post
Share on other sites

I love this contribution. As far as I can tell it's the only thing I've found that allows you to properly display a category drop-down menu when viewing a manufacturer's page. It's much better than the default drop-down, which seems to simply list all categories and subcategories in alphabetical order.

 

I've had a couple problems with it so far though.

 

One problem is that if there are no subcategories within the parent category, the parent category doesn't show up in the drop-down.

 

The other issue is I would like the sub-categories to be ordered by the sort order specified in the admin page (sort_order in the "categories" sql table). Currently it seems it's only alphabetical.

 

You can see my site at BFAFoodservice.com. It's still under construction and we're not exactly live yet. I am relatively new to php programming, so any help would be appreciated.

 

Thanks,

Brian

Share this post


Link to post
Share on other sites

I need help and each word is welcome.

 

Is there any possibility to don't reset category fields after the latest category was pick out?!

The main problem is because script doesn't remember which 1st category was choose.

 

I need help indeed.

 

Thanks in advance

 

here is the code

 

	  //DRAW THE FIRST MAIN DROP DOWN
	echo tep_draw_pull_down_menu('Menu', $category_main, '', 'onChange="updateOptions(0,this.options[this.selectedIndex].value);"');

	$default_text = array(array('id' => '', 'text' => FILTER_DEFAULT_TEXT_INACTIVE));

	// DRAW THE REST OF THE DROP DOWNS - start at 1, 0 is already drawn
	for ($i=1, $n=$num_max_cats; $i<$n; ++$i) {
		$menu_number = $i;
		echo FILTER_DROP_DOWN_DEVIDER;
		echo tep_draw_pull_down_menu('Menu', $default_text, '', 'onChange="updateOptions(' . $menu_number . ',this.options[this.selectedIndex].value);"');
	}

	//DRAW DEFAULT HIDDEN FIELDS
	echo tep_draw_hidden_field('sort', $HTTP_GET_VARS['sort']);
	echo tep_draw_hidden_field('manufacturers_id', $HTTP_GET_VARS['manufacturers_id']);
	echo tep_draw_hidden_field('filter_id', '', 'value=""');	  

  echo '</form></td>' . "\n";

Share this post


Link to post
Share on other sites

Hi everyone, did this script develop into a full contrib?

 

Keep getting this error:

 

 

TEXT_SHOW

Warning: in_array() [function.in-array]: Wrong datatype for second argument in /home/nas04l/c/**********/user/htdocs/test.php on line 327

Share this post


Link to post
Share on other sites

Hi everyone, did this script develop into a full contrib?

 

Keep getting this error:

 

 

TEXT_SHOW

Warning: in_array() [function.in-array]: Wrong datatype for second argument in /home/nas04l/c/**********/user/htdocs/test.php on line 327

 

 

Any one get this to work for 2.2? im getting the same array warning.... any help would be useful.

 

Or

 

 

Another way to list products in a drop down by category?

 

Cheers

 

Henry

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
Sign in to follow this  

×