Создание фильтра (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)