Простейший фильтр для каталога с помощью getResources

Начну пожалуй с того, что этот скрипт я писал для сайта-каталога graon-stone.ru. Данный сайт - это каталог продукции компании, занимающейся изготовлением изделий из различных пород камней. Поэтому фильтрами были: тип камня, цвет камня, поверхность камня, ну и признак в наличии. Фильтры задаются tv-параметрами, всего их оказалось 4. В данной статье я расскажу вам, как самому реализовать фильтр для простого каталога с помощью MODx API и getResources.

Итак, начнем. Фильтр будет применяться (отправляться) с помощью GET формы на ту же страницу. Для страниц каталога камней и каждого типа камня я буду использовать один и тот же шаблон. В котором и будет вызываться наш сниппет.

Форма фильтра, как и его обработка будут происходить в одном сниппете. В данном случае я назвал его catalogFilter.

В сниппете сперва необходимо получить идентификатор страницы, это в дальнейшем поможет нам определить в каком уровне мы находимся, для применения необходимых "стандартных" фильтров. Это делается совсем просто. Вызовем метод модх resource get

    
    $page_id = $modx->resource->get('id');
    

Далее нам необходимо сделать форму для фильтра. Как вы и поняли, она будет генерироваться внутри сниппета.

    
    

Повторюсь еще раз форму мы будем отправлять методом GET, дабы избежать вопросов о повторной отправке данных, что совсем не понравиться пользователю.

Первое, что мы будем использовать в фильтре это тип камня. В моем случае тип камня - это и есть категория каталога. Поэтому сперва мы получим все категории и разберем их форичем (foreach). А так же отметим, если данная запись есть в запросе, или же, если мы находимся в этой категории.

Данное условие будет отмечать выбранный фильтр. В данном примере 8 - это id верхнего уровня каталога. Разберем подробно: если значение данного параметра есть в GET-запросе ИЛИ если оно равно значению страницы, на которой мы находимся и при этом GET-запрос пустой и страница не равна 8, т.е. корневому каталогу, то отмечаем его как выбранный.

В данном случае, если был применен какой-то фильтр, то они отметятся в списке, если нет и мы находимся на страницы одной из категории, то отметиться та категория в которую мы зашли. В конце статьи мы еще раз вернямся к этому условию, что установить родителей для getResources.

    
    if(in_array($value, $_GET['rock_type']) || ($page_id!=8 && !isset($_GET['rock_type']) && $page_id==$value )) echo "checked";
    

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

    
    
<?
    //тип камня
    $rock_type = $modx->getChildIds(8,1);
?>
    <a href="javascript:;" id="rocktypelink">Вид камня</a>
        <div class="rock_type" hidden="hidden">
<?
        foreach($rock_type as $key => $value)
        {
?>
            <div class="one">
                <input type="checkbox" name="rock_type[]" <? if(in_array($value, $_GET['rock_type']) || ($page_id!=8 && !isset($_GET['rock_type']) && $page_id==$value )) echo "checked"; ?> value="<? echo trim($value); ?>">
                <? echo $modx -> getObject('modResource', $value)->get("pagetitle"); ?>
            </div>
<?
        }
?>
        </div>
    
    

Далее мы сформируем оставшиеся фильтры. Цвет камня и поверхность камня. Заданы списком с одиночным выбором. В данном случае мы получаем все возможные варианты TV параметра и при формировании списка сравниваем их значения с массивом GET запроса.

    
    
<?
        //цвет камня
        $tv_rock_color = $modx->getObject('modTemplateVar',array('name'=>'rockColor'));
        $rock_color = $tv_rock_color->get('elements');
        $rock_color = explode("||",$rock_color);
?>
            <a href="javascript:;" id="rockcolorlink">Цвет</a>
            <div class="rock_color" hidden="hidden">
<?
            foreach($rock_color as $key => $value)
            {
                $color_val = explode("==",$value);
?>
                <div class="one">
                    <input type="checkbox" name="rock_color[]" <? if(in_array(trim($color_val[1]), $_GET['rock_color'])) echo "checked"; ?> value="<? echo trim($color_val[1]); ?>"><? echo trim($color_val[0]); ?>
                </div>
<?
            }
?>
            </div>
<?
        //поверхность камня
        $tv_rock_surface = $modx->getObject('modTemplateVar',array('name'=>'rockSurface'));
        $rock_surface = $tv_rock_surface->get('elements');
        $rock_surface = explode("||",$rock_surface);
?>
            <a href="javascript:;" id="rocksurfacelink">Поверхность</a>
            <div class="rock_surface" hidden="hidden">
<?
            foreach($rock_surface as $key => $value)
            {
                $surface_val = explode("==",$value);
                
?>
                <div class="one">
                    <input type="checkbox" name="rock_surface[]" <? if(in_array(trim($surface_val[1]), $_GET['rock_surface'])) echo "checked"; ?> value="<? echo trim($surface_val[1]); ?>"><? echo trim($surface_val[0]); ?>
                </div>
<?
            }
?>
            </div>

    
    

А теперь сделаем фильтр по наличию, думаю тут все просто и объяснять не нужно.

    
    
    <div class="instock">
        <input type="checkbox" name="in_stock" <? if($_GET['in_stock']==1) echo "checked"; ?> value="1">В наличии
    </div>
    
    

С формированием списка параметров фильтра мы разобрались, теперь когда список сформирован мы можем выводить записи с помощью getResources отфильтрованные нашим фильтром. Сформируем строку TV фильтра из полученных параметров GET запроса. Именно сформируем, т.к. tvFilters принимают только строку с указанием условий. Подробнее об условиях параметра TV-фильтров тут: документация getResources.

    
    //фильтр по цвету
    
    $rockColor=="";
    foreach($_GET['rock_color'] as $key => $value)
    {
        if($_GET['in_stock']==1) $rockColor.="instock==1,";
        /*
        если установлено в наличии, то добавляем (instock==1,) -
        это означает, что запись должна быть в наличии и определенного цвета. 
        Далее действуем таким же способом для поверхности.
        */
        $rockColor.="rockColor==%" . $value . "%||";
    }
    
    $rockSurface=="";
    foreach($_GET['rock_surface'] as $key => $value)
    {
        if($_GET['in_stock']==1) $rockSurface.="instock==1,";
        $rockSurface.="rockSurface==%" . $value . "%||";
    }
    
    $filter .= $rockColor . $rockSurface;
    //скеиваем фильтры

    //если фильтруем по цвету или покрытию, то урезаем 2 последних символа, т.е. логическое или || 
    if($rockColor!="" || $rockSurface!="")
    {
        $filter = substr($filter, 0, -2);
    }
    //иначе, если указан фильтр по наличию, прописываем этот параметр.
    else
    {
        if($_GET['in_stock']==1) $filter.="instock==1";
    }
    

Далее все просто, вызываем сниппет getResources с наборо параметров $settings. Так же мы проверим на выбранность категории (типа камня) и установим значение, если мы пришли на страницу категории.

    
    
    $settings = array(
        'elementClass'=>'modSnippet', 
        'element'=>'getResources',
        'tpl'=>'rocksTpl', 
        'includeTVs'=>'1', 
        'processTVs'=>'1',
        'includeContent'=>'1',
        'hideContainers' =>'1',
        'limit' => '9',
        'pageLimit'=>'6',
        'pageFirstTpl'=>'',
        'pageLastTpl'=>'',
        'pageActiveTpl'=>'
  • ', 'sortby' => '{"createdon":"ASC"}', 'tvFilters'=>$filter ); if($page_id!=8 && !isset($_GET['rock_type'])) { $settings['parents']=$page_id; //устанавливаем категорию, если ничего не выбрано и мы не в каталоге } elseif(isset($_GET['rock_type'])) { //склеиваем список категорий для фильтрации, если они выбраны, при этом в TV параметре должен быть выбраны параметры вывода "Строка". $types = implode(",",$_GET['rock_type']); $settings['parents']=$types; } else { //Иначе выводим товары вех категорий $settings['parents']=8; } $output = $modx->runSnippet('getPage', $settings); echo $output; $modx->getPlaceholder('page.nav');

    Возможно это не самый простой вариант как можно организовать фильтрацию для каталога, но один из первых, который пришел мне в голову. Он прост в реализации и не требует затрат на выполнение. Но я готов поделитья с вами своими начинаниями в оcвоении MODx Revolution.