Ruslan Brest, rb.labtodo.com

Разработка ПО, сайтов и веб-сервисов. CodeIgniter, PHP, MySQL, W3C CSS/XHTML, MaxSite CMS, OpenCart, PrestaShop

Улучшение поиска в OpenCart 1.5: поиск по описанию, подкатегориям, по модели и SKU

Опубликовано: 3 июля 2011.
Автор: Ruslan Brest.

Рубрика: Howto | E-commerce | OpenCart.

Просмотров: 2650.
Подписаться на комментарии по RSS.

По умолчанию поиск в OpenCart производится только по названиям продуктов. Что довольно неудобно для покупателя и не оправдано, если продуктов на сайте не так уж и много (думаю, на нескольких сотнях наименований никакой разницы не будет заметно).

Поиск по описаниям и подкатегориям

На странице расширенного поиска есть возможность включить поиск по описаниям товаров и во всех категориях, но по умолчанию эти опции отключены и чаще всего пользователь видит отсутствие результатов.

Для того, чтобы исправить поведение поиска по умолчанию в версиях OpenCart от v1.5.0.5 до 1.5.2 (а может и в более поздних, но на данный момент я знаю только про эти), надо отредактировать файл catalog/view/javascript/common.js:

строки #9 и #22 изменить с

url += '&filter_name=' + encodeURIComponent(filter_name);

на

url += '&filter_name=' + encodeURIComponent(filter_name) +
'&filter_sub_category=true&filter_description=true';

Поиск по модели и SKU (артикулу) - вариант для версий 1.5.0.5 - 1.5.1.2 и может более ранних 1.5.x

Чтобы добавить поиск по модели и SKU (артикулу), надо модифицировать ещё один файл:

commit 56a765ccb474075b7073f11474100e2251e0d762
Author: Ruslan Brest <rb@labtodo.com>
Date:   Mon Sep 5 11:55:51 2011 +0300
    [+] catalog: search: добавлен поиск по модели и SKU
diff --git a/public_html/catalog/model/catalog/product.php b/public_html/catalog/model/catalog/product.php
index 520bc34..e9a3d73 100644
--- a/public_html/catalog/model/catalog/product.php
+++ b/public_html/catalog/model/catalog/product.php
@@ -106,10 +106,12 @@ class ModelCatalogProduct extends Model {
 			. (int)$this->config->get('config_store_id') . "'";
 
 			if (isset($data['filter_name']) && $data['filter_name']) {
+				$sFilterName = $this->db->escape(mb_strtolower($data['filter_name'], 'UTF-8'));
+				$sql_search_model_sku = 'LCASE(p.model) LIKE "%' . $sFilterName . '%" OR LCASE(p.sku) LIKE "%' . $sFilterName . '%"';
 				if (isset($data['filter_description']) && $data['filter_description']) {
-					$sql .= " AND (LCASE(pd.name) LIKE '%" . $this->db->escape(mb_strtolower($data['filter_name'], 'UTF-8')) . "%' OR p.product_id IN (SELECT pt.product_id FROM " . DB_PREFIX . "product_tag pt WHERE pt.language_id = '" . (int)$this->config->get('config_language_id') . "' AND LCASE(pt.tag) LIKE '%" . $this->db->escape(mb_strtolower($data['filter_name'], 'UTF-8')) . "%') OR LCASE(pd.description) LIKE '%" . $this->db->escape(mb_strtolower($data['filter_name'], 'UTF-8')) . "%')";
+					$sql .= " AND (".$sql_search_model_sku." OR LCASE(pd.name) LIKE '%" . $sFilterName . "%' OR p.product_id IN (SELECT pt.product_id FROM " . DB_PREFIX . "product_tag pt WHERE pt.language_id = '" . (int)$this->config->get('config_language_id') . "' AND LCASE(pt.tag) LIKE '%" . $sFilterName . "%') OR LCASE(pd.description) LIKE '%" . $sFilterName . "%')";
 				} else {
-					$sql .= " AND (LCASE(pd.name) LIKE '%" . $this->db->escape(mb_strtolower($data['filter_name'], 'UTF-8')) . "%' OR p.product_id IN (SELECT pt.product_id FROM " . DB_PREFIX . "product_tag pt WHERE pt.language_id = '" . (int)$this->config->get('config_language_id') . "' AND LCASE(pt.tag) LIKE '%" . $this->db->escape(mb_strtolower($data['filter_name'], 'UTF-8')) . "%'))";
+					$sql .= " AND (".$sql_search_model_sku." OR LCASE(pd.name) LIKE '%" . $sFilterName . "%' OR p.product_id IN (SELECT pt.product_id FROM " . DB_PREFIX . "product_tag pt WHERE pt.language_id = '" . (int)$this->config->get('config_language_id') . "' AND LCASE(pt.tag) LIKE '%" . $sFilterName . "%'))";
 				}
 			}

Поиск по модели и SKU (артикулу) - вариант для версии 1.5.1.3 (и наверное выше)

commit 77611b6dcad3fb21484c889bb7726688cb68de34
Author: Ruslan Brest <rb@labtodo.com>
Date:   Mon Oct 10 11:58:24 2011 +0300
    [+] catalog: search by model and SKU
diff --git a/upload/catalog/model/catalog/product.php b/upload/catalog/model/catalog/product.php
index 25a7861..a9ed128 100644
--- a/upload/catalog/model/catalog/product.php
+++ b/upload/catalog/model/catalog/product.php
@@ -54,13 +54,19 @@ class ModelCatalogProduct extends Model {
 					$implode = array();
 					
 					$words = explode(' ', $data['filter_name']);
 					foreach ($words as $word) {
-						if (!empty($data['filter_description'])) {
-							$implode[] = "LCASE(pd.name) LIKE '%" . $this->db->escape(utf8_strtolower($word)) . "%' OR LCASE(pd.description) LIKE '%" . $this->db->escape(utf8_strtolower($word)) . "%'";
-						} else {
-							$implode[] = "LCASE(pd.name) LIKE '%" . $this->db->escape(utf8_strtolower($word)) . "%'";
-						}				
+						if( !empty($word) )
+						{
+							$lword = $this->db->escape(utf8_strtolower(trim($word)));
+							// Add search by model and SKU
+							$implode[] = 'LCASE(p.model) LIKE "%' . $lword . '%" OR LCASE(p.sku) LIKE "%' . $lword . '%"';
+							if (!empty($data['filter_description'])) {
+								$implode[] = "LCASE(pd.name) LIKE '%" . $lword . "%' OR LCASE(pd.description) LIKE '%" . $lword . "%'";
+							} else {
+								$implode[] = "LCASE(pd.name) LIKE '%" . $lword . "%'";
+							}
+						}
 					}
 					
 					if ($implode) {

А как же админка? Там тоже SKU не хватает!

Можете также добавить возможность поиска по SKU в админ-зоне магазина.

twitter.com facebook.com vkontakte.ru odnoklassniki.ru mail.ru ya.ru digg.com friendfeed.com liveinternet.ru livejournal.ru yandex.ru del.icio.us

Комментариев: 44

  1. Владимир
    05.09.2011 в 23:34:02 | #1

    Поиск по модели и SKU (артикулу)

    все хорошо, но какой файл модифицировать то? модифицировать - ? изменить или заменить?

  2. Ruslan Brest
    06.09.2011 в 09:35:45 | #2

    Файл - catalog/model/catalog/product.php

    @@ -106,10 +106,12 @@ -- строки, т.е. примерно на 106 строке вы должны найти похожий кусок кода, перед и после блока изменений обычно выводится пара строк текста. "Примерно 106" - потому что я множество правок вношу в свой магазин и содержимое файлов может не совпадать с оригинальным OpenCart 1.5.1.1.

    Правки индицируются значками "-" и "+" в самом начале строки: те, что с минусом, были убраны (они должны совпадать с тем, что вы у себя видите перед внесением изменений), а те, что с плюсом -- добавлены в это место. Поэтому можно руками внести и проконтролировать все изменения.

  3. 05.10.2011 в 22:09:44 | #3

    Спасибо огромное

  4. 05.10.2011 в 22:10:19 | #4

    Как вот еще отдельный столбец по SKU в админке получить можно.

    А то поле есть,а по нему работать в списке - нельзя 8(

  5. Ruslan Brest
    06.10.2011 в 09:33:36 | #5

    Марат, это не проблема - сам об этом думал, собирался добавлять. У нас в магазине основное поле -- уникальный SKU. Колонка модели лично нам вообще не нужна (разве что если захочется сортировать по ней), поскольку номер модели включается в название товара и поиск по нему после моих модификаций производится без проблем и в колонке названия.

    Поэтому вопрос лишь в реализации. Добавлять ли ещё колонку (с поиском и сортировкой) или просто вывести SKU где-то для информации (под названием например). Или поле модель убрать. Этого делать не хочется, но ещё меньше хочется возиться с появляющейся горизонтальной прокруткой при расширении таблицы. Ну или подправить вёрстку в админке, сделав её более "резиновой" и без DIV-а со скроллом. Если и скролл, то пусть лучше у броузера - им хоть пользоваться удобней на невысоких экранах (нетбуки например).

  6. 06.10.2011 в 10:01:47 | #6

    Да пусть будет скролл. Это не так страшно.

  7. 06.10.2011 в 21:54:31 | #7

    В 1.5.1.3 уже не работает.

    Там теперь код другой. Что делать?

  8. Ruslan Brest
    07.10.2011 в 08:38:21 | #8

    Спасибо, посмотрю на выходных 1.5.1.3

  9. 09.10.2011 в 18:28:50 | #9

    Руслан, может денежку надо?

  10. Ruslan Brest
    09.10.2011 в 19:14:34 | #10

    Я, конечно, люблю денежку, но тормозит не это. Сейчас у меня очень сложно со временем. Вдобавок к этому 1.5.1.3 значительно менялась, и мне надо аккуратно сравнить её и влить в мою копию с изменениями. Это не очень просто.

    Можно поставить рядом чистый 1.5.1.3 и разносить правки... Не очень хотелось на это идти (потом ещё и с третьей копией синхронизировать, если парни успеют следующую стабильную версию опубликовать). Но видимо так всё же быстрей получится.

  11. 10.10.2011 в 01:22:33 | #11

    Да там они форму запроса изменили.

    if (!empty($data['filter_name']) || !empty($data['filter_tag'])) {

    $sql .= " AND (";

    ... и т.д.

    Вот почему они сразу не могут сделать нормальный поиск? Я диву даюсь.

    Без поиска по SKU я совсем пропадаю. Обновился на свое горе до 1.5.1.3

    Кстати, Color Options в 1.5.1.3 не идеальный. Есть что поковырять для опенкарт маркета. )))

  12. Ruslan Brest
    10.10.2011 в 02:01:44 | #12

    Обновил пост, вроде работает. Не делают наверное потому, что поиск по SKU покупателями - довольно редкая идея. А вот в админке да, странно что нет.

    В админке тоже ничего сложного нет, но у меня уже глаза слипаются. Отвлекали по делам, поэтому только в каталоге сделал.

  13. 10.10.2011 в 10:03:05 | #13

    Мне для фронтенда достаточно.

    Сколько куда перевести?

  14. Ruslan Brest
    10.10.2011 в 15:12:38 | #14

    Спасибо :) Изменение мелкое, так что это совсем необязательно.

    Если очень хочется - любой из указанных способов мне удобен (PayPal, Webmoney). Про пайпэл немного описано на странице "Обо мне". А сколько - личное дело каждого.

    Добавил сегодня SKU ещё в админку - см. http://rb.labtodo.com/page/opencart-admin-sku-column

    Если 1.5.1.3 свежая и не успела обрасти изменениями, можно файлы из "admin" поверх скопировать, чтобы вручную не править.

  15. 18.11.2011 в 14:20:44 | #15

    Без поиска по SKU ищет 1 сек.

    Добавил поиск по sku начинает тормозить поиск ищет 4 сек.

    Даже если делаешь только по SKU поиск (т.е. убираешь поиск по полю name) также ищет 4 сек.

    Посоветовали добавить индекс ALTER TABLE `opencart_product` ADD INDEX ( `sku` )

    Вместо "opencart_" свой префикс поставьте

    Помогите пожалуйста.

    Заранее спасибо.

  16. Ruslan Brest
    18.11.2011 в 15:05:35 | #16

    Это я и советовал. Не видя реальную базу, очень сложно гадать, в чём причина и действительно ли с индексом и без него скорость одинакова. В то, что наличие индекса никак не влияет на скорость - не верится.

    В 1.5.1.3 поиск изменён, поэтому причина может быть ещё и в появившихся доп. условиях и для больших баз надо изучать ситуацию внимательней. Но первым делом желательно всё же исключить ошибку по первой версии и убедиться, что индекс точно добавлен в таблице.

  17. 18.11.2011 в 16:49:13 | #17

    Подскажите пожалуйста. Я нашёл решение для себя. Но как реализовать?

    У меня есть номер 0443812300 (так он забит в базу) как сделать если человек ввёл в поиск 04438-12300 или так 04438-123-00 он игнорировал пробелы и тире и находил нужный номер?

  18. Ruslan Brest
    18.11.2011 в 17:35:35 | #18

    Если запрос будет только в указанном виде, то в файле catalog/controller/product/search.php в самом начале найдите

    if (isset($this->request->get['filter_name'])) {

    $filter_name = $this->request->get['filter_name'];

    } else {

    $filter_name = '';

    }

    и после $filter_name = $this->request->get['filter_name']; добавьте пару строк:

    $ubiraem = array('-', ' ');

    $filter_name = str_replace($ubiraem, '', $filter_name);

  19. 06.12.2011 в 18:20:09 | #19

    Спасибо вам большое. Я опять к вам за советом.

    Проблема такая.

    Когда я захожу в админке в список категорий то:

    Ужасно тормозит, чем больше товаров тем сильнее тормозит.

    И вот, доавил ещё товаров вылезла ошибка

    SELECT * FROM product p LEFT JOIN product_description pd ON (p.product_id = pd.product_id) WHERE pd.language_id = '1' GROUP BY p.product_id ORDER BY pd.name ASC LIMIT 0,1000 in /home/a/avtodubai/oae-avto.ru/public_html/system/database/mysql.php on line 49

    если постаить отображение 10 товаров в админке, то ошибка исчезает, но тормозит всё равно ужасно\

    Вот что ответила служба поддержки хостинга.

    Мы проверили выполнение приведенного SQL-запроса и обнаружили что данные, которые скрипт пытается выгрузить в /tmp превышает размер серверного раздела /tmp (4G). Поэтому выполнение запроса завершается с ошибкой.

    Вы можете отредактировать настройки Вашего сайта так, чтобы запись производилась на дисковое пространство Вашего аккаунта или же оптимизировать скрипт выводящий товары.

    Подскажите что нужно сделать прямо таки не к кому больше обратиться.

    Заранее спасибо.

  20. Ruslan Brest
    06.12.2011 в 19:17:16 | #20

    Как раз только что в форуме ответил. Лучше там продолжим - у меня сейчас слишком плохо со временем, а там может ещё кто-то присоединится и подскажет.

  21. Олег
    09.01.2012 в 14:43:25 | #21

    Добрый вечер, а возможно расширенный поиск разместить на главной, и как это сделать если возможно?

  22. Ruslan Brest
    09.01.2012 в 16:05:39 | #22

    Олег, наверное проще всего будет оформитьстраницу поиска так же, как главную (обвесить её боковыми панелями и т.п.) и настроить редирект на неё.

  23. Максим
    12.02.2012 в 13:39:06 | #23

    Что нужно сделать, чтоб оставить поиск только по артикулу? То есть исключить поиск по модели?

  24. Ruslan Brest
    12.02.2012 в 13:51:34 | #24

    Укоротить соответствующую строчку:

    v1.5.1.3:

    $implode[] = 'LCASE(p.sku) LIKE "%' . $lword . '%"';

    v1.5.1.2 / ocStore 1.0.1:

    $sql_search_model_sku = 'LCASE(p.sku) LIKE "%' . $sFilterName . '%"';

  25. 12.02.2012 в 18:15:13 | #25

    Добрый день, Руслан. Спасибо, за очень полезный пост! Только вот возникла проблема с поиском товара, если искать по артикулу - находит нужную позицию и "все четко", но если вводить название товара полностью (как указано в админке), то находит кучу позиций и нужная не всегда располагается на первой странице поиска. Не знаете в чем может быть дело?

  26. 12.02.2012 в 23:27:05 | #26

    Присоединяюсь к Deus

    Точно такая же проблема. Помогите с решением.

  27. 13.02.2012 в 11:14:33 | #27

    Еще у меня есть такая проблема.

    Сначала сделал так,

    $ubiraem = array('-', ' ');

    $filter_name = str_replace($ubiraem, '', $filter_name); (как было описано ранее)

    Когда я в ПОИСКЕ ввожу например "adventure 3", то пишет "Нет товаров, которые соответствуют критериям поиска.". Но если Я сразу нажимаю опять поиск (в раширеном), то все находит, (потому что уже пробел удалился).

    Как сделать чтобы он сразу учитывался. Чтобы клиенты по два раза не нажимали поиск.?

  28. 24.02.2012 в 19:03:37 | #28

    Спасибо за статью,подскажите, а как реализовать поиск по названию каталогов (категорий), в которых находится товар?

  29. Алексей
    27.02.2012 в 12:18:53 | #29

    Сделал то что указано тут: Улучшение поиска в OpenCart 1.5: поиск по описанию, подкатегориям, по модели и SKU

    Но что-то не работает, т.е. ввожу запрос, строчку из описания товара в главный поиск, ничего не находит, появляется форма расширенного поиска с тем же запросом, ставлю 2 галочки (искать в описании и подкатегориях) делаю опять поиск и находит нужный товар. Что не так, почему после указанной правки при основном поиске не находятся эти результаты? как сделать что поиск работал по умолчанию по описанию товаров и в подкатегориях?

  30. Ruslan Brest
    27.02.2012 в 12:53:25 | #30

    @Алексей: Сайт покажите. Как я могу угадать, что там не так?

    @mx: позже постараюсь ответить про поиск по категориям, времени нет.

  31. 27.02.2012 в 14:52:56 | #31

    Спасибо! Жду с нетерпением!:)

  32. Алексей
    28.02.2012 в 00:14:13 | #32

    магазин в стадии разработки, я побовал у себя на локалке, но программист который мне помогает запустить магазин пробовал на демо магазине на хосте, вот ссылка

    http://test.life-happy.org.ua/

    ---- rb: ----

    Открываем http://test.life-happy.org.ua/catalog/view/javascript/common.js

    Не вижу, чтобы указанные изменения были внесены. Потому и не работает.

  33. Алексей
    28.02.2012 в 13:02:47 | #33

    Спасибо за подсказку. Действительно программист, почему то решил сделать последнюю правку с Вашей страницы, так как она указана что подходит под 1.5.1.3 а косательно поиска по содержанию в описании, так не указано что работает в 1.5.1.3 не стал делать :))))ох уж эти программисты :) Но странно почему не локалке не работало, хотя та же причина была, файл не заменился, хотя я правил его... сегодня еще раз сделал, работает и там и там. Большое Вам спасибо.

  34. Сергей
    21.03.2012 в 23:09:53 | #34

    Руслан, подскажите, пож-та, как можно сделать, чтобы при поиске строки с пробелом в конце, пробел не учитывался (например, "сладкие ватрушки ")? Из-за этого пробела, в поиск попадают все товары

  35. Ruslan Brest
    22.03.2012 в 00:45:30 | #35

    Действительно. Исправил код для версии 1.5.1.3

  36. Сергей
    22.03.2012 в 01:17:43 | #36

    Руслан, спасибо за фикс...Очень быстро и оперативно отреагировали...

  37. Сергей
    22.03.2012 в 01:52:36 | #37

    Чуть ещё потестировал. При введении в поиск одного или нескольких пробелов выпадает ошибка и выводится полный текст SQL-запроса.

    С ув.

  38. Ruslan Brest
    22.03.2012 в 02:39:12 | #38

    Маловероятно. В коде я не вижу никаких предпосылок для возникновения таких проблем. Воспроизвести у себя не могу. Ни с несколькими словами с кучей пробелов между ними, ни со строкой поиска, состоящей только из пробелов или одного пробела.

    Проверьте, может неправильно перенесли исправления?

  39. Сергей
    22.03.2012 в 12:41:50 | #39

    Вроде всё правильно перенёс.

    Вот такая ошибка:

    Notice: Error: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'OR LCASE(pt.tag) LIKE '% %' AND pt.language_id = '1' OR LCASE(pt.tag) LIKE '% ' at line 1

    Error No: 1064

    SELECT p.product_id, (SELECT AVG(rating) AS total FROM review r1 WHERE r1.product_id = p.product_id AND r1.status = '1' GROUP BY r1.product_id) AS rating FROM product p LEFT JOIN product_description pd ON (p.product_id = pd.product_id) LEFT JOIN product_to_store p2s ON (p.product_id = p2s.product_id) LEFT JOIN product_tag pt ON (p.product_id = pt.product_id) WHERE pd.language_id = '1' AND p.status = '1' AND p.date_available

  40. Ruslan Brest
    22.03.2012 в 13:32:53 | #40

    Ну вот, в ошибке я вижу проблемы с pt.tag - а этого нет и в помине в версии для 1.5.1.3. Я же писал, что только её исправлял - в ней реализован поиск по отдельным словам, я думал речь о ней.

    На более реаннюю версию не смотрел - но там и поиска по отдельным словам нет. Так что определитесь сначала, какая точно у вас версия движка и те ли изменения вы вносили. Потому что приведенная ошибка соответствует коду для 1.5.1 - там как раз и поиск по тегу виднеется.

    Если ничего с версиями не напутали - внесите ещё и там проверку после $sFilterName = ... на пустую строку. Чтобы если пустая - к SQL запросу ничего не дописывалось. Что-то вроде

    if( !empty(trim($sFilterName)) ) и дальше скобочки по смыслу.

    Но поиска по отдельным словам это не добавит. До версии 1513 поиск велся полностью по введенной фразе, и я это не менял.

  41. Сергей
    22.03.2012 в 14:01:17 | #41

    У меня версия ocSrore 1.5.1.3 с последними изменениями из SVN (r357). Может быть, команда ocSrore этот файл оставила от более ранних версий?

    Изменения для поиска делал следующие:

    1) В файле catalog/view/javascript/common.js , как написано в начале Вашей статьи

    2) В файде catalog/model/catalog/product.php как написано в конце Вашей статьи

    Сейчас у меня, в СВН ocStore, в оригинальном OpenCart 1.5.1.3 в файле catalog/model/catalog/product.php нет переменной $sFilterName.

    Создал тему на форуме ocStore (http://opencartforum.ru/topic/8011-поиск-в-ocstore-1513/), предлагаю перенести обсуждения туда.

  42. Ruslan Brest
    22.03.2012 в 14:57:38 | #42

    В ocStore код поиска такой же, как в Opencart 1513. Просмотрите мои правки для этой версии - там нет поиска по тегам. Только SKU, model, name и description. Если взглянете на своё сообщение об ошибке, то увидите там спотыкание рядом с pt.tag. То есть скорей всего всё же напутано что-то с кодом и версиями.

    $sFilterName и не должно быть -- про неё я писал, думая, что вы используете более раннюю версию движка. Она там была мной добавлена. В общем, забудьте про эту переменную. Просто возьмите оригинальный файл из SVN и исправьте его заново правками для этой версии (самый низ статьи).

    Если опять возникнет проблема - я внесу сейчас это в dev branch ocStore на гитхабе, см. https://github.com/rb2/ocstoreru/blob/dev/trunk/catalog/model/catalog/product.php#L56

    Возьмёте тогда оттуда этот файл.

  43. Виталий
    22.03.2012 в 19:27:35 | #43

    Руслан,

    не подскажите, как с таблицу результатов поиска добавить отображение производителя (в виде ссылки) для каждого из найденных товаров?

    Спасибо,

    Виталий.

  44. Ruslan Brest
    22.03.2012 в 20:14:19 | #44

    Спросите на форуме, пожалуйста - вопрос простой, там минимум десяток человек легко на него ответят. Я работать не успеваю.

Оставьте комментарий!

Гость
Комментатор / хотите им стать

Чтобы стать комментатором, введите email и пароль. Напишите комментарий. В дальнейшем ваша связка email-пароль позволит комментировать, получать уведомления об ответах и редактировать свои данные. Не забудьте про активацию (инструкция придёт на email, указанный при регистрации).

Авторизация: Facebook. MaxSiteAuth. Loginza

(обязательно)