Причины создания
Недавно попросили сделать геотаргетинг по городам для сайта на wordpress. Пересмотрев существующие геотаргетинг-плагины (в том числе платные), не нашёл не одного работающего с городами (только страны). Поэтому решил сделать свой, используя какую-нибудь существующую базу для определения местоположения по IP-адресу. Сначала начал с разработки функции в шаблоне, но потом решил создать плагин и выложить на github, так как думаю, что он может пригодиться кому-нибудь ещё.
Выбор базы
Первым делом нужно было выбрать базу. И это, наверное, одна из самых сложных проблем. В процессе разработки пробовал много вариантов, даже делал CURL-запросы на сайты, определяющие местоположение по ip, и парсил их. Но все они были не точны, к примеру, один Московский IP определяло как Москву, другой — просто Россия. Также нужно было, чтобы плагин работал не только с Россией, но и с Беларусью и Украиной. Перепробовав
Функционал
Как я уже писал, начинал я делать не с плагина, а с функции в шаблоне. Сначала думал только об условно-платной версии базы, но количество бесплатных запросов закончилось за день-два. Поэтому перешёл на бесплатную, используя готовый класс для работы с файлом базы.
При разработке плагина я решил сделать выбор между локальной базой и REST API. В будущем планирую сделать кнопку автоматического обновления базы.
Также из базы можно вернуть русские и английские имена городов (стран, регионов). В связи с этим сделал выбор языка.
Ещё столкнулся с тем, что нужно включить список несколько городов или наоборот исключить какой-то.
Настройка плагина в админке
Реализация
Так как с Wordpress я работаю редко (как и со всеми CMS) и написанием плагинов для него никогда не занимался, начал читать, как их писать и смотреть, как устроены существующие. Идею реализации взял с существующих гео-плагинов. Ещё долго думал писать функционально или объектно-ориентированно. Решил функционально, так как плагин не большой.
Вкратце опишу его работу.
При активации плагина инициируем две опции: тип бд и язык на котором будем вводить названия.
register_activation_hook(__FILE__, 'wp_sypexgeo_activation');
function wp_sypexgeo_activation() {
update_option('sgeo_language', 'en');
update_option('sgeo_dbase', 'loc');
}
Далее
add_filter('the_content', 'geotargeting_filter');
add_filter('the_content_rss', 'geotargeting_filter');
add_filter('the_excerpt', 'geotargeting_filter');
add_filter('the_excerpt_rss', 'geotargeting_filter');
вызывают функцию geotargeting_filter
В которую приходит текущий контент. В зависимости от типа базы вызывается функция для получения данных. Затем идёт поиск специальных тегов в шаблоне и сверка их с данными о местоположении. Если данные совпадают то конструкция заменяется на содержимое из тегов, если нет — она удаляется.function geotargeting_filter($s) {
//parse Country
preg_match_all("#\[" . GEOTARGETING_COUNTY . "\s*(in|out)=([^\]]+)\](.*?)\[/" . GEOTARGETING_COUNTY . "\]#isu", $s, $country);
//parse Country
preg_match_all("#\[" . GEOTARGETING_REGION . "\s*(in|out)=([^\]]+)\](.*?)\[/" . GEOTARGETING_REGION . "\]#isu", $s, $region);
//parse Country
preg_match_all("#\[" . GEOTARGETING_CITY . "\s*(in|out)=([^\]]+)\](.*?)\[/" . GEOTARGETING_CITY . "\]#isu", $s, $city);
if (empty($country) && empty($region) && empty($city)) {
return $s;
}
$base_type = get_option('sgeo_dbase');
if ($base_type == 'loc') {
$ipdata = getLocInfo();
} elseif ($base_type == 'rm') {
$ipdata = getRemInfo();
}
if (!empty($country)) {
foreach ($country[0] as $i => $raw) {
$type = strtolower($country[1][$i]);
$countries = strtolower(trim(str_replace(array("\"", "'", "\n", "\r", "\t", " "), "", $country[2][$i])));
$content = $country[3][$i];
$countries = explode(",", $countries);
$replacement = "";
if ((($type == "in") && in_array($ipdata['country'], $countries)) || (($type == "out") && !in_array($ipdata['country'], $countries))) {
$replacement = $content;
}
$s = str_replace($raw, $replacement, $s);
}
}
if (!empty($region)) {
foreach ($region[0] as $i => $raw) {
$type = strtolower($region[1][$i]);
$regions = strtolower(trim(str_replace(array("\"", "'", "\n", "\r", "\t"), "", $region[2][$i])));
$content = $region[3][$i];
$regions = explode(",", $regions);
$replacement = "";
if ((($type == "in") && in_array($ipdata['region'], $regions)) || (($type == "out") && !in_array($ipdata['region'], $regions))) {
$replacement = $content;
}
$s = str_replace($raw, $replacement, $s);
}
}
if (!empty($city)) {
foreach ($city[0] as $i => $raw) {
$type = strtolower($city[1][$i]);
$cities = strtolower(trim(str_replace(array("\"", "'", "\n", "\r", "\t", " "), "", $city[2][$i])));
$content = $city[3][$i];
$cities = explode(",", $cities);
$replacement = "";
if ((($type == "in") && in_array($ipdata['city'], $cities)) || (($type == "out") && !in_array($ipdata['city'], $cities))) {
$replacement = $content;
}
$s = str_replace($raw, $replacement, $s);
}
}
return $s;
}
Использование
Для указания списка стран:
[GeoCountry in=Belarus,Russia]Привет Belarus,Russia![/GeoCountry]
Для указания списка регионов:
[GeoRegion in=Moscow]Привет Moscow Region![/GeoRegion]
Для указания списка городов:
[GeoCity in=Минск,Брест]Привет Минск,Брест![/GeoCity]
Если вы хотите выбрать страны (регионы, города) за исключением указанных, используйте «out»:
[GeoRegion out=Minsk,Brest]Привет всем, кроме Minsk,Brest![/GeoRegion]
Пример использования в шаблоне:
Добро пожаловать в WordPress. Это ваша первая запись. Отредактируйте или удалите её, затем пишите! Наши контакты: [GeoCity in=Minsk]+375295552255[/GeoCity][GeoCity out=Minsk]+375475552255[/GeoCity]
Заключение
Надеюсь, мой плагин кому-нибудь пригодится. Если есть вопросы или предложение — пишите. Также, если кто-то считает, что нужно использовать другую базу (геосервис или ещё что-нибудь), предлагайте, я добавлю или можете добавить сами.
Ссылка на плагин: wp-sypexgeo
olen
Для шорткодов правильнее и проще использовать add_shortcode().
Только в чем смысл статьи? Вы взяли готовую базу и с помощью готового класса получаете информацию. Что полезного для читателей?
И вообще, плагин довольно специфичный получился. Тот же номер телефона с его помощью в шапке сайта или в футере не получится выводить.
Apathetic
Нет никакой проблемы в том, чтобы напрямую вызывать функцию geotargeting_filter.
Но согласен с вами, что использовать add_shortcode — правильней.
DEMONofNIGHT Автор
Про add_shortcode спасибо, учту.
Смысл простой, если кому-нибудь понадобиться решить похожую задачу, ему не надо будет искать базу и класс для неё, писать парсер шаблона и тд. Для этого ведь и делаются плагины.
Про футер и хедер согласен, в коде плагин не используешь. Это проблема, тогда уже нужно писать эти функции в код шаблона к примеру.
olen
Если вы хотели поделиться плагином, то для этого есть соответствующий каталог.
> ему не надо будет искать базу и класс для неё
Это вы взяли уже готовое. Более того, база в вашем плагине через некоторое время устареет.
> писать парсер шаблона
Парсер шаблона писать не надо, надо использовать add_shortcode.
> и тд
Что и т.д.? В том то и дело, что тут ничего нет.
В статье на Хабре хотелось бы видеть какие-то не совсем очевидные вещи.