[mSearch] Фильтрация ресурсов без MS2

Эта заметка в помощь тем, кто хочет настроить фильтрацию вывода ресурсов, как это сделано на сайте minishop2. Как фильтровать товары в minishop2 описано здесь. Я лишь хочу подробнее рассмотреть возможности mFilter для фильтрации ресурсов по TV без установленного компонента minishop2.

Что такое mFilter?
Начинающие творческий путь web-программисты, устанавливая расширение mSearch, могут по незнанию проигнорировать mFilter, входящий в данный пакет.
А ведь mFilter — это красивый ajax-фильтр, дополняющий возможности поиска. И не только. Его можно использовать в двух режимах — с поиском и без. Рассмотрим подробнее второй вариант, так как первый уже подробно разжеван.
И так, давайте начнем. Хочу сразу отметить, что у меня версия mSearch 1.5.1.
Для примера возьмем такую структуру каталога товаров.

У товаров есть 4 TV: price — стоимость, maker — производитель, bronzer — бронзатор, product_image — картинка. Фильтр будем строить по price, bronzer, maker.
Открываем ресурс Косметика и вставляем в него такую строчку
[[$mFilter?&parents=`7` &depth=`2`]]
Чанк вызывается с параметрами:
1. parents — id контейнера с ресурсами для фильтрации. Можно указывать несколько id через запятую. В моем случае, parents=`7` — это контейнер «Косметика».
2. depth=`2` — товары находятся на 2-ом уровне.

Сам чанк у меня выглядит так:
<div class="filter">
     <form action="[[~[[*id]]]]" method="post" id="mFilter">
        [[!mFilter?
                &resources=`[[!getChildId?&parents=`[[+parents]]` &depth=`[[+depth]]`]]`
                &includeTVs=`1`
                &includeTVList=`bronzer,price,maker,product_image`
                &excludeTVList=`product_image`
                &tvPrefix=``
                &tpl=`cosmetics.tpl`
		&sortFilters=`tv_price,tv_maker,tv_bronzer`
                &limit=`4`
                &pageLimit=`5`
                &sortby=`{"parent":"ASC","id":"ASC"}`
               
        ]]
          <input type="hidden" name="query" value="[[+mse.query]]">
          <input type="hidden" name="page" value="1">
          <input type="hidden" name="parents" value="[[+parents]]">
          <input type="hidden" name="action" value="filter">
     </form>
</div><!-- end_filter -->
<div class="mFilter_catalog" id="mItems"></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 отображаемых ресурсов. Id ресурсов мы получаем сниппетом getChildId, переделанный из сниппета getCatIds, входящего в minishop2. Невооруженным глазом видно, что в него передаются параметры вызова чанка mFilter. Это нужно для того, чтобы можно было вызывать один и тот же чанк mFilter, ежели понадобится создать несколько страниц с разными фильтрами. Код сниппета getChildId:
<?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('modResource', array('id:IN' => $parents, 'isfolder' => 0, 'published' => 1, 'deleted' => 0));
$q->select('id');
if ($q->prepare() && $q->stmt->execute()) {
     $ids = $q->stmt->fetchAll(PDO::FETCH_COLUMN);
}

return implode(',', $ids);

Следующие параметры должны быть понятны.
&includeTVs=`1`
&includeTVList=`bronzer,price,maker,product_image`
&excludeTVList=`product_image`
&tvPrefix=``
&tpl=`cosmetics.tpl`

Добавлю только, что в параметр includeTVList нужно передавать не только те TV-шки, по которым фильтруем (bronzer,price,maker), но и те, которые используются в шаблоне (product_image — картинка товара). В параметре excludeTVList указываем TV, по которым не нужно строить фильтр (product_image). Не забываем указывать префикс для TV в шаблоне.
Шаблон cosmetics.tpl
<div class="product">
   <a href="[[~[[+id]]]]">
	<img src="[[+product_image]]" alt="[[+longtitle]]">
	<h3>[[+pagetitle]]</h3>
	<p class="maker">[[+maker]]</p>    
	<p class="price">[[+price]]</p>
   </a>	
</div>

В параметре &sortFilters=`tv_price,tv_maker,tv_bronzer` указываем в какой последовательности выводить фильтры. Обязательно указывать префикс «tv_».
Про &limit=`4`и &pageLimit=`5` все ясно.
А вот с параметром &sortby=`{«parent»:«ASC»,«id»:«ASC»}` не все так просто. Он разбирается в сниппете mFilter по своим правилам и до getResource в таком виде не доходит. Поэтому сниппет придется поправить. Открываем его и редактируем строчку 37
,'sortby' => !empty($_POST['sortby']) ? $_POST['sortby'] : $scriptProperties['sortby']

Хотя если нужно сортировать только по одному полю (например, id), сниппет можно не трогать, а вместо параметра &sortby добавить еще один input:
<input type="hidden" name="sort" value="id,asc">

Почти готово. Осталось подключить плагин jquery.form, без которого форма работать не будет
<script type="text/javascript" src="http://yandex.st/jquery/form/3.14/jquery.form.min.js"></script>
и немного изменить чанк tpl.mFilter.outer
[[+rows]]
<div class="pagination">
    <ul>
          [[+page.nav]]
     </ul>
</div>

Запускаем и получаем красивый фильтр с галочками и слайдером.

На всякий случай скажу, что слайдер рисуется для TV с числовым типом.

Собственно, это всё. Заметка рассчитана на людей, только начинающих свое погружение в мир web-программирования. Но надеюсь, что пригодится и опытным товарищам.

Информация по mSearch и mFilter.
Описание mSearch
Заметка от автора про mSearch и mFilter
Подробнее о том, как фильтровать товары в minishop2

Следующая заметка
[eventsCalendar2] Новая версия - 2.2.4
Предыдущая заметка
[miniShop2] Версия 2.0.1-beta2


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

  1. Алексей Марченко 03 июня 2013, 20:21 # 0
    Спасибо за материал, думаю многим пригодится
    1. Сергей Шлоков 04 июня 2013, 08:52 # 0
      Василий, после редактирования заметка уехала в раздел «Вопросы».
      1. Николай 10 июня 2013, 22:14 # 0
        А постраничная навигация в этом случае работает?

        kedr.ruyou-show.ru/menu/news/

        Просто перезагружается страничка…

        <div class="tagas">
             <form action="[[~[[*id]]]]" method="post" id="mFilter">
                [[!mFilter?
                        &resources=`[[!getChildId?&parents=`[[+parents]]` &depth=`[[+depth]]`]]`
                        &includeTVs=`1`
                        &includeTVList=`tags1,tags2,tags3,tags4,tags5`
                        &tvPrefix=``
                        &tpl=`n_item`
                        &limit=`3`
                        &where=`{"isfolder":"0"}`
                        &tplParamCheckbox=`nw_chykn_checkbox`
                ]]
                  <input type="hidden" name="query" value="[[+mse.query]]">
                  <input type="hidden" name="page" value="1">
                  <input type="hidden" name="sort" value="id,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 -->
        
        <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/mfilternw.js" type="text/javascript"></script>
        
        <script type="text/javascript" src="http://yandex.st/jquery/form/3.14/jquery.form.min.js"></script>
        1. Николай 11 июня 2013, 01:20 # 0
          Разобрался…
        2. Tanya Tretinnikova 23 июня 2013, 12:34 # 0
          Привет, всем!!! Уже больше недели пытаюсь понять в чем моя ошибка при реализации этого фильтра. Делала все по данному описанию.
          	[[$mFilter?&parents=`2` &depth=`2`]] // вызываю фильтр в ресурсе
            <div id="mItems"> // вывожу результаты 
          	[[!getPage?
              	&element=`GetResources`
              	&tpl=`cosmetics.tpl`    	
              	&includeContent=`1`
              	&includeTVs=`1`
              	&processTVs=`1`
            	]]
          	</div>
          	<div class="pagination">
          	<ul>
             		[[!+page.nav]]
          		</ul>
          </div>
          следующим образом у меня выглядит фильтр
          <div class="filter">
               <form action="[[~[[*id]]]]" method="post" id="mFilter">
                  [[!mFilter?              
                          &resources=`[[!getChildId?&parents=`[[+parents]]` &depth=`[[+depth]]`]]`
                          &includeTVs=`1`
                          &includeTVList=`price,maker`               
                          &tvPrefix=``
                          &tpl=`cosmetics.tpl`
          		&sortFilters=`tv_price,tv_maker`
                          &limit=`4`
                          &pageLimit=`5`
                   ]]
                    <input type="hidden" name="query" value="[[+mse.query]]">
                    <input type="hidden" name="page" value="1">
                    <input type="hidden" name="parents" value="[[+parents]]">
                    <input type="hidden" name="action" value="filter">
                    <input type="hidden" name="sort" value="id,asc">
               </form>
          </div>
          <!-- end_filter -->
          <div class="mFilter_catalog" id="mItems"></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>
          И в head подключен след скрипт:
          <script type="text/javascript" src="http://yandex.st/jquery/form/3.14/jquery.form.min.js"></script>
          Вот сдесь находится неработающее чудо http://t6.yourline.biz/index.php?id=2
          Понять не могу почему он не работает( Не использую miniShop Просмотрела демо, и все 62 результата поиска по mfilter на этом сайте
          1. Tanya Tretinnikova 23 июня 2013, 14:20 # 0
            После дополнительного подключения в head
            <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js"></script>
            Фильтр заработал, только в логе пишет
            файл jquery.min.js (строка 4)
            Error: Syntax error, unrecognized expression: input[name=tv_price[]][value=100]
            ...){var t=e.nodeName.toLowerCase();return"input"===t&&"button"===e.type||"button"=...
            И input не работает
            1. Tanya Tretinnikova 23 июня 2013, 14:49 # 0
              Для активизации input смотрите чанк tpl.mFilter.param.number
              <input type=«text» id=«max_[[+idx]]» name="[[+paramname]][]" value="[[+max]]" class=«input-small vmax» readonly /> и readonly в конце убирайте.
            Добавление новых комментариев отключено.