Адаптивный фильтр для UMI CMS на PHP

27.06.2019

Добавляем в блок к объектами дополнительные атрибуты:

<?php
$products = $this->macros('catalog', 'getSmartCatalogCustom', array('', PAGE_ID, CATALOG_PER_PAGE, false, 10, SORT_FIELD, IS_ASC_DIRECTION, OBJECT_TYPE_ID));
$total = getArrayKey($products, 'total');
?>
<ul id="objects" data-total="<?=$total?>" data-module="catalog" data-category_id="<?=PAGE_ID;?>" data-type_id="<?=OBJECT_TYPE_ID;?>">

В шаблоне категории вызываем шаблон фильтра:

<?= $this->render($variables,'modules/catalog/blocks/category/filter'); ?>

Шаблон фильтра:

<?php /** @var umiTemplaterPHP|ViewPhpExtension|AjaxExtension|DemomarketPhpExtension|UpmixExtension  $this */?>
<?php /** @var array $variables */?>
<!-- noindex -->
<div id="filter" style="display:none"></div>
<!-- /noindex -->

Создаем файл:

templates/xxx/php/ajax/templates/catalog/filter.phtml

Содержимое:

<?php /** @var umiTemplaterPHP|ViewPhpExtension|AjaxExtension|DemomarketPhpExtension|UpmixExtension  $this */?>
<?php /** @var array $variables */?>
<?php
$filter = $this->macros('catalog', 'getSmartFiltersCustom', array('default', PAGE_ID, 0, 15, OBJECT_TYPE_ID));
?>
<form class="catalog_filter">
	<?= $this->render($filter,'modules/catalog/blocks/category/getSmartFiltersCustom'); ?>
	<div class="filter-buttons">
		<input class="filtr-btn" type="submit" value="Показать" />
		<input class="reset-btn" type="reset" value="Сбросить фильтр" />
	</div>
</form>
<div class="goods-num" id="js_count_block">
	<div class="top-triangle"></div>
	<div class="bottom-triangle"></div>
	<div class="clear-after goods-count-wp" >
		<div class="goods-count">Найдено товаров: <span id="js_filtered_count"></span></div>
		<div class="show-btn-wp"><span id="js_show_objects" class="btn-order">Показать</span></div>
	</div>
	<div class="form-btn-wp"><span class="js_close_filter">Скрыть фильтр</span><span class="js_reset_filter_mobile">Сбросить фильтр</span></div>
</div>

Создаем файл

templates/xxx/php/modules/catalog/blocks/category/getSmartFiltersCustom.phtml

Содержимое:

<?php /** @var umiTemplaterPHP|ViewPhpExtension|AjaxExtension|DemomarketPhpExtension|UpmixExtension  $this */?>
<?php /** @var array $variables */?>
<?php
$filter = $variables;
$groups = $filter["group"] ?? null;
if (!empty($groups)){
	foreach ($groups as $group){
		//if ($group['name'] == 'tovar_dnya' || $group['name'] == 'manage_options') continue; //можно убрать некоторые группы из фильтра
		$filterGroup[$group['name']] = $group['field'];
		foreach ($filterGroup[$group['name']] as $field){
			$key = $field["name"];
			//убираем физ фильтра ненужные поля
			if ($key=='razmer_lista' and ROOT_TYPE!='plitka') continue; //размер листа только в плитке
			if ($key=='common_quantity') continue; //количество не показываем
			if ($key=='tip') continue; //тип в фильтре не нужен
			if ($key=='diler' and !USER_IS_SV) continue; //поставщик для админа
			if ($key == 'price_rur_filter' or $key ==  'cvet' or $key == 'material' or $key == 'forma_chipa' or $key == 'osobennosti'){
				$filterGroupFirst[$group['name']][$key] = $field;
			} else {
				$filterGroupSecond[$group['name']][$key] = $field;
			}
		}
	}
}
?>
<?php if(!empty($filterGroupFirst)):?>
	<?php foreach ($filterGroupFirst as $keyGroup=>$group):?>
		<?php foreach ($group as $keyField=>$field):?>
			<?php if($keyField == 'price_rur_filter'):?>
				<?php if(isset($field['minimum'])):?>
					<?php echo($this->render(array('field' => $field), 'modules/catalog/blocks/category/filter/range')); ?>
				<?php endif;?>
			<?php else:?>
				<?php echo($this->render(array('field' => $field), 'modules/catalog/blocks/category/filter/checkbox')); ?>
			<?php endif;?>
		<?php endforeach;?>
	<?php endforeach;?>
<?php endif;?>
<?php if(!empty($filterGroupSecond)):?>
	<?php foreach ($filterGroupSecond as $keyGroup=>$group):?>
		<?php foreach ($group as $keyField=>$field):?>
			<?php if(!USER_IS_SV and $keyField=="diler") continue;?>
			<?php echo($this->render(array('field' => $field), 'modules/catalog/blocks/category/filter/checkbox')); ?>
		<?php endforeach;?>
	<?php endforeach;?>
<?php endif;?>

Создаем файл для фильтров типа чекбокс:

templates/xxx/php/modules/catalog/blocks/category/filter/checkbox.phtml

Содержимое:

<?php /** @var umiTemplaterPHP|ViewPhpExtension|AjaxExtension|DemomarketPhpExtension|UpmixExtension  $this */?>
<?php /** @var array $variables */?>
<?php
$field = getArrayKey($variables, 'field');
$title = getArrayKey($variables, 'name') ?? $field['title'];
$name = $field['name'];
$tip = getArrayKey($field, 'tip') ?? false;
$filter = getRequest('filter');
$sqlType = 'or';

if (isset($filter[$name])){
	reset($filter[$name]);
	$sqlType = key($filter[$name]);
	if ($sqlType === 0){ //для старых ссылок filter[cvet][]
		$sqlType = 'or';
	}
}

?>
<?php if(isset($field['item'])):?>
	<div class="clear-after filter-wp<?php if (isset($filter[$name])) echo ' open'?>">
		<div class="filter-title-js"><span class="filtr-title"><?=$title?> <?php if($tip):?><i data-tooltip-content="#tooltip_content_<?=$name?>" class="tooltip fas fa-question-circle"></i><?php endif;?> <i class="<?php if (isset($filter[$name])) echo 'hidden '?>fas fa-chevron-down"></i><i class="<?php if (!isset($filter[$name])) echo 'hidden '?>fas fa-chevron-up"></i></span></div>
		<?php if($tip):?>
			<div class="tooltip_templates">
			    <span id="tooltip_content_<?=$name?>">
			        <?=$tip?>
			    </span>
			</div>
		<?php endif;?>
		<?php if (count($field['item'])>7):?>
			<div class="filter-search"><input class="js_search" placeholder="поиск по свойствам" type="search"/></div>
		<?php endif;?>
		<?php //для некоторых фльтров делаем возможным искать сразу не нескольким характеритикам, например товары у которых есть сразу 2 цвета: белый и зеленый ?>
		<?php if($name=='cvet' or $name=='osobennosti' or $name=='primenenie' or $name=='material' or $name=='sort_kamnya'):?>
			<div class="checkbox-mode">
				<span>Искать cвойства вместе</span>
				<span class="switch">
					<span id="c_<?=$name?>_mode" data-name="<?=$name?>" data-value="<?=$sqlType?>" class="slider round mode_selector<?php if($sqlType=='and') echo(' checked')?>"></span>
				</span>
			</div>
		<?php endif;?>
		<div class="filter-box<?php if (count($field['item'])>7):?> scroll-pane<?php endif;?>" id="<?=$name?>">
			<?php foreach($field["item"] as $key=>$item):?>
				<?php
				if (!isset($item['value'])) continue;
				$checkedKey = false;
				$id = $this->translitStr($item["value"]);
				$value = $item["value"];
				if (isset($filter[$name])){
					if (!empty($filter[$name][$sqlType])){
						$checkedKey = array_search($value,$filter[$name][$sqlType]);
					} else {
						$checkedKey = array_search($value,$filter[$name]); //для старых ссылок filter[cvet][]
					}
				}
				?>
				<div class="checkbox">
					<input data-name="<?=$name?>" type="checkbox" id="c_<?=$name?>_<?=$id?>" name="filter[<?=$name?>][<?=$sqlType?>][<?=$key?>]" value="<?=$value?>" <?php if(isset($filter[$name]) and $checkedKey!==false) echo ' checked'?>>
					<label class="label" for="c_<?=$name?>_<?=$id?>"><?=$value?></label>
				</div>
			<?php endforeach;?>
		</div>
	</div>
<?php endif?>

Создаем файл для фильтров типа ползунки:

templates/xxx/php/modules/catalog/blocks/category/filter/range.phtml

Содержимое:

<?php /** @var umiTemplaterPHP|ViewPhpExtension|AjaxExtension|DemomarketPhpExtension|UpmixExtension  $this */?>
<?php /** @var array $variables */?>
<?php
$field = getArrayKey($variables, 'field');
$title = getArrayKey($variables, 'name');
$name = $field["name"];
$filter = getRequest('filter');
$umiHierarchy = umiHierarchy::getInstance();
/* @var iUmiHierarchyElement $page */
$page = $umiHierarchy->getElement(PAGE_ID);
$valueMin = $page->getValue('minimum_price') ?? $field["min"];
$valueMax = $page->getValue('maximum_price') ?? $field["max"];
$valueCurMin = $filter[$name]['from'] ?? $valueMin;
$valueCurMax = $filter[$name]['to'] ?? $valueMax;

$range = 'range_'.$name;


?>

<div class="price-filtr filter-wp">
	<?php if(!empty($title)):?><div><?=$title?></div><?php endif;?>
	<input type="hidden" id="<?= $range;?>" class="js_range_slider" data-min="<?= $valueMin;?>" data-max="<?= $valueMax;?>" data-curmin="<?= $valueCurMin;?>" data-curmax="<?= $valueCurMax;?>">
	<div>
		<input type="text" maxlength="6" class="js_<?= $range;?>_from js_input_from" name="filter[<?= $name;?>][from]" value="<?php echo($valueCurMin);?>">
		<label>₽<?=FILTER_EDIZM?></label>
	</div>
	<div class="right-align">
		<input type="text" maxlength="6" class="js_<?= $range;?>_to js_input_to" name="filter[<?= $name;?>][to]" value="<?php echo($valueCurMax);?>">
		<label>₽<?=FILTER_EDIZM?></label>
	</div>
</div>

Создаем файл:

templates/xxx/js/custom/category/category.js
var $objectBlock = $('#objects'), //блок с объектами
    $filter = $('#filter'), //фильтр
    preloader = '<div id="js_loader" class="wait_for"><img src="/templates/xxx/images/loading.gif"/></div>',
    pageId = $objectBlock.data('category_id'), //ID категории
    typeId = $objectBlock.data('type_id'); //Тип товаров в категории

$(document).ready(function() {
    if ($filter.length > 0) {
        reloadFilter();
    }
    initInputFilters();
});

    //изменение или добавление GET параметра
    function changeParam(sParam, paramValue) {
        var queryParameters = {},
            queryString = location.search.substring(1),
            re = /([^&=]+)=([^&]*)/g,
            m;
        while (m = re.exec(queryString)) {
            queryParameters[decodeURIComponent(m[1])] = decodeURIComponent(m[2]);
        }
        queryParameters[sParam] = paramValue;
        return '?' + $.param(queryParameters);
    }

    //удаление GET параметра из строки запроса "p=1&filter[cena]=100"
    function removeParam(sParam) {
        var urlQueue = window.location.search.substring(1),
            rtn,
            param,
            params_arr = [];
        if (urlQueue !== "") {
            params_arr = urlQueue.split("&");
            for (var i = params_arr.length - 1; i >= 0; i -= 1) {
                param = params_arr[i].split("=")[0];
                if (param === sParam) {
                    params_arr.splice(i, 1);
                }
            }
            rtn = params_arr.join("&");
            if (rtn !== "") {
                rtn = '?' + rtn;
            }
        } else {
            rtn = "";
        }
        return rtn;
    }

    //получение GET параметра
    function getUrlParameter(sParam) {
        var urlQueue = window.location.search.substring(1),
            sURLVariables = urlQueue.split('&'),
            sParameterName,
            i;

        for (i = 0; i < sURLVariables.length; i++) {
            sParameterName = sURLVariables[i].split('=');

            if (sParameterName[0] === sParam) {
                return sParameterName[1] === undefined ? true : decodeURIComponent(sParameterName[1]);
            }
        }
    }

    //пересчет количества товаров при выборе фильтров
    function recalcFiltredCount(element) {
        var $countBlock = $('#js_count_block'); //блок: выбрано 10 товаров. Показать
        var url_q  = $filter.find('input[type!=hidden]').filter(function() {
            if (this.value  !== "" && this.value  !== '0') { //если значение не пустое-используем в расчете
                if ($(this).attr('name')==='filter[price_rur_filter][from]'){ //для слайдера
                    if (this.value != $('#range_price_rur_filter').data('min')){ //если не изменялась минимальная цена - не учитываем
                        return this.value;
                    }
                }
                else if ($(this).attr('name')==='filter[price_rur_filter][to]'){ //если не изменялась максимальная цена - не учитываем
                    if (this.value != $('#range_price_rur_filter').data('max')){
                        return this.value;
                    }
                } else {
                    return this.value;
                }

            }
        }).serialize();
        if (url_q !== ''){
            var url = "?" + url_q;
        }
        //запрос количества товаров
        $.ajax(url, {
            dataType: 'json',
            async:true,
            type: "POST",
            data: {
                template: 'catalog/filter-count',
                r: Math.random()
            },
            success: function(response) {
                $('#js_show_objects').attr('href', '?' + url_q); //ссылка показать
                $('#js_filtered_count').text(response); //блок с количеством товара
                //расположение блока
                if ($(window).width() > 767) {
                    if (typeof (element) !== "undefined"){
                        var Y = element.offset().top-210;
                        var X = element.closest('.filter-wp').offset().left+239-$filter.offset().left;
                        $countBlock.css('top', Y+'px');
                        $countBlock.css('left', X+'px');
                        $countBlock.show();
                    }
                }

            }, //конец успешной отправки
            error: function(xhr, ajaxOptions, thrownError) {
                console.log(thrownError + "\r\n" + xhr.statusText + "\r\n" + xhr.responseText);
            }
        });
    }

     //показ фильтра
    function reloadFilter() {
        urlQueue = removeParam('p'); //убираем пагинацию
        $.ajax({
            url: urlQueue,
            type: 'POST',
            async: true,
            data: {
                template: 'catalog/filter',
                r: Math.random()
            },
            success: function (html) {
                $filter.html(html);
				$('#js_filtered_count').text($objectBlock.data('total'));
                $filter.fadeIn(700);
                initFilter();
            },
            error: function (xhr, ajaxOptions, thrownError) {
                console.log(thrownError + "\r\n" + xhr.statusText + "\r\n" + xhr.responseText);
            }
        });
    }

    //инициализация слайдера с ценами и других range слайдеров
    function initFilter() {
        $('.js_range_slider').each(function() {
            var sliderName = $(this).attr('id'),
                $slider = $("#"+sliderName),
                $inputFrom = $(".js_"+sliderName+"_from"),
                $inputTo = $(".js_"+sliderName+"_to"),
                instance,
                min = $(this).data('min'),
                max = $(this).data('max'),
                from = $(this).data('curmin'),
                to = $(this).data('curmax');
            $slider.ionRangeSlider({
                skin: "round",
                type: "double",
                //postfix : 'm2',
                min: min,
                max: max,
                from: from,
                to: to,
                grid: false,
                onFinish: function (data) {
                    $($inputFrom).val(data.from);
                    $($inputTo).val(data.to);
                    recalcFiltredCount($inputTo);
                    processFilters($inputTo);
                }
            });
            instance = $slider.data("ionRangeSlider");
            $inputFrom.inputFilter(function(value) {
                return /^\d*$/.test(value); });
            $inputFrom.on("input", function (e) {
                var val = $(this).prop("value");
                if (val < min) {
                    val = min;
                } else if (val > to) {
                    val = to;
                }
                instance.update({
                    from: val
                });
                recalcFiltredCount($inputTo);
                processFilters($(this));
            });
            $inputTo.inputFilter(function(value) {
                return /^\d*$/.test(value); });
            $inputTo.on("input", function (e) {
                var val = $(this).prop("value");
                if (val < from) {
                    val = from;
                } else if (val > max) {
                    val = max;
                }
                instance.update({
                    to: val
                });
                recalcFiltredCount($inputTo);
                processFilters($(this));
            });
        });
        $('.scroll-pane').jScrollPane({contentWidth: '0px'});
        $('.tooltip').tooltipster({
            theme: 'tooltipster-light',
            trigger: 'custom',
            triggerOpen: {
                mouseenter: true,
                touchstart: true
            },
            triggerClose: {
                click: true,
                scroll: true,
                tap: true
            }
        });
    }

    //пересчет фильтров - делаем значения неактивными, если они неприменимы
    function processFilters(e) {
        var name = e.data('name');
        var url_q  = $filter.find('input[type!=hidden]').filter(function() {
            if (this.value  !== "" && this.value  !== '0') { //если значение не пустое-используем в расчете
                return this.value;
            }
        }).serialize();
        if (url_q !== '') url_q = '?' + url_q;
        var url = "/udata/catalog/getSmartFiltersCustom//"+pageId+"/0/15/"+typeId+"/.json" + url_q;
        $.getJSON(url, function(data){
            $filter.find('.checkbox').find('input:not(:checked)').each(function(){
                if ($(this).attr('name').indexOf(name) !== -1){
                    if($(this).attr('name').indexOf('[or]') === -1){ //если AND
                        $(this).attr('disabled', true);
                        $(this).parent().addClass('disabled');
                    }
                } else {
                    $(this).attr('disabled', true);
                    $(this).parent().addClass('disabled');

                }

            });
            $.each(data.group, function() {
                $.each(this.field, function() {
                    var name = this.name;
                    var items = this.item;
                    $.each(items, function() {
                        var value = this.value;
                        $('#'+name).find('input').each(function(index, element){
                            if (this.value === value){
                                $(this).attr('disabled', false);
                                $(this).parent().removeClass('disabled');
                            }
                        });
                    });
                });
            });
        });
    }

    //изменение значений фильтра
    $filter.on('change', '.checkbox input', function (e) {
        processFilters($(this));
        recalcFiltredCount($(this));
        $(this).toggleClass('checked');
    });

    //Нажатие кнопки "показать"
    $filter.on('click', '#js_show_objects',  function (e) {
        e.preventDefault();
        var url = $(this).attr('href');
        if ($(window).width() < 768) {
            $('.js_get_popup').trigger('click');
        } else {
            $('#js_count_block').fadeOut(100);
        }

        processObjects(url, 'replace');
        reloadFilter();
        return false;
    });

    //Галочка выбирать несколько
    $filter.on('click', '.mode_selector', function (e) {
        e.preventDefault();
        $(this).toggleClass('checked');
        var mode = $(this).data('value')==='or'?'and':'or';
        $(this).data('value', mode);
        $(this).parents('.checkbox-mode').siblings('.filter-box').find('input').each(function() {
            $(this).attr('name', function(index, name) {
                if(mode==='or'){
                    return name.replace('[and]', '[or]');
                } else {
                    return name.replace('[or]', '[and]');
                }

            });
            $(this).attr('disabled', false);
            $(this).parent().removeClass('disabled');
        });
        processFilters($(this));
        recalcFiltredCount($(this));
        return false;
    });

    //раскрытие-закрытие фильтра
    $filter.on('click', '.filter-title-js', function () {
        var $this = $(this);
        var $parent = $this.parent('div');
        $parent.toggleClass('open');
        $this.find('.fa-chevron-up').toggleClass('hidden');
        $this.find('.fa-chevron-down').toggleClass('hidden');
        $('.scroll-pane').jScrollPane({contentWidth: '0px'});
    });

    //перемещение выбранного значения вверх
    $filter.on('change', '.scroll-pane .checkbox input', function () {
        var $this = $(this);
        var $parent = $this.parent('div');
        $parent.prependTo($parent.parent());
        var api = $this.closest('.scroll-pane').data('jsp');
        api.scrollToElement($this);
    });

    //поиск по значениям фильтра
    $filter.on("keyup", '.js_search', function() {
        var value = $(this).val().toLowerCase();
        $(this).parent().siblings('.scroll-pane').find("label").filter(function() {
            $(this).parent().toggle($(this).text().toLowerCase().indexOf(value) > -1)
        });
    });

    //очистка строки поиска по фильтру
    $filter.on("click", '.js_clear', function() {
        var $input = $(this).siblings('input');
        $input.val('');
        $(this).parent().siblings('.scroll-pane').find('.checkbox').each(function() {
            $(this).fadeIn();
        });
    });

    //обнуление фильтра
    $filter.on('click', '.reset-btn', function (e) {
        processObjects('', 'replace');
        reloadFilter();
    });

    //скрытие фильтра на мобиле
    $filter.on('click', '.js_reset_filter_mobile', function (e) {
        $('.js_get_popup').trigger('click');
        processObjects('', 'replace');
        reloadFilter();
    });

    //обнуление фильтра на мобиле
    $filter.on('click', '.js_close_filter', function (e) {
        $('.js_get_popup').trigger('click');
    });

    //
    $('#show_filter').click(function () {
        $('#sidebar').slideToggle(300);
        $('.scroll-pane').jScrollPane({contentWidth: '0px'});
    });



Создаем файл шаблона вывода количества отфильтрованных объектов

templates/xxx/php/ajax/templates/catalog/filter-count.phtml

Содержимое:

<?php /** @var umiTemplaterPHP|ViewPhpExtension|AjaxExtension|DemomarketPhpExtension|UpmixExtension  $this */?>
<?php /** @var array $variables */?>
<?php
$countArray = $this->macros('catalog', 'getSmartCatalogCustom', array('', PAGE_ID, 99999, 1, 15, '', '', OBJECT_TYPE_ID, 1));
$count = getArrayKey($countArray, 'total') ?? 0;
echo ($count);
?>

Подключаем плагины:

http://ionden.com/a/plugins/ion.rangeSlider/ – для ползунков

http://jscrollpane.kelvinluck.com/examples/ – прокрутка в блоке с чекбоксами

https://iamceege.github.io/tooltipster/ – всплывающие подсказки

FontAwesome – понадобится brands и solid. Нет смысла все подключать.

Примерный CSS

.price-filtr{padding:20px 10px 40px 10px;}
#slider{background-color:#e6e6e6;height:5px;}
.filtr-title{color:#000;font-size:14px;font-weight:700;display:block;padding:10px;position:relative;cursor:pointer;line-height: 22px}
.price-filtr label{color:#000;font-size:13px;font-weight:500;margin-left:3px;}
.price-filtr div {width: 50%;float: left}
.price-filtr input{width:50%;height:26px;border: 1px solid #b2b2b2;text-align:center;color:#000;font-size:13px;}
.flex_price{display:flex;}
.flex_price_body{display:flex;justify-content:space-between;align-items:center;}
.slider-num{padding:17px 0 0 0;margin:0 0 12px 0;}
.num1,.num2,.num3{color:#808080;font-size:12px;float:left;display:block;position:relative;top:-10px;}

.num2{margin:0 0 0 111px;}

.num3{float:right;}

.checkbox-choice{position:relative;min-height:17px;margin:0 0 18px 10px;}
.checkbox-choice label{color:#000;font-size:14px;}
.checkbox-box{display:inline;position:relative;}

.color-filtr{border-bottom:1px solid #dadada;}
.filter-title-js{padding-right:10px;}
.hided_more{margin-bottom:10px;}
.cat-menu .more-cat-menu{padding:0;}
.filtr-btn{width:122px;height:38px;border:none;background-color:#e6e6e6;cursor:pointer;color:#4b4b4b;font-size:14px;margin:42px 16px 0 0;}
.reset-btn{border:none;background:none;cursor:pointer;color:#818181;font-size:13px;border-bottom:1px dashed #818181;padding:0;margin:54px 0 0 0;}
.filtr-btn:hover{background-color:#C6BFBF;}
.reset-btn:hover{border:none;}
:focus::-moz-placeholder{color:transparent;}
:focus:-moz-placeholder{color:transparent;}
:focus:-ms-input-placeholder{color:transparent;}
.scrollbar-inner{max-height:200px;display:none;}
.open .scrollbar-inner{display:block;padding:10px 0;}

.reset-btn{margin:17px auto 8px;display:block;}
.filtr-btn{margin:42px auto 0;display:block;}
@media screen and (max-width: 767px) {
    .goods-num {
        position: fixed;
        bottom: 0;
        z-index: 99999;
        width: 100%;
        background-color: #ffffff;
        border: 1px solid #9c9c9c;
        box-sizing: border-box;
    }

    .goods-count {
        float:left;
        width:calc(100% - 130px);
        padding: 0 0 0 10px;
        height: 60px;
        line-height: 60px;
        font-size:14px;
        font-weight: 700;


    }


}

.goods-count span{
    color: #e35222;
    font-size:17px;
    font-weight: 700;



}

.form-btn-wp{
    padding:10px 0;


}
.sidebar #filter {
    padding: 0 0 140px 0;
}

.form-btn-wp span{
    display: inline-block;
    width: 50%;
    text-align: center;
    text-decoration: underline;
    cursor: pointer;
}

.form-btn-wp span:hover, .form-btn-wp span:active{
    text-decoration: none;
}




.show-btn-wp {
    float:left;
    width:100px;
    margin:0 10px;
}

.filter-box
{
    display: none;

}
.open .filter-box
{
    display: block;
}

.scroll-pane {
    width: 100%;
    height: 200px;
    overflow: auto;
    padding: 7px 0;
}



.fa-times-circle {
    position: absolute;
    font-size: 20px;
    right: 20px;
    cursor: pointer;
    padding-top: 5px;
    color:#b2b2b2;
}


.hidden.fas {display: none}
.filtr-title .fas{font-size: 22px;float:right;color:#0077c6}
.filter-search {width:100%;height: 30px;border-bottom: 1px solid #b2b2b2;border-top: 1px solid #b2b2b2;display:none;background-color:#e9e9e9;}
.checkbox-mode{display: none; text-align: center;padding:3px 0;}
.open .filter-search, .open .checkbox-mode{display: block}
.filter-search input {padding: 0 0 0 10px;width: calc(100% - 10px);height: 90%;border: none;background-color:#e9e9e9;}


/* The switch - the box around the slider */
.switch {
    position: relative;
    display: inline-block;
    width: 60px;
    height: 34px;
    vertical-align: middle;
}

/* The slider */
.slider {
    position: absolute;
    cursor: pointer;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
    background-color: #b2b2b2;
    -webkit-transition: .4s;
    transition: .4s;
}

.slider:before {
    position: absolute;
    content: "";
    height: 26px;
    width: 26px;
    left: 4px;
    bottom: 4px;
    background-color: white;
    -webkit-transition: .4s;
    transition: .4s;
}

.slider.checked {
    background-color: #0077c6;
}

.slider:focus {
    box-shadow: 0 0 1px #0077c6;
}

.slider.checked:before {
    -webkit-transform: translateX(26px);
    -ms-transform: translateX(26px);
    transform: translateX(26px);
}

/* Rounded sliders */
.slider.round {
    border-radius: 34px;
}

.slider.round:before {
    border-radius: 50%;
}

.filter-wp {
    border-top: 1px solid #b2b2b2;
}

.checkbox {
    margin: 0 0 7px 10px;

}

.checkbox input{
    width: 20px;
    height: 20px;
    vertical-align: middle;
}

.checkbox label{
    display: inline-block;
    width:calc(100% - 30px);
}

.checkbox.disabled label{
    color:#b2b2b2;
}


.jspTrack{
    background-color: #e9e9e9;
}

.jspDrag {
    background-color: #b2b2b2;
}

.irs-from, .irs-to, .irs-single {
    background-color: #0077c6;
}

.irs-bar {
    height: 10px; top: 33px;
    border-top: 1px solid #0077c6;
    border-bottom: 1px solid #0077c6;
    background: #0077c6;
    background: linear-gradient(to top, rgba(0,119,198,1) 0%,rgba(129,195,231,1) 100%); /* W3C */
}
.irs-bar-edge {
    height: 10px; top: 33px;
    width: 14px;
    border: 1px solid #0077c6;
    border-right: 0;
    background: #0077c6;
    background: linear-gradient(to top, rgba(0,119,198,1) 0%,rgba(129,195,231,1) 100%); /* W3C */
    border-radius: 16px 0 0 16px;
    -moz-border-radius: 16px 0 0 16px;
}

.tooltip_templates { display: none; }


.filtr-title i.tooltip {
    color:#b2b2b2;
    font-size: 16px;
    vertical-align: text-top;
    float:none;
}
#filter form .filter-search input {
	margin:0;
}

.jspPane .checkbox:first-child{
	padding: 10px 0 0 0;
}

@media screen and (min-width: 768px){
	.goods-num {
		position: absolute;
		z-index: 99999;
		display: none;
	}
	.form-btn-wp {
		display: none;
	}
	.goods-count-wp {
		border-top: 2px solid #0053a4;
		border-right: 2px solid #0053a4;
		border-bottom: 2px solid #0053a4;
		border-radius: 4px;
		width: 260px;
		height: 32px;
		margin-left: 18px;
		background-color: #fff;
	}
	.goods-count {
		float: left;
		font-size: 13px;
		line-height: 32px;
		padding: 0 0 0 10px;
	}
	.show-btn-wp {
		float: right;
		margin: 0;
		width: auto;
	}
	.goods-count-wp .btn-order {
		padding: 0 8px;
		height: 26px;
		margin: 2px 7px 0 5px;
		line-height: 26px;
	}
	.top-triangle {
		top: 3px;
		left: 3px;
		display: inline-block;
		width: 0;
		height: 0;
		border-style: solid;
		border-width: 15px 17px 15px 0;
		border-color: transparent #fff transparent transparent;
		position: absolute;
		z-index: 99999999;
	}
	.bottom-triangle {
		display: inline-block;
		width: 0;
		height: 0;
		border-style: solid;
		border-width: 18px 20px 18px 0;
		border-color: transparent #0053a4 transparent transparent;
		position: absolute;
		z-index: 99999998;
	}

}

В файле

templates/xxx/classes/modules/catalog/FilterQueriesMakerCustom.php

Cоздаем функцию parseFiltersCustom:

	public function parseFiltersCustom() {
		$allFilteredFields = $this->getAllFilteredFields();
		$filters = getRequest('filter');
		
		$event = new umiEventPoint('parse_filter');
		$event->setMode('before');
		$event->addRef('raw_filter', $filters);
		$event->setParam('queries_maker', $this);
		$event->call();
		
		if (!$filters || !is_array($filters)) {
			return $this->setFilters([]);
		}
		
		$isNeedToShowSelectedValues = $this->isNeedToShowSelectedValues();

		foreach ($filters as $key => $value) {
			//$type = array_key_first($value); //PHP 7.3
			reset($value);
			$sqlType = key($value);
			
			
			
			if (!isset($allFilteredFields[$key])) {
				unset($filters[$key]);
				continue;
			}
			/* @var iUmiField $field */
			$field = $allFilteredFields[$key];
			if ($field->getDataType() == 'date') {
				foreach ($value as $type => $date) {
					if (!is_numeric($date) && is_string($date)) {
						$value[$type] = strtotime($date);
					}
				}
			}

			
			if ($sqlType === 'and' or $sqlType === 'or'){
				
				
				
				$condition = $this->getCondition($field, $key, $value[$sqlType]);
				
				$condition = str_replace('OR', strtoupper($sqlType), $condition);
			} elseif($sqlType === 0) { // если заходят по старым ссылкам filter[cvet][]

				$condition = $this->getCondition($field, $key, $value[$sqlType]);
				
			} else {

				$condition = $this->getCondition($field, $key, $value);
			}
			

			if ($condition === null) {
				unset($filters[$key]);
			} else {
				$filters[$key] = $condition;
			}
			
			if (!$isNeedToShowSelectedValues) {
				continue;
			}

			$val = array();
			
			if (is_array($value[$sqlType])) {
				$value = array_map('htmlspecialchars', $value[$sqlType]);
			} else {
				$value = [htmlspecialchars($value[$sqlType])];
			}

			$val[$sqlType] = $value;

			$this->pushSelectedFilterValue($key, $val);

		}

		$event->setMode('after');
		$event->addRef('processed_filter', $filters);
		$event->call();

		return $filters;
	}

Добавляем в lib/extensions/UpmixExtension.php

	public function translitStr($s) {
		$s = (string)$s; // преобразуем в строковое значение
		$s = strip_tags($s); // убираем HTML-теги
		$s = str_replace(array("\n", "\r"), " ", $s); // убираем перевод каретки
		$s = preg_replace("/\s+/", ' ', $s); // удаляем повторяющие пробелы
		$s = trim($s); // убираем пробелы в начале и конце строки
		$s = function_exists('mb_strtolower') ? mb_strtolower($s) : strtolower($s); // переводим строку в нижний регистр (иногда надо задать локаль)
		$s = strtr($s, array('а' => 'a', 'б' => 'b', 'в' => 'v', 'г' => 'g', 'д' => 'd', 'е' => 'e', 'ё' => 'e', 'ж' => 'j', 'з' => 'z', 'и' => 'i', 'й' => 'y', 'к' => 'k', 'л' => 'l', 'м' => 'm', 'н' => 'n', 'о' => 'o', 'п' => 'p', 'р' => 'r', 'с' => 's', 'т' => 't', 'у' => 'u', 'ф' => 'f', 'х' => 'h', 'ц' => 'c', 'ч' => 'ch', 'ш' => 'sh', 'щ' => 'shch', 'ы' => 'y', 'э' => 'e', 'ю' => 'yu', 'я' => 'ya', 'ъ' => '', 'ь' => ''));
		$s = preg_replace("/[^0-9a-z-_ ]/i", "", $s); // очищаем строку от недопустимых символов
		$s = str_replace(" ", "-", $s); // заменяем пробелы знаком минус
		return $s; // возвращаем результат
	}

Добавляем файл: templates/xxx/php/ajax/templates/catalog/objects.phtml

Содержимое:

<?php
$html = $this->render($variables, 'modules/catalog/category/blocks/object-list');
$response = $this->prepareAjaxResponseForTemplate($html);
$this->sendAjaxResponse($response);
?>

Comments 0

Добавить комментарий

Your email address will not be published. Required fields are marked *