Bitrix automatic city detection in php
Rus
Eng
Битрикс автоматическое определение города на php
Order site
By contacting me you will receive a reliable and knowledgeable contractor who will quickly and efficiently implement any task for you and your business.

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

Please message me to discuss the task. I work remotely and officially (as a self-employed professional); my hourly rate is 1,800 RUB, and I can dedicate 3–4 hours a day to the project. I respond quickly, and the consultation is free.

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