SDWSKi.COM
Каталог мест и организаций для журнала Doberman Media

Каталог мест и организаций для журнала Doberman Media

Срок 6 недель
Клиент NGO Doberman Media
Год 2026
Бюджет до 2 500 €
О
проекте
Бюджет
Профи
до 2 500 €
Продуманное решение для роста вашего бизнеса

Каталог на doberman.media/catalog — это карта и список из 295 ЛГБТК+-мест в 25 странах: клубы, сауны, отели, кафе, медицинская и юридическая помощь. Я сделал его целиком как WordPress-плагин sdwski-directory (версия 1.28.0, около 14 тысяч строк PHP, JS и CSS), без конструкторов и внешних API-ключей. Ниже — как каталог устроен и что о нём можно рассказать на странице проекта.

О проекте. Журналу Doberman.media нужен был каталог мест, где читателю можно безопасно и быстро найти клуб, сауну, врача или юриста в любом городе. Я спроектировал и написал его целиком: данные, карту, модерацию заявок, кабинет для владельцев мест и рекламные места.

Посетитель выбирает страну, город и категорию и видит все места на карте, а не только первую страницу списка. Карта рисует тысячи точек быстро, а вблизи превращает их в значки категорий. На странице места — фото, часы работы с статусом «открыто сейчас», маршрут в пяти картах, оценки и отзывы без пароля, форма «Сообщить об ошибке». Владельцы заведений сами правят свои страницы через отдельный кабинет, а я вижу каждое изменение.

  • Фильтры. Выбор страны, затем города и категории; вкладки категорий со счётчиками (на сегодня: клубы и бары — 154, отели — 58, сауны и бани — 52, Cruising — 37, общественные организации — 25). Сверху итог «Найдено: 295».
  • Поиск по названию, в том числе по переведённым названиям на другом языке сайта.
  • Карточки. Фото, категория, название, рейтинг и число отзывов, адрес, график работы, кнопки телефона, Instagram, Facebook, сайта и «Отзывы».
  • Переключатель «Список / Карта» на телефоне и плавающая панель фильтров поверх карты.
  • «Обновлять при перемещении карты». Список подстраивается под видимую область карты.
  • «Показать, где я». Геопозиция посетителя и сортировка списка от ближайших мест.
  • Избранное. Сохранённые места лежат в браузере, без регистрации.
  • Полноэкранный режим без шапки и подвала сайта и киоск-режим для демонстрации на экране.
  • Кнопка «Добавить в каталог» и блок «Нет вашего места в каталоге?» в конце списка.

Реклама. В каталог встроена реклама: баннер между карточками после каждых N мест, вертикальный баннер у карты и блоки на странице места. Всё помечено честно, баннеры меняются из админки без правки кода. Также реклама есть в карте каталога.

Технологии. PHP и WordPress, Leaflet и MapLibre GL, OpenFreeMap, чистый JavaScript, REST API, schema.org, адаптивная вёрстка без фреймворков. Без ключей API и лимитов на показы.

Карта и поиск

Карта — главная часть интерфейса, и делает она не то, что обычный плагин с точками. Её движок — Leaflet, а векторные тайлы рисует MapLibre GL; аккаунты и ключи API не нужны, тайлы берутся из OpenFreeMap.

  • Все места на карте, а не только текущая страница. Отдельный запрос без пагинации отдаёт координаты всех найденных мест (потолок — 5000), поэтому карта не зависит от того, на какой странице списка человек.
  • Три уровня детализации. Далеко — маленькие цветные точки, нарисованные одним canvas, это быстро. Со среднего масштаба «пинами» становятся проверенные места; вблизи пины с иконкой категории получают все места в видимой области (не более 300 одновременно).
  • Цвет и иконка категории. Из библиотеки встроенных иконок выбирается подходящая по названию (пламя для саун, бокал для баров, крест для медицины), и её можно поменять вручную.
  • Стартовый вид — Европа. Если ничего не выбрано, карта открывается на ЕС, а после фильтра подстраивается под найденные места. Карта не повторяет мир по бокам и не уходит за полюса.
  • Три стиля («Цветная», «Светлая», «Тёмная») с запоминанием выбора в браузере; в тёмной теме сайта карта сама берёт светлый стиль. Если у посетителя нет WebGL или векторные тайлы не загрузились за 12 секунд, карта автоматически переключается на растр OpenStreetMap.
  • Попап места по клику на точку связан со списком: карточка слева подсвечивается и прокручивается к нужному месту.
  • «Показать, где я». Точка посетителя с кругом точности рисуется поверх карты, а список сортируется по расстоянию, с подписью «км / м от вас». Геопозиция работает только по запросу посетителя и только по https.
  • Список следит за картой. Если отмечено «Обновлять при перемещении карты», в списке остаются места из видимой области, с кнопкой «Показать ещё» и сообщением, если в этой части карты мест нет.
  • Страница на всю ширину окна даже внутри узкой колонки темы; карта «прилипает» под шапкой сайта, высоту шапки скрипт определяет сам.

Страница места

Каждое место — это отдельная страница со своим шаблоном: в левой колонке текст, фото и отзывы, в правой — контакты, карта и часы работы. Шаблон работает и в классических, и в блочных темах WordPress; тема может подменить его своим файлом.

  • Галерея с просмотром фото на весь экран и три видео YouTube. Видео сначала показывается как постер, а плеер загружается по клику, поэтому страница не тянет чужие скрипты.
  • Удобства. Список того, что есть, и того, чего нет: недоступное отмечается красным крестиком, например «нет безбарьерного входа».
  • Часы работы по дням недели (открыто, закрыто, круглосуточно). Статус «Сейчас открыто» считается в браузере по часовому поясу сайта, чтобы кэш страницы не показывал вчерашний статус. Ночные графики, когда клуб работает до утра, учтены.
  • Маршрут. Посетитель выбирает «на машине / общественным транспортом / пешком», и ссылки на Google Maps, Яндекс Карты, Apple Maps, Waze и OpenStreetMap перестраиваются под этот режим; старт — текущая позиция человека.
  • Карта места — тот же движок, что и в каталоге, с теми же стилями и запасным вариантом.
  • «Сохранить» и «Поделиться». Избранное общее с главной страницей каталога: сохранённые места показывает одна панель в левом нижнем углу.
  • Плашка «Данные не подтверждены». Если место не отмечено как «Проверено», посетитель честно увидит, что часы и контакты могут быть неактуальны, а рядом — кнопка «Это моя организация».

Отзывы и рейтинг

Оценки и отзывы работают поверх плагина комментариев SDWSKi Comments. Вход без пароля: код приходит на e-mail, один подтверждённый адрес — одна оценка на место, её можно изменить. После оценки открывается форма отзыва. Рейтинг виден и в карточках списка, а кнопка «Отзывы» ведёт прямо к блоку комментариев. Для одного места оценки можно отключить.

Обратная связь

В карточке «Обратная связь» пять причин: сообщить об ошибке, «это моя организация», «закрыто или переехало», пожаловаться, оставить комментарий. Сообщения сохраняются в админке и приходят на почту; если отправитель оставил почту, ответить можно прямо из письма. Защита от спама — скрытое поле-ловушка, одноразовый токен и лимит 5 сообщений в час с одного IP (хранится только хэш адреса).

Заявки, модерация и владельцы мест

Каталог наполняют три источника: я вручную или из CSV, посетители через форму «Добавить в каталог» и сами владельцы. Публичным списком и картой пользуются только опубликованные записи.

Форма «Добавить место»

  1. Посетитель заполняет форму; от ботов защищают поле-ловушка и лимит — 3 заявки в час с одного IP.
  2. Заявка сохраняется со статусом «На утверждении», а администратору уходит письмо со ссылкой.
  3. Адрес в фоне превращается в координаты. Существующие страна и город прикрепляются сразу, новые только запоминаются и создаются при публикации — список городов нельзя засорить заявками.
  4. Я проверяю заявку, правлю, ставлю «Проверено» и публикую.

Владельцы мест

Ресторатор, директор клуба или представитель НКО нажимает «Это моя организация». Этот повод сам по себе никаких прав не даёт: я проверяю человека и одним нажатием выдаю доступ.

  • Создаётся аккаунт с ролью «Владелец места» без доступа в админку, и человеку приходит письмо со ссылкой для пароля.
  • В кабинете владелец видит свои места и меняет название, описание, контакты, часы, удобства, точку на карте и фото.
  • Категория, страна и город, отметка «Проверено» и включение отзывов остаются за администратором.
  • Правки публикуются сразу, а я получаю письмо «было → стало» по каждому полю: ничего не происходит незаметно.
  • Владелец может публиковать короткие новости места: не больше трёх, четвёртая вытесняет самую старую. Новости показываются на странице места и в любом блоке сайта шорткодом.

Инструменты администратора

В админке есть встроенная документация с быстрым стартом, всеми шорткодами и готовыми примерами; раздел «Группировка городов по странам» и инструмент латинских адресов; настройки страницы места и рекламы.

Рекламные места

Реклама встроена в плагин и настраивается в одном разделе админки «Каталог → Реклама». В каталоге три типа размещения, и каждый помечен надписью «Реклама», чтобы посетитель не путал её с местами.

РазмещениеГде видноКак работает
Баннер в спискемежду карточками мест, на всю ширину колонкипосле каждых N карточек (N от 2 до 30, по умолчанию 4); баннеры идут по кругу, после последней карточки рекламы нет
Вертикальный баннер у картывысокая колонка у правого края карты, на экранах от 1024 pxкартинка со ссылкой или готовый HTML-файл; ширина задаётся вручную, у HTML-файла по умолчанию 300 px
Блок на странице местав правой колонке и под отзывамиHTML-файлы sidebar.html и comments.html из папки wp-content/lgbtd-ads/; тот же блок можно вставить куда угодно на сайте

Каждый баннер в списке — это либо картинка со ссылкой, либо код рекламной сети. Под баннером всегда стоит кнопка «Разместить баннер здесь» со ссылкой на страницу покупки рекламы журнала, поэтому каталог сам приводит рекламодателей к медиапредложению.

Детали, которые стоят отдельного упоминания

  • Реклама живёт вместе со списком. Когда посетитель фильтрует места, двигает карту или сортирует по расстоянию, баннеры заново расставляются после каждых N видимых карточек, а не остаются на местах, где их оставил сервер.
  • Блокировщики рекламы. У блока у карты нейтральные имена CSS-классов без слов «ad» и «banner», чтобы его не скрывали списки фильтров.
  • Честная разметка. Ссылки баннеров открываются в новой вкладке с rel="sponsored nofollow noopener", картинки грузятся лениво.
  • Кэш. После смены рекламы плагин sdwski-directory сам сбрасывает кэш популярных плагинов (WP Rocket, W3 Total Cache, LiteSpeed, SG Optimizer и др.), иначе посетители видели бы старый баннер.
  • Диагностика для администратора. На странице настроек показано, что именно сохранено и почему баннер может не появляться; в исходном коде страницы для администратора оставляется служебный комментарий.
  • Безопасность. Произвольный код в баннерах может сохранить только тот, у кого есть право unfiltered_html; остальным скрипты вырезаются.
  • HTML-файлы по FTP. Рекламный блок можно не набирать в админке, а залить готовым файлом с анимацией и вёрсткой рекламодателя; имя файла проверяется (латиница, цифры, - и _), чтобы нельзя было выйти за пределы папки.

Технические решения

Весь каталог — один плагин без зависимостей от конструкторов и тяжёлых фреймворков: PHP для серверной части, чистый JavaScript для карты и интерфейса, свой CSS. Из чужого — только Leaflet и MapLibre GL, оба лежат внутри плагина.

СлойЧто используется
СерверWordPress, PHP: типы записей, таксономии, метаполя, REST API, AJAX, собственная таблица рейтингов
КартаLeaflet 1.9.4, MapLibre GL 4.7.1, тайлы OpenFreeMap, резерв — OpenStreetMap
ГеокодингNominatim (OpenStreetMap), фоновая задача WordPress
Клиентбез фреймворков: directory.js (около 1300 строк), single.js, избранное в localStorage
Отзывыплагин SDWSKi Comments, оценки привязаны к его подтверждённым аккаунтам
Переводфайлы перевода ru_RU + стыковка с плагином перевода сайта (поиск по переведённым названиям, параметр lang в API)

Производительность

  • Тысячи точек рисуются одним canvas, полноценные пины — только для видимой области и не больше 300 штук.
  • Стили каталога (46 КБ) подключаются только на страницах, где есть шорткод каталога, место или архив; на остальных страницах журнала они не грузятся.
  • Версия файла скрипта собирается из версии плагина и времени изменения файла: браузер не держит старую копию после обновления.
  • Данные, зависящие от времени («Открыто сейчас»), считаются в браузере, поэтому кэширование страниц не мешает.
  • Карта не зависит от платных API: нет ключей Google или Mapbox и нет лимитов на показы.

Приватность и безопасность

  • Избранное и позиция посетителя не уходят на сервер: первое хранится в браузере, вторая нужна только на карте и по запросу.
  • Для лимитов на формы хранится только хэш IP; ответы форм защищены одноразовыми токенами и полем-ловушкой.
  • Владельцы мест не получают доступа в админку, а каждое их изменение дублируется письмом администратору.
  • Для неподтверждённых мест на странице стоит прямое предупреждение; в каталоге допускаются только вечные данные, без цен и анонсов событий.
  • При удалении плагина места, категории и города остаются, пока я сам не включу полное удаление в wp-config.php.
  • Плагин расширяется фильтрами WordPress (lgbtd_rest_place, lgbtd_utm_params, lgbtd_schema_type, lgbtd_map_max_markers, lgbtd_kiosk_param и другими), чтобы поведение менялось без правки ядра.