Создание фильтра (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>
На этом все. Фильтр самому создать не сложно, если нужно ввести свои значения для фильтрации.
Комментарии находятся на модерации или не добавлены.
Для добавления комментариев необходимо зарегистрироваться и авторизоваться
Также возможно авторизоваться через Социальную сеть Вконтакте (VK)