[mSearch] Фильтрация товаров в MS2

Василий недавно подправил плагин для первого Minishop. Теперь мы можем использовать mSearch и mFilter для MiniShop2.

mSearch работает как и прежде — поиск по страницам с возможностью индексирования TV-полей, а также по полям товаров Minishop2. Чтобы он начал искать от нас требуется немного — проиндексировать один раз страницы сайта. Делается это следующим образом:
[[!mSearch?
	&indexer=`1`
	&limit=`0`
	&indexFields=`pagetitle,longtitle,description,content,article`
]]


Параметр &indexFields=`` нужен, чтобы включить в поиск определенные поля страниц или товаров (например, поле article товара MiniShop2). Вставляем этот вызов на любую страницу и переходим на нее. По прошествии некоторого времени будет показан результат. Теперь можно пользоваться поиском.
Как пользоваться рассказывать не буду — для этого уже создана тема о mSearch.

Лучше расскажу как дружить поиск с фильтром. Для чего это нужно? Допустим, посетитель вашего магазина противогазов и химзащиты ввел в поиске слово «противогаз» и попал на страницу с длинным списком противогазов который сформировал mSearch. По большому счету, пользы никакой. Теперь представьте, что вместе со списком ему предоставляется возможность ползунком определить диапазон цены, цвета противогазов, их вес и степень защиты. Делается это следующим образом:

1. Если еще не проиндексировали страницы — делаем это.
2. Размещаем на наших страницах форму поиска
<form class="form-inline" action="[[~idстраницы_с_фильтром]]" method="get">
	<input type="text" class="search-query" name="query" placeholder="поиск..." value="[[+mse.query]]" />
	<button type="submit" class="btn"><i class="icon-search"></i></button>
</form>
3. Создаем страницу (Назовем её «Результаты поиска») вывода результатов, на которую будут попадать ищущие. :) Айди (ID) созданной страницы и нужно вписать в атрибут action= вышеприведенной формы.
4. На созданной странице Результатов поиска выводим чанк [[$mFilter]]
У меня он следующего содержания —
<div class="row">
	<div class="span3">
		<div class="filter">
			<form action="[[~[[*id]]]]" method="post" id="mFilter">
				[[!mFilter?
					&resources=``
					&includeTVs=`0`
					&includeMS=`1`
					&includeMSList=`price,new,favorite,popular,size,color`
					&sortFilters=`ms_new,ms_favorite,ms_popular,ms_size,ms_color,ms_price`
					&tpl=`tpl.msProducts.row`
				]]
				<input type="hidden" name="query" value="[[+mse.query]]">
				<input type="hidden" name="page" value="1">
				<input type="hidden" name="sort" value="ms_price,asc">
				<input type="hidden" name="limit" value="3">
				<input type="hidden" name="parents" value="[[+parents]]">
				<input type="hidden" name="action" value="filter" />
			</form>
		</div><!-- end_filter -->
	</div>
	<div class="span9" id="mItems"></div>
</div>

<link href="http://yandex.st/jquery-ui/1.10.3/themes/smoothness/jquery-ui.min.css" rel="stylesheet" />
<script src="http://yandex.st/jquery-ui/1.10.3/jquery-ui.min.js" type="text/javascript"></script>
<script src="/assets/components/msearch/js/mfilter.js" type="text/javascript"></script>

Основные параметры mFilter:
&resources — список ресурсов для работы, через запятую. Использует ID ресурсов, а не родителей. Если не указать, будет выводить результаты нашего с вами поиска в mSearch.
&includeTVs — включить ТВ для отображения фильтрации по ним
&includeTVList — использовать эти ТВ, через запятую
&excludeTVList — не использовать эти ТВ, через запятую
&includeMS — брать параметры miniShop2 для построения фильтра
&includeMSList — какие именно поля товаров miniShop2 выводить для фильтрации
&sortFilters — порядок вывода фильтров, с префиксами, например: `tv_category,tv_subcategory,ms_add2,tv_color,tv_size,tv_action,ms_price`
+ если будете искать ресурсы, то любые параметры mSearch
+ любые параметры getPage и\или getResources\msGetResources

Для вывода результатов фильтра необходимы сниппет для вывода и пагинации. В случае работы с MS2 — это getPage и msProducts, по умолчанию.
Для изменения этих сниппетов есть 2 паарметра: &paginator=`` и &snippet=``.

Также требуются jquery плагины:
jQuery 1.7+ — основной помошник
jQueryUI 1.8+ — нужен только виджет slider для цен и других числовых значений
jQuery Form 2.7+ — отправка формы и прием ответа

Помните, что нужно подключать в шаблоне скрипт
<script type="text/javascript" src="/assets/components/minishop2/js/web/default.js"></script>
и объявить для него функцию
<script type="text/javascript">
	miniShop2Config = {
		cssUrl: "/assets/components/minishop2/css/web/"
		,jsUrl: "/assets/components/minishop2/js/web/"
		,imagesUrl: "/assets/components/minishop2/images/web/"
		,actionUrl: "/assets/components/minishop2/action.php"
		,ctx: "web"
		,close_all_message: "закрыть все"
		,price_format: [2, ".", " "]
		,price_format_no_zeros: 0
		,weight_format: [3, ".", " "]
		,weight_format_no_zeros: 1
	};
</script>


Теперь давайте рассмотрим случай, когда мы хотим выводить фильтр по умолчанию, например при загрузке страницы-категории товаров, не используя поиск. Для этого добавляем чанк mFilter на страницу-категорию или на любую другую, а в вызов mFilter добавляем сниппет:

<div class="row">
	<div class="span3">
		<div class="filter">
			<form action="[[~[[*id]]]]" method="post" id="mFilter">
				[[!mFilter?
					&resources=`[[!getCatIds?parents=`idкатегории`]]`
					&includeTVs=`0`
					&includeMS=`1`
					&includeMSList=`price,new,favorite,popular,size,color`
					&sortFilters=`ms_new,ms_favorite,ms_popular,ms_size,ms_color,ms_price`
					&tpl=`tpl.msProducts.row`
				]]
				<input type="hidden" name="query" value="[[+mse.query]]">
				<input type="hidden" name="page" value="1">
				<input type="hidden" name="sort" value="ms_price,asc">
				<input type="hidden" name="limit" value="3">
				<input type="hidden" name="parents" value="[[+parents]]">
				<input type="hidden" name="action" value="filter" />
			</form>
		</div><!-- end_filter -->
	</div>
	<div class="span9" id="mItems"></div>
</div>

<link href="http://yandex.st/jquery-ui/1.10.3/themes/smoothness/jquery-ui.min.css" rel="stylesheet" />
<script src="http://yandex.st/jquery-ui/1.10.3/jquery-ui.min.js" type="text/javascript"></script>
<script src="/assets/components/msearch/js/mfilter.js" type="text/javascript"></script>

Как вы видите, в параметре &resources вызывается этот самый сниппет getCatIds. Его код приведен ниже. Все, что нужно сделать — подставить в parents=`` идентификаторы категорий, которые содержат нужные нам товары.

Код сниппета getCatIds:
<?php
if (!empty($_REQUEST['query'])) {
	$modx->setPlaceholder('parents', @$_REQUEST['parents']);
	return;
}

if (!isset($parents) || empty($parents)) {
	$parents = $modx->resource->id;
}
	
if (empty($depth)) {$depth = 1;}
$pids = array_map('trim', explode(',', $parents));
$parents = $pids;
foreach ($pids as $v) {
	if (!is_numeric($v)) {continue;}
	$parents = array_merge($parents, $modx->getChildIds($v, $depth));
}

$ids = array();
$q = $modx->newQuery('msProduct', array('parent:IN' => $parents, 'class_key' => 'msProduct', 'published' => 1, 'deleted' => 0));
$q->select('id');
if ($q->prepare() && $q->stmt->execute()) {
	$ids = $q->stmt->fetchAll(PDO::FETCH_COLUMN);
}

$q = $modx->newQuery('msCategoryMember', array('category_id:IN' => $parents));
$q->select('product_id');
if ($q->prepare() && $q->stmt->execute()) {
	$members = $q->stmt->fetchAll(PDO::FETCH_COLUMN);
}

if (!empty($members)) {$ids = array_merge($ids, $members);}
return implode(',', $ids);

Дополнительная информация по mSearch
Объявление про mFilter
Рабочий пример на minishop2.com

Все приведенные примеры можно посмотреть на том же minishop2 под демо доступом — пользователь demo, пароль demo.

Мануал будет дополняться.

Следующая заметка
[Tickets] Версия 1.0.0 rc2
Предыдущая заметка
mSearch1 в нашем репозитории


Комментарии ()

  1. Василий Наумкин 27 мая 2013, 06:25 # 0
    Спасибо за мануал! Перенес в другой раздел и немного отредактировал.

    Одно замечание: мне кажется, что miniShop2Config для работы фильтра не обязателен. Во всяком случае, при адаптации я не менял скрипты фронтенда, и никаких зависимостей не вносил. У тебя, наверное, был какой-то jquery конфликт.

    В любом случае, этот конфиг появляется в странице при обычном вызове сниппета миникорзины.
    1. Wassi Wassinen 27 мая 2013, 17:42 # 0
      Рад помочь. По мере более глубокого изучения фильтрации буду дополнять. Дополню пассивным фильтром (фильтр не выводит продукты, пока не будет нажата кнопка «Фильтровать» или не поменяется один из переключателей фильтра).
      1. Wassi Wassinen 27 мая 2013, 20:04 # 0
        Кстати, Василий, для того, чтобы по-умолчанию грузился контент страницы, а не отфильтрованные товары, нужно просто поменять событие в скрипте и все?
        1. Василий Наумкин 27 мая 2013, 20:09 # 0
          Моя твоя не понимай. С выводом контента давай как-нибудь сам, ладно?
          1. Wassi Wassinen 27 мая 2013, 20:15 # 0
            **пожал плечами** Ладно :)
        2. Сергей Шлоков 01 июня 2013, 14:45 # 0
          В 3-м абзаце статьи ссылка на mSearch битая.
          1. Василий Наумкин 01 июня 2013, 15:08 # 0
            Fixed.
        3. Andrey 27 мая 2013, 11:41 # 0
          Дополнительная информация по mSearch
          Объявление про mFilter
          Рабочий пример на minishop2.com
          Ссылки битые, поправьте пожалуйста.
          1. Василий Наумкин 27 мая 2013, 14:06 # 0
            Поправил.
          2. Александр Котлов 27 мая 2013, 11:47 # 0
            Кстати на минишоп2ком странно работает — можно выделить популярный «YES» и «NO» одновременно. Или это так надо?
            1. Василий Наумкин 27 мая 2013, 14:06 # 0
              Есть товары популярные, есть непопулярные — можно показать и те и другие одновременно. Почему нет?
              1. Александр Котлов 27 мая 2013, 23:16 # 0
                Что то я на момент написания вопроса кофе мало выпил и тупил)))
            2. Александр Котлов 28 мая 2013, 01:44 # 0
              Или я чего-то не понимаю, или тут в первом примере чанка фильтра ошибка:

              [[!mFilter?
              &resources=` ` ?????????? 
              &includeTVs=`0`
              Если я правильно понял, в связке мфильтр + поиск фильтр просто показывает то, что попадает под [[+mse.query]] которое ему поиск передает. И для работы ему список ресурсов которые проверяться будут ему нужен.

              Или опять туплю?
              1. Wassi Wassinen 28 мая 2013, 04:03 # 0
                Если выборка после поиска должна вестись только по определенным ресурсам — да, нужно оставить сниппет getCatIds.
                1. Василий Наумкин 28 мая 2013, 06:05 # 0
                  resources работает, если нет query.
                2. Кирилл 28 мая 2013, 14:05 # 0
                  Господа, прошу Вас обратить внимание на мои молитвы :)
                  В этом посту я описал проблему: bezumkin.ru/sections/help/1169/
                  Сделал все по инструкции (пока только на поиск), но выводит некорректно. Например на поиск по «5000» выводит меню выборки цен. %) Как быть? Помогите, молю! :)
                  1. Сергей Шлоков 28 мая 2013, 18:11 # 0
                    Помните, что нужно подключать в шаблоне скрипт
                    <script type="text/javascript" src="/assets/components/minishop2/js/web/default.js"></script>
                    и объявить для него функцию
                    А если не стоит MS2, то фильтр работать не будет?
                    1. Василий Наумкин 28 мая 2013, 18:36 # 0
                      Прочитай первый комментарий.
                      1. Сергей Шлоков 28 мая 2013, 18:48 # 0
                        Я подозревал это.:) Тогда будем обновляться!
                        1. Василий Наумкин 28 мая 2013, 18:49 # 0
                          Ты только имей в виду, что принципиальных отличий для работы с неMS2 нет.

                          Так, пара опечаток поправлено. С MS1 же эта версия не работает вовсе.
                          1. Сергей Шлоков 29 мая 2013, 11:01 # 0
                            Маэстро, вопрос не по теме. В шаблонах minishop2.com есть такая строчка:
                            [[[[*id:isnot=`[[++site_start]]`:then=`$Breadcrumb`:else=`--`]]]]
                            Может быть имелось ввиду:
                            [[*id:isnot=`[[++site_start]]`:then=`[[$Breadcrumb]]`:else=`--`]]
                            1. Василий Наумкин 29 мая 2013, 12:33 # 0
                              Неа. Подумай на досуге, в чем хитрость =)

                              Даю подскаpку: в твоем условии Breadcrumb выполняется всегда.
                              1. Сергей Шлоков 30 мая 2013, 09:27 # 0
                                Неведомо мне твое колдовство. :) У меня почти такая же конструкция:
                                [[*id:isnot=`[[++site_start]]`:then=`[[$breadcrumb]]`:else=``]]
                                Все работает.
                                1. Василий Наумкин 30 мая 2013, 09:39 # 0
                                  Оно и будет работать, но при твоем вызове чанк Breadcrumb выполняется всегда (со всем содержимым), а при моём — только если срабатывает условие. А если не срабатывает — выходит отключенный пустой чанк [[$--]], который просто пропускается парсером.

                                  Мой вариант быстрее, вот и всё.
                              2. Wassi Wassinen 29 мая 2013, 13:12 # 0
                                Дополню: попробуй вставить [[--]] на любую страницу. :)
                                1. Сергей Шлоков 30 мая 2013, 08:48 # 0
                                  Все пропало. Компьютер накрылся, с работы выгнали, банк разорился, жена ушла к Цигенбогену, в носке дырка. :)
                      2. Марк Львов 29 мая 2013, 14:00 # 0
                        Забавную вещь заметил у вас на демо сайте MS2, при переключении языка сайта, он переключается у всех пользователей, а не только у того, кто его переключал :) Бага? Или так и должно быть?
                        1. Василий Наумкин 29 мая 2013, 14:13 # 0
                          Это не бага, это кэширование.

                          Делал на скорую руку, особо не напрягает.
                        2. Максим Степанов 29 мая 2013, 18:45 # 0
                          Подскажите, можно ли фильтровать товар по дополнительным полям?, к примеру я создал поле «year» и хочу отфильтровать по нему
                          1. Кирилл 30 мая 2013, 11:54 # 0
                            Подскажите пожалуйста как можно вывести фильтрацию товаров по категориям:

                            Пользователь выбирает категорию товара, вводит бюджет ( максимальная цена ) и нажимает поиск. После этого пользователя кидает на страницу с Поиском с выводом этих товаров (по цене)
                            Готов отблагодарить финансово. Заранее благодарю.
                            Для связи: aisve1@yandex.ru
                            1. Николай 09 августа 2013, 12:58 # 0
                              Товарищи, подскажите пожалуйста. Я вывожу обыкновенные ресурсы с помощью mSearch 1.5.1
                              Мне нужно сортировать результаты по дате создания, как это сделать? Я пытался всяко, и в
                              <input type="hidden" name="sort" value="id,asc">
                              писал, и &sortby и как в заметке… по publishedon он не фильтрует что бы я не делал
                              1. Николай 09 августа 2013, 19:46 # 0
                                Я так понимаю единственная сортировка результатов только через input и это или id или price?
                                1. Николай 12 августа 2013, 18:33 # 0
                                  Василий?
                              Добавление новых комментариев отключено.