Блок выбора города на drupal-сайте (+ автоматически по ip)

На многих корпоративных сайтах вверху есть блок выбора своего города, и при его изменении на сайте уже отображаются статьи или какой-то материал, специфичный именно для этого места.
Примеры таких блоков: на сайте Альфа-банка или Эльдорадо, даже Сбербанк не отстаёт и перенаправляет пользователя сразу на нужный раздел сайта.

Итак, чтобы сделать такое на Друпале, нам понадобится:
Модуль Smart IP: https://drupal.org/project/smart_ip
Модуль интеграции русской базы ip-адресов с модулем Smart IP: http://nikita-petrov.com/sites/default/files/articles/blok-vybora-goroda... (в модуле так же есть база ip адресов на 2013 год, если вам нужно новее, обновляйте базу отсюда http://ipgeobase.ru/cgi-bin/Archive.cgi )
Дальше есть выбор - делать всплывающую форму вручную или воспользоваться кучкой соответствующих модулей. Писать свой код всё равно придется, так что выбор не так очевиден, как кажется на первый взгляд.
Я пошел по пути использования модулей, поэтому здесь описан только этот вариант.
Связка Webform + modalform, а так же небольшое дополнение Webform Term Options

Устанавливаем всю эту радость, в настройках /admin/config/people/smart_ip выставляем использовать нашу локальную базу (в самом конце), импортируем свежие данные о диапазонах ip-адресов с сайта ipgeobase.ru,
создаем блок в шапку, куда пишем примерно такой код:
<?php print 'Ваш город: ' . '<a href="' . base_path() . 'modal_forms/nojs/webform/572"  class="ctools-use-modal ctools-modal-modal-popup-small choose_city" >' . $_SESSION['smart_ip']['location']['city'] . '</a>'; ?>
Вместо 572 надо будет потом подставить ид своей вебформы, когда мы её создадим.
Выводим его в шапку. Если всё настроено правильно, у нас сразу определится наш город по нашему же ip-адресу (если только это не локальная машина)

Дальше делаем всплывающую форму для выбора и изменения города.
Создаем вебформу, в неё ставим всего один параметр "Город", "Выпадающий список", далее, там выбираем "подставить предопределенные значения", выбираем словарь таксономии, в котором у нас хранятся все города. В поле "Сообщение о подтверждении" (в самом верху) пишем следующее:

Ваши настройки сохраняются...
<script>
//jQuery(".popups-close").click(); 
location.reload();
</script>

Собственно, всё. Сохраняем, изменяем в коде блока ид на текущий ид вебформы, кликаем на город, должна всплыть форма выбора города.
Еще нужно сделать кастомный модуль и туда засунуть примерно такой код:

 
function вашмодуль_form_alter(&$form, $form_state, $form_id) {
if ($form_id == 'webform_client_form_572') {
    if ($_SESSION['smart_ip']['location']) {
      $form['submitted']['gorod']['#default_value'] = 'tid_' . $_SESSION['smart_ip']['location']['zip'];
      $form['#submit'][] = '_webform_city_submit';
    }
  }
}
 
function _webform_city_submit($form, $form_state) {
  //тут сохраняем в сессию
  $tid = substr($form_state['values']['submitted_tree']['gorod'], 4); //because 'tid_X';
  if ($_SESSION['smart_ip']['zip'] != $tid) {
    //тут перезаписываем
    $_SESSION['smart_ip']['zip'] = $tid;
    $_SESSION['smart_ip']['city'] = db_select('taxonomy_term_data', 'terms')
          ->fields('terms', array('name'))
          ->condition('tid', $tid, '=')
          ->execute()->fetchField();
    global $user;
    $location = $_SESSION['smart_ip'];
    smart_ip_set_location_data($user, $location); 
  }
}

Готово. Теперь при изменении города в вебформе и сохранении, город так же будет изменяться и в сессии пользователя.

Осталось только настроить фильтрацию контента в зависимости от выбранного города.

Для этого заходим в любую вьюху, которую надо фильтровать в зависимости от города, там создаем контекстный фильтр по полю "Город", там ставим "если значения фильтра нет в url", выполнить php-код,
пишем:

if($_SESSION['smart_ip']['zip']) {
return $_SESSION['smart_ip']['zip'];
}
else return 1;

сохраняем. Вот и всё, теперь вьюха фильтруется в зависимости от города, который определяется автоматически по ip пользователя.

В дальнейшнейшем при желании можно настроить работу модуля Context в зависимости от выбранного города (показывать определенные блоки только определенным городам).

Удачи!

Прикреплённые файлы: 
Drupal 7

Комментарии

Гость 03.12.2013 - 02:39

Давно заморачивался с этой задачей, делал без определения ip через global filter, Ваш способ гораздо лучше.

Андрей 14.12.2013 - 22:03

Очень заинтересовал данный пост. Остановился на этапе импорта базы с ipgeobase.ru.
Пытался указывать разлитчные варианты архивов ipgeobase.ru в поле "CSV URL source", однако возникает ошибка "Smart IP database update has already been initiated by cron"

Скажите подробнее, как импортировать базу ipgeobase.ru?

Drush 11.01.2014 - 13:58

Не верьте ему, он всё импортирует. Посмотрите, что он выводит в блоке "Ваш город: <название вашего города>".

Дмитрий 29.08.2014 - 11:35

Можно подробней о создании формы. Просто у меня нет таких параметров как "Выпадающий список"

Nikita Petrov 13.10.2014 - 10:58

Возможно, у вас старая версия модуля webform, обновите его или поищите решение этой проблемы в issues модуля webform.

Гость 11.09.2014 - 20:29

Здравствуйте.
Иногда выводится такая ошибка:
Fatal error: Class 'PharData' not found in ...\modules\smart_ip\includes\smart_ip.utility.inc on line 437
После отключения и подключения снова ошибка уходит, но возвращается.

Станислав 24.09.2014 - 19:47

Добрый день. Вы не указали ссылки на модуль интеграции ipgeobase с Smart IP.

Александр 10.11.2014 - 17:40

Help! Поставил все как написано, но в выборе предопределенных значений ТОЛЬКО: день недели, страны и штаты. Не могу понять как выбрать города...Все делаю по инструкции, но не проходит...Drupal 7. Срочно нужно!

Nikita Petrov 27.11.2014 - 18:20

Словарь таксономии "Города" вам нужно создать самостоятельно, например через модуль taxonomy_manager импортировать список городов, взятых из интернета.

Александр 10.11.2014 - 18:50

И еще при попытке выставления в people/smart_ip варианта с нашей базой выпадает ошибка

Notice: Trying to get property of non-object in smart_ip_ipgeobase_source_smart_ip_get_location_alter() (line 20 of /home/potol844/public_html/drupal/sites/all/modules/smart_ip_ipgeobase_source/smart_ip_ipgeobase_source.module).
Notice: Trying to get property of non-object in smart_ip_ipgeobase_source_smart_ip_get_location_alter() (line 22 of /home/potol844/public_html/drupal/sites/all/modules/smart_ip_ipgeobase_source/smart_ip_ipgeobase_source.module).
Notice: Trying to get property of non-object in smart_ip_ipgeobase_source_smart_ip_get_location_alter() (line 23 of /home/potol844/public_html/drupal/sites/all/modules/smart_ip_ipgeobase_source/smart_ip_ipgeobase_source.module).
Notice: Trying to get property of non-object in smart_ip_ipgeobase_source_smart_ip_get_location_alter() (line 24 of /home/potol844/public_html/drupal/sites/all/modules/smart_ip_ipgeobase_source/smart_ip_ipgeobase_source.module).

Сергей 27.11.2014 - 16:45

День добрый.

Да, но при переходе на другую страницу выбор города не сохраняется.
В какую сторону копать?

Nikita Petrov 27.11.2014 - 18:17

Проверьте функцию вашмодуль_form_alter из статьи - в ней указывается default_value для выбранного города. Вообще все сохраняется глобально в $_SESSION, используйте её как вам угодно.

Сергей 28.11.2014 - 17:59

в форму $_SESSION['smart_ip']['location']['city'] подставляется правильно, и сразу, и после ручного изменения

после ручного изменения правильно перезаписываются переменные:

if ($_SESSION['smart_ip']['location']['city'] != $city) {
$_SESSION['smart_ip']['location']['city'] = $city;
$_SESSION['smart_ip']['maxmind_location']['city'] = $city;

но после перехода на другую страницу переменная ['smart_ip']['location']['city'] снова изменяется на прежнюю.

Такое впечатление, что не работает
global $user;
$location = $_SESSION['smart_ip']['location'];
smart_ip_set_location_data($user, $location);

PS
Кстати, в Вашей версии выполнение
$location = $_SESSION['smart_ip'];
smart_ip_set_location_data($user, $location);
приводит к вложению массива ['location'] в $_SESSION['smart_ip']['location'].
В итоге получаем $_SESSION['smart_ip']['location']['location'].
Так и задумано?

Nikita Petrov 28.11.2014 - 18:19

Честно, уже не помню, давно это было.
Возможно, что у вас отключена поддержка сессий на сервере. Погуглите на эту тему. Вы так и не разобрались конкретно, не работает именно $location = $_SESSION['smart_ip']['location']; или всё же smart_ip_set_location_data($user, $location);
В общем, доберитесь конкретно до одной строчки, которая работает неправильно, и разберитесь в причине.
У меня на двух сайтах завелось все сразу без проблем, так что думаю проблема должна быть не в коде.

Сергей 29.11.2014 - 14:29

Спасибо за рецепт и подсказку.
Решено.
В состав модуля Smart_IP входит подмодуль Device Geolocation.
Он в переменные сессии тоже записывает свои данные.
Если этот модуль отключить, то всё работает как задумано.

Nikita Petrov 30.11.2014 - 11:49

Отлично!
Молодец, что решил, и вдвойне отлично, что поделился решением, спасибо!

Павел 29.11.2014 - 22:31

Никита, спасибо за ваш сайт.
Хотелось бы уточнить несколько моментов.
1. В случае, если город автоматически не определяется, в шапке отображается только "выберите город". Что необходимо дописать в блоке в шапке, чтобы если город не определен высвечивалась ссылка "выберите город" ведущая на форму?
2. Не совсем понятно, как связывается созданный словарь городов с создаваемой вебформой. Не могли бы Вы подробнее описать в каком виде необходимо создать словарь таксономии, чтобы его данные импортировались в вебформу в нужном виде?
Спасибо.

Nikita Petrov 30.11.2014 - 11:58

1. http://clip2net.com/s/jnCrS4 вам нужно изменить этот код в шапке. Изучите php, если город неопределен, в переменной $_SESSION не будет значения города.
2. См. скриншот, наверно вы забыли установить этот модуль, затем создаешь выпадающий список в вебформе, выбираешь в нем "Использовать термины словаря", выбираешь словарь, сохраняешь.

Дмитрий 21.01.2015 - 13:07

Здравствуйте, Никита. Спасибо за статью.
Хотелось бы узнать как можно сделать что бы это модальное окно выводилось автоматически при первом заходе на сайт?

Nikita Petrov 21.01.2015 - 19:19

Можно через php добавить проверку на наличие в сессии какой-то переменной и в зависимости от этого добавлять или нет класс к ссылке. Например
if (!isset($_SESSION['first_time'])) {
$_SESSION['first_time'] = TRUE;
$class = 'first_time';
} else $class = '';
потом я бы этот класс добавил к ссылке на выбор города, и затем добавил бы jQuery крипт запускающий окно если такой класс существует: $("a.first_class").click();

Дима 16.03.2015 - 02:42

Никита, здравствуйте.
Правильно ли я делаю?
if (isset($_SESSION['towns'])) {
print 'Ваш город: ' . ' '.$_SESSION['towns'].'';
$class = '';
}
else{
$class = 'first_time';
print 'Ваш город: ' . ' выбор города';
}
Вы не могли бы описать подробнее скрипт jQuery пожалуйста?

Дима 16.03.2015 - 02:44

извиняюсь
вот код
if (isset($_SESSION['towns'])) {
print 'p Ваш город: ' . 'a href="' . base_path() . 'modal_forms/nojs/webform/357" class="ctools-use-modal ctools-modal-modal-popup-medium choose_city" '.$_SESSION['towns'].'/a';
$class = '';
}
else{
$class = 'first_time';
print 'Ваш город: ' . ' a href="' . base_path() . 'modal_forms/nojs/webform/357" class="ctools-use-modal ctools-modal-modal-popup-medium choose_city first_time" выбор города /a';
}

Павел 21.02.2015 - 23:30

Здравствуйте! Помогите пожалуйста
Выдается такая ошибка в админке:
Notice: Trying to get property of non-object в функции smart_ip_ipgeobase_source_smart_ip_get_location_alter() (строка 20 в файле /home/gbizarizin/domains/piterfolio.ru/public_html/portal/sites/all/modules/smart_ip_ipgeobase_source/smart_ip_ipgeobase_source.module).
Notice: Trying to get property of non-object в функции smart_ip_ipgeobase_source_smart_ip_get_location_alter() (строка 22 в файле /home/gbizarizin/domains/piterfolio.ru/public_html/portal/sites/all/modules/smart_ip_ipgeobase_source/smart_ip_ipgeobase_source.module).
Notice: Trying to get property of non-object в функции smart_ip_ipgeobase_source_smart_ip_get_location_alter() (строка 23 в файле /home/gbizarizin/domains/piterfolio.ru/public_html/portal/sites/all/modules/smart_ip_ipgeobase_source/smart_ip_ipgeobase_source.module).
Notice: Trying to get property of non-object в функции smart_ip_ipgeobase_source_smart_ip_get_location_alter() (строка 24 в файле /home/gbizarizin/domains/piterfolio.ru/public_html/portal/sites/all/modules/smart_ip_ipgeobase_source/smart_ip_ipgeobase_source.module).

То есть не считывается информация из БД

Базы импортировал в smart_ip_ipgeobase_source_regions и в smart_ip_ipgeobase_source_blocks соответственно.

В настройках Smart IP проверяю IP, местоположение показывает.
НО на странице ничего не выводит $_SESSION['smart_ip']['location']['city'];

Nikita Petrov 10.03.2015 - 14:27

Вы имеете ввиду импорт новой базы ipgeobase в модуль smart_ip? Я здесь его и не рассматривал, мне хватало исходной базы за 2013 год. Кстати, если вы столкнулись с этой задачей и решили её, пожалуйста, выложите решение здесь, чтобы помочь другим с этим вопросом. Спасибо!

chewarer 11.08.2016 - 11:05

У меня та же ошибка иногда вылазит. Посмотрел что в модуле. Эта ошибка возникает когда IP пользователя нет в базе IP адресов. Думаю нужно добавить проверку на наличие IP в базе, и если его нет, то подставлять какое-то дефолтное значение, например IP Москвы.
Кстати я обновил базу пару недель назад. Сконвертировал из нового формата, в формат используемый модулем.

алексей 10.03.2015 - 14:34

да вот сейчас пытаюсь решить но я буду писать отдельный модуль для этого в виде блока.

Nikita Petrov 10.03.2015 - 15:13

Хорошо, если вам не сложно будет, выложите потом куда-нибудь код модуля для остальных и оставьте здесь ссылку, мало ли когда снова столкнётесь с этой проблемой, а гугл снова приведет вас сюда :)

Nikita Petrov 14.03.2015 - 21:23

Решил сам. В последнее время сервис ipgeobase.ru стал глючить (в плане долгого подвисания при запросах к этому сервису, да так что поисковики стали думать что мой сайт не работает), пришлось искать новое решение. Единственное нормальное решение из бесплатных на данный момент это geoplugin.com
Для Drupal есть специальный модуль для него https://www.drupal.org/project/geoplugin, но пока что до выхода нового релиза приходится его патчить https://www.drupal.org/node/2452375

Алла 03.04.2015 - 15:27

Здравствуйте, подскажите при создании вебформы в обязательное поле "Параметры" что нужно писать?

martian 25.08.2015 - 17:45

Не очень понимаю принцип работы.
Связь между элементами словаря и данными геолокации идет по tid элемента = zip из геолокации.
У меня же словарь создан вручную с tid=1..5. А zip = 191119 (например), и они никогда не будут равны.
Получается словарь городов должен быть как-то хитро создан, ведь zip по-идее в больших городах может быть разным...
Либо тема эта не раскрыта, либо я что-то не понял.

Александр 03.01.2016 - 15:21

Все делаю по инструкции. Базы импортировал, но вылетает ошибка. В чем проблема?

Notice: Trying to get property of non-object в функции smart_ip_ipgeobase_source_smart_ip_get_location_alter() (строка 20 в файле /home/a/adminicb/adminicb.bget.ru/public_html/sites/all/modules/smart_ip_ipgeobase_source/smart_ip_ipgeobase_source.module).
Notice: Trying to get property of non-object в функции smart_ip_ipgeobase_source_smart_ip_get_location_alter() (строка 22 в файле /home/a/adminicb/adminicb.bget.ru/public_html/sites/all/modules/smart_ip_ipgeobase_source/smart_ip_ipgeobase_source.module).
Notice: Trying to get property of non-object в функции smart_ip_ipgeobase_source_smart_ip_get_location_alter() (строка 23 в файле /home/a/adminicb/adminicb.bget.ru/public_html/sites/all/modules/smart_ip_ipgeobase_source/smart_ip_ipgeobase_source.module).
Notice: Trying to get property of non-object в функции smart_ip_ipgeobase_source_smart_ip_get_location_alter() (строка 24 в файле /home/a/adminicb/adminicb.bget.ru/public_html/sites/all/modules/smart_ip_ipgeobase_source/smart_ip_ipgeobase_source.module).

Александр 03.01.2016 - 22:01

А как в веб-форме значение по-умолчанию вообще может работать? У нас же zip и идентификатор терминов таксономии различается. Чтобы это все работало нужно ключи вручную для каждого города писать, но это с ума можно сойти. Или я что-то не так понимаю?

Nikita Petrov 03.01.2016 - 23:20

Александр, к сожалению совсем не помню уже как я решил эту проблему. Очевидно, что здесь вообще надо написать отдельный друпал-модуль для задачи блока выбора города, т.к. очень много людей с этим сталкиваются, да и я несколько раз тоже, но пока что никак не могу уделить на это время. Пожалуйста, если разберетесь в этом вопросе отпишитесь здесь в комментариях чтобы помочь другим. Спасибо!

Алексей 29.02.2016 - 23:41

День добрый Никит. Долго не писал нет времени. Мне удалось допилить твой код до некого компромиссного варианта, но я принял решение использовать локально хранимую базу c ipgeobase.ru. Мне не очень нравится что получилось moilgoti.ru. Буду допиливать до нормального состояния.

Алексей 29.02.2016 - 23:46

Насколько я понял правильные блоки выбора города должны использовать механизм двойной проверки с одно стороны по ip адресу с другой по географическим координатам устройства которые можно получить например с мобильных устройств

Илья 26.06.2016 - 06:46

Да это ерунда полная. Какой смысл вот так плясать с бубном если по итогу сео не получится сделать. Точнее получиться сделать для каждого города, но плясать придется еще больше и в бубен стучать сильнее))) Куда проще сделать через симлинки и поддомены типа krsk.sitename.ru. И кстате определение города по ip можно оставить. Банально написать условие, типо если ip_smart = Абакан делаем редирект на abakan.sitename.ru (грубо). Единственный минус придется создавать поддомены ну и симлинки пхп скриптом. Через симлинки я сделал гдето за 30 мин. а через этот вариант делала 2 дня в итоге не сделал. Я не понял каким х.ем zip будет равен термину.

Алексей 26.06.2016 - 06:53

У меня немного другая задача стоит. Мне не контент надо выводить а использовать идентификатор города при запросе в базу. Тот вариант с поддоменами для вывода индивидуального контента так ведь? У меня такой задачи не стоит

Илья 26.06.2016 - 07:04

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

Дмитрий 09.10.2016 - 15:18

Вариант вообще не рабочий. Информация устарела. Не работает НИЧЕГО. Автор, удалите пожалуйста эту статью, не вводите людей в заблуждение и не тратьте их время зря.
Либо обновите статью, исправьте.

Добавить комментарий