Создание фильтра (Smart фильтра, умного фильтра) по розничной, оптовой и крупнооптовым ценам

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

1. Настройки компонента

Для начала необходимо в каталоге в файле section.php вызвать компонент. Расположен он может быть по разным путям, у меня он расположен:

/local/templates/mytemplates/components/bitrix/catalog/catalog_bw

      $APPLICATION->IncludeComponent(
	"bitrix:catalog.smart.filter", 
	"section_one", 
	array(
		"COMPONENT_TEMPLATE" => $template,
		"IBLOCK_TYPE" => $arParams["IBLOCK_TYPE"],
		"IBLOCK_ID" => $arParams["IBLOCK_ID"],
		"SECTION_ID" => "",
		"SECTION_CODE" => $arResult["VARIABLES"]["SECTION_CODE"],
		"FILTER_NAME" => $arParams["FILTER_NAME"],
		"HIDE_NOT_AVAILABLE" => "N",
		"TEMPLATE_THEME" => "blue",
		//"FILTER_VIEW_MODE" => "vertical",
		"FILTER_VIEW_MODE" => "horizontal",
		"POPUP_POSITION" => "left",
		"DISPLAY_ELEMENT_COUNT" => "Y",
		"SEF_MODE" => "N",
		"CACHE_TYPE" => "A",
		"CACHE_TIME" => "36000000",
		"CACHE_GROUPS" => "N",
		"SAVE_IN_SESSION" => "N",
		"INSTANT_RELOAD" => "N",
		"PAGER_PARAMS_NAME" => "arrPager",
		"PRICE_CODE" => array(
			0 => "BASE",
			1 => "OPT",
			2 => "LARGE",
		),
		"CONVERT_CURRENCY" => "N",
		"XML_EXPORT" => "N",
		"SECTION_TITLE" => "-",
		"SECTION_DESCRIPTION" => "-"
	),
	false
);

Также необходимо создать 3 свойства в инфоблоке с товарами, чтобы записать туда актуальные цены.

В данном случае это: MINIMUM_PRICE1 (минимальная розничная цена), MINIMUM_OPT1 (минимальная оптовая цена), MINIMUM_OPT_KR1 (минимальная крупнооптовая цена).

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

2. Код компонента Smart фильтра

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


        <?
ini_set('display_errors', 1);
//путь до дирректории сайта, необходим для запуска скрипта по крону
$_SERVER["DOCUMENT_ROOT"] = "/hdd/www-hdd/data/www/";
$DOCUMENT_ROOT = $_SERVER["DOCUMENT_ROOT"];

require($_SERVER["DOCUMENT_ROOT"]."/bitrix/modules/main/include/prolog_before.php");
CModule::IncludeModule('iblock');
CModule::IncludeModule('catalog');
// ID инфоблока  товаров
$ID_BLOCK = 2;
 //$i = 0;
$arSelect = Array("ID", "NAME", "DATE_ACTIVE_FROM");
$arFilter = Array("IBLOCK_ID"=>$ID_BLOCK,"ACTIVE"=>"Y");
$res = CIBlockElement::GetList(
                  Array('ID',"NAME"), 
      $arFilter, false, 
      Array("nPageSize"=>5000), 
      $arSelect);
 
while($ob = $res->GetNextElement()){
   $arFields = $ob->GetFields();
   $MIN_PRICE  = get_offer_min_price($ID_BLOCK,$arFields['ID']);
   $MIN_PRICE_OPT  = get_offer_min_price2($ID_BLOCK,$arFields['ID']);
   $MIN_PRICE_OPT_KR  = get_offer_min_price3($ID_BLOCK,$arFields['ID']);
   //echo $arFields['ID'].' min= '.$MIN_PRICE.' max='.$MAX_PRICE.' - '.$arFields['NAME'];echo '
//$i++; echo $i;

   if(!empty($MIN_PRICE) and !empty($MAX_PRICE) and $MIN_PRICE >0 and $MAX_PRICE >0){
	   //Обновляем свойства товара
	   CIBlockElement::SetPropertyValuesEx($arFields['ID'], false,
                                   array('MINIMUM_PRICE1' => $MIN_PRICE));
          CIBlockElement::SetPropertyValuesEx($arFields['ID'], false, 
                              array('MINIMUM_OPT1' => $MIN_PRICE_OPT));
	   CIBlockElement::SetPropertyValuesEx($arFields['ID'], false, 
                 array('MINIMUM_OPT_KR1' => $MIN_PRICE_OPT_KR));
   	
   }
   else{
      $MIN_PRICE  = getMinPriceBySectionID($ID_BLOCK,$arFields['ID']);
      $MIN_PRICE_OPT  = getMinPriceBySectionID2($ID_BLOCK,$arFields['ID']);
   		$MIN_PRICE_OPT_KR  = getMinPriceBySectionID3($ID_BLOCK,$arFields['ID']);
      CIBlockElement::SetPropertyValuesEx($arFields['ID'], false, array('MINIMUM_PRICE1' => $MIN_PRICE));
      CIBlockElement::SetPropertyValuesEx($arFields['ID'], false, array('MINIMUM_OPT1' => $MIN_PRICE_OPT));
   		CIBlockElement::SetPropertyValuesEx($arFields['ID'], false, array('MINIMUM_OPT_KR1' => $MIN_PRICE_OPT_KR));
   }
}
 
//-------------------------------
/*
Возвращает минимальную цену товара из тп
*/

function get_offer_min_price($IBLOCK_ID,$item_id){
    $ret = 0;
    $arInfo = CCatalogSKU::GetInfoByProductIBlock($IBLOCK_ID);  
  
    //var_dump($arInfo); 
    
    if (is_array($arInfo)) {
        $res = CIBlockElement::GetList(
          //Array("PRICE"=>"ASC"), 
          Array("catalog_PRICE_1"=>"ASC"),  
         array('IBLOCK_ID'=>$arInfo['IBLOCK_ID'], 
         'ACTIVE'=>'Y',
           'PROPERTY_'.$arInfo['SKU_PROPERTY_ID'] => $item_id), 
           false, 
           false, 
         array('ID', 'NAME'))->GetNext();
        if ($res){
            $ret = GetCatalogProductPrice($res["ID"], 1);
            if ($ret['PRICE']){
                $ret = $ret['PRICE'];
            }
        }
    }
    return $ret;
}

function getMinPriceBySectionID($IBLOCK_ID,$tovarID){

    //$CATALOG_ID = 4;
    $rsProducts = CIBlockElement::GetList(
        Array('CATALOG_GROUP_1' => 'ASC'),
        Array('IBLOCK_ID' => $IBLOCK_ID, 'ID' => $tovarID/*'SECTION_ID' => $sectionID*/),
        false,
        Array('nTopCount' => 1),
        Array('IBLOCK_ID', 'ID', 'NAME', 'CATALOG_GROUP_1')
    );

    $arProducts = $rsProducts->Fetch();

    $price = $arProducts["CATALOG_PRICE_1"];
    if (!empty( $price))
        // return App::priceFormat($price);
        return $price;
    else
        return 0;
}

function getMaxPriceBySectionID($IBLOCK_ID,$tovarID){

    //$CATALOG_ID = 4;
    $rsProducts = CIBlockElement::GetList(
        Array('CATALOG_GROUP_1' => 'DESC'),
        Array('IBLOCK_ID' => $IBLOCK_ID,
        'ID' => $tovarID/*'SECTION_ID' => $sectionID*/),
        false,
        Array('nTopCount' => 1),
        Array('IBLOCK_ID', 'ID',
         'NAME', 'CATALOG_GROUP_1')
    );

    $arProducts = $rsProducts->Fetch();

    $price = $arProducts["CATALOG_PRICE_1"];
    if (!empty( $price))
        // return App::priceFormat($price);
        return $price;
    else
        return 0;
}

//-------------------------------
/*
Возвращает минимальную цену товара из тп
*/

function get_offer_min_price2($IBLOCK_ID,$item_id){
    $ret = 0;
    $arInfo = CCatalogSKU::GetInfoByProductIBlock($IBLOCK_ID);  
   
    //var_dump($arInfo); 
  
    if (is_array($arInfo)) {
        $res = CIBlockElement::GetList(
          //Array("PRICE"=>"ASC"), 
          Array("catalog_PRICE_2"=>"ASC"),  
          array('IBLOCK_ID'=>$arInfo['IBLOCK_ID'],
          'ACTIVE'=>'Y',
         'PROPERTY_'.$arInfo['SKU_PROPERTY_ID'] => $item_id), 
           false, 
           false, 
         array('ID', 'NAME'))->GetNext();
        if ($res){
            $ret = GetCatalogProductPrice($res["ID"], 2);
           //// if($item_id==="51165") {var_dump($ret);}
            if ($ret['PRICE']){
                $ret = $ret['PRICE'];
            }
        }
    }
    return $ret;
}



function getMinPriceBySectionID2($IBLOCK_ID,$tovarID){

    //$CATALOG_ID = 4;
    $rsProducts = CIBlockElement::GetList(
        Array('CATALOG_GROUP_2' => 'ASC'),
        Array('IBLOCK_ID' => $IBLOCK_ID,
         'ID' => $tovarID/*'SECTION_ID' => $sectionID*/),
        false,
        Array('nTopCount' => 1),
        Array('IBLOCK_ID', 'ID', 'NAME', 'CATALOG_GROUP_2')
    );

    $arProducts = $rsProducts->Fetch();

    $price = $arProducts["CATALOG_PRICE_2"];
    if (!empty( $price))
        // return App::priceFormat($price);
        return $price;
    else
        return 0;
}



//-------------------------------
/*
Возвращает минимальную цену товара из тп
*/

function get_offer_min_price3($IBLOCK_ID,$item_id){
    $ret = 0;
    $arInfo = CCatalogSKU::GetInfoByProductIBlock($IBLOCK_ID);  
   
    //var_dump($arInfo); 
   
    if (is_array($arInfo)) {
        $res = CIBlockElement::GetList(
          //Array("PRICE"=>"ASC"), 
          Array("catalog_PRICE_3"=>"ASC"),  
           array('IBLOCK_ID'=>$arInfo['IBLOCK_ID'],
           'ACTIVE'=>'Y',
           'PROPERTY_'.$arInfo['SKU_PROPERTY_ID'] => $item_id), 
           false, 
           false, 
            array('ID', 'NAME'))->GetNext();
        if ($res){
            $ret = GetCatalogProductPrice($res["ID"], 3);
           /// if($item_id==="51165") {var_dump($ret);}
            if ($ret['PRICE']){
                $ret = $ret['PRICE'];
            }
        }
    }
    return $ret;
}



function getMinPriceBySectionID3($IBLOCK_ID,$tovarID){

    //$CATALOG_ID = 4;
    $rsProducts = CIBlockElement::GetList(
        Array('CATALOG_GROUP_3' => 'ASC'),
        Array('IBLOCK_ID' => $IBLOCK_ID,
 'ID' => $tovarID/*'SECTION_ID' => $sectionID*/),
        false,
        Array('nTopCount' => 1),
        Array('IBLOCK_ID', 'ID', 'NAME', 'CATALOG_GROUP_3')
    );

    $arProducts = $rsProducts->Fetch();

    $price = $arProducts["CATALOG_PRICE_3"];
    if (!empty( $price))
        // return App::priceFormat($price);
        return $price;
    else
        return 0;
}


Данный скрипт нужно проверить ,что работает правильно, а после поставить на исполнение по крону ночью.

Отмечу, что с 18 версии каталога цена получается при помощи вызова catalog_PRICE_1, а не просто PRICE. В более поздних версиях нужно использовать именно PRICE, а не catalog_PRICE_1. В целом можно и так, и так проверить и выбрать то, что работает. В 18 версии каталога скрипт успешно работал. Также необходимо подкорректировать в самом начале путь к дирректории сайта и номеру инфоблока с товарами. В остальном изменений делать не придется.

Код template.php фильтра, где пропускается стандартная цена, и выбираются поля, которые были заданы выше.


     if(!defined("B_PROLOG_INCLUDED") || B_PROLOG_INCLUDED!==true)die();
/** @var array $arParams */
/** @var array $arResult */
/** @global CMain $APPLICATION */
/** @global CUser $USER */
/** @global CDatabase $DB */
/** @var CBitrixComponentTemplate $this */
/** @var string $templateName */
/** @var string $templateFile */
/** @var string $templateFolder */
/** @var string $componentPath */
/** @var CBitrixComponent $component */
$this->setFrameMode(true);

$templateData = array(
	'TEMPLATE_THEME' => 
$this->GetFolder().'/themes/'.$arParams['TEMPLATE_THEME'].'/colors.css',
	'TEMPLATE_CLASS' => 'bx-'.$arParams['TEMPLATE_THEME']
);
/**/



if (isset($templateData['TEMPLATE_THEME']))
{
	$this->addExternalCss($templateData['TEMPLATE_THEME']);
}
//$this->addExternalCss("/bitrix/css/main/bootstrap.css");
$this->addExternalCss("/bitrix/css/main/font-awesome.css");

Здесь расположены файлы стилей. Можно оставить в этом файле, обернув их в тег "style".


input[type="" i] {
    -webkit-appearance: push-button;
    user-select: none;
    white-space: pre;
    align-items: flex-start;
    text-align: center;
    cursor: default;
    color: buttontext;
    background-color: buttonface;
    box-sizing: border-box;
    padding: 2px 6px 3px;
    border-width: 2px;
    border-style: outset;
    border-color: buttonface;
    border-image: initial;
}

.main .box-filter{
	   /* height: 100%;*/
	   height: 42px;
}

.buttons .btn:first-child {
    margin-right: 3px;
}

.bx-filter .payment-title {
    padding: 0;
    /* width: 70px; */
    /* float: left; */
    width: 42px;
    float:left;
    display: inline-block;
    padding-top: 2px;
    text-transform: uppercase;
    padding-right: 3px;
    margin-bottom: 3px;
    padding-top: 7px;
}

.bx-filter .bx-filter-parameters-box-container-block{
	    color: #fff;
    font-size: 14px;
    font-style: normal;
    padding-bottom: 5px;
}

.bx-filter select {height: 24px;}
.bx-filter .bx-filter-parameters-box-container-block {
    display: inline-flex;
    top: -3px;
    position: relative;
}

Дальше уже идет код самого фильтра. Где arrFilter_197_MIN - минимальная цена (розничная цена), высвечивается в адресной строке браузера гет параметрами(в этом фильтре нету чпу), поэтому сделать подмену достаточно просто. Значение может отличаться, нужно смотреть это в свойстве инфоблока.


<div class="box red box-filter">
   <div class="bx-filter <?=$templateData["TEMPLATE_CLASS"]?> 
      <?if ($arParams["FILTER_VIEW_MODE"] == "HORIZONTAL") 
        echo "bx-filter-horizontal"?>">
<div class="bx-filter-section container-fluid">
	<form name="<?echo $arResult["FILTER_NAME"]."_form"?>" 
          action="<?echo $arResult["FORM_ACTION"]?>" method="get" 
            class="smartfilter form-inline">
	<div class="payment-title">Цена:</div>
             <div class="bx-filter-block" data-role="bx_filter_block" 
              style="display: inline-block;margin-top: 8px;position: absolute;top: 0px;">
	<div class="row bx-filter-parameters-box-container">
	<div class="col-6 bx-filter-parameters-box-container-block bx-left" data-id="min_price_n">
	<i class="bx-ft-sub"><?=GetMessage("CT_BCSF_FILTER_FROM")?></i>
	<div class="bx-filter-input-container">
		<input
			class="min-price"
			type="text"
			name="arrFilter_197_MIN"
			id="arrFilter_197_MIN"
			value=""
			size="5"
			onkeyup="smartFilter.keyup(this)"
	/>
								
	</div>
</div>
<div class="col-6 bx-filter-parameters-box-container-block bx-right" data-id="max_price_n">
	<i class="bx-ft-sub"><?=GetMessage("CT_BCSF_FILTER_TO")?></i>
	<div class="bx-filter-input-container">
		<input
		class="max-price"
		type="text"
		name="arrFilter_197_MAX"
		id="arrFilter_197_MAX"
		value=""
		size="5"
		onkeyup="smartFilter.keyup(this)"
	/>
</div>
</div>
</div>
</div>

<div style="position: absolute;right: 17px;top: 5px;">
	<select onchange="getValue_one(this.value);" 
      style="/*width: 100%;*//*background-color: white;border-radius: 2px;" 
      name="f_smartFilterSelect1" id="filter_<?=$arItem['CODE']?>">
<?
//пропускаем стандартные свойства, которые неверно фильтруют по цене
foreach($arResult["ITEMS"] as $key=>$arItem) {
	if($arItem["NAME"] ==="Розничная цена" || 
       $arItem["NAME"] ==="Оптовая цена" ||
       $arItem["NAME"] ==="Крупный опт"){
	continue;

}
if($arItem["NAME"] != 'Артикул'){ ?>
  <option<?if (isset($_GET['f_smartFilterSelect1']) && 
   $_GET['f_smartFilterSelect1'] == $arItem['CODE']) {
       echo " selected"; }?> 
    value="<?=$arItem['CODE']?>">
        <?=$arItem["NAME"]?>
</option>
<? }
} ?>
</select>
<script type="text/javascript">
$(document).ready(function() {
	$('div[data-id=MINIMUM_PRICE1]').css("display","inline-block");
	 $('div[data-id=MINIMUM_OPT1]').css("display","none");
	$('div[data-id=MINIMUM_OPT_KR1]').css("display","none");
});
</script>

<script>	
function getValue(value) {
//alert(value);
						
//$(document).ready(function() {
if(value ==="MINIMUM_PRICE1"){
$('div[data-id=MINIMUM_PRICE1]').css("display","inline-block");
$('div[data-id=MINIMUM_OPT1]').css("display","none");
$('div[data-id=MINIMUM_OPT_KR1]').css("display","none");

}
else if(value ==="MINIMUM_OPT1"){
$('div[data-id=MINIMUM_OPT1]').css("display","inline-block");
$('div[data-id=MINIMUM_PRICE1]').css("display","none");
$('div[data-id=MINIMUM_OPT_KR1]').css("display","none");
}
else if(value ==="MINIMUM_OPT_KR1"){
$('div[data-id=MINIMUM_OPT_KR1]').css("display","inline-block");
$('div[data-id=MINIMUM_PRICE1]').css("display","none");
$('div[data-id=MINIMUM_OPT1]').css("display","none");
}
							//}
}
function getValue_one(value) {
//alert(value);
						
//$(document).ready(function() {
//здесь происходит подмена свойств при выборе в sеlect Розничной,
//Оптовой и крупнооптовой цены
if(value ==="MINIMUM_PRICE1"){
$('div[data-id=min_price_n] input').attr("name","arrFilter_197_MIN");
$('div[data-id=max_price_n] input').attr("name","arrFilter_197_MAX");
$('div[data-id=min_price_n] input').attr("id","arrFilter_197_MIN");
$('div[data-id=max_price_n] input').attr("id","arrFilter_197_MAX");
//name="arrFilter_197_MIN"
//	id="arrFilter_197_MIN";
//$('div[data-id=MINIMUM_OPT1]').css("display","none");
//$('div[data-id=MINIMUM_OPT_KR1]').css("display","none");
}
else if(value ==="MINIMUM_OPT1"){
$('div[data-id=min_price_n] input').attr("name","arrFilter_201_MIN");
$('div[data-id=max_price_n] input').attr("name","arrFilter_201_MAX");
$('div[data-id=min_price_n] input').attr("id","arrFilter_201_MIN");
$('div[data-id=max_price_n] input').attr("id","arrFilter_201_MAX");
//$('div[data-id=MINIMUM_PRICE1]').css("display","none");
//$('div[data-id=MINIMUM_OPT_KR1]').css("display","none");
}
else if(value ==="MINIMUM_OPT_KR1"){
$('div[data-id=min_price_n] input').attr("name","arrFilter_202_MIN");
$('div[data-id=max_price_n] input').attr("name","arrFilter_202_MAX");
$('div[data-id=min_price_n] input').attr("id","arrFilter_202_MIN");
$('div[data-id=max_price_n] input').attr("id","arrFilter_202_MAX");
//$('div[data-id=MINIMUM_PRICE1]').css("display","none");
//$('div[data-id=MINIMUM_OPT1]').css("display","none");
}
							//}
}
</script>

<script>
function ready() {
var url_string = document.location.href; //window.location.href
var url = new URL(url_string);
var m_filter = url.searchParams.get("f_smartFilterSelect1");
if(m_filter !==""){
getValue_one(m_filter);
$('select[name="f_smartFilterSelect1"] option[value='+m_filter+']').prop('selected', true);
}
var m1_price_min = url.searchParams.get("arrFilter_197_MIN");
var m1_price_max = url.searchParams.get("arrFilter_197_MAX");
if(m1_price_min !==null){
	$('div[data-id=min_price_n] input').val(m1_price_min);
}
if(m1_price_max !==null){
	$('div[data-id=max_price_n] input').val(m1_price_max);
}

var m2_price_min = url.searchParams.get("arrFilter_201_MIN");
var m2_price_max = url.searchParams.get("arrFilter_201_MAX");

if(m2_price_min !==null){
	$('div[data-id=min_price_n] input').val(m2_price_min);
}
if(m2_price_max !==null){
	$('div[data-id=max_price_n] input').val(m2_price_max);
}

var m3_price_min = url.searchParams.get("arrFilter_202_MIN");
var m3_price_max = url.searchParams.get("arrFilter_202_MAX");
						
if(m3_price_min !==null){
	$('div[data-id=min_price_n] input').val(m3_price_min);
}
if(m3_price_max !==null){
		$('div[data-id=max_price_n] input').val(m3_price_max);
}
						
console.log(m1_price_min);
console.log(m1_price_max);

console.log(m2_price_min);
console.log(m2_price_max);

console.log(m3_price_min);
console.log(m3_price_max);
//console.log(url_string);
}
document.addEventListener("DOMContentLoaded", ready);
</script>
<div class="buttons" style="/*float:right;*//*margin-right:20px;*/">
	<input class="btn btn-themes button" type="submit"
            id="set_filter" name="set_filter" 
           value="<?=GetMessage("CT_BCSF_SET_FILTER")?>" />
	<?/**?>
	<input class="btn btn-link button-del" type="submit" 
          id="del_filter" name="del_filter" 
       value="<?=GetMessage("CT_BCSF_DEL_FILTER")?>" />
	<input class="btn btn-link button-del" type="button" 
           id="" name=""  
           onclick="window.location.href='/catalog/'"  
           value="<?=GetMessage("CT_BCSF_DEL_FILTER")?>" />
		</div>
	</div>

<div class="clb"></div>
</form>
<script type="text/javascript">
	$(function() {
if($('*').is('.bx-filter-block')) {
//some code
} else {
						
}
});
</script>
</div>
</div>
<script>
		var smartFilter = new JCSmartFilter('
               <?echo CUtil::JSEscape($arResult["FORM_ACTION"])?>',
               '<?=CUtil::JSEscape($arParams["FILTER_VIEW_MODE"])?>', 
              <?=CUtil::PhpToJSObject($arResult["JS_FILTER_PARAMS"])?>);
	</script>
</div>

Скачать исходники Скачать исходники

На этом все. Фильтр самому создать не сложно, если нужно ввести свои значения для фильтрации.

Интересные статьи по программированию:

Уважаемый читатель!

Ты можешь сделать проект Mirdeveloper.ru лучше!

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

Оставь чаевые, и будут новые статьи, и появятся видео.

Это даст новые возможности в улучшении сайта

Спасибо за то, что Вы с нами!


Комментарии находятся на модерации или не добавлены.

Для добавления комментариев необходимо зарегистрироваться и авторизоваться

Также возможно авторизоваться через Социальную сеть Вконтакте (VK)