WordPress модуль для Яндекс.Карт: проекты на карте с ACF и кластеризацией
Практический модуль для WordPress: кастомный тип записи для проектов, ACF поля для координат, интеграция с Яндекс.Картами, кластеризация меток и адаптивный дизайн. Готовое решение для отображения реализованных проектов на карте.
Требования
- WordPress 5.0+
- PHP 7.2+
- ACF (Advanced Custom Fields) плагин
- API ключ Яндекс.Карт
WordPress модуль для Яндекс.Карт: проекты на карте с ACF и кластеризацией
Если тебе нужно показать реализованные проекты на карте — например, установленное оборудование в разных городах — обычные решения либо слишком сложные, либо не дают нужной гибкости. Модуль проектов для WordPress решает эту задачу просто: кастомный тип записи для проектов, ACF поля для координат и адресов, интеграция с Яндекс.Картами с кластеризацией меток. Всё готово к использованию, легко переносится в другой сайт. (GitHub)
Главное преимущество: проекты не имеют публичных страниц — они используются только для отображения на карте. Это идеально для случаев, когда нужно показать локации без создания отдельных страниц для каждого проекта.
Задача: что нужно было решить
Типичная ситуация: у тебя есть список реализованных проектов (например, установленное оборудование), и нужно показать их на карте с информацией:
- координаты (широта/долгота)
- адрес
- тип и модель оборудования
- описание проекта
При этом:
- проекты должны управляться через админку WordPress
- карта должна автоматически группировать близкие метки (кластеризация)
- решение должно быть переносимым в другой сайт
- если проектов нет — показывать тестовые данные для демонстрации
Архитектура решения
Модуль состоит из четырёх основных файлов:
projects.php— регистрация кастомного типа записи и таксономииprojects-acf.php— ACF поля для координат и данных проектовprojects-map.php— функции для работы с картой, подключение скриптовprojects-loader.php— главный файл, который подключает всё остальное
Почему именно такая структура
Разделение на файлы делает модуль:
- понятным — каждый файл отвечает за свою задачу
- переносимым — можно скопировать папку и подключить в другом сайте
- расширяемым — легко добавить новые поля или функции
Шаг 1: Регистрация кастомного типа записи
Файл: projects.php
<?php
add_action('init', function(){
register_post_type('projects', array(
'labels' => array(
'name' => 'Проекты',
'singular_name' => 'Проект',
'add_new' => 'Добавить новый',
'add_new_item' => 'Добавить новый проект',
'edit_item' => 'Редактировать проект',
'menu_name' => 'Проекты',
),
'public' => false, // Проекты только для карты
'publicly_queryable' => false, // Нельзя открыть отдельную страницу
'show_in_nav_menus' => false, // Не показывать в меню
'supports' => ['title', 'editor', 'thumbnail'],
'show_ui' => true, // Показывать в админке
'has_archive' => false, // Нет архива
'show_in_rest' => true,
'menu_icon' => 'dashicons-location-alt'
));
});
Важно: 'public' => false означает, что проекты не имеют публичных URL. Они используются только для карты, что идеально для локаций без отдельных страниц.
Регистрация таксономии для типов оборудования
add_action('init', function(){
register_taxonomy('project-equipment', ['projects'], [
'label' => 'Тип оборудования',
'public' => false, // Таксономия не публичная
'show_ui' => true,
'show_in_rest' => true,
'hierarchical' => true,
'show_admin_column' => true
]);
});
Шаг 2: ACF поля для координат и данных
Файл: projects-acf.php
ACF поля создаются программно через acf_add_local_field_group(). Это удобно, потому что поля автоматически создаются при активации темы — не нужно настраивать их вручную.
<?php
if(function_exists('acf_add_local_field_group')):
acf_add_local_field_group(array(
'key' => 'group_projects_fields',
'title' => 'Поля проекта',
'fields' => array(
array(
'key' => 'field_project_latitude',
'label' => 'Широта (Latitude)',
'name' => 'project_latitude',
'type' => 'text',
'required' => 1,
'placeholder' => '55.751574',
),
array(
'key' => 'field_project_longitude',
'label' => 'Долгота (Longitude)',
'name' => 'project_longitude',
'type' => 'text',
'required' => 1,
'placeholder' => '37.573856',
),
array(
'key' => 'field_project_address',
'label' => 'Адрес',
'name' => 'project_address',
'type' => 'text',
),
array(
'key' => 'field_project_equipment_type',
'label' => 'Тип оборудования',
'name' => 'project_equipment_type',
'type' => 'text',
),
array(
'key' => 'field_project_equipment_model',
'label' => 'Модель оборудования',
'name' => 'project_equipment_model',
'type' => 'text',
),
),
'location' => array(
array(
array(
'param' => 'post_type',
'operator' => '==',
'value' => 'projects',
),
),
),
));
endif;
Почему программное создание полей:
- Поля создаются автоматически при активации темы
- Не нужно настраивать их вручную в админке
- Легко перенести модуль в другой сайт
Шаг 3: Функция получения проектов для карты
Файл: projects.php
/**
* Получить все проекты для карты
* @return array Массив проектов с координатами
*/
function get_projects_for_map() {
$projects = get_posts(array(
'post_type' => 'projects',
'posts_per_page' => -1,
'post_status' => 'publish'
));
$projects_data = array();
foreach ($projects as $project) {
$latitude = get_field('project_latitude', $project->ID);
$longitude = get_field('project_longitude', $project->ID);
$address = get_field('project_address', $project->ID);
$equipment_type = get_field('project_equipment_type', $project->ID);
$equipment_model = get_field('project_equipment_model', $project->ID);
// Пропускаем проекты без координат
if (empty($latitude) || empty($longitude)) {
continue;
}
$projects_data[] = array(
'id' => $project->ID,
'title' => get_the_title($project->ID),
'latitude' => floatval($latitude),
'longitude' => floatval($longitude),
'address' => $address ?: '',
'equipment_type' => $equipment_type ?: '',
'equipment_model' => $equipment_model ?: '',
'description' => wp_strip_all_tags(get_the_excerpt($project->ID))
);
}
return $projects_data;
}
Что делает функция:
- Получает все опубликованные проекты
- Извлекает ACF поля (координаты, адрес, оборудование)
- Пропускает проекты без координат
- Возвращает массив, готовый для передачи в JavaScript
Шаг 4: Подключение Яндекс.Карт и скриптов
Файл: projects-map.php
/**
* Подключение скриптов и стилей для карты проектов
*/
function enqueue_projects_map_assets() {
// Подключаем только на странице с шаблоном карты
if (is_page_template('template-projects-map.php')) {
// Получаем API ключ из настроек ACF
$yandex_api_key = get_field('yandex_maps_api_key', 'options') ?: '';
if (empty($yandex_api_key)) {
$yandex_api_key = 'YOUR_API_KEY'; // Замените на ваш API ключ
}
// Регистрируем API Яндекс.Карт
wp_register_script(
'yandex-maps-api',
'https://api-maps.yandex.ru/2.1/?apikey=' . esc_attr($yandex_api_key) . '&lang=ru_RU',
array(),
'2.1',
false
);
// Получаем данные проектов
$projects_data = get_projects_map_data();
// Передаем данные в JavaScript
wp_localize_script('yandex-maps-api', 'projectsMapData', array(
'projects' => $projects_data
));
// Подключаем скрипты
wp_enqueue_script('yandex-maps-api');
wp_enqueue_script(
'projects-map-js',
get_template_directory_uri() . '/inc/modules/projects/assets/js/projects-map.js',
array('yandex-maps-api'),
'1.0.0',
true
);
// Подключаем стили
wp_enqueue_style(
'projects-map-css',
get_template_directory_uri() . '/inc/modules/projects/assets/css/projects-map.css',
array(),
'1.0.0'
);
}
}
add_action('wp_enqueue_scripts', 'enqueue_projects_map_assets');
Важные моменты:
- Скрипты подключаются только на странице с шаблоном карты
- API ключ берётся из настроек ACF (можно настроить в админке)
- Данные проектов передаются в JavaScript через
wp_localize_script()
Шаг 5: JavaScript для инициализации карты
Файл: assets/js/projects-map.js
(function () {
"use strict";
document.addEventListener("DOMContentLoaded", function () {
if (
typeof ymaps !== "undefined" &&
typeof projectsMapData !== "undefined"
) {
ymaps.ready(function () {
var projectsData = projectsMapData.projects || [];
// Создаем карту
var myMap = new ymaps.Map("yandex-map", {
center: [55.751574, 37.573856], // Москва по умолчанию
zoom: 5,
controls: ["zoomControl", "typeSelector", "fullscreenControl"],
});
// Создаем кластеры для меток
var clusterer = new ymaps.Clusterer({
preset: "islands#invertedBlueClusterIcons",
groupByCoordinates: false,
clusterDisableClickZoom: true,
clusterHideIconOnBalloonOpen: false,
geoObjectHideIconOnBalloonOpen: false,
});
// Добавляем метки для каждого проекта
projectsData.forEach(function (project) {
var placemark = new ymaps.Placemark(
[project.latitude, project.longitude],
{
balloonContentHeader:
"<strong>" + escapeHtml(project.title) + "</strong>",
balloonContentBody:
(project.equipment_type
? "<p><strong>Тип оборудования:</strong> " +
escapeHtml(project.equipment_type) +
"</p>"
: "") +
(project.equipment_model
? "<p><strong>Модель:</strong> " +
escapeHtml(project.equipment_model) +
"</p>"
: "") +
(project.address
? "<p><strong>Адрес:</strong> " +
escapeHtml(project.address) +
"</p>"
: "") +
(project.description
? "<p>" + escapeHtml(project.description) + "</p>"
: ""),
hintContent: escapeHtml(project.title),
},
{
preset: "islands#blueIcon",
}
);
clusterer.add(placemark);
});
myMap.geoObjects.add(clusterer);
// Устанавливаем границы карты, чтобы показать все метки
if (projectsData && projectsData.length > 0) {
myMap.setBounds(clusterer.getBounds(), {
checkZoomRange: true,
duration: 300,
});
}
});
}
});
// Функция для экранирования HTML (защита от XSS)
function escapeHtml(text) {
if (!text) return "";
var map = {
"&": "&",
"<": "<",
">": ">",
'"': """,
"'": "'",
};
return text.replace(/[&<>"']/g, function (m) {
return map[m];
});
}
})();
Что делает код:
- Инициализирует карту Яндекс.Карт
- Создаёт кластеры для группировки близких меток
- Добавляет метки для каждого проекта с балунами
- Автоматически подстраивает границы карты под все метки
- Экранирует HTML для защиты от XSS
Шаг 6: Fallback данные для демонстрации
Если проектов нет в базе данных, модуль автоматически использует тестовые данные. Это удобно для демонстрации функционала.
Файл: projects-map.php
/**
* Получить данные проектов для карты (с fallback на тестовые данные)
*/
function get_projects_map_data() {
// Пытаемся получить данные из базы
if (function_exists('get_projects_for_map')) {
$projects_data = get_projects_for_map();
if (!empty($projects_data)) {
return $projects_data;
}
}
// Если проектов нет, возвращаем тестовые данные
return array(
array(
'id' => 1,
'title' => 'Крематор КД-300',
'latitude' => 55.751574,
'longitude' => 37.573856,
'address' => 'г. Москва, ул. Красная площадь, д. 1',
'equipment_type' => 'Крематор',
'equipment_model' => 'КД-300',
'description' => 'Установлен крематор КД-300 для утилизации отходов.'
),
// ... другие тестовые проекты
);
}
Зачем это нужно:
- Можно показать карту клиенту до добавления реальных проектов
- Удобно для тестирования и разработки
- Не нужно создавать тестовые записи в базе
Использование: создание страницы с картой
1. Создай шаблон страницы
Файл: template-projects-map.php (в корне темы)
<?php
/**
* Template Name: Карта проектов
*/
get_header();
?>
<div class="projects-map-page">
<?php
// Вывод заголовка и описания из ACF
$header = get_field('header');
$description = get_field('description');
if ($header) {
echo '<h1>' . esc_html($header) . '</h1>';
}
if ($description) {
echo '<div class="projects-map-description">' . wp_kses_post($description) . '</div>';
}
// Вывод карты
if (function_exists('render_projects_map')) {
render_projects_map();
}
?>
</div>
<?php
get_footer();
2. Создай страницу в WordPress
- Перейди в Страницы → Добавить новую
- Название: “Реализованные проекты”
- Выбери шаблон: Карта проектов
- Заполни поля ACF (заголовок, описание)
- Опубликуй страницу
3. Добавь проекты
- Перейди в Проекты → Добавить новый
- Заполни обязательные поля:
- Название проекта: например, “Крематор КД-300”
- Широта:
55.751574 - Долгота:
37.573856 - Адрес: “г. Москва, ул. Красная площадь, д. 1”
- Тип оборудования: “Крематор”
- Модель оборудования: “КД-300”
- Опубликуй проект
Перенос модуля в другой сайт
Модуль легко переносится в другой сайт:
-
Скопируй папку модуля
cp -r projects /path/to/new/theme/inc/modules/ -
Подключи модуль в
functions.phprequire_once get_template_directory() . '/inc/modules/projects/projects-loader.php'; -
Установи ACF (если ещё не установлен)
-
Настрой API ключ
- Получи ключ на developer.tech.yandex.ru
- Установи в настройках темы: Настройки контента → Настройки Яндекс.Карт
-
Создай шаблон страницы (см. раздел “Использование”)
-
Создай страницу с картой и добавь проекты
Кастомизация
Изменение внешнего вида карты
Файл: assets/css/projects-map.css
.projects-map__container {
width: 100%;
height: 600px;
margin: 20px 0;
}
.projects-map__map {
width: 100%;
height: 100%;
border-radius: 8px;
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
}
Изменение настроек карты
Файл: assets/js/projects-map.js
// Изменить центр карты
center: [59.934280, 30.335098], // Санкт-Петербург
// Изменить масштаб
zoom: 10,
// Изменить иконки меток
preset: 'islands#redIcon'
Добавление дополнительных полей
- Добавь поле в ACF (
projects-acf.php) - Добавь поле в функцию
get_projects_for_map()(projects.php) - Используй поле в JavaScript (
assets/js/projects-map.js)
Безопасность
Модуль включает базовые меры безопасности:
- ✅ Проверка прав доступа — все функции проверяют права доступа
- ✅ Экранирование данных — все выходные данные экранируются через
esc_html(),esc_attr(),wp_kses_post() - ✅ Валидация координат — проверка корректности координат перед добавлением на карту
- ✅ Защита от XSS — экранирование HTML в JavaScript через функцию
escapeHtml()
Частые проблемы и решения
Проблема: Карта не отображается
- Решение: Проверь API ключ Яндекс.Карт, проверь консоль браузера на ошибки
Проблема: Метки не появляются на карте
- Решение: Убедись, что проекты опубликованы и имеют координаты
Проблема: Поля ACF не отображаются
- Решение: Убедись, что ACF установлен и активирован
Проблема: Скрипты не подключаются
- Решение: Проверь, что страница использует шаблон
template-projects-map.php
Итог
Модуль проектов для WordPress — это готовое решение для отображения локаций на карте:
- ✅ Кастомный тип записи для управления проектами
- ✅ ACF поля для координат и данных
- ✅ Интеграция с Яндекс.Картами с кластеризацией меток
- ✅ Адаптивный дизайн
- ✅ Fallback данные для демонстрации
- ✅ Легкий перенос в другой сайт
Если тебе нужно показать реализованные проекты на карте без создания отдельных страниц для каждого проекта — этот модуль решает задачу просто и эффективно.
Ссылки
- WordPress модуль для Яндекс.Карт на GitHub
- Документация Яндекс.Карт API
- ACF (Advanced Custom Fields) — плагин для кастомных полей
- Получить API ключ Яндекс.Карт — регистрация и получение ключа



Комментарии