Jump to content

Recommended Posts

This thread is about having a products sorting possibility like

Sort by:

Products A-Z

Products Z-A

Price High > Low

Price Low < High

Bestseller

Latest added

 

and maybe few other...

 

I think this topic deserve it's own thread and I see that @@vampirehunter is very interested in getting this to work and so am I.

If anyone has something like this working properly with osC please share your work here. Or if you have any ideas as to how approach this please share.

 

Here is what I found a while back somewhere here in the forum. And I use this in my current non-BS shop but it is not coded properly and it requires at least 2 different manufacturers to be assigned to 2 products from the same category to make this filter work...stupid right? And you have to hard code the numbers and assign the text to each one of them.

 

So here is my code

  if (isset($HTTP_GET_VARS['manufacturers_id']) && !empty($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 '<div class="filter2">' . tep_draw_form('sort', FILENAME_DEFAULT, 'get') . TEXT_SORT;
	     if (isset($HTTP_GET_VARS['manufacturers_id']) && !empty($HTTP_GET_VARS['manufacturers_id'])) {
	         echo tep_draw_hidden_field('manufacturers_id', $HTTP_GET_VARS['manufacturers_id']);
	     } else {
	         echo tep_draw_hidden_field('cPath', $cPath);
	     }
	     $sort_list = array('2a' => SORT_NAME_A_Z,
	                        '2d' => SORT_NAME_Z_A,
	                        '3a' => SORT_PRICE_L_H,
                                '3d' => SORT_PRICE_H_L);
				//'1a' => SORT_MODEL_A_Z,
				//'1d' => SORT_MODEL_Z_A);
	     foreach($sort_list as $id=>$text) {
	      $sort_range[] = array('id' => $id, 'text' => $text);
	     }
	     echo tep_draw_pull_down_menu('sort', $sort_range, (isset($HTTP_GET_VARS['sort']) ? $HTTP_GET_VARS['sort'] : ''), 'onchange="this.form.submit()"');
	     echo tep_draw_hidden_field('filter_id', (isset($HTTP_GET_VARS['filter_id']) ? $HTTP_GET_VARS['filter_id'] : ''));
	     echo '</form></div>' . "\n";
	    }

Share this post


Link to post
Share on other sites

hi thanks.

Yes, i'm surprised this isn't default as part of oscommerce.

 

It should be mandatory as a default sorting option.

 

 

The + and - dropdown is ok, but there definitely needs to be more options as a minimum such as "newly added" and "best sellers" and possibly more.

I don't know why we've been told this should be an "addon". This is basic ecommerce sorting options which should be default, not as "addon".

 

Flat out refusing to add it to default is baffling to be honest. Seems like important features like this aren't taken seriously it seems.

 

 

So what i've done so far is added 2 new sorting options, "Best Sellers" and "Newly Added".

 

 

I did the following;

 

1.) Edited the Index.php file and added "newly added" and "best sellers" to both of the if/else switch case statements

2.) Edited the product_listing.php file and added both to the if/else statements

3.) Manually inserted both options as configurations into the database using Phpmyadmin.

 

 

Obviously, you still don't get the seperate dropdowns for each possibility, you still end up with a single dropdown which changes to a + or - depending on when clicked and its still not as descriptive as the type we want above.

 

Its acceptable for now, but i was told even adding these 2 options to the sort dropdowns is considered an "addon"!?

 

I've had to edit the core code just to have these added on, which is why I don't get it why this isn't part of the default setup.

 

We have to get into the 21st century of ecommerce, and a lack of sorting options is preventing this.

Edited by vampirehunter

Share this post


Link to post
Share on other sites

@@vampirehunter

 

i know that it is kinda frustrating but getting stuck there doesn't bring anything. Better let it go and go forward.

Let's get this somehow to work and add it as additional feature here in the forum or even as addon if necessary.

Share this post


Link to post
Share on other sites

@@vampirehunter

 

i know that it is kinda frustrating but getting stuck there doesn't bring anything. Better let it go and go forward.

Let's get this somehow to work and add it as additional feature here in the forum or even as addon if necessary.

 

The problem we have is that we are having to edit the core code just to get this functionality, in particular the index file and product listing file.

 

The above edit i did was not even major, all i did was add new statements to the existing ones and it added the new options to admin for sort dropdowns. Changes to 2 core files.

 

The reason i asked if this would be added the default oscommerce was that it makes sense to have it as default. And since you cannot add it as a module, how else do we expect to get this functionality?

 

Being told this has to be an "addon" is frankly ridiculous since it cannot be done as an "addon" as its direclty hacking core code.

 

If you have to hack core code just to get this functionality, then you are going back to the days of terrible addons which are a mission to install and hack up your code.

Edited by vampirehunter

Share this post


Link to post
Share on other sites

@@vampirehunter

 

i know that it is kinda frustrating but getting stuck there doesn't bring anything. Better let it go and go forward.

Let's get this somehow to work and add it as additional feature here in the forum or even as addon if necessary.

 

I just suggested it as a default option, but was told "end of discussion", so good luck getting this done as part of a default oscommerce.

 

More core hacking it seems.

Share this post


Link to post
Share on other sites

Nobody said you cannot change core code. Just as long you, yourself can remember what changes you did so that you can update in future without trouble.

At the moment osC is not "fully" modularized and therefore some stuff needs core changes. SEO URLs, this sorting thing and few other things.

Of course to be an "official" correct addon for osC BS core changes need to be avoided that would be best but not always possible at the moment.

But again nobody said you "have" to.

Share this post


Link to post
Share on other sites

Ok ... I allready did some chatting with Lambros about Product Sorting but I will start from scratch to make it clear for everyone..

 

Some background first. For me the sorting bits of code in index.php have always been messy. If you deep dive .. well then you can follow waht's going on. But I like selfexplanatory code.

 

First existing 2.3.4BS code in index.php

// create column list
$define_list = array('PRODUCT_LIST_MODEL' => PRODUCT_LIST_MODEL,
'PRODUCT_LIST_NAME' => PRODUCT_LIST_NAME,
'PRODUCT_LIST_MANUFACTURER' => PRODUCT_LIST_MANUFACTURER,
'PRODUCT_LIST_PRICE' => PRODUCT_LIST_PRICE,
'PRODUCT_LIST_QUANTITY' => PRODUCT_LIST_QUANTITY,
'PRODUCT_LIST_WEIGHT' => PRODUCT_LIST_WEIGHT,
'PRODUCT_LIST_IMAGE' => PRODUCT_LIST_IMAGE,
'PRODUCT_LIST_BUY_NOW' => PRODUCT_LIST_BUY_NOW);
asort($define_list);
$column_list = array();
reset($define_list);
while (list($key, $value) = each($define_list)) {
if ($value > 0) $column_list[] = $key;
}
$select_column_list = '';
for ($i=0, $n=sizeof($column_list); $i<$n; $i++) {
switch ($column_list[$i]) {
case 'PRODUCT_LIST_MODEL':
$select_column_list .= 'p.products_model, ';
break;
case 'PRODUCT_LIST_NAME':
$select_column_list .= 'pd.products_name, ';
break;
case 'PRODUCT_LIST_MANUFACTURER':
$select_column_list .= 'm.manufacturers_name, ';
break;
case 'PRODUCT_LIST_QUANTITY':
$select_column_list .= 'p.products_quantity, ';
break;
case 'PRODUCT_LIST_IMAGE':
$select_column_list .= 'p.products_image, ';
break;
case 'PRODUCT_LIST_WEIGHT':
$select_column_list .= 'p.products_weight, ';
break;
}
}

Remarks:

 - This piece of code ....... $define_list = array('PRODUCT_LIST_MODEL' => PRODUCT_LIST_MODEL,  ... etc .... What it does is .. it gets the value out of DB you set for this PRODUCT_LIST_MODEL  ....  list? I thougt column?  ^_^  ... Duhhh ... but we are sorting here? Why not call it  PRODUCT_SORT_MODEL etcetera .... And  $define_list .. I call it $define_sorting_list

 - What is a column list? We are sorting here? .. Then why not call it what it is? I call it sorting list! .. so I change $column_list to $sorting_list

 

Then existing 2.3.4BS code in   includes/modules/product_listing.php

for ($col=0, $n=sizeof($column_list); $col<$n; $col++) {
switch ($column_list[$col]) {
case 'PRODUCT_LIST_MODEL':
$lc_text = TABLE_HEADING_MODEL;
$lc_show_model = true;
break;
case 'PRODUCT_LIST_NAME':
$lc_text = TABLE_HEADING_PRODUCTS;
break;
case 'PRODUCT_LIST_MANUFACTURER':
$lc_text = TABLE_HEADING_MANUFACTURER;
$lc_show_manu = true;
break;
case 'PRODUCT_LIST_PRICE':
$lc_text = TABLE_HEADING_PRICE;
break;
case 'PRODUCT_LIST_QUANTITY':
$lc_text = TABLE_HEADING_QUANTITY;
$lc_show_qty = true;
break;
case 'PRODUCT_LIST_WEIGHT':
$lc_text = TABLE_HEADING_WEIGHT;
$lc_show_lbs = true;
break;
case 'PRODUCT_LIST_IMAGE':
$lc_text = TABLE_HEADING_IMAGE;
break;
case 'PRODUCT_LIST_BUY_NOW':
$lc_text = TABLE_HEADING_BUY_NOW;
break;
case 'PRODUCT_LIST_ID':
$lc_text = TABLE_HEADING_LATEST_ADDED;
break;
}

This piece of code is used for language defines - to put the text in the dropdown / heading. I will grab this piece of code and use it  earlier.

Because i will introduce a new file which will assemble the product sorter ... The new file is includes/modules/product_listing_sort.php and it looks like this:

  $Id: product_listing_sort.php
  osCommerce, Open Source E-Commerce Solutions
  http://www.oscommerce.com

  Copyright (c) 2010 osCommerce

  Released under the GNU General Public License

<?php

	// create sorting list 
		$define_sorting_list = array('PRODUCT_SORT_DEFAULT' => '0',      // HARD-CODED NUMBERS TO SIMPLIFY
					     'PRODUCT_SORT_RECOMMENDED' => '2',  // COULD OR SHOULD BE FROM DB
					     'PRODUCT_SORT_NEW' => '3',							 
					     'PRODUCT_SORT_MANUFACTURER' => '4', 
					     'PRODUCT_SORT_PRICE_LOWEST' => '5',
					     'PRODUCT_SORT_PRICE_HIGHEST' => '6',
					     'PRODUCT_SORT_MODEL' => '7',         // EG PRODUCT_LIST_MODEL
					     'PRODUCT_SORT_MOST_SOLD' => '8',
					     'PRODUCT_SORT_BEST_REVIEWED' => '9',
					     'PRODUCT_SORT_STOCK_STATUS' => '0'); // DO NOT SHOW IN MENU - SET VALUE TO 0 
		asort($define_sorting_list);
		$sorting_list = array();
		reset($define_sorting_list);

		### $sorting_list FOR SORTING IN index.php ETC
		while (list($key, $value) = each($define_sorting_list)) {
		  if ($value > 0) $sorting_list[] = $key;
		}


		  for ($i=0, $n=sizeof($sorting_list); $i<$n; $i++) {  // ADDS SORT NAME DEFINE
			switch ($sorting_list[$i]) {
			  case 'PRODUCT_SORT_DEFAULT':
				$text = TEXT_SORT_DEFAULT;
			  break;
			  case 'PRODUCT_SORT_RECOMMENDED':
				$text = TEXT_SORT_RECOMMENDED;
			  break;
			  case 'PRODUCT_SORT_NEW':
				$text = TEXT_SORT_NEW;
			  break;
			  case 'PRODUCT_SORT_MANUFACTURER':
				$text = TEXT_SORT_MANUFACTURER;
			  break;
			  case 'PRODUCT_SORT_PRICE_LOWEST':
				$text = TEXT_SORT_PRICE_LOWEST;
			  break;
			  case 'PRODUCT_SORT_PRICE_HIGHEST':
				$text = TEXT_SORT_PRICE_HIGHEST;
			  break;
			  case 'PRODUCT_SORT_MODEL':
				$text = TEXT_SORT_MODEL;
			  break;
			  case 'PRODUCT_SORT_MOST_SOLD':
				$text = TEXT_SORT_MOST_SOLD;
			  break;
			  case 'PRODUCT_SORT_BEST_REVIEWED':
				$text = TEXT_SORT_BEST_REVIEWED;
			  break;
			  case 'PRODUCT_SORT_STOCK_STATUS':
				$text = TEXT_SORT_STOCK_STATUS;
			  break;

			  default: 
				$text = '';
			  break;
			}
			### $products_sorter_array WILL BE USED IN PULL-DOWN
			$products_sorter_array[] = array('id' => $i,
							 'text' => $text);

		}

?>

Now in index.php we comment out and put in

// create column list
	// INTRODUCED NEW MODULE FOR SORTING SETUP
	//    $define_list = array('PRODUCT_LIST_MODEL' => PRODUCT_LIST_MODEL,
	//                         'PRODUCT_LIST_NAME' => PRODUCT_LIST_NAME,
	//                         'PRODUCT_LIST_MANUFACTURER' => PRODUCT_LIST_MANUFACTURER,
	//                         'PRODUCT_LIST_PRICE' => PRODUCT_LIST_PRICE,
	//                         'PRODUCT_LIST_QUANTITY' => PRODUCT_LIST_QUANTITY,
	//                         'PRODUCT_LIST_WEIGHT' => PRODUCT_LIST_WEIGHT,
	//                         'PRODUCT_LIST_IMAGE' => PRODUCT_LIST_IMAGE,
	//                         'PRODUCT_LIST_BUY_NOW' => PRODUCT_LIST_BUY_NOW);
	//
	//    asort($define_list);
	//
	//    $column_list = array();
	//    reset($define_list);
	//    while (list($key, $value) = each($define_list)) {
	//      if ($value > 0) $column_list[] = $key;
	//    }
	//
	//    $select_column_list = '';
	//
	//    for ($i=0, $n=sizeof($column_list); $i<$n; $i++) {
	//      switch ($column_list[$i]) {
	//        case 'PRODUCT_LIST_MODEL':
	//          $select_column_list .= 'p.products_model, ';
	//          break;
	//        case 'PRODUCT_LIST_NAME':
	//          $select_column_list .= 'pd.products_name, ';
	//          break;
	//        case 'PRODUCT_LIST_MANUFACTURER':
	//          $select_column_list .= 'm.manufacturers_name, ';
	//          break;
	//        case 'PRODUCT_LIST_QUANTITY':
	//          $select_column_list .= 'p.products_quantity, ';
	//          break;
	//        case 'PRODUCT_LIST_IMAGE':
	//          $select_column_list .= 'p.products_image_default, ';
	//          break;
	//        case 'PRODUCT_LIST_WEIGHT':
	//          $select_column_list .= 'p.products_weight, ';
	//          break;
	//      }
	//    }
	 ############# NEW DEFAULT SORTING PULLD-DOWN ##################
	 include(DIR_WS_MODULES . 'product_listing_sort.php'); 

To prevent this post from becoming to long - I will only show changes to the default query for products. The other queries should also be changed!

// We show them all
      // osC 2.3.4BS native query -- splittted in $select_str - $from_str - $where_str
      //$listing_sql = "select " . $select_column_list . " p.products_id, SUBSTRING_INDEX(pd.products_description, ' ', 20) as products_description, p.manufacturers_id,
 p.products_price, p.products_tax_class_id, IF(s.specials_status, s.specials_new_products_price, NULL) as specials_new_products_price, IF(s.specials_status, s.specials_new_products_price, p.products_price) as final_price from " . TABLE_PRODUCTS_DESCRIPTION . " pd, " . TABLE_PRODUCTS . " p left join " . TABLE_MANUFACTURERS . " m on p.manufacturers_id = m.manufacturers_id left join " . TABLE_SPECIALS . " s on p.products_id = s.products_id, " . TABLE_PRODUCTS_TO_CATEGORIES . " p2c where p.products_status = '1' and p.products_id = p2c.products_id and pd.products_id = p2c.products_id and pd.language_id = '" . (int)$languages_id . "' and p2c.categories_id = '" . (int)$current_category_id . "'";

        $select_str = "select p.products_id, p.products_model,  p.products_image, SUBSTRING_INDEX(pd.products_description, ' ', 20) as products_description, pd.products_name, p.manufacturers_id, p.products_price_basis, p.products_price, p.products_tax_class_id, IF(s.specials_status, s.specials_new_products_price, NULL) as specials_new_products_price, IF(s.specials_status, s.specials_new_products_price, p.products_price) as final_price ";
	$from_str = "from " . TABLE_PRODUCTS_DESCRIPTION . " pd, " . TABLE_PRODUCTS . " p left join " . TABLE_MANUFACTURERS . " m on p.manufacturers_id = m.manufacturers_id left join " . TABLE_SPECIALS . " s on p.products_id = s.products_id, " . TABLE_PRODUCTS_TO_CATEGORIES . " p2c ";
	$where_str = " where p.products_status = '1' and p.products_id = p2c.products_id and pd.products_id = p2c.products_id and pd.language_id = '" . (int)$languages_id . "' and p2c.categories_id = '" . (int)$current_category_id . "'";

Note I dropped $select_column_list from query and put in the fields we alway need in my opinion ... p.products_model, p.products_image. Furthermore I splitted the query for more felexibilty (but that is off-topic).

 

Now the piece off-code that looks if a sorting action was done by website visitor:

    if ( (!isset($HTTP_GET_VARS['sort'])) || (!preg_match('/^[1-8][ad]$/', $HTTP_GET_VARS['sort'])) || (substr($HTTP_GET_VARS['sort'], 0, 1) > sizeof($column_list)) ) {
      for ($i=0, $n=sizeof($column_list); $i<$n; $i++) {
        if ($column_list[$i] == 'PRODUCT_LIST_NAME') {
          $HTTP_GET_VARS['sort'] = $i+1 . 'a';
          $listing_sql .= " order by pd.products_name";
          break;
        }
      }
    } else {

I change it to:

	if ( (!isset($HTTP_GET_VARS['sort'])) || (!preg_match('/^[1-8]$/', $HTTP_GET_VARS['sort']))  || (substr($HTTP_GET_VARS['sort'], 0, 1) > sizeof($sorting_list)) ) {
      for ($i=0, $n=sizeof($sorting_list); $i<$n; $i++) {
        if ($sorting_list[$i] == 'PRODUCT_SORT_DEFAULT') {  // changed PRODUCT_LIST_NAME to PRODUCT_SORT_DEFAULT
           //$HTTP_GET_VARS['sort'] = $i+1 . 'a';
           $HTTP_GET_VARS['sort'] = 1;  // Sets default sort-order to 1
	   // $sort = 1; // Could also be
           //$listing_sql .= " order by pd.products_name";
	   $order_str .= " order by p.products_sort_order asc"; 
		 
          break;
        }
      }
    } 

What is does? It takes out the asc and desc postfix (eg 2a and 4d). Why? Because I think it is only relevant for price ..  In  oSC 2.3.4BS as it is there is only the + and - and you will have to click twice ... I kind of replace it in product_listing_sort.php with PRODUCT_SORT_PRICE_LOWEST and PRODUCT_SORT_PRICE_HIGHEST. So this is the important change here (!preg_match('/^[1-8][ad]$/', $HTTP_GET_VARS['sort'])) to (!preg_match('/^[1-8]$/', $HTTP_GET_VARS['sort']))

 

Now the next piece existing code after the } else {

    } else {
      $sort_col = substr($HTTP_GET_VARS['sort'], 0 , 1);
      $sort_order = substr($HTTP_GET_VARS['sort'], 1);

      switch ($column_list[$sort_col-1]) {
        case 'PRODUCT_LIST_MODEL':
          $listing_sql .= " order by p.products_model " . ($sort_order == 'd' ? 'desc' : '') . ", pd.products_name";
          break;
        case 'PRODUCT_LIST_NAME':
          $listing_sql .= " order by pd.products_name " . ($sort_order == 'd' ? 'desc' : '');
          break;
        case 'PRODUCT_LIST_MANUFACTURER':
          $listing_sql .= " order by m.manufacturers_name " . ($sort_order == 'd' ? 'desc' : '') . ", pd.products_name";
          break;
        case 'PRODUCT_LIST_QUANTITY':
          $listing_sql .= " order by p.products_quantity " . ($sort_order == 'd' ? 'desc' : '') . ", pd.products_name";
          break;
        case 'PRODUCT_LIST_IMAGE':
          $listing_sql .= " order by pd.products_name";
          break;
        case 'PRODUCT_LIST_WEIGHT':
          $listing_sql .= " order by p.products_weight " . ($sort_order == 'd' ? 'desc' : '') . ", pd.products_name";
          break;
        case 'PRODUCT_LIST_PRICE':
          $listing_sql .= " order by final_price " . ($sort_order == 'd' ? 'desc' : '') . ", pd.products_name";
          break;
      }
    }

Will be changed to

    } else {

      $sort_col = substr($HTTP_GET_VARS['sort'], 0 , 1);
      $sort_order = substr($HTTP_GET_VARS['sort'], 1);

	  ################### To execute sorting we do not need the field value in the select of query
      //switch ($sorting_list[$sort_col-1]) {
      switch ($sorting_list[$sort_col]) {	  
//        case 'PRODUCT_LIST_MODEL':
//          $listing_sql .= " order by p.products_model " . ($sort_order == 'd' ? 'desc' : '') . ", pd.products_name";
//          break;
//        case 'PRODUCT_LIST_NAME':
//          $listing_sql .= " order by pd.products_name " . ($sort_order == 'd' ? 'desc' : '');
//          break;
//        case 'PRODUCT_LIST_MANUFACTURER':
//          $listing_sql .= " order by m.manufacturers_name " . ($sort_order == 'd' ? 'desc' : '') . ", pd.products_name";
//          break;
//        case 'PRODUCT_LIST_QUANTITY':
//          $listing_sql .= " order by p.products_quantity " . ($sort_order == 'd' ? 'desc' : '') . ", pd.products_name";
//          break;
//        case 'PRODUCT_LIST_IMAGE':
//          $listing_sql .= " order by pd.products_name";
//          break;
//        case 'PRODUCT_LIST_WEIGHT':
//          $listing_sql .= " order by p.products_weight " . ($sort_order == 'd' ? 'desc' : '') . ", pd.products_name";
//          break;
//        case 'PRODUCT_LIST_PRICE':
//          $listing_sql .= " order by final_price " . ($sort_order == 'd' ? 'desc' : '') . ", pd.products_name";
//          break;
        case 'PRODUCT_SORT_DEFAULT'  :
          $order_str .= " order by p.products_sort_order , pd.products_name";
          break;
        case 'PRODUCT_SORT_RECOMMENDED'  :
          $order_str .= " order by p.products_sort_order , pd.products_name";
          break;
        case 'PRODUCT_SORT_NEW' :
          $order_str .= " order by p.products_date_added desc";
          break;
        case 'PRODUCT_SORT_MANUFACTURER' :
          $order_str .= " order by p.manufacturers_id asc";
          break;
        case 'PRODUCT_SORT_PRICE_LOWEST' :
         $order_str .= " order by final_price asc, pd.products_name";
          break;
        case 'PRODUCT_SORT_PRICE_HIGHEST' :
         $order_str .= " order by final_price desc, pd.products_name";
          break;
        case 'PRODUCT_SORT_MODEL'   :
          $order_str .= " order by p.products_model ";
          break;
        case 'PRODUCT_SORT_MOST_SOLD'   :
          $order_str .= " order by p.products_ordered desc ";
          break;
        case 'PRODUCT_SORT_BEST_REVIEWED'   :
          $order_str .= " order by pd.products_viewed desc ";
          break;
        case 'PRODUCT_SORT_STOCK_STATUS':
          $order_str .= " order by p.stock_status desc, pd.products_name";
          break;
		  
      }
    }
    // putting it all togehter for query used in product_listing.php
    $listing_sql = $select_str . $from_str . $where_str . $order_str;  


You can see THREE important changes:

- switch ($sorting_list[$sort_col-1]) {  to switch ($sorting_list[$sort_col]) .....

- EG  order by final_price " . ($sort_order == 'd' ? 'desc' : '') . " replaced by  order by final_price desc

- And now ... Assemble the query $listing_sql = $select_str . $from_str . $where_str . $order_str;

 

Now the existing code in includes/modules/product_listing.php

      <div class="btn-group btn-group-sm pull-right">
        <button type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown">
          <?php echo TEXT_SORT_BY; ?><span class="caret"></span>
        </button>

        <ul class="dropdown-menu text-left">
          <?php
          $lc_show_model = false;
          $lc_show_manu = false;
          $lc_show_qty = false;
          $lc_show_lbs = false;
          for ($col=0, $n=sizeof($sorting_list); $col<$n; $col++) {
            switch ($sorting_list[$col]) {
              case 'PRODUCT_SORT_MODEL':
              $lc_text = TABLE_HEADING_MODEL;
		          $lc_show_model = true;
              break;
              case 'PRODUCT_SORT_NAME':
              $lc_text = TABLE_HEADING_PRODUCTS;
              break;
              case 'PRODUCT_LIST_MANUFACTURER':
              $lc_text = TABLE_HEADING_MANUFACTURER;
		          $lc_show_manu = true;
              break;
              case 'PRODUCT_LIST_PRICE':
              $lc_text = TABLE_HEADING_PRICE;
              break;
              case 'PRODUCT_LIST_QUANTITY':
              $lc_text = TABLE_HEADING_QUANTITY;
              $lc_show_qty = true;
              break;
              case 'PRODUCT_LIST_WEIGHT':
              $lc_text = TABLE_HEADING_WEIGHT;
              $lc_show_lbs = true;
              break;
              case 'PRODUCT_LIST_IMAGE':
              $lc_text = TABLE_HEADING_IMAGE;
              break;
              case 'PRODUCT_LIST_BUY_NOW':
              $lc_text = TABLE_HEADING_BUY_NOW;
              break;
              case 'PRODUCT_LIST_ID':
              $lc_text = TABLE_HEADING_LATEST_ADDED;
              break;
            }

            if ( ($sorting_list[$col] != 'PRODUCT_LIST_BUY_NOW') && ($sorting_list[$col] != 'PRODUCT_LIST_IMAGE') ) {
              $lc_text = tep_create_sort_heading($HTTP_GET_VARS['sort'], $col+1, $lc_text);
	            echo '        <li>' . $lc_text . '</li>';
            }
          }
		      ?>
        </ul>
      </div>

I get rid of the button group AND tep_create_sort_heading($HTTP_GET_VARS['sort'], $col+1, $lc_text) ... In my opinion this is a pulldown menu - it acts as pull-down menu ...SO use a pull-down menu ;)

<div class="col-sm-3 pull-right">
  <?php
  echo tep_draw_form('sort', tep_href_link(FILENAME_DEFAULT,tep_get_all_get_params(array('view')) ), 'get');		
  echo tep_draw_pull_down_menu('sort', $products_sorter_array, $sort, 'onchange="this.form.submit()"');
  echo tep_hide_session_id() . '</form>';
  ?>
</div>

This will put in the pull-down menu based on $products_sorter_array we assembled in includes/modules/ product_listing_sort.php.

 

Remember .. these changes will break all files where product_listing.php is used eg. specials.php .. So all of them need these changes.

 

Hop this helps!

Share this post


Link to post
Share on other sites

Could not edit anymore but in the last part ..

 

echo tep_draw_form('sort', tep_href_link(FILENAME_DEFAULT,tep_get_all_get_params(array('view')) ), 'get');

 

should be

 

echo tep_draw_form('sort', FILENAME_DEFAULT, 'get');

Share this post


Link to post
Share on other sites

Previous post still misses something important .... the cPath and filter_id!

 

So it should be

     <div id="sort" class="col-sm-3 pull-right">
	  <?php
	  echo tep_draw_form('sort', tep_href_link(FILENAME_DEFAULT,tep_get_all_get_params(array('view')) ), 'get');

	  echo (isset($_GET['cPath']) ? tep_draw_hidden_field('cPath', $_GET['cPath']) : '') ;
	  echo (isset($_GET['filter_id']) ? tep_draw_hidden_field('filter_id', $_GET['filter_id']) :'');									
	  
	  echo tep_draw_pull_down_menu('sort', $products_sorter_array, $sort, 'onchange="this.form.submit()"');
	  echo tep_hide_session_id() . '</form>';
	  ?>
     </div>

Edited by azpro

Share this post


Link to post
Share on other sites

@@azpro, thanks for your time and code. May be is time to zip all in a addon?

 

I'm not 100% sure but if you zip it in a addom will be easy to find it in the future searching in the 'addons area' instead find it in the 'stratum' forum.


Get the latest current code (community-supported responsive 2.3.4.1BS Edge) here

No pierdas el tiempo. Si quieres usar la versión más estable de osCommerce (la realizada por la comunidad, que además es 'responsive', la 2.3.4.1BS Edge) pincha aquí y aquí para descargarte el idioma Español.

Share this post


Link to post
Share on other sites

@@azpro, thanks for your time and code. May be is time to zip all in a addon?

 

I'm not 100% sure but if you zip it in a addom will be easy to find it in the future searching in the 'addons area' instead try to find it in the 'stratum' forum.


Get the latest current code (community-supported responsive 2.3.4.1BS Edge) here

No pierdas el tiempo. Si quieres usar la versión más estable de osCommerce (la realizada por la comunidad, que además es 'responsive', la 2.3.4.1BS Edge) pincha aquí y aquí para descargarte el idioma Español.

Share this post


Link to post
Share on other sites

When I find time I will push to add-ons.

 

But this is more like a guideline and not a definite instruction. I coded on-the-fly while modding-up osc 2.3.4BS and took bits and pieces of earlier work on oSC2.3.4 ...

 

For example ... Later today I realised you need  $PHP_SELF in product_listing.php because product_listing.php is included in different files ... So tep_draw_form() in product_listing.php will be

tep_draw_form('sort', tep_href_link($PHP_SELF, tep_get_all_get_params(array('view')) ), 'get')

And please note 'view' is a param from my own template.

Share this post


Link to post
Share on other sites

@@azpro

 

Thanks again for the explanation and code. :thumbsup:

 

I have now everything in place, added new sort filters, added language definitions....but now i have encountered an issue which I can't solve.

I have a total of 16 sort filters.

$define_sorting_list = array('PRODUCT_SORT_DEFAULT' => '1',					 
                             'PRODUCT_SORT_MANUFACTURER_A_Z' => '2', 
                             'PRODUCT_SORT_MANUFACTURER_Z_A' => '3',
                             'PRODUCT_SORT_NAME_A_Z' => '4',
                             'PRODUCT_SORT_NAME_Z_A' => '5',
                             'PRODUCT_SORT_PRICE_LOWEST' => '6',
                             'PRODUCT_SORT_PRICE_HIGHEST' => '7',
                             'PRODUCT_SORT_MODEL_A_Z' => '8',
                             'PRODUCT_SORT_MODEL_Z_A' => '9',
                             'PRODUCT_SORT_QUANTITY_LOW' => '10',							 
                             'PRODUCT_SORT_QUANTITY_HIGH' => '11',
                             'PRODUCT_SORT_WEIGHT_LOW' => '12',							 
                             'PRODUCT_SORT_WEIGHT_HIGH' => '13',
                             'PRODUCT_SORT_MOST_SOLD' => '14', 
                             'PRODUCT_SORT_MOST_VIEWED' => '15',
                             'PRODUCT_SORT_LATEST' => '16');

Now they show all inside the drop down but only the ones between number 1-9 work. If I choose sort by Most Sold (14) it will jump to the PRODUCT_SORT_DEFAULT.

If i set PRODUCT_SORT_MOST_SOLD let's say from 14 to value 8 and "remove" the value 8 from PRODUCT_SORT_MODEL_A_Z  then it works. So anything that is inside the value 1-9 works.

Why is that happening? What is the code that checks for that value and decides what is the max value? Which right now is 9.

 

Make sense?

Edited by Tsimi

Share this post


Link to post
Share on other sites

@@Tsimi

 

It probably has to do with (!preg_match('/^[1-8]$/', $HTTP_GET_VARS['sort'])) ... Probably before changing the code (as in untouched 2.3.4BS) anything above 8 would also not work ...

 

I will look in to it later ... Now on sunday visit to mother in law :D

Edited by azpro

Share this post


Link to post
Share on other sites

aiii mother in law......

 

Last week i was having diner with my father/mother in law..... we had chicken and pork....

My mother in law stabbed the fork in a piece of chicken.

She asked:

"Is this chicken or pork?"

 

I responded:

"it depends on which end of the fork."

 

:lol:

Edited by Tsimi

Share this post


Link to post
Share on other sites

I responded:

"it depends on which end of the fork."

 

And you're still with us.  :thumbsup:

 

Dan

Share this post


Link to post
Share on other sites

whitehat was so kind to help me out with the issue I had and he could solve it.

Now I can add more then 9 sort values. Here is the fix

 

Find this code

if ( (!isset($HTTP_GET_VARS['sort'])) || (!preg_match('/^[1-8]$/', $HTTP_GET_VARS['sort']))  || (substr($HTTP_GET_VARS['sort'], 0, 1) > sizeof($sorting_list)) ) {

and change it to
 

if ( (!isset($HTTP_GET_VARS['sort'])) || (!preg_match('/^[1-9]|1[0-6]$/', $HTTP_GET_VARS['sort'])) || ($HTTP_GET_VARS['sort'] > sizeof($sorting_list)) ) {

look for this code
 

$sort_col = substr($HTTP_GET_VARS['sort'], 0 , 1);
$sort_order = substr($HTTP_GET_VARS['sort'], 1);

     
and change it to
 

$sort_col = $HTTP_GET_VARS['sort'];
$sort_order = $HTTP_GET_VARS['sort'];

I don't know exactly why this regex code is inside it but that alone is not the culprit. Removing it didn't help so the guess is that the substr is also part of the restriction.

Share this post


Link to post
Share on other sites

@@Tsimi  ... @@wHiTeHaT ... Whitehats solution is kind of what I figured out ..

 

 

I have a slightly different preg_match which should work for 1-99 :

 if ( (!isset($HTTP_GET_VARS['sort'])) || (!preg_match('/^[0-9]{1,2}$/', $HTTP_GET_VARS['sort']))  || (substr($HTTP_GET_VARS['sort'], 0, 1) > sizeof($sorting_list)) ) {

I think whitehat's solution is better because my preg_match will also be  valid for 0 ... And we don't want that.
 

So it is better to use whitehat's preg_match but be aware this does restrict to 16 sort options (which should be more than enough sort options if not too much)

if ( (!isset($HTTP_GET_VARS['sort'])) || (!preg_match('/^[1-9]|1[0-6]$/', $HTTP_GET_VARS['sort'])) || ($HTTP_GET_VARS['sort'] > sizeof($sorting_list)) ) {

I don't know exactly why this regex code is inside it but that alone is not the culprit. Removing it didn't help so the guess is that the substr is also part of the restriction.

 

The preg_match regex is used to evaluate the input and restrict input to ... original code : numbers 1-8 and letters a and d EG sort=2a .. The changed code I give wil restrict to numbers 0-99 EG sort=16 ..... Changed code by whitehat restricts to number 1-16

 

The part $sort_order is not used anymore in this sorting  solution and could be commented out.

//$sort_order = substr($HTTP_GET_VARS['sort'], 1);

As for   ...

$sort_col = substr($HTTP_GET_VARS['sort'], 0 , 1);

  ... As far as I know should be changed to    

$sort_col = substr($HTTP_GET_VARS['sort'], 0 , 2); 

  ... Simply changing to

$sort_col = $HTTP_GET_VARS['sort'];

  does creae a potential security risk IMHO ....

 

Maybe @@wHiTeHaT could comment on that.

Edited by azpro

Share this post


Link to post
Share on other sites

@@wHiTeHaT@@azpro

 

Thank you very much guys!

Finally we got a Unicorn!  (w00t)  (Don't ask, long story...)

 

All works fine now.

 

Sorting for all 16 different values works. Best Seller, Most viewed, Latest added and so and so on...

Share this post


Link to post
Share on other sites

Until someone puts this together as module I thought I put all together into one install manual for those who are willing to amend core code.

If you don't want to change core code do not install this!

 

Here is the package:

 

Sort_Filter.zip

 

All credits for this go to @@azpro! Thank you.

Edited by Tsimi

Share this post


Link to post
Share on other sites

Forgot to mention. The code changes from the above package will deactivate the whole extra contents part inside the product listing.

    // here it goes the extras, yuck
    $extra_list_contents = NULL;
    // manufacturer
	  if (($lc_show_manu == true) && ($listing['manufacturers_id'] !=  0)) $extra_list_contents .= '<dt>' . TABLE_HEADING_MANUFACTURER . '</dt><dd><a href="' . tep_href_link(FILENAME_DEFAULT, 'manufacturers_id=' . $listing['manufacturers_id']) . '">' . $listing['manufacturers_name'] . '</a></dd>';
    // model
	  if ( ($lc_show_model == true) && tep_not_null($listing['products_model'])) $extra_list_contents .= '<dt>' . TABLE_HEADING_MODEL . '</dt><dd>' . $listing['products_model'] . '</dd>';
    // stock
	  if (($lc_show_qty == true) && (tep_get_products_stock($listing['products_id'])!= 0) ) $extra_list_contents .= '<dt>' . TABLE_HEADING_QUANTITY . '</dt><dd>' . tep_get_products_stock($listing['products_id']) . '</dd>';
    // weight
	  if (($lc_show_lbs == true) && ($listing['products_weight'] != 0)) $extra_list_contents .= '<dt>' . TABLE_HEADING_WEIGHT . '</dt><dd>' . $listing['products_weight'] . '</dd>';

    if (tep_not_null($extra_list_contents)) {
       $prod_list_contents .= '    <dl class="dl-horizontal list-group-item-text">';
       $prod_list_contents .=  $extra_list_contents;
       $prod_list_contents .= '    </dl>';
    }

if you want to show quantity, weight, manufacturer and model no. you will have to recode that part.

Share this post


Link to post
Share on other sites

Ah...food for thought...

 

I once had a lot of filtering setup but then I had decided to keep it simple and came up with an algorithm that was based on the value driven idea by assigning weight and implemented a pseudo half-life aging function that would push unpopular aging products to the back of the list...I called that the What's Hot filter and five factors were taken into account...

 

DAYS_ADDED, VIEWS_PER_DAY, BASKET_QTY, PRODUCTS_ORDERED, and ONHAND.

 

This way I was hoping to take into account of customer interactions of a product as well as the page would index differently every time. I then had placed the update in a stored procedure so we would do a nightly update...so occasionally we would just have to go to the back of the list and obsolete products that've been there too long and had not enough views, not enough customer interactions such as adding to basket or ordering, and were zero stock... 

Share this post


Link to post
Share on other sites

Forgot to mention. The code changes from the above package will deactivate the whole extra contents part inside the product listing.

    // here it goes the extras, yuck
    $extra_list_contents = NULL;
    // manufacturer
	  if (($lc_show_manu == true) && ($listing['manufacturers_id'] !=  0)) $extra_list_contents .= '<dt>' . TABLE_HEADING_MANUFACTURER . '</dt><dd><a href="' . tep_href_link(FILENAME_DEFAULT, 'manufacturers_id=' . $listing['manufacturers_id']) . '">' . $listing['manufacturers_name'] . '</a></dd>';
    // model
	  if ( ($lc_show_model == true) && tep_not_null($listing['products_model'])) $extra_list_contents .= '<dt>' . TABLE_HEADING_MODEL . '</dt><dd>' . $listing['products_model'] . '</dd>';
    // stock
	  if (($lc_show_qty == true) && (tep_get_products_stock($listing['products_id'])!= 0) ) $extra_list_contents .= '<dt>' . TABLE_HEADING_QUANTITY . '</dt><dd>' . tep_get_products_stock($listing['products_id']) . '</dd>';
    // weight
	  if (($lc_show_lbs == true) && ($listing['products_weight'] != 0)) $extra_list_contents .= '<dt>' . TABLE_HEADING_WEIGHT . '</dt><dd>' . $listing['products_weight'] . '</dd>';

    if (tep_not_null($extra_list_contents)) {
       $prod_list_contents .= '    <dl class="dl-horizontal list-group-item-text">';
       $prod_list_contents .=  $extra_list_contents;
       $prod_list_contents .= '    </dl>';
    }

if you want to show quantity, weight, manufacturer and model no. you will have to recode that part.

 

hi, did you add the show 12, 24, etc dropdown to this?

thanks

Share this post


Link to post
Share on other sites

hi, did you add the show 12, 24, etc dropdown to this?

thanks

That is a different code and it comes before this code

<?php
  if ( ($listing_split->number_of_rows > 0) && ( (PREV_NEXT_BAR_LOCATION == '1') || (PREV_NEXT_BAR_LOCATION == '3') ) ) {
?>

The code for the products per page is this

<!-- BOF MAX PRODUCTS PER PAGE //-->
<?php
if (!tep_session_is_registered('max_products_per_page')) tep_session_register('max_products_per_page');
  if (!isset($max_products_per_page) || !is_integer($max_products_per_page) || ($max_products_per_page < 1)) $max_products_per_page = MAX_DISPLAY_SEARCH_RESULTS;
  if (isset($HTTP_GET_VARS['mppp']) && is_numeric($HTTP_GET_VARS['mppp']) && ($HTTP_GET_VARS['mppp'] > 0)) $max_products_per_page = intval($HTTP_GET_VARS['mppp']);
  $mppp_list = array();
  for ($i = 1; $i <= 5; $i += 1) {
	$mppp = intval($i * 12);
	$mppp_list[] = array('id' => $mppp, 'text' => $mppp);
	}
	$mppp_list[] = array('id' => 9999999, 'text' => TEXT_ALL_ITEMS);	
  $gvhf = '';
  $ignore = array('page', 'mppp');
  if (is_array($HTTP_GET_VARS) && (sizeof($HTTP_GET_VARS) > 0)) {
	reset($HTTP_GET_VARS);
	while (list($key, $value) = each($HTTP_GET_VARS)) {
	  if ( (strlen($value) > 0) && ($key != tep_session_name()) && (!in_array($key, $ignore)) ) {
		$gvhf .= tep_draw_hidden_field($key, $value);
	  }
	}
  }
  $maxpppform = tep_draw_form('prod_per_page', basename($PHP_SELF), 'get') . $gvhf . tep_draw_pull_down_menu('mppp', $mppp_list, $max_products_per_page, 'class="form-control text-center" style="width:70px;" onchange="this.form.submit()"') . '</form>';
  $listing_split = new splitPageResults($listing_sql, $max_products_per_page, 'p.products_id');
?>

<?php echo $maxpppform; ?>
<!-- EOF MAX PRODUCTS PER PAGE //-->

You might have to adjust the code a bit to match your site and fit your needs.

Edited by Tsimi

Share this post


Link to post
Share on other sites

Ah...food for thought...

 

I once had a lot of filtering setup but then I had decided to keep it simple and came up with an algorithm that was based on the value driven idea by assigning weight and implemented a pseudo half-life aging function that would push unpopular aging products to the back of the list...I called that the What's Hot filter and five factors were taken into account...

 

DAYS_ADDED, VIEWS_PER_DAY, BASKET_QTY, PRODUCTS_ORDERED, and ONHAND.

 

This way I was hoping to take into account of customer interactions of a product as well as the page would index differently every time. I then had placed the update in a stored procedure so we would do a nightly update...so occasionally we would just have to go to the back of the list and obsolete products that've been there too long and had not enough views, not enough customer interactions such as adding to basket or ordering, and were zero stock... 

 

@@clustersolutions - were/are you updating a sort order column and using that for this sort? That would fit with the 'product sort order within category' that I've just ported to BS, which has an admin page for manually setting the default order that individual products appear within a category.


For a new install or if your store isn't mobile-friendly, get the community-supported responsive osCommerce (2.3.4.1 CE) here: https://github.com/gburton/Responsive-osCommerce/archive/2341-Frozen.zip

Working on generalising bespoke solutions for Quickbooks integration, Easify integration and pay4later (DEKO) integration at 2.3.x

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

×