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

All English-language materials have been translated fully automatically using the Google service

This material is not intended to be a comprehensive guide. The code is supplied free of charge and "as is". Use it at your own risk

MaxMind has good instructions for using their databases: maxmind- db / reader . Check it out or keep reading my implementation experience.

You can download free MaxMind databases here: GeoLite2 Free Downloadable Databases < / a> (account registration required)

Place the downloaded database GeoLite2-City.mmdb in any convenient folder, for example, in /local/libs/maxmind/

To read MaxMind databases for php, a special "reader" is required. Go to the ssh console under the root account and install MaxMind DB Reader

  yum install php-maxminddb  

If you get an error, you can use the command

  apt install libmaxminddb-dev  

Let's assume that composer is already included in your project. Go to the console and put

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

Cross-browser user city selection form

In init.php add

require($_SERVER ['DOCUMENT_ROOT'>] .'/local/libs/init/geolocationMaxMInd.php');</code> </pre>
<p> Listing of the file <code>geolocationMaxMInd.php</code> </p>
<pre> <code> // Feel free to get rid of extra. parameters (REGION_ID, REGION_NAME) they are needed in very rare cases
require $ _SERVER ['DOCUMENT_ROOT']. '/ vendor / autoload.php';
use GeoIp2 \ Database \ Reader;

AddEventHandler ("main", "OnPageStart", "OnPageStart");
function OnPageStart () {
    global $ CITY; // Define a global variable on the site where we write the information received

    if (! CModule :: IncludeModule ("sale")) // could not connect the module
        return;

    // I split the geolocation cookies into 3 separate ones (for convenience), you can use any post format
    if (! $ _ COOKIE ['geoCity'] ||! $ _ COOKIE ['geoRegion'] ||! $ _ COOKIE ['geoID']) {// If all 3 cookies are not defined, then we define via MaxMind
        $ reader = new Reader ($ _ SERVER ['DOCUMENT_ROOT']. '/ local / libs / maxmind / GeoLite2-City.mmdb'); // Tell the reader where to read the database

        $ ip = \ Bitrix \ Main \ Service \ GeoIp \ Manager :: getRealIp (); // Get ip using standard Bitrix methods
        $ record = $ reader-> city ($ ip); // Get an array of data by ip

        $ CITY = array (
            'REGION_NAME' => $ record-> mostSpecificSubdivision-> names ['ru'], // define the area
            'CITY_NAME' => $ record-> city-> names ['ru'], // define the city
        );

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

$ CITY ['CITY_ID'] = $ location ['ID'];
        $ CITY ['REGION_ID'] = $ location ['REGION_ID'];

        // Set an array with the default city in case the city is not found
        if (! $ CITY ['CITY_NAME']) {
            $ CITY = array (
                'REGION_NAME' => 'Moscow region',
                'CITY_NAME' => 'Moscow',
                'CITY_ID' => '84',
            );
        }
// Set cookies
        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 {
        // Since the cookies were found, we fill the array with data from them
        $ 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']! = 'Moscow') {// In my case, Moscow did not have regions
        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) {
// Looking for a match of the found city in Bitrix locations
$ 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 ();
}
</code> </pre>
<p> In <code> header.php </code> add a form call </p>
<pre><code><a class = "js-select-city" href = "javascript: void (0);" data-city = "Moscow" data-region = "Moscow region" data-id = "216" data-code = "0000073738"> Moscow </a> 

In footer.php display the form

<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> City selection: </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> or select from the list: </h4>
        <hr />
<div class = "row citiesQuick">
            <div class = "col-xs-4"> <a href="#" class="cityQuick <?if($CITY ['CITY_NAME'> ]=='Moscow') might {?> active <?}?> " data-title = "Moscow" data-region = "Moscow region" data-id = "84" data-code = "0000073738" title = "Moscow"> Moscow </a> </div>
            <div class = "col-xs-4"> <a href="#" class="cityQuick <?if($CITY ['CITY_NAME' ]=='Saint-Petersburg') gauge-active <?}? > "data-title =" Saint Petersburg "data-region =" Leningrad region "data-id =" 85 "data-code =" 0000103664 "title =" Saint Petersburg "> Saint Petersburg </a> </ div>
            <div class = "col-xs-4"> <a href="#" class="cityQuick <?if($CITY ['CITY_NAME' ]=='Balashikha')(?> active <?}?> " data-title = "Balashikha" data-region = "Moscow region" data-id = "87" data-code = "0000033889" title = "Balashikha"> Balashikha </a> </div>
            <div class = "col-xs-4"> <a href="#" class="cityQuick <?if($CITY ['CITY_NAME'> ]=='Voronezh')(?> active <?}?> " data-title = "Voronezh" data-region = "Voronezh Region" data-id = "740" data-code = "0000293598" title = "Voronezh"> Voronezh </a> </div>
            <div class = "col-xs-4"> <a href="#" class="cityQuick <?if($CITY ['CITY_NAME'> ]=='Ekaterinburg')(?> active <?}?> " data-title = "Yekaterinburg" data-region = "Sverdlovsk region" data-id = "2203" data-code = "0000812044" title = "Yekaterinburg"> Yekaterinburg </a> </div>
            <div class = "col-xs-4"> <a href="#" class="cityQuick <?if($CITY ['CITY_NAME'> ]=='Kazan') animated <?}?> " data-title = "Kazan" data-region = "Republic of Tatarstan" data-id = "1558" data-code = "0000550426" title = "Kazan"> Kazan </a> </div>
            <div class = "col-xs-4"> <a href="#" class="cityQuick <?if($CITY ['CITY_NAME'> ]=='Queens') {?> active <?}?> " data-title = "Korolev" data-region = "Moscow region" data-id = "91" data-code = "0000030318" title = "Korolev"> Korolev </a> </div>
            <div class = "col-xs-4"> <a href="#" class="cityQuick <?if($CITY ['CITY_NAME'> ]=='Krasnogorsk')(?> active <?}?> data-title = "Krasnogorsk" data-region = "Moscow region" data-id = "142" data-code = "0000044453" title = "Krasnogorsk"> Krasnogorsk </a> </div>
            <div class = "col-xs-4"> <a href="#" class="cityQuick <?if($CITY ['CITY_NAME' ]=='Krasnodar')(?> active <?}?> " data-title = "Krasnodar" data-region = "Krasnodar Territory" data-id = "1132" data-code = "0000386590" title = "Krasnodar"> Krasnodar </a> </div>
            <div class = "col-xs-4"> <a href="#" class="cityQuick <?if($CITY ['CITY_NAME' ]=='Lubertsy')(?> active <?}?> " data-title = "Lyubertsy" data-region = "Moscow region" data-id = "149" data-code = "0000046203" title = "Lyubertsy"> Lyubertsy </a> </div>
<div class = "col-xs-4"> <a href="#" class="cityQuick <?if($CITY ['CITY_NAME'> ]=='Washers') {?> active <?}?> " data-title = "Mytishchi" data-region = "Moscow region" data-id = "153" data-code = "0000049473" title = "Mytishchi"> Mytishchi </a> </div>
            <div class = "col-xs-4"> <a href="#" class="cityQuick <?if($CITY ['CITY_NAME'> ]=='Nizhny Novgorod')(?> active <?}?> "data-title =" Nizhny Novgorod "data-region =" Nizhny Novgorod region "data-id =" 1698 "data-code =" 0000600317 "title =" Nizhny Novgorod "> Nizhny Novgorod </a> </div>
            <div class = "col-xs-4"> <a href="#" class="cityQuick <?if($CITY ['CITY_NAME'> ]=='Novosibirsk') {?> active <?}?> " data-title = "Novosibirsk" data-region = "Novosibirsk region" data-id = "2614" data-code = "0000949228" title = "Novosibirsk"> Novosibirsk </a> </div>
            <div class = "col-xs-4"> <a href="#" class="cityQuick <?if($CITY ['CITY_NAME' ]=='Odintsovo')(?> active <?}?> " data-title = "Odintsovo" data-region = "Moscow region" data-id = "166" data-code = "0000054606" title = "Odintsovo"> Odintsovo </a> </div>
            <div class = "col-xs-4"> <a href="#" class="cityQuick <?if($CITY ['CITY_NAME'> ]=='Perm') 0000-00-00 <?}?> " data-title = "Perm" data-region = "Perm Territory" data-id = "1869" data-code = "0000670178" title = "Perm"> Perm </a> </div>
            <div class = "col-xs-4"> <a href="#" class="cityQuick <?if($CITY ['CITY_NAME'> ]=='Подольск')›?> active <?}?> " data-title = "Podolsk" data-region = "Moscow region" data-id = "109" data-code = "0000032609" title = "Podolsk"> Podolsk </a> </div>
            <div class = "col-xs-4"> <a href="#" class="cityQuick <?if($CITY ['CITY_NAME'> ]=='Pushkin')(?> active <?}?> " data-title = "Pushkin" data-region = "Leningrad Region" data-id = "3139" data-code = "0000107443" title = "Pushkin"> Pushkin </a> </div>
            <div class = "col-xs-4"> <a href="#" class="cityQuick <?if($CITY ['CITY_NAME' ]=='Rostov-na-Donu') 0000-00-00 <? }?> "data-title =" Rostov-on-Don "data-region =" Rostov region "data-id =" 1248 "data-code =" 0000445112 "title =" Rostov-on-Don "> Rostov-on -Donu </a> </div>
            <div class = "col-xs-4"> <a href="#" class="cityQuick <?if($CITY ['CITY_NAME'> ]=='Samara')›?> active <?}?> " data-title = "Samara" data-region = "Samara Region" data-id = "1831" data-code = "0000650509" title = "Samara"> Samara </a> </div>
            <div class = "col-xs-4"> <a href="#" class="cityQuick <?if($CITY ['CITY_NAME' ]=='Sochi') gauge {?> active <?}?> " data-title = "Sochi" data-region = "Krasnodar Territory" data-id = "1137" data-code = "0000394020" title = "Sochi"> Sochi </a> </div>
            <div class = "col-xs-4"> <a href="#" class="cityQuick <?if($CITY ['CITY_NAME'> ]=='Khimki')›?> active <?}?> " data-title = "Khimki" data-region = "Moscow region" data-id = "111" data-code = "0000033097" title = "Khimki"> Khimki </a> </div>
            <div class = "col-xs-4"> <a href="#" class="cityQuick <?if($CITY ['CITY_NAME'> ]=='Chelyabinsk')(?> active <?}?> " data-title = "Chelyabinsk" data-region = "Chelyabinsk Region" data-id = "2354" data-code = "0000854968" title = "Chelyabinsk"> Chelyabinsk </a> </div>
        </div>
    </div>
</div> 

Writing the styles of the form to 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 # abs; * /}

.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;} * /
}  

In the main script of the template, for example, main.js add

  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 // <--- required number of days
    var hours = 24; // 24 // <--- required number of hours
    var minutes = 60; // 60 // <--- required number of minutes
    var seconds = 60; // <--- required number of seconds

    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 we are on the checkout page
    if ($ ('# bx-soa-order-form'). length) {
        // Call changing the city in the old template
        //BX.saleOrderAjax.changeLoc(id);
        $ ('. dropdown-field'). val (code) .fadeOut (0);
        $ ('. bx-ui-sls-fake'). val (code) .fadeOut (0);

        // Call changing the city in a new template
        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) {// Tracking the click on the element
            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  

Listing of file 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;
    }

}  

Editing the file \bitrix\js\sale\core_ui_etc.js

Function call BX.util.wrapSubstring = function (haystack, chunks, wrapTagName, escapeParts) { (~ 404st) change to

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

Also change the line

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

to

  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,'  ');
} else {
return haystack.replace (/ # A # / g, '<' + wrapTagName + '>'). replace (/ # B # / g, '');
}  

In the file bitrix \ components \ bitrix \ sale.location.selector.search \ templates \ .default \ script.js change the line (~ 71st)

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

to

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

The form looks like this

City selection form

Automatic loading of the user's city in the location selection field in sale.order.ajax

Add code to 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;

                // Get the location code by its ID
                $ arLocs = CSaleLocation :: GetByID ($ CITY ['ID'], LANGUAGE_ID);

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

Change city on the fly

We hang the handler on the object for which we will preset the fields data-city, data-region, data-id, data-code . For example like this:

<a class = "js-select-city" href = "javascript: void (0);" data-city = "Moscow" data-region = "Moscow region" data-id = "216" data-code = "0000073738"> Moscow </a>

Then the javascript for changing the city will look like this:

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

// Remember the city
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 // <--- required number of days
        hours = 24, // 24 // <--- required number of hours
        minutes = 60, // 60 // <--- required number of minutes
        seconds = 60; // <--- required number of seconds

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

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

    // If we are on the checkout page
    if ($ ('# bx-soa-order-form'). length) {

        // Call changing the city in the old template
        //BX.saleOrderAjax.changeLoc(id);

        $ ('. dropdown-field'). val (code) .fadeOut (0);
        $ ('. bx-ui-sls-fake'). val (code) .fadeOut (0);

// Call changing the city in a new template
        BX.Sale.OrderAjaxComponent.params.newCity = code;
        BX.Sale.OrderAjaxComponent.locations [id];
        BX.Sale.OrderAjaxComponent.editFadeRegionBlock (true);
        BX.Sale.OrderAjaxComponent.sendRequest ();

    }
}  

Getting a list of locations

Please note that Id of cities in Bitrix locations will be different for us

You can get a list of cities and their id in Bitrix like this:

  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;  

Comments

There are no comments yet, you can be the first to leave it

Leave a comment

The site uses a comment pre-moderation system, so your message will be published only after approval by the moderator

You are replying to a user's comment

Send

FEEDBACK

Email me

Are you developing a new service, making improvements to the existing one and want to be better than your competitors? You have come to the right place. I offer you a comprehensive studio-level website development. From me you can order design, layout, programming, development of non-traditional functionality, implementation of communication between CMS, CRM and Data Analitics, as well as everything else related to sites, except for promotion.

Contact, I will always advise on all questions and help you find the most effective solution for your business. I am engaged in the creation of sites in Novosibirsk and in other regions of Russia, I also work with the CIS countries. You will be satisfied with our cooperation

An error occurred while sending, please try again after a while
Message sent successfully

Phones

+7(993) 007-18-96

Email

info@tichiy.ru

Address

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

By submitting the form, you automatically confirm that you have read and accept the Privacy Policy site

Contact with me
Send message
By submitting the form, you automatically confirm that you have read and accept Privacy policy of site
Sending successful!
Thank you for contacting :) I will contact you as soon as possible
Sending failed
An error occurred while sending the request. Please wait and try again after a while or call my phone number