These instructions are for sorting products in xcart product listing pages what ever sort order is used but the out of stock items are always shown at the bottom.
edit the /include/fun/func.product.php
//find
if (
stripos($query, XCRangeProductIds::getSqlMINPriceField()) !== false
&& preg_match('/ORDER BY .*\b' . XCRangeProductIds::getSqlMINPriceField('get_alias_name') . '\b/i', $query)
) {
// To avoid sql error related to 'GROUP BY price '
$substr_fields = "$sql_tbl[products].productid, " . XCRangeProductIds::getSqlMINPriceField();
} else {
$substr_fields = "$sql_tbl[products].productid";
}replace with
//replace
if (
stripos($query, XCRangeProductIds::getSqlMINPriceField()) !== false
&& preg_match('/ORDER BY .*\b' . XCRangeProductIds::getSqlMINPriceField('get_alias_name') . '\b/i', $query)
) {
// To avoid sql error related to 'GROUP BY price '
$substr_fields = "$sql_tbl[products].productid, IF($sql_tbl[products].avail=0,0,1) AS instock, " . XCRangeProductIds::getSqlMINPriceField();
} else {
$substr_fields = "$sql_tbl[products].productid, IF($sql_tbl[products].avail=0,0,1) AS instock";
}edit the /include/search.php
//find the code below
if (empty($data['is_modify'])) {
$fields[] = $sql_tbl['products'] . '.*';
} else {
$fields[] = $sql_tbl['products'] . '.productid';
}
//replace with
if (empty($data['is_modify'])) {
$fields[] = $sql_tbl['products'] . '.*';
//2022-03-08 add field to sort by out of stock last
$fields[] = 'IF('.$sql_tbl['products'].'.avail=0,0,1) AS instock';
} else {
$fields[] = $sql_tbl['products'] . '.productid';
}//find the code
switch ($data['sort_field']) {
case 'productcode':
$sort_string = "$sql_tbl[products].productcode $direction";
break;
case 'title':
$sort_string = "$sql_tbl[products_lng_current].product $direction";
break;
case 'orderby':
$sort_string = "$sql_tbl[products_categories].orderby $direction";
break;
case 'sales_stats':
$inner_joins['product_sales_stats'] = array(
'on' => "$sql_tbl[product_sales_stats].productid = $sql_tbl[products].productid",
'only_select' => TRUE,
);
$sort_string = "$sql_tbl[product_sales_stats].sales_stats $direction";
break;
case 'quantity':
$sort_string = empty($active_modules['Product_Options'])
? "$sql_tbl[products].avail $direction"
: XCVariantsSQL::getVariantField('avail') . " $direction";
break;
case 'price':
if (
!empty($active_modules['Special_Offers'])
&& isset($search_data['products']['show_special_prices'])
&& $search_data['products']['show_special_prices']
) {
$sort_string = "x_special_price $direction, price $direction";
} else {
$sort_string = "price $direction";
}
break;
default:
$sort_string = "$sql_tbl[products_lng_current].product";
}//replace with
//find the code
switch ($data['sort_field']) {
case 'productcode':
$sort_string = "instock DESC, $sql_tbl[products].productcode $direction";
break;
case 'title':
$sort_string = "instock DESC, $sql_tbl[products_lng_current].product $direction";
break;
case 'orderby':
$sort_string = "instock DESC, $sql_tbl[products_categories].orderby $direction";
break;
case 'sales_stats':
$inner_joins['product_sales_stats'] = array(
'on' => "$sql_tbl[product_sales_stats].productid = $sql_tbl[products].productid",
'only_select' => TRUE,
);
$sort_string = "instock DESC, $sql_tbl[product_sales_stats].sales_stats $direction";
break;
case 'quantity':
$sort_string = empty($active_modules['Product_Options'])
? "$sql_tbl[products].avail $direction"
: XCVariantsSQL::getVariantField('avail') . " $direction";
break;
case 'price':
if (
!empty($active_modules['Special_Offers'])
&& isset($search_data['products']['show_special_prices'])
&& $search_data['products']['show_special_prices']
) {
$sort_string = "x_special_price $direction, price $direction";
} else {
$sort_string = "instock DESC, price $direction";
}
break;
default:
$sort_string = "instock DESC, $sql_tbl[products_lng_current].product";
}After this make sure you clear cache in the maintenance>tools section.