Help - Search - Members - Calendar
Full Version: Multiple Category Drop-Downs When Filtered By MFG - WIP
osCommerce Community Support Forums > osCommerce Online Merchant v2.x > Contributions / Add-Ons > Contribution Development
uscetech
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 tongue.gif. 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:

CODE
// 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:

CODE
// 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.
uscetech
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




CODE
<?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
// ###############################
?>

&lt;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>

OG-Designs
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!!!!
sychosyd_28
This is a beautiful thing you've done here, friend.

Installed, working great.
1trackmind
QUOTE (sychosyd_28 @ Jul 12 2007, 03:30 PM) *
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.
1trackmind
QUOTE (1trackmind @ Sep 1 2007, 10:58 AM) *
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?
1trackmind
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
abuelo_12
I have the same problem and have not been able to figure out what the problem is. it is driving me crazy .... anyone help!!
abuelo_12
I have finally figure it out why biggrin.gif biggrin.gif .

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

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

CODE

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.
western
QUOTE
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.gif

Hi, grat code, do you think i can do the same with customers? whistling.gif 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 . laugh.gif

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

Thank you for your help!

Western
horsewhip
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));
millend
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
Tasawer
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
aftabn10
QUOTE (Tasawer @ Apr 5 2008, 11:51 PM) *
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?
USKeyser
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
Johnatan
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

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";

This is a "lo-fi" version of our main content. To view the full version with more information, formatting and images, please click here.
Invision Power Board © 2001-2009 Invision Power Services, Inc.