Opencart. Товары с ценой "0" в конце списка + BrainyFilter | NikonoroW.ru

Opencart. Товары с ценой «0» в конце списка + BrainyFilter — цена 0 рублей (или нулевая цена любой другой валюты) для товара в магазине на базе Opencart (OcStore) может использоваться с разной целью. Например, цена на товар меняется очень быстро и в некоторых случаях 0 в цене меняют на фразу «По запросу». А иногда нулевую цену используют как условия для запрета покупки данной вещи, оставляя при этом товар в каталоге для расширения ассортимента и улучшения по SEO. Примеров можно привести достаточно много и каждый использует нулевую цену по-разному.

Однако, товар с ценой «0» в каталоге при сортировке цен «по возрастанию» занимает первые места каталога, а иногда и вовсе портит картину сайта перемешиваясь с остальным товаром, сбивая с толку и нередко раздражая посетителей Вашего сайта. Исправить это можно достаточно быстро.

Изменения вносятся только в 1 файл, а именно в модель продукта, которая находится в директории:

catalog/model/catalog/product.php

В OcStore 2.1 примерно строка 160 метод getProducts(), OcStore 2.3 примерно строка 169 метод getProducts()

Находим фрагмент кода:

		if (isset($data['sort']) && in_array($data['sort'], $sort_data)) {
			if ($data['sort'] == 'pd.name' || $data['sort'] == 'p.model') {
				$sql .= " ORDER BY LCASE(" . $data['sort'] . ")";
			} elseif ($data['sort'] == 'p.price') {
				$sql .= " ORDER BY (CASE WHEN special IS NOT NULL THEN special WHEN discount IS NOT NULL THEN discount ELSE p.price END)";
			} else {
				$sql .= " ORDER BY " . $data['sort'];
			}
		} else {
			$sql .= " ORDER BY p.sort_order";
		}

и меняем его на следующий фрагмент:

		if (isset($data['sort']) && in_array($data['sort'], $sort_data)) {
			if ($data['sort'] == 'pd.name' || $data['sort'] == 'p.model') {
				$sql .= " ORDER BY IF(p.price = '0', 1, 0), LCASE(" . $data['sort'] . ")";
			} elseif ($data['sort'] == 'p.price') {
				$sql .= " ORDER BY IF(p.price = '0', 1, 0), (CASE WHEN special IS NOT NULL THEN special WHEN discount IS NOT NULL THEN discount ELSE p.price END)";
			} else {
				$sql .= " ORDER BY IF(p.price = '0', 1, 0), " . $data['sort'];
			}
		} else {
			$sql .= " ORDER BY IF(p.price = '0', 1, 0), p.sort_order";
		}

Сохраняем, обновляем файл на Вашем сайте. Не забываем обновлять кеш модификаторов! Готово!
Так же можно создать модификатор, не меняя файл product.php напрямую, выглядит он следующим образом:

<?xml version="1.0" encoding="utf-8"?>
<modification>
  <name>Товар с 0 ценой в конец списка</name>
  <code>last_price_null</code>
  <version>1</version>
  <author>valdemariuses</author>
  <link>https://nikonorow.ru/</link>
  <file path="catalog/model/catalog/product.php">
    <operation>
      <search index="0"><![CDATA[if (isset($data['sort']) && in_array($data['sort'], $sort_data)) {]]></search>
      <add position="replace" offset="10"><![CDATA[		if (isset($data['sort']) && in_array($data['sort'], $sort_data)) {
			if ($data['sort'] == 'pd.name' || $data['sort'] == 'p.model') {
				$sql .= " ORDER BY IF(p.price = '0', 1, 0), LCASE(" . $data['sort'] . ")";
			} elseif ($data['sort'] == 'p.price') {
				$sql .= " ORDER BY IF(p.price = '0', 1, 0), (CASE WHEN special IS NOT NULL THEN special WHEN discount IS NOT NULL THEN discount ELSE p.price END)";
			} else {
				$sql .= " ORDER BY IF(p.price = '0', 1, 0), " . $data['sort'];
			}
		} else {
			$sql .= " ORDER BY IF(p.price = '0', 1, 0), p.sort_order";
		}]]></add>
    </operation>
  </file>
</modification>

Данный способ я обнаружил на сайте oc-new.com и благодарю автора под ником valdemariuses за решение проблемы.

Но что делать, если у Вас установлен Brainy Filter или как его еще называют — умный фильтр?

Через стандартную модель product.php и способ сортировки товаров, описанный выше, сделать не получится, поскольку у плагина умного фильтра своя сортировка и она перезаписывает стандартную функцию getProducts. Что же требуется сделать для того, чтобы убрать товар с ценой «0» в конец списка?

Находим модель плагина bf, находится он по следующему адресу:

/catalog/model/extension/module/brainyfilter.php

Ищем функцию prepareQueryForCategory(), выглядит она так:

  public function prepareQueryForCategory()
    {
        $sql = $this->_prepareFilterQuery()->limit($this->productsLimit, $this->productsStart);
        
        $sql->innerJoin(array('pd' => 'product_description'), 'pd.product_id = p.product_id')
            ->where('pd.language_id = ?', (int)$this->config->get('config_language_id'));
        switch ($this->sortBy) 
        {
            case 'pd.name' : {
                $sql->order(array("LCASE(pd.name) {$this->order}"));
                break;
            }
            case 'p.model' : {
                $sql->select(array('pp.model'))->order(array("LCASE(pp.model) {$this->order}"))
                    ->innerJoin(array('pp' => 'product'), 'pp.product_id = p.product_id');
                break;
            }
            case 'p.quantity' : {
                $sql->select(array('pp.quantity'))->order(array("pp.quantity {$this->order}", ))
                    ->innerJoin(array('pp' => 'product'), 'pp.product_id = p.product_id');
                break;
            }
            case 'p.price' : {
                if (self::$SKIP_TMP_TABLE) {
                    $this->_applyPriceFilterCondition($sql);
                }
                $sql->order(array("actual_price {$this->order}"));
                break;
            }
            case 'rating' : {
                $sql->leftJoin(array('f' => self::TBL_FILTER), 'f.product_id = p.product_id')
                    ->where('f.filter_group = "r0"')
                    ->order(array("f.filter_id {$this->order}"));
                break;
            }
            case 'p.sort_order' : {
                $sql->select(array('pp.sort_order'))->order(array("pp.sort_order {$this->order}"))
                    ->innerJoin(array('pp' => 'product'), 'pp.product_id = p.product_id');
                break;
            }
            case 'p.date_added' : {
                $sql->select(array('pp.date_added'))->order(array("pp.date_added {$this->order}"))
                    ->innerJoin(array('pp' => 'product'), 'pp.product_id = p.product_id');
                break;
            }
        }
        
        if ($this->sortBy !== 'pd.name') {
            $sql->order(array("pd.name {$this->order}"));
        } 
        
        return (string)$sql;
    }
    

и после фрагмента:

        if ($this->sortBy !== 'pd.name') {
            $sql->order(array("pd.name {$this->order}"));
        } 

вставляем следующий код:

	if ($this->sortBy == 'p.price') {
		$sql = (string)$sql;
		$pos = strrpos($sql, 'ORDER BY');
		if ($pos !== false) {
			$sql1 = substr($sql,0,$pos);
			$sql2 = str_replace(', pd.name ' . $this->order, '' ,substr($sql,$pos-1 + 9));
			$sql3 = "SELECT * from (" . $sql1 . ") pt " . " ORDER BY actual_price = 0, " . $sql2;
			$sql = $sql3;
		}
	}

Не вижу смысла перестраивать запрос, проще сделать так, пускай и код будет не самым красивым.
Аналогично с первым способом, сохраняем, обновляем файл на Вашем сайте. Не забываем обновлять кеш модификаторов! Готово! Теперь мы подружили Brainy Filter c нужной нам сортировкой нулевой цены.

UPD: Найден способ перемещением товара, которого нет в наличии в конец списка при использовании Brainy Filter. Благодарю Александра Сергеева за то, что написал мне в личные сообщения ВКонтакте. Задача была таковой, цитирую: «стоит сортировка по цене, но надо дополнительно еще было сделать вниз сортировку по количеству, чтобы нулевые вниз ушли».
Итак, приступим:

Как я писал выше, находим модель плагина bf, находится он по следующему адресу:

/catalog/model/extension/module/brainyfilter.php

Изменения в коде модели (описание). Перед строкой:

$sql->order(array("actual_price {$this->order}"));

Добавил:

$sql->order(array("p.quantity=0 {$this->order}")); 

И получилось, что в конце запрос содержит:

... match_filters = 1 ORDER BY actual_price ASC, p.quantity=0 ASC LIMIT 0, 100

Изменения в коде модели (полный фрагмент после применения изменений), заменяем его в самом файле фильтра:

case 'p.price' : {
if (self::$SKIP_TMP_TABLE) {
$this->_applyPriceFilterCondition($sql);
}
$sql->order(array("p.quantity=0 {$this->order}"));
$sql->order(array("actual_price {$this->order}"));

break;
}

Протестировано на OcStore 2.3

Дата создания статьи: 05.06.2021

Рубрика: Веб-разработка

Комментарии

Оставьте Ваше сообщение

Подписаться
Уведомить о
guest
2 Комментарий
Старые
Новые Популярные
Межтекстовые Отзывы
Посмотреть все комментарии
Денис
Денис
1 год назад

Спасибо большое, очень помогли!

Смотрите далее

Ознакомьтесь с другими работами

2
0
Оставьте комментарий! Напишите, что думаете по поводу статьи.x
()
x