Jump to content

[SOLVED] Problem with sorting multiple fields in category


pskz

Recommended Posts

I want to sort products in category by default filters (like: position, price...) and by quantity. Products with quantity = 0 must be on the end of the list.

 

Default query in Category.php (function getProducts() - line 688, presta 1.6.1.x)

 

I'm trying to add quantity to ORDER BY, but results are sorted only by position

if ($random === true) {
	$sql .= ' ORDER BY RAND(), stock.`quantity` DESC LIMIT '.(int)$random_number_products;
} else {
	$sql .= ' ORDER BY '.(!empty($order_by_prefix) ? $order_by_prefix.'.' : '').'`'.bqSQL($order_by).'` '.pSQL($order_way).', stock.`quantity` DESC
	LIMIT '.(((int)$p - 1) * (int)$n).','.(int)$n;
}

I'm trying to change this query by adding subquery for avaliable_stock, but results are the same, sorted only by position

$sql = 'SELECT p.*, product_shop.*, real_quantity.*'.(Combination::isFeatureActive() ? ', IFNULL(product_attribute_shop.id_product_attribute, 0) AS id_product_attribute,
			product_attribute_shop.minimal_quantity AS product_attribute_minimal_quantity' : '').', pl.`description`, pl.`description_short`, pl.`available_now`,
			pl.`available_later`, pl.`link_rewrite`, pl.`meta_description`, pl.`meta_keywords`, pl.`meta_title`, pl.`name`, image_shop.`id_image` id_image,
			il.`legend` as legend, m.`name` AS manufacturer_name, cl.`name` AS category_default,
			DATEDIFF(product_shop.`date_add`, DATE_SUB("'.date('Y-m-d').' 00:00:00",
			INTERVAL '.(int)$nb_days_new_product.' DAY)) > 0 AS new, product_shop.price AS orderprice
		FROM `'._DB_PREFIX_.'category_product` cp
		LEFT JOIN `'._DB_PREFIX_.'product` p
			ON p.`id_product` = cp.`id_product`
		'.Shop::addSqlAssociation('product', 'p').
		(Combination::isFeatureActive() ? ' LEFT JOIN `'._DB_PREFIX_.'product_attribute_shop` product_attribute_shop
		ON (p.`id_product` = product_attribute_shop.`id_product` AND product_attribute_shop.`default_on` = 1 AND product_attribute_shop.id_shop='.(int)$context->shop->id.')':'').'
		LEFT JOIN `'._DB_PREFIX_.'category_lang` cl
			ON (product_shop.`id_category_default` = cl.`id_category`
			AND cl.`id_lang` = '.(int)$id_lang.Shop::addSqlRestrictionOnLang('cl').')
		LEFT JOIN `'._DB_PREFIX_.'product_lang` pl
			ON (p.`id_product` = pl.`id_product`
			AND pl.`id_lang` = '.(int)$id_lang.Shop::addSqlRestrictionOnLang('pl').')
		LEFT JOIN `'._DB_PREFIX_.'image_shop` image_shop
			ON (image_shop.`id_product` = p.`id_product` AND image_shop.cover=1 AND image_shop.id_shop='.(int)$context->shop->id.')
		LEFT JOIN `'._DB_PREFIX_.'image_lang` il
			ON (image_shop.`id_image` = il.`id_image`
			AND il.`id_lang` = '.(int)$id_lang.')
		LEFT JOIN `'._DB_PREFIX_.'manufacturer` m
			ON m.`id_manufacturer` = p.`id_manufacturer`
		LEFT JOIN (SELECT * FROM `'._DB_PREFIX_.'stock_available` ORDER BY `quantity` DESC) AS real_quantity
			ON (real_quantity.id_product = p.id_product AND real_quantity.id_product_attribute = 0 AND real_quantity.id_shop = '.(int)$context->shop->id.')
		WHERE product_shop.`id_shop` = '.(int)$context->shop->id.'
			AND cp.`id_category` = '.(int)$this->id
			.($active ? ' AND product_shop.`active` = 1' : '')
			.($front ? ' AND product_shop.`visibility` IN ("both", "catalog")' : '')
			.($id_supplier ? ' AND p.id_supplier = '.(int)$id_supplier : '');

if ($random === true) {
	$sql .= ' ORDER BY RAND(), real_quantity.`quantity` DESC LIMIT '.(int)$random_number_products;
} else {
	$sql .= ' ORDER BY '.(!empty($order_by_prefix) ? $order_by_prefix.'.' : '').'`'.bqSQL($order_by).'` '.pSQL($order_way).', real_quantity.`quantity` DESC
	LIMIT '.(((int)$p - 1) * (int)$n).','.(int)$n;
}

Can anyone help/advise me with this problem?

Edited by pskz (see edit history)
Link to comment
Share on other sites

I did try this once! Jsut a notice : Try disabling LayeredNavigation. This module bugged me out of my development. I was trying to develops a stable the "On Sale First" in the listing. Never worked because of LayeredNavigation.

 

I still don't know where his cache is or how it retrieve the products. I don't want ot touch such an important module or override it, sounds like a bad pitfall during an update.

 

Martin.

Link to comment
Share on other sites

This code :

'.(!empty($order_by_prefix) ? $order_by_prefix.'.' : '').'`'.bqSQL($order_by).'` '.pSQL($order_way).',

Must return the sort selected no? If you remove it, it should go directly to your quantity order. Althought, if you do that, your "sorting selector" won't work on category, it will always go to quantity.

 

Hmmm. you need to add Quantity to the select on the page and work with it as a condition too...

 

Martin.

Link to comment
Share on other sites

I can't remove this code, because it is respons for the default sorting within the category.

 

I want to sort by default filters and quantity like:

ORDER BY cp.`position` ASC, stock.`quantity` DESC

or:

ORDER BY pl.`name` ASC, stock.`quantity` DESC 

but this not working

Link to comment
Share on other sites

Oh! Okay, that sounds better.

 

so you want to have FIRST : The position (Which is default) and then the Quantity. The problem is that the position is numeric from 1 to # of products. So, let'S say you have 9 products:  The first will be #1,#2,#3,#4,etc. The problem is that

ORDER BY cp.`position` ASC, stock.`quantity` DESC

Doesn't have any situation to use the quantity sort. None of the position are equals. The first sort is fully discriminating, the second sort (Quantity) is never checked.

 

With the name

ORDER BY pl.`name` ASC, stock.`quantity` DESC 

Quantity will be used only if both product have the exact same name. This doesn't happen a lot in my clients cases...

 

Try naming 3 products the same way and have them have different quantities. Pretty sure they'll be sorted in the right way.

 

Martin.

Link to comment
Share on other sites

The first sort is fully discriminating, the second sort (Quantity) is never checked.

 

 

You're right, I forgot about that :P

I will create two statements: for products with quantity > 0, and the other one for products with quantity = 0, and merge results.

Edited by pskz (see edit history)
Link to comment
Share on other sites

I need both. As I wrote in the first post:

 

I want to sort products in category by default filters (like: position, price...) and by quantity. Products with quantity = 0 must be on the end of the list.

 

Not excluding pagination.

 

For example:

- first 3 pages have products with quantity > 0,

- 4th page have 2 products with quantity > 0 and 2 products with quantity = 0

- next pages only products with quantity = 0

 

So two sql queries and merging results solves my problem.

 

If you have a better solution please reply :)

Link to comment
Share on other sites

2 queries is too long, 1 query is always better.

$sql .= ' ORDER BY real_quantity.`quantity` > 0 DESC, '.(!empty($order_by_prefix) ? $order_by_prefix.'.' : '').'`'.bqSQL($order_by).'` '.pSQL($order_way).'
	LIMIT '.(((int)$p - 1) * (int)$n).','.(int)$n;

Quantity > 0 will return 1 if in stock, 0 if oos. Putting DESC means, takes the one that are in stock first, then the one oos. Order same value of stock with default data.

 

Could also be quantity = 0 ASC. You get the point.

 

Martin.

Edited by Martin Uker K (see edit history)
  • Like 1
Link to comment
Share on other sites

In that way PrestaShop sorts products by the price, this is related to promotions, etc., and it is not dependent on me.

Thank you for suggestions on using a single query, I didn't know that in the ORDER BY I can use the comparison, this works. For the price, I found another solution.

 

That's why I wrote to the forum, to find an optimal solution to a problem which I could not solve. I didn't ask for a judge of my work.

 

Anyway, thanks for your help.

Link to comment
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
×
×
  • Create New...