Битрикс автоматическое определение города на php
Rus
Eng
Битрикс автоматическое определение города на php

Данный материал не является исчерпывающим руководством. Код поставляется бесплатно и "как есть". Используйте его на свой страх и риск

У MaxMind есть хорошая инструкция по использованию их баз данных: maxmind-db/reader. Ознакомьтесь с ней или продолжайте читать мой опыт внедрения.

Скачать бесплатные базы MaxMind можно здесь: GeoLite2 Free Downloadable Databases (требуется регистрация аккаунта)

Скачанную базу данных GeoLite2-City.mmdb положите в любую удобную папку, например, в /local/libs/maxmind/

Для чтения баз данных MaxMind для php требуется специальная "читалка". Переходим в консоль ssh под root аккаунтом и ставим MaxMind DB Reader

yum install php-maxminddb

Если вы получили ошибку, то можно воспользоваться командой

apt install libmaxminddb-dev

Будем считать, что composer уже подключен на вашем проекте. Переходим в консоль и ставим

php composer.phar require maxmind-db/reader:~1.0
composer require geoip2/geoip2

Кроссбраузерная форма выбора города пользователя

В init.php добавляем

require($_SERVER['DOCUMENT_ROOT'].'/local/libs/init/geolocationMaxMInd.php');

Листинг файла geolocationMaxMInd.php

//Смело избавляйтесь от доп. параметров (REGION_ID, REGION_NAME) они нужны в очень редких случаях
require $_SERVER['DOCUMENT_ROOT'].'/vendor/autoload.php';
use GeoIp2\Database\Reader;

AddEventHandler("main", "OnPageStart", "OnPageStart");
function OnPageStart(){
    global $CITY; //Определяем глобальную переменную на сайте куда запишем полученную информацию

    if(!CModule::IncludeModule("sale")) // не смогли подключить модуль
        return;

    //Я разделил куки с геолокацией на 3 отдельных (для удобства), вы можете использовать любой формат записи
    if(!$_COOKIE['geoCity'] || !$_COOKIE['geoRegion'] || !$_COOKIE['geoID']){//Если не определены все 3 куки, то определяем через MaxMind
        $reader = new Reader($_SERVER['DOCUMENT_ROOT'].'/local/libs/maxmind/GeoLite2-City.mmdb');//Говорим ридеру откуда читать базу данных

        $ip = \Bitrix\Main\Service\GeoIp\Manager::getRealIp(); //Получаем ip стандартными методами Битрикс
        $record = $reader->city($ip); //Получаем массив данных по айпи

        $CITY = array(
            'REGION_NAME' => $record->mostSpecificSubdivision->names['ru'],//определяем область
            'CITY_NAME'=> $record->city->names['ru'],//определяем город
        );

		$location = getLocationByName(CITY['CITY_NAME']);
		
		$CITY['CITY_ID'] = $location['ID'];
        $CITY['REGION_ID'] = $location['REGION_ID'];

        //Устанавливаем массив с городом по умолчанию на случай, если город не найден
        if(!$CITY['CITY_NAME']){
            $CITY = array(
                'REGION_NAME' => 'Московская область',
                'CITY_NAME'=> 'Москва',
                'CITY_ID'=> '84',
            );
        }

        //Устанавливаем куки
        setcookie("geoCity", $CITY['CITY_NAME'], time()+60*60*24*30*12*2, "/");
        setcookie("geoRegion", $CITY['REGION_NAME'], time()+60*60*24*30*12*2, "/");
        setcookie("geoID", $CITY['CITY_ID'], time()+60*60*24*30*12*2, "/");
        setcookie("geoRegionID", $CITY['REGION_ID'], time()+60*60*24*30*12*2, "/");
    }else{
        //Поскольку куки найдены, то заполняем массив данными из них
        $CITY = array(
            'REGION_NAME' => $_COOKIE['geoRegion'],
            'CITY_NAME'=> $_COOKIE['geoCity'],
            'CITY_ID'=> $_COOKIE['geoID'],
            'REGION_ID'=> $_COOKIE['geoRegionID'],
        );
    }

    if($_COOKIE['changeRegionID']=='Y' && $_COOKIE['CITY_NAME']!='Москва'){//В моем случае у Москвы регионы не было
        setcookie("changeRegionID", null, -1, "/");

		$location = getLocationByName(CITY['CITY_NAME']);
		
        $CITY['REGION_ID'] = location['REGION_ID'];

        setcookie("geoRegionID", $CITY['REGION_ID'], time()+60*60*24*30*12*2, "/");
    }
}

function getLocationByName($name){
	//Ищем совпадение найденного города в местоположениях Битрикс
	$db_vars = CSaleLocation::GetList(
		array(
			"SORT" => "ASC",
			"COUNTRY_NAME_LANG" => "ASC",
			"CITY_NAME_LANG" => "ASC"
		),
		array("LID" => LANGUAGE_ID,'CITY_NAME' =>name),
		false,
		false,
		array()
	);
	
	return $db_vars->Fetch();
}

В header.php добавляем вызов формы

<a class="js-select-city" href="javascript:void(0);" data-city="Москва" data-region="Московская область" data-id="216" data-code="0000073738">Москва</a>

В footer.php выводим форму

<div class="topOuter absCenter">
    <div class="topInner">
        <div class="topWindowClose"><svg version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 52 52" style="enable-background:new 0 0 52 52;" xml:space="preserve"><g><path d="M26,0C11.664,0,0,11.663,0,26s11.664,26,26,26s26-11.663,26-26S40.336,0,26,0z M26,50C12.767,50,2,39.233,2,26 S12.767,2,26,2s24,10.767,24,24S39.233,50,26,50z"/><path d="M35.707,16.293c-0.391-0.391-1.023-0.391-1.414,0L26,24.586l-8.293-8.293c-0.391-0.391-1.023-0.391-1.414,0 s-0.391,1.023,0,1.414L24.586,26l-8.293,8.293c-0.391,0.391-0.391,1.023,0,1.414C16.488,35.902,16.744,36,17,36 s0.512-0.098,0.707-0.293L26,27.414l8.293,8.293C34.488,35.902,34.744,36,35,36s0.512-0.098,0.707-0.293 c0.391-0.391,0.391-1.023,0-1.414L27.414,26l8.293-8.293C36.098,17.316,36.098,16.684,35.707,16.293z"/></g></svg></div>
        <h3>Выбор города:</h3>
        <?= bitrix_sessid_post() ?>
        <?
        global $CITY;
        if(CModule::IncludeModule("sale"))
        {
            CSaleLocation::proxySaleAjaxLocationsComponent(
                array(
                    "AJAX_CALL" => "Y",
                    'CITY_OUT_LOCATION' => 'Y',
                    'COUNTRY_INPUT_NAME' => 'RUSSIA_COUNTRY',
                    'CITY_INPUT_NAME' => "ORDER_PROP_CITY",
                    //'LOCATION_VALUE' => $CITY['CITY_ID'], //5
                    "ONCITYCHANGE" => "",
                    "INDEX_ON " => "N",
                ),
                array(),
                'search',
                true,
                'popup-location-block-wrapper'
            );
        }

        ?>
        <h4>или выберите из списка:</h4>
        <hr />
        <div class="row citiesQuick">
            <div class="col-xs-4"><a href="#" class="cityQuick <?if($CITY['CITY_NAME']=='Москва'){?>active<?}?>" data-title="Москва" data-region="Московская область" data-id="84" data-code="0000073738" title="Москва">Москва</a></div>
            <div class="col-xs-4"><a href="#" class="cityQuick <?if($CITY['CITY_NAME']=='Санкт-Петербург'){?>active<?}?>" data-title="Санкт-Петербург" data-region="Ленинградская область" data-id="85" data-code="0000103664" title="Санкт-Петербург">Санкт-Петербург</a></div>
            <div class="col-xs-4"><a href="#" class="cityQuick <?if($CITY['CITY_NAME']=='Балашиха'){?>active<?}?>" data-title="Балашиха" data-region="Московская область" data-id="87" data-code="0000033889" title="Балашиха">Балашиха</a></div>
            <div class="col-xs-4"><a href="#" class="cityQuick <?if($CITY['CITY_NAME']=='Воронеж'){?>active<?}?>" data-title="Воронеж" data-region="Воронежская область" data-id="740" data-code="0000293598" title="Воронеж">Воронеж</a></div>
            <div class="col-xs-4"><a href="#" class="cityQuick <?if($CITY['CITY_NAME']=='Екатеринбург'){?>active<?}?>" data-title="Екатеринбург" data-region="Свердловская область" data-id="2203" data-code="0000812044" title="Екатеринбург">Екатеринбург</a></div>
            <div class="col-xs-4"><a href="#" class="cityQuick <?if($CITY['CITY_NAME']=='Казань'){?>active<?}?>" data-title="Казань" data-region="Республика Татарстан" data-id="1558" data-code="0000550426" title="Казань">Казань</a></div>
            <div class="col-xs-4"><a href="#" class="cityQuick <?if($CITY['CITY_NAME']=='Королёв'){?>active<?}?>" data-title="Королёв" data-region="Московская область" data-id="91" data-code="0000030318" title="Королёв">Королёв</a></div>
            <div class="col-xs-4"><a href="#" class="cityQuick <?if($CITY['CITY_NAME']=='Красногорск'){?>active<?}?>" data-title="Красногорск" data-region="Московская область" data-id="142" data-code="0000044453" title="Красногорск">Красногорск</a></div>
            <div class="col-xs-4"><a href="#" class="cityQuick <?if($CITY['CITY_NAME']=='Краснодар'){?>active<?}?>" data-title="Краснодар" data-region="Краснодарский край" data-id="1132" data-code="0000386590" title="Краснодар">Краснодар</a></div>
            <div class="col-xs-4"><a href="#" class="cityQuick <?if($CITY['CITY_NAME']=='Люберцы'){?>active<?}?>" data-title="Люберцы" data-region="Московская область" data-id="149" data-code="0000046203" title="Люберцы">Люберцы</a></div>
            <div class="col-xs-4"><a href="#" class="cityQuick <?if($CITY['CITY_NAME']=='Мытищи'){?>active<?}?>" data-title="Мытищи" data-region="Московская область" data-id="153" data-code="0000049473" title="Мытищи">Мытищи</a></div>
            <div class="col-xs-4"><a href="#" class="cityQuick <?if($CITY['CITY_NAME']=='Нижний Новгород'){?>active<?}?>" data-title="Нижний Новгород" data-region="Нижегородская область" data-id="1698" data-code="0000600317" title="Нижний Новгород">Нижний Новгород</a></div>
            <div class="col-xs-4"><a href="#" class="cityQuick <?if($CITY['CITY_NAME']=='Новосибирск'){?>active<?}?>" data-title="Новосибирск" data-region="Новосибирская область" data-id="2614" data-code="0000949228" title="Новосибирск">Новосибирск</a></div>
            <div class="col-xs-4"><a href="#" class="cityQuick <?if($CITY['CITY_NAME']=='Одинцово'){?>active<?}?>" data-title="Одинцово" data-region="Московская область" data-id="166" data-code="0000054606" title="Одинцово">Одинцово</a></div>
            <div class="col-xs-4"><a href="#" class="cityQuick <?if($CITY['CITY_NAME']=='Пермь'){?>active<?}?>" data-title="Пермь" data-region="Пермский край" data-id="1869" data-code="0000670178" title="Пермь">Пермь</a></div>
            <div class="col-xs-4"><a href="#" class="cityQuick <?if($CITY['CITY_NAME']=='Подольск'){?>active<?}?>" data-title="Подольск" data-region="Московская область" data-id="109" data-code="0000032609" title="Подольск">Подольск</a></div>
            <div class="col-xs-4"><a href="#" class="cityQuick <?if($CITY['CITY_NAME']=='Пушкин'){?>active<?}?>" data-title="Пушкин" data-region="Ленинградская область" data-id="3139" data-code="0000107443" title="Пушкин">Пушкин</a></div>
            <div class="col-xs-4"><a href="#" class="cityQuick <?if($CITY['CITY_NAME']=='Ростов-на-Дону'){?>active<?}?>" data-title="Ростов-на-Дону" data-region="Ростовская область" data-id="1248" data-code="0000445112" title="Ростов-на-Дону">Ростов-на-Дону</a></div>
            <div class="col-xs-4"><a href="#" class="cityQuick <?if($CITY['CITY_NAME']=='Самара'){?>active<?}?>" data-title="Самара" data-region="Самарская область" data-id="1831" data-code="0000650509" title="Самара">Самара</a></div>
            <div class="col-xs-4"><a href="#" class="cityQuick <?if($CITY['CITY_NAME']=='Сочи'){?>active<?}?>" data-title="Сочи" data-region="Краснодарский край" data-id="1137" data-code="0000394020" title="Сочи">Сочи</a></div>
            <div class="col-xs-4"><a href="#" class="cityQuick <?if($CITY['CITY_NAME']=='Химки'){?>active<?}?>" data-title="Химки" data-region="Московская область" data-id="111" data-code="0000033097" title="Химки">Химки</a></div>
            <div class="col-xs-4"><a href="#" class="cityQuick <?if($CITY['CITY_NAME']=='Челябинск'){?>active<?}?>" data-title="Челябинск" data-region="Челябинская область" data-id="2354" data-code="0000854968" title="Челябинск">Челябинск</a></div>
        </div>
    </div>
</div>

Записываем стили формы в template_styles.css

.absCenter { display: -webkit-box; display: -moz-box; display: -ms-flexbox; display: -webkit-flex; display: flex; -webkit-box-align: center; -moz-box-align: center; -ms-flex-align: center; -webkit-align-items: center; align-items: center; -webkit-box-pack: center; -moz-box-pack: center; -ms-flex-pack: center; -webkit-justify-content: center; justify-content: center; text-align: center; flex-direction: column}

.topOuter{background-color: rgba(0,0,0,0.5);position: fixed;top:0;left:0;width:100%;height:100%;z-index: 1000;display: none}
.topInner {background-color: #fff;padding:40px 40px;border-radius: 10px;position: relative;min-width: 320px;max-width:700px;-webkit-box-shadow: 0px 5px 10px 0px rgba(0,0,0,0.2); -moz-box-shadow: 0px 5px 10px 0px rgba(0,0,0,0.2); box-shadow: 0px 5px 10px 0px rgba(0,0,0,0.2);text-align: left;max-height: 500px;overflow-y: auto;width: 100%}
.topInner h2{font-family: Gotham-Pro-Bold,"HelveticaNeueCyr", "PT Sans", sans-serif;font-size: 24px; font-weight: 600;line-height: 32px;margin-bottom:14px;text-align: left}
.topInner .formClose{position: absolute;right: 0;top:0;background-color: #E31D23;border-radius: 50%;width: 28px;height:28px; -webkit-transform: translate(50%,-50%); -moz-transform: translate(50%,-50%); -ms-transform: translate(50%,-50%); -o-transform: translate(50%,-50%); transform: translate(50%,-50%);cursor:pointer}
.topInner .formClose .svgBox{margin-top:3px;}
.topInner .formClose svg{width: 8px;height:8px;fill:#fff;stroke:#fff;}
.topInner .formClose:hover{background-color: #d21a20}

.topInner h3{text-align: left;text-transform: uppercase;font-weight:600;border-bottom:1px solid #12472f;padding-bottom:10px;}
.topInner h4{text-align: left;font-weight:600;font-size: 14px;margin-top:20px;margin-bottom:15px}
#autocomplete{margin-bottom: 20px;font-size: 14px;}

.cityQuick {font-weight:400;font-size: 14px;color: #202020}
.cityQuick.active {font-weight:600;}
.cityQuick:hover {color:#d6000a;}
.citiesQuick.row{padding:0 15px;/*margin:0;background: #f7f7f7;border: 1px solid #E5E5E5;*/}

.topWindowClose {position:  absolute;top:8px;right:8px;width: 52px;height:52px;cursor: pointer}
.topOuter .topWindowClose {top:12px;right:12px;width: 28px;height:28px;}
.topWindowClose svg{fill:#383838}
.topWindowClose:hover svg {fill:#888888;}
.topWindowTitle {color:#a00200;font-family:Ubuntu, Arial, Helvetica, sans-serif;font-size:64px;font-weight: 600;margin-top: 60px}
.topWindowTitle span{font-size:130px;position: relative;bottom: -15px;}
.topWindowTitle span:after{position: absolute;top:10px;right:-8px;content: '';background-image: url('/upload/stock/shapka.png');width: 65px;height:37px;}
.topWindowText {margin-top: 35px;margin-left:0;margin-right:0;}
.topWindowText p{margin-bottom: 14px;text-align: left;color: #1d1a1a;font-family:Ubuntu, Arial, Helvetica, sans-serif;font-size:14px;font-weight: 400;line-height: 19px;padding:0 20px 0 40px;}
.topWindowText p span{font-weight: 600}

.topWindowClose svg {-moz-transition: all 0.5s;-webkit-transition: all 0.5s;-o-transition: all 0.5s;-ms-transition: all 0.5s}

/* Geolocation autocomplete */
.autocomplete-suggestions { border: 1px solid #999; background: #FFF; overflow: auto; }
.autocomplete-suggestion { padding: 2px 5px; white-space: nowrap; overflow: hidden;cursor: pointer}
.autocomplete-selected { background: #F0F0F0; }
.autocomplete-suggestions strong { font-weight: normal; color: #3399FF; }
.autocomplete-group { padding: 2px 5px; }
.autocomplete-group strong { display: block; border-bottom: 1px solid #000; }

.topInner .bx-sls .bx-ui-sls-pane{max-height: 200px;}
.topInner .bx-sls .bx-ui-sls-fake, .topInner .bx-sls .bx-ui-sls-route{height: 25px;}
.topInner .bx-sls .dropdown-item-text span{color:#3399ff}
.topInner .bx-sls .dropdown-item-text{color:#888888}
.topInner .bx-sls .bx-ui-sls-variants .bx-ui-sls-variant:hover,.topInner .bx-sls .bx-ui-sls-variant-active{background-color: #f7f7f7;}
.topInner .location-block-wrapper .bx-sls .dropdown-icon{top:13px;body .newHeader .newPhoneWrap}

.citiesQuick {display: flex;flex-wrap: wrap;}
.citiesQuick > div{flex-grow: 1;width: 33%;}

.topInner .bx-sls .bx-ui-sls-fake, .topInner .bx-sls .bx-ui-sls-route{min-height: 25px}
.topInner .bx-sls .dropdown-icon{top: 5px}
.topInner .bx-sls .dropdown-fade2white{top: 0;height: 25px;}
.topInner .bx-sls .dropdown-item-text{font-size: 1.4rem;line-height: 2rem;font-weight: 400;margin-bottom: 10px;color: #202020}
.topInner .bx-sls .dropdown-item-text:hover{color: #d6000a}
.topInner .bx-sls .bx-ui-sls-variants .bx-ui-sls-variant, .topInner .bx-sls .bx-ui-sls-error{padding: 0}
.topInner .bx-sls .dropdown-item{margin: 0}
.topInner .bx-ui-sls-error > div{display: none}

@media all and (max-width: 600px) {
    .topInner {min-width: calc(320px - 80px);max-width: calc(320px - 80px);width: 100%;}
    .citiesQuick .col-xs-4{-ms-flex-preferred-size: 100%;flex-basis: 100%;max-width: 100%;}
    body .newHeader .cityChoice .row,body .newHeader .cityChoice{margin-top:0;}
    body .newHeader .newPhoneBlock{position: absolute;top:20px}
    body .newHeader .newPhoneWrap{top:0 !important;}
    body .newHeader .logo_wrapp {margin-bottom: 0}
    body .newHeader .cityChoice .row {margin-top:0 !important;}
    .cityWrap {min-height: 30px;position: relative;padding-left: 15px !important;}
    body .newHeader .cityChoice {bottom:0;position: absolute;bottom:0;}
}

@media all and (max-width: 400px) {
    /*body .newHeader .cityPodpis{display: none}
    body .newHeader .cityName {margin-left: 0 !important;}*/
}

В основной скрипт шаблона, например, main.js добавляем

function closeForm(){
    $('.topOuter').removeClass('active').fadeOut(600,function(){});
}

function showForm(){
    $('.topOuter').css("display", "flex").addClass('active').hide().fadeIn(600);
}

function setCity(city, region, id, code,geoRegionID) {
    var date = new Date();
    var days = 365;//3 // <--- нужное количество дней
    var hours = 24;//24 // <--- нужное количество часов
    var minutes = 60;//60 // <--- нужное количество минут
    var seconds = 60; // <--- нужное количество секунд

    date.setTime(date.getTime() + (days * hours * minutes * seconds * 1000));

    $.cookie("geoCity", city, {expires: date, path: '/'});
    $.cookie("geoRegion", region, {expires: date, path: '/'});
    $.cookie("changeRegionID", 'Y', {expires: date, path: '/'});
    $.cookie("geoID", id, {expires: date, path: '/'});

    $.cookie("BITRIX_SM_CITY_NAME", city, {expires: date, path: '/'});
    $.cookie("BITRIX_SM_CITY_ID", id, {expires: date, path: '/'});
    $.cookie("BITRIX_SM_REGION_NAME", region, {expires: date, path: '/'});

    $('.js-cityChoose').html(city);

    $('.cityQuick').removeClass('active');
    $(".cityQuick[data-title='" + city + "']").addClass('active');

    //Если мы на странице оформления заказа
    if ($('#bx-soa-order-form').length) {
        //Вызов смены города в старом шаблоне
        //BX.saleOrderAjax.changeLoc(id);
        $('.dropdown-field').val(code).fadeOut(0);
        $('.bx-ui-sls-fake').val(code).fadeOut(0);

        //Вызов смены города в новом шаблоне
        BX.Sale.OrderAjaxComponent.params.newCity=code;
        BX.Sale.OrderAjaxComponent.locations[id];
        BX.Sale.OrderAjaxComponent.editFadeRegionBlock(true);
        BX.Sale.OrderAjaxComponent.sendRequest();
    }

    location.reload();

    closeForm();
}

function IsJsonString(str) {
    try {
        JSON.parse(str);
    } catch (e) {
        return false;
    }
    return true;
}

$(document).ready(function(){

    $('body').on('click', '.topOuter', function (e) {
        if ($('.topOuter').has(e.target).length === 0) {//Отслеживаем клик именно по элементу
            closeForm();
        }
    });

    $('body').on('click touch', '.topWindowClose', function (e) {
        closeForm();
    });

    $('body').on('click touch', '.cityQuick', function (e) {
        e.preventDefault();
        var city = $(this).text();

        if(city !== $('.cityName').text()){
            setCity(city,$(this).attr('data-region'),$(this).attr('data-id'),$(this).attr('data-code'));
        }else{
            closeForm();
        }
        closeForm();
    });

    $('body').on('click touch', '.js-cityChoose', function (e) {
        e.preventDefault();
        showForm();
    });

    $('body').on('click', '.topInner .bx-ui-sls-variant', function (e) {
        var el = $(this).find('.dataLocation'),
            data = {'AJAX': 'Y', 'sessid':$("#sessid").val(), 'DATA': {'CODE':el.attr('data-code'),'ID':el.attr('data-id')}};

        $.ajax({
            type: 'post',
            url: '/local/ajax/setCity.php',
            data: data,
            //dataType: 'json',
            success: function (data) {
                if(IsJsonString(data)){
                    data=$.parseJSON(data);
                    setCity(data.CITY,data.REGION,data.ID,data.REGION_ID);

                }
            }
        });
    });
    $(document).keydown(function (e) {
        if (e.keyCode === 27) {//Esc
            var popup = $('.topOuter:visible');
            if (popup) {
                closeForm(popup);
                return false;
            }
        }
    });
});

function changeCity(){
    var el = $('.topInner .bx-ui-sls-variant-active').find('.dataLocation'),
        data = {'AJAX': 'Y', 'sessid':$("#sessid").val(), 'DATA': {'CODE':el.attr('data-code'),'ID':el.attr('data-id')}};

    $.ajax({
        type: 'post',
        url: '/local/ajax/setCity.php',
        data: data,
        //dataType: 'json',
        success: function (data) {
            console.log(data);
            if(IsJsonString(data)){
                data=$.parseJSON(data);
                setCity(data.CITY,data.REGION,data.ID,data.CODE,data.REGION_ID);
            }
        }
    });
}

/*!
 * jQuery Cookie Plugin v1.4.1
 * https://github.com/carhartl/jquery-cookie
 *
 * Copyright 2006, 2014 Klaus Hartl
 * Released under the MIT license
 */
(function (factory) {
    if (typeof define === 'function' && define.amd) {
        // AMD (Register as an anonymous module)
        define(['jquery'], factory);
    } else if (typeof exports === 'object') {
        // Node/CommonJS
        module.exports = factory(require('jquery'));
    } else {
        // Browser globals
        factory(jQuery);
    }
}(function ($) {

    var pluses = /\+/g;

    function encode(s) {
        return config.raw ? s : encodeURIComponent(s);
    }

    function decode(s) {
        return config.raw ? s : decodeURIComponent(s);
    }

    function stringifyCookieValue(value) {
        return encode(config.json ? JSON.stringify(value) : String(value));
    }

    function parseCookieValue(s) {
        if (s.indexOf('"') === 0) {
            // This is a quoted cookie as according to RFC2068, unescape...
            s = s.slice(1, -1).replace(/\\"/g, '"').replace(/\\\\/g, '\\');
        }

        try {
            // Replace server-side written pluses with spaces.
            // If we can't decode the cookie, ignore it, it's unusable.
            // If we can't parse the cookie, ignore it, it's unusable.
            s = decodeURIComponent(s.replace(pluses, ' '));
            return config.json ? JSON.parse(s) : s;
        } catch(e) {}
    }

    function read(s, converter) {
        var value = config.raw ? s : parseCookieValue(s);
        return $.isFunction(converter) ? converter(value) : value;
    }

    var config = $.cookie = function (key, value, options) {

        // Write

        if (arguments.length > 1 && !$.isFunction(value)) {
            options = $.extend({}, config.defaults, options);

            if (typeof options.expires === 'number') {
                var days = options.expires, t = options.expires = new Date();
                t.setMilliseconds(t.getMilliseconds() + days * 864e+5);
            }

            return (document.cookie = [
                encode(key), '=', stringifyCookieValue(value),
                options.expires ? '; expires=' + options.expires.toUTCString() : '', // use expires attribute, max-age is not supported by IE
                options.path    ? '; path=' + options.path : '',
                options.domain  ? '; domain=' + options.domain : '',
                options.secure  ? '; secure' : ''
            ].join(''));
        }

        // Read

        var result = key ? undefined : {},
            // To prevent the for loop in the first place assign an empty array
            // in case there are no cookies at all. Also prevents odd result when
            // calling $.cookie().
            cookies = document.cookie ? document.cookie.split('; ') : [],
            i = 0,
            l = cookies.length;

        for (; i < l; i++) {
            var parts = cookies[i].split('='),
                name = decode(parts.shift()),
                cookie = parts.join('=');

            if (key === name) {
                // If second argument (value) is a function it's a converter...
                result = read(cookie, value);
                break;
            }

            // Prevent storing a cookie that we couldn't decode.
            if (!key && (cookie = read(cookie)) !== undefined) {
                result[name] = cookie;
            }
        }

        return result;
    };

    config.defaults = {};

    $.removeCookie = function (key, options) {
        // Must not alter options, thus extending a fresh object...
        $.cookie(key, '', $.extend({}, options, { expires: -1 }));
        return !$.cookie(key);
    };

}));

Листинг файла setCity.php

require($_SERVER["DOCUMENT_ROOT"] . "/bitrix/modules/main/include/prolog_before.php");

use Bitrix\Sale\Location\LocationTable;

if (check_bitrix_sessid() && $_SERVER["REQUEST_METHOD"] == "POST") {

    $parameters = array();
    $parameters['filter']['=CODE'] = $_POST['DATA']['CODE'];
    $parameters['filter']['NAME.LANGUAGE_ID'] = "ru";

    $parameters['limit'] = 1;
    $parameters['select'] = array('LNAME' => 'NAME.NAME', '*');

    $item = Bitrix\Sale\Location\LocationTable::getList( $parameters )->fetch();

    if(strlen( $item[ 'LNAME' ] ) > 0)
    {
        $city = $item['LNAME'];
        $id = $item['ID'];
        $code = $item['CODE'];
        $regionID = $item['REGION_ID'];

        if($item['DEPTH_LEVEL']>=5){
            $item = \Bitrix\Sale\Location\LocationTable::getById($item['PARENT_ID'])->fetch();
        }

        if($item['DEPTH_LEVEL']=4){
            $item = \Bitrix\Sale\Location\LocationTable::getById($item['PARENT_ID'])->fetch();
        }

        $parameters['filter']['=CODE'] = $item['CODE'];
        $arVal = Bitrix\Sale\Location\LocationTable::getList( $parameters )->fetch();

        if ( $arVal && strlen( $arVal[ 'LNAME' ] ) > 0 )
        {
            $region = $arVal['LNAME'];
        }

        echo json_encode(array('CITY'=>$city, 'REGION'=>$region, 'ID'=>$id, 'CODE'=>$code, 'REGION_ID'=>$regionID));
    }else{
        return false;
    }

}

Правим файл \bitrix\js\sale\core_ui_etc.js

Вызов функции BX.util.wrapSubstring = function(haystack, chunks, wrapTagName, escapeParts){ (~404ст) меняем на

BX.util.wrapSubstring = function(haystack, chunks, wrapTagName, escapeParts, full = false){

Так же меняем строку

return haystack.replace(/#A#/g, '<'+wrapTagName+'>').replace(/#B#/g, '</'+wrapTagName+'>');	(~444ст) 

на

if(full){
	return haystack.replace(/#A#/g, '<'+wrapTagName+' class="dataLocation newFilLCode" data-code="'+full.CODE+'" data-type="'+full.TYPE_ID+'" data-id="'+full.VALUE+'">').replace(/#B#/g, '</'+wrapTagName+'>');
}else{
	return haystack.replace(/#A#/g, '<'+wrapTagName+'>').replace(/#B#/g, '</'+wrapTagName+'>');
}

В файле bitrix\components\bitrix\sale.location.selector.search\templates\.default\script.js меняем строчку (~71ст)

itemData['=display_wrapped'] = BX.util.wrapSubstring(itemData.DISPLAY+itemData.PATH, chunks, this.opts.wrapTagName, true, itemData);

на

itemData['=display_wrapped'] = BX.util.wrapSubstring(itemData.DISPLAY+itemData.PATH, chunks, this.opts.wrapTagName, true, itemData);

Выглядит форма примерно так

Форма выбора города

Автоматическая подгрузка города пользователя в поле выбора местоположения в sale.order.ajax

Добавляем в init.php код:

\Bitrix\Main\EventManager::getInstance()->addEventHandlerCompatible(
    'sale',
    'OnSaleComponentOrderProperties',
    'SaleOrderEvents::fillLocation'
);

class SaleOrderEvents{
    function fillLocation(&$arUserResult, $request, &$arParams, &$arResult)
    {
        $registry = \Bitrix\Sale\Registry::getInstance(\Bitrix\Sale\Registry::REGISTRY_TYPE_ORDER);
        $orderClassName = $registry->getOrderClassName();
        $order = $orderClassName::create(\Bitrix\Main\Application::getInstance()->getContext()->getSite());
        $propertyCollection = $order->getPropertyCollection();

        foreach ($propertyCollection as $property){
            if ($property->isUtil())
                continue;

            $arProperty = $property->getProperty();

            if(
                $arProperty['TYPE'] === 'LOCATION'
                && array_key_exists($arProperty['ID'],$arUserResult["ORDER_PROP"])
                && !$request->getPost("ORDER_PROP_".$arProperty['ID'])
                && (
                    !is_array($arOrder=$request->getPost("order"))
                    || !$arOrder["ORDER_PROP_".$arProperty['ID']]
                )
            ) {
                global $CITY;

                //Получаем код местоположения по его айди
                $arLocs = CSaleLocation::GetByID($CITY['ID'], LANGUAGE_ID);

                $arUserResult["ORDER_PROP"][$arProperty['ID']] = $arLocs['CODE'];
            }
        }
    }
}

Смена города "на лету"

Вешаем обработчик на объект для которого заранее зададим поля data-city, data-region, data-id, data-code. Например так:

<a class="js-select-city" href="javascript:void(0);" data-city="Москва" data-region="Московская область" data-id="216" data-code="0000073738">Москва</a>

Тогда javascript для смены города будет выглядеть так:

$('.js-select-city').click(function(){
	var el = $(this);

	//Запоминаем город
	setCity(el.attr('data-city'),el.attr('data-region'),el.attr('data-id'),el.attr('data-code'));
});

function setCity(city, region, id, code) {
    var date = new Date(),
        days = 365,//3 // <--- нужное количество дней
        hours = 24,//24 // <--- нужное количество часов
        minutes = 60,//60 // <--- нужное количество минут
        seconds = 60; // <--- нужное количество секунд

    date.setTime(date.getTime() + (days * hours * minutes * seconds * 1000));

    //Устанавливаем куки
    $.cookie("geoCity", city, {expires: date, path: '/'});
    $.cookie("geoRegion", region, {expires: date, path: '/'});
    $.cookie("geoID", id, {expires: date, path: '/'});

    //Если мы на странице оформления заказа
    if ($('#bx-soa-order-form').length) {

        //Вызов смены города в старом шаблоне
        //BX.saleOrderAjax.changeLoc(id);
		
        $('.dropdown-field').val(code).fadeOut(0);
        $('.bx-ui-sls-fake').val(code).fadeOut(0);

		//Вызов смены города в новом шаблоне
        BX.Sale.OrderAjaxComponent.params.newCity=code;
        BX.Sale.OrderAjaxComponent.locations[id];
        BX.Sale.OrderAjaxComponent.editFadeRegionBlock(true);
        BX.Sale.OrderAjaxComponent.sendRequest();

    }
}

Получение списка местоположений

Учтите, что Id городов в местоположениях Битрикс у нас будут отличаться

Получить перечень городов и их id в Битрикс можно например так:

Bitrix\Main\Loader::includeModule('sale');
$db_vars = CSaleLocation::GetList(
    array(
        "SORT" => "ASC",
        "COUNTRY_NAME_LANG" => "ASC",
        "CITY_NAME_LANG" => "ASC"
    ),
    array("LID" => LANGUAGE_ID),
    false,
    false,
    array()
);

while ($location = $db_vars->Fetch()):
    echo $location["CITY_NAME"] .' - '. $location["ID"].'
';
     print_r(CSaleLocation::GetByID($location["ID"]));
endwhile;

Комментарии

Комментариев еще нет, Вы можете стать первым кто его оставит

Оставьте комментарий

На сайте используется система премодерирования комментариев, поэтому ваше сообщение будет опубликовано лишь после одобрения модератором

Вы отвечаете на комментарий пользователя

Отправить

ОБРАТНАЯ СВЯЗЬ

Напишите мне

Вы разрабатываете новый сервис, вносите доработки в существующий и хотите лучше чем у конкурентов? Вы обратились по адресу. Предлагаю вам комплексную разработку сайтов студийного уровня. У меня вы можете заказать дизайн, верстку, програмированние, разработку нетрадиционного функционала, реализацию связи между CMS, CRM и Data Analitics, а так же все остальное касаемое сайтов, кроме продвижения.

Обращайтесь, я всегда проконсультирую по всем вопросам и помогу подобрать наиболее эффективное решение для Вашего бизнеса. Я занимаюсь созданием сайтов в Новосибирске и в других регионах России, также работаю со странами СНГ. Вы останетесь довольны нашим сотрудничеством

Во время отправки произошла ошибка, пожалуйста попробуйте еще раз через некоторое время
Сообщение отправлено успешно

Телефоны

+7(993) 007-18-96

Email

info@tichiy.ru

Адрес

Россия, г. Москва

Отправляя форму Вы автоматически подтверждаете, что ознакомились и принимаете Политику конфиденциальности сайта

Написать мне
Отправить
Отправляя форму Вы автоматически подтверждаете, что ознакомились и принимаете Политику конфиденциальности сайта
Отправка успешна!
Thank you for your feedback. I will answer you within the next working hours
Отправка не удалась
Во время отправки запроса произошла ошибка. Пожалуйста, подождите и попробуйте снова через некоторое время или свяжитесь со мной