Bitrix automatic city detection in php
The last notes
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, '' + wrapTagName + '>'); (~ 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,' '+ wrapTagName +'> ');
} else {
return haystack.replace (/ # A # / g, '<' + wrapTagName + '>'). replace (/ # B # / g, '' + wrapTagName + '>');
}
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
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