Создаём (кастомизируем) свои запросы в Фильтре

Чтоб вывести Товар на страницу сайта в особом виде/порядке (скрыть, отсортировать, интеграция с другим модулем/шаблоном), предусмотрен механизм внедрения собственных Запросов в Фильтр.
Например. - "Нужно отсортировать Товар так, что когда у него цена 0 (ноль), то перемещать его в конец списка".
Для этого нужно вставить (лучше модификатором) в массив параметров $filter_data своё условие.
Пример для контроллера категории:

//стандартный массив параметров контроллера Категории
$filter_data = array(
    'filter_category_id' => $category_id,
    'filter_filter'      => $filter,
    'sort'               => $sort,
    'order'              => $order,
    'start'              => ($page - 1) * $limit,
    'limit'              => $limit
);

/*ВАШ код*/
$filter_data['query_order_by'] = "IF(p.`price` = '0', 1, 0)";
//или можно добавить собственное условие, например, когда будет сортировка по Цене
if($sort == 'p.price') {
    $filter_data['query_order_by'] = "IF(p.`price` = '0', 1, 0)";
}
/*end ВАШ код*/
//запросы к БД - стандартный код Opencart
$product_total = $this->model_catalog_product-> getTotalProducts($filter_data);
$results = $this->model_catalog_product-> getProducts($filter_data);

Пример кода модификатора:

<?xml version="1.0" encoding="utf-8"?>
<modification>
    <name>FIX Price if 0 end in FilterVier_SEO</name>
    <code>fix_price_fv</code>
    <version>1.0</version>
    <author>Vier</author>
    <link></link>
    <file path="catalog/controller/product/category.php">
        <operation>
            <search><![CDATA[$results = $this->model_catalog_product-> getProducts($filter_data);]]></search>
            <add position="before"><![CDATA[
            /*fix_price_fv*/
            if($sort == 'p.price') {$filter_data['query_order_by'] = "IF(p.`price` = '0', 1, 0)";}
            /*end fix_price_fv*/
            ]]></add>
        </operation>
    </file>
</modification>

Пояснение по дополнительным ключам переменной $filter_data для запросов к Фильтру (значения ключей - это примеры):

//для getTotalProducts
$filter_data['query_total_pole'] = " COUNT(DISTINCT IF('ВАШЕ_условие')) AS `total` "; // условие по Полю, и должно возвращать одно поле `total`
$filter_data['query_total_join'] = " LEFT JOIN `".DB_PREFIX."ВАША_таблица` AS tabl2 ON (p.`product_id` = tabl2.`product_id`)"; // JOIN-запрос для подсоединения дополнительной таблицы
$filter_data['query_total_where'] = " tabl2.`pole` > 5 AND p.`pole` = tabl2.`pole` "; // условие в WHERE (вначале без WHERE и AND)
$filter_data['query_total_group_by'] = " GROUP BY tabl2.`pole` "; // Группировка (вначале с GROUP BY)

//для getProducts
$filter_data['query_pole'] = " tabl2.`pole`, tabl2.`pole2` AS `colum` "; // добавить поле (можно несколько через запятую)
$filter_data['query_join'] = " LEFT JOIN `".DB_PREFIX."ВАША_таблица` AS tabl2 ON (p.`product_id` = tabl2.`product_id`)"; // JOIN-запрос для подсоединения дополнительной таблицы
$filter_data['query_where'] = " tabl2.`pole` > 5 AND p.`pole` = tabl2.`pole` "; // условие в WHERE (вначале без WHERE и AND)
$filter_data['query_group_by'] = " GROUP BY tabl2.`pole` "; // Группировка (вначале с GROUP BY)
$filter_data['query_order_by'] = " tabl2.`pole` DESC, `colum` "; // Сортировка (вначале без ORDER BY - можно несколько через запятую)