/ Scripts & jquery / Посты — метки на карте

Посты — метки на карте

HIT

11.08.2018

2031

Пытаясь реализовать удобный функционал по созданию меток на интерактивной карте я пришел к следующей системе. Заводим произвольный тип записи и таксономии чтобы структурировать и удобно манипулировать городами и точками.

Основа

В основе решения находиться плагин Oi Yandex.Maps for WordPress (хотя я использую его только частично), который в свою очередь основан на Яндекс Api. т.е. плагин необходимо установить.

Создаем пользовательский тип записи city (название не вполне соответствует, т.к. это будут точки. конкретное место в городе):

// Добавляем произвольный тип записей
add_action( 'init', 'register_post_type_city' ); // Использовать функцию только внутри хука init
function register_post_type_city() {
    $labels = array(
        'name' => 'Где купить',
        'singular_name' => 'City', // админ панель Добавить->Функцию
        'add_new' => 'Добавить точку',
        'add_new_item' => 'Добавить новую точку', // заголовок тега <title>
        'edit_item' => 'Редактировать точку',
        'new_item' => 'Новая точка',
        'all_items' => 'Все точки',
        'view_item' => 'Просмотр страницы точки на сайте',
        'search_items' => 'Искать точку',
        'not_found' =>  'Точка не найдена.',
        'not_found_in_trash' => 'В корзине нет точки.',
        'menu_name' => 'Где купить' // ссылка в меню в админке
    );
    $args = array(
        'labels' => $labels,
        'public' => true,
        'show_ui' => true, // показывать интерфейс в админке
        'has_archive' => true, // показывать страницу архива данного типа записей
        'menu_icon' => 'dashicons-location-alt', // иконка dashicons в меню
        'menu_position' => 20, // порядок в меню
        'supports' => array( 'title', 'editor', 'comments', 'author', 'thumbnail'),
        //'taxonomies' => array('cities') // добавляем поддержку стандартных таксономий 'post_tag', 'category', либо пользовательскую 'album' (через запятую)
    );
    register_post_type('city', $args);
}


// Тексты уведомлений для типа постов
add_filter( 'post_updated_messages', 'true_post_type_messages_city' );
function true_post_type_messages_city( $messages ) {
    global $post, $post_ID;
    $messages['city'] = array( // city - название созданного нами типа записей
        0 => '', // Данный индекс не используется.
        1 => sprintf( 'Точка обновлена. Просмотр', esc_url( get_permalink($post_ID) ) ),
        2 => 'Точка обновлёна.',
        3 => 'Точка удалёна.',
        4 => 'Точка обновлена.',
        5 => isset($_GET['revision']) ? sprintf( 'Точка восстановлена из редакции: %s', wp_post_revision_title( (int) $_GET['revision'], false ) ) : false,
        6 => sprintf( 'Точка опубликована на сайте. Просмотр', esc_url( get_permalink($post_ID) ) ),
        7 => 'Точка сохранена.',
        8 => sprintf( 'Отправлена на проверку. Просмотр', esc_url( add_query_arg( 'preview', 'true', get_permalink($post_ID) ) ) ),
        9 => sprintf( 'Запланирована на публикацию: %1$s. Просмотр', date_i18n( __( 'M j, Y @ G:i' ), strtotime( $post->post_date ) ), esc_url( get_permalink($post_ID) ) ),
        10 => sprintf( 'Черновик обновлён. Просмотр', esc_url( add_query_arg( 'preview', 'true', get_permalink($post_ID) ) ) ),
    );
    return $messages;
}

// Произвольные поля для пользовательского типа записей
function true_custom_fields_city() {
    add_post_type_support( 'city', 'custom-fields'); // в качестве первого параметра укажите название типа поста
}
add_action('init', 'true_custom_fields_city');


//Создаем пользовательскую таксономию (элементами этой таксономии будут города)

// Пользовательская таксономия Город
function add_new_taxonomies() {
    register_taxonomy('cities', // создаем функцию с произвольным именем и вставляем в неё register_taxonomy()
    array('city'),
    array(
        'hierarchical' => false, // true - по типу рубрик, false - по типу меток, по умолчанию - false 
        'labels' => array(
            /* ярлыки, нужные при создании UI, можете не писать ничего, тогда будут использованы ярлыки по умолчанию */
            'name' => 'Город',
            'singular_name' => 'City',
            'search_items' => 'Найти город',
            'popular_items' => 'Популярные города',
            'all_items' => 'Все города',
            'parent_item' => null,
            'parent_item_colon' => null,
            'edit_item' => 'Редактировать город',
            'update_item' => 'Обновить город',
            'add_new_item' => 'Добавить новый город',
            'new_item_name' => 'Название нового города',
            'separate_items_with_commas' => 'Разделяйте города запятыми',
            'add_or_remove_items' => 'Добавить или удалить город',
            'choose_from_most_used' => 'Выбрать из наиболее часто используемых городов',
            'menu_name' => 'Города'
        ),
        'public' => true, // каждый может использовать таксономию, либо только администраторы, по умолчанию - true
        'show_in_nav_menus' => true, // добавить на страницу создания меню
        'show_ui' => true, // добавить интерфейс создания и редактирования
        'show_tagcloud' => true, // нужно ли разрешить облако тегов для этой таксономии
        'update_count_callback' => '_update_post_term_count', // callback-функция для обновления счетчика $object_type
        'query_var' => true, // разрешено ли использование query_var, также можно указать строку, которая будет использоваться в качестве него, по умолчанию - имя таксономии
        'rewrite' => array( // настройки URL пермалинков
        'slug' => 'cities', // ярлык
        'hierarchical' => false // разрешить вложенность
        ),
    )
    );
}
add_action( 'init', 'add_new_taxonomies', 0 );

Города точкам назначать будем как метки.

Произвольные поля

Задаем для записей типа city поля Координаты точки, Название точки, Контакты точки:

// Поле Координаты точки
add_action('add_meta_boxes', 'coordinati_tochka_box');
function coordinati_tochka_box() { add_meta_box('material_box', 'Координаты', 'coordinati_tochka_box_func', 'city', 'normal'); }
function coordinati_tochka_box_func($post){
    $coordinati_tochka = get_post_meta($post->ID, 'coordinati_tochka', 1);
    ?>
    <label><input style="width:100%;" type="text" name="extra[coordinati_tochka]" value="<?php if($coordinati_tochka){echo $coordinati_tochka;}?>" /></label>
    <input type="hidden" name="atb_nonce" value="<?php echo wp_create_nonce(__FILE__); ?>" />
    <?php
}

add_action('save_post', 'coordinati_tochka_box_update');
function coordinati_tochka_box_update($post_id){
    if (!wp_verify_nonce($_POST['atb_nonce'], __FILE__)) return false; // Проверка, что сохраняется именно нужная нам страница.
    if (defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) return false; // Проверка, что это не автосохранение
    if (!current_user_can('edit_post', $post_id)) return false; // Проверка, что пользователь может изменять этот пост
    if(!isset($_POST['extra']) ) return false;    // Проверка, что нам пришли все поля
    foreach($_POST['extra'] as $key=>$value){ // Циклом добавляем поля. Можно и в ручную это делать... Но так проще добавить новое поле
        if(empty($value) AND $value != 0){ // Если значение пустое и не равно 0
            delete_post_meta($post_id, $key); // Удаляем это поле из мета-данных
            continue; // Продолжаем
        }
        update_post_meta($post_id, $key, $value); // Обновляем или добавляем мета-данные
    }
    return $post_id;
}



// Поле Название точки
add_action('add_meta_boxes', 'name_tochka_box');
function name_tochka_box() { add_meta_box('material_box_2', 'Название точки', 'name_tochka_box_func', 'city', 'normal'); }
function name_tochka_box_func($post){
    $name_tochka = get_post_meta($post->ID, 'name_tochka', 1);
    ?>
    <label><input style="width:100%;" type="text" name="extra[name_tochka]" value="<?php if($name_tochka){echo $name_tochka;}?>" /></label>
    <input type="hidden" name="atb_nonce" value="<?php echo wp_create_nonce(__FILE__); ?>" />
    <?php
}

add_action('save_post', 'name_tochka_box_update');
function name_tochka_box_update($post_id){
    if (!wp_verify_nonce($_POST['atb_nonce'], __FILE__)) return false; // Проверка, что сохраняется именно нужная нам страница.
    if (defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) return false; // Проверка, что это не автосохранение
    if (!current_user_can('edit_post', $post_id)) return false; // Проверка, что пользователь может изменять этот пост
    if(!isset($_POST['extra']) ) return false;    // Проверка, что нам пришли все поля
    foreach($_POST['extra'] as $key=>$value){ // Циклом добавляем поля. Можно и в ручную это делать... Но так проще добавить новое поле
        if(empty($value) AND $value != 0){ // Если значение пустое и не равно 0
            delete_post_meta($post_id, $key); // Удаляем это поле из мета-данных
            continue; // Продолжаем
        }
        update_post_meta($post_id, $key, $value); // Обновляем или добавляем мета-данные
    }
    return $post_id;
}



// Поле Контакты точки
add_action('add_meta_boxes', 'contacts_tochka_box');
function contacts_tochka_box() { add_meta_box('material_box_3', 'Контакты точки', 'contacts_tochka_box_func', 'city', 'normal'); }
function contacts_tochka_box_func($post){
    $contacts_tochka = get_post_meta($post->ID, 'contacts_tochka', 1);
    ?>
    <label><input style="width:100%;" type="text" name="extra[contacts_tochka]" value="<?php if($contacts_tochka){echo $contacts_tochka;}?>" /></label>
    <input type="hidden" name="atb_nonce" value="<?php echo wp_create_nonce(__FILE__); ?>" />
    <?php
}

add_action('save_post', 'contacts_tochka_box_update');
function contacts_tochka_box_update($post_id){
    if (!wp_verify_nonce($_POST['atb_nonce'], __FILE__)) return false; // Проверка, что сохраняется именно нужная нам страница.
    if (defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) return false; // Проверка, что это не автосохранение
    if (!current_user_can('edit_post', $post_id)) return false; // Проверка, что пользователь может изменять этот пост
    if(!isset($_POST['extra']) ) return false;    // Проверка, что нам пришли все поля
    foreach($_POST['extra'] as $key=>$value){ // Циклом добавляем поля. Можно и в ручную это делать... Но так проще добавить новое поле
        if(empty($value) AND $value != 0){ // Если значение пустое и не равно 0
            delete_post_meta($post_id, $key); // Удаляем это поле из мета-данных
            continue; // Продолжаем
        }
        update_post_meta($post_id, $key, $value); // Обновляем или добавляем мета-данные
    }
    return $post_id;
}

В последствии в поле Координаты точки мы будем прописывать реальные координаты точки, беря их из карт Яндекс. Поля Название точки и Контакты точки нужны для сопроводительного текста при нажатии на точку, или если точки выводить в виде списка.

Зададим произвольное поле и для таксономии с городами:

// Создание метаполя Координаты для города
function pippin_taxonomy_add_new_meta_field() { // this will add the custom meta field to the add new term page
    ?>
    <div class="form-field">
    <label for="term_meta[custom_term_meta]"><?php _e( 'Example meta field', 'pippin' ); ?></label>
    <input type="text" name="term_meta[custom_term_meta]" id="term_meta[custom_term_meta]" value="">
    <p class="description"><?php _e( 'Enter a value for this field','pippin' ); ?></p>
    </div>
    <?php
}
add_action( 'cities_add_form_fields', 'pippin_taxonomy_add_new_meta_field', 10, 2 );


// Редактирование мета поля
function pippin_taxonomy_edit_meta_field($term) {
    $t_id = $term->term_id;  // put the term ID into a variable
    $term_meta = get_option( "taxonomy_$t_id" ); // retrieve the existing value(s) for this meta field. This returns an array
    ?> 
    <tr class="form-field">
    <th scope="row" valign="top"><label for="term_meta[custom_term_meta]"><?php _e( 'Example meta field', 'pippin' ); ?></label></th>
    <td>
    <input type="text" name="term_meta[custom_term_meta]" id="term_meta[custom_term_meta]" value="<?php echo esc_attr( $term_meta['custom_term_meta'] ) ? esc_attr( $term_meta['custom_term_meta'] ) : ''; ?>">
    <p class="description"><?php _e( 'Enter a value for this field','pippin' ); ?></p>
    </td>
    </tr>
    <?php
}
add_action( 'cities_edit_form_fields', 'pippin_taxonomy_edit_meta_field', 10, 2 );


// Сохранение метаполя
function save_taxonomy_custom_meta( $term_id ) {
    if ( isset( $_POST['term_meta'] ) ) {
        $t_id = $term_id;
        $term_meta = get_option( "taxonomy_$t_id" );
        $cat_keys = array_keys( $_POST['term_meta'] );
        foreach ( $cat_keys as $key ) {
            if ( isset ( $_POST['term_meta'][$key] ) ) { $term_meta[$key] = $_POST['term_meta'][$key]; }
        }
        update_option( "taxonomy_$t_id", $term_meta ); // Save the option array.
    }
}
add_action( 'edited_cities', 'save_taxonomy_custom_meta', 10, 2 );
add_action( 'create_cities', 'save_taxonomy_custom_meta', 10, 2 );

Это поле нужно чтобы вписывать координаты городов, которые придется предварительно уточнять в Яндекс картах.

Найти способ генерации координатов налету по адресу точки или города

Шаблоны вывода

Шаблон archive-city.php — здесь будем выводить список всех городов, причем размечая их по алфавиту. Для меню шаблон доступен по ссылке /city/

<?php $terms = get_terms( 'cities'); ?>

<script type="text/javascript" src="https://api-maps.yandex.ru/2.1/?lang=ru_RU"></script>

<style>.YMaps {position: relative; height: 400px; width:100%;}</style>

<div id="YMaps_0" class="YMaps"></div>

<script type="text/javascript">
ymaps.ready(init);

function init () {
    var myMap = new ymaps.Map("YMaps_0", {
        center: [47.413167,40.532044],
        zoom: 7
    });
    myMap.controls.add("routeEditor");
    
    <?php foreach( $terms as $term ): ?>
        <?php $term_meta = get_option( "taxonomy_$term->term_id" ); 
        $term_link = get_term_link($term->term_id, 'cities'); ?>
        myPlacemark_1 = new ymaps.Placemark([<?php echo esc_attr( $term_meta['custom_term_meta'] ) ? esc_attr( $term_meta['custom_term_meta'] ) : ''; ?>], 
        {balloonContentHeader: "<a href='<?php echo $term_link; ?>'><?php echo $term->name; ?></a>",},
        {preset: "islands#redDotIcon"}
        );
        myMap.geoObjects.add(myPlacemark_1);
    <?php endforeach; ?>
}

</script>

<h1 id="title"><i class="fa fa-map-marker" aria-hidden="true"></i> Где купить</h1> 

<div id="all-city">

<?php global $query_string;
parse_str($query_string, $args);  // добавляем базовые параметры в массив $args
$args['posts_per_page'] = -1;  // добавляем/заменяем параметр в массиве
query_posts( $args ); ?>  

<?php echo '<div class="city-letter">'; 
foreach( $terms as $k => $term ){
    $fl = get_first_letter( $term->name );  // первая буква
    $prev_fl = isset( $terms[ ($k-1) ] ) ? get_first_letter( $terms[ ($k-1) ]->name ) : '';
    if( $prev_fl !== $fl ) 
    echo '</div><div class="city-letter"><h3>'.$fl.'</h3>'; // Буква
    printf ( '<a href="%s">%s</a><br>' , get_term_link($term->term_id, 'cities'), $term->name ); // Выводим название записи в виде ссылки на неё
}
echo '</div>';
wp_reset_postdata(); ?>

<?php // Функция возвращает первую букву переданного в неё слова
function get_first_letter( $str ){ return mb_substr($str, 0, 1, 'utf-8'); } ?> 

</div>

Выглядеть это должно примерно так:

Шаблон taxonomy-cities.php будет выводить элементы пользовательской таксономии (отдельный город с точками)

<?php $term_slug = get_query_var( 'cities' ); 
$term = get_term_by('slug', $term_slug, 'cities'); 
$term_meta = get_option( "taxonomy_$term->term_id" ); ?>

<script type="text/javascript" src="https://api-maps.yandex.ru/2.1/?lang=ru_RU"></script>

<style>.YMaps {position: relative; width:100%; height:650px;}}</style>

<div id="YMaps_0" class="YMaps"></div>

<script type="text/javascript">
ymaps.ready(init);
function init () {
    var myMap = new ymaps.Map("YMaps_0", {
        center: [<?php echo esc_attr( $term_meta['custom_term_meta'] ) ? esc_attr( $term_meta['custom_term_meta'] ) : ''; ?>], //найти какая функция отвечает за определение центра, а пока сделать полем
        zoom: 11
    });
    myMap.controls.add("routeEditor");

    <?php if ( have_posts() ) : ?>
    <?php while ( have_posts() ) : the_post(); ?> 
        myPlacemark_1 = new ymaps.Placemark([<?php echo get_post_meta($post->ID, 'coordinati_tochka', 1); ?>], //научиться налету конвертировать координаты
        {balloonContentHeader: "<?php echo get_post_meta($post->ID, 'name_tochka', 1); ?>",
        balloonContentBody: "<?php echo get_post_meta($post->ID, 'contacts_tochka', 1); ?>"},
        {preset: "islands#redDotIcon"}
        );
        myMap.geoObjects.add(myPlacemark_1);
    <?php endwhile; ?>
    <?php endif; ?>
}
</script>

<h1 id="title"><?php echo $term->name; ?></h1>

<?php if ( have_posts() ) : ?><ul> 
<?php while ( have_posts() ) : the_post(); ?>

    <li><strong><?php echo get_post_meta($post->ID, 'name_tochka', 1); ?></strong> <?php the_title(); ?> <?php echo get_post_meta($post->ID, 'contacts_tochka', 1); ?></li>

<?php endwhile; ?></ul>
<?php endif; ?>

В этом шаблоне мне пришлось оказаться от хлебных крошек от Kama (получалась несуразица) и прописать свои:

<div id="path"><div class="kama_breadcrumbs" itemscope="" itemtype="http://schema.org/BreadcrumbList">
    <span itemprop="itemListElement" itemscope="" itemtype="http://schema.org/ListItem"><a href="https://site.ru" itemprop="item"><span itemprop="name">Главная</span></a></span> / 
    <a href="/city/" itemprop="item"><span itemprop="name">Где купить</span></a> / <span class="current"><?php echo $term->name; ?></span></div>
</div>

В итоге должно получиться примерно так:

Информация в balloonContentBody

В всплывающий блок balloonContentBody можно вставлять любую верстку html и контент. Пример:

balloonContentBody: "<img src='/wp-content/uploads/2019/09/image.jpg'><br><p>г. Ростов-на-Дону, пр. Космонавтов, 39</p>"

Поделиться в соц. сетях:

  • Похожие записи
  • Комментарии
  • Вложения
Множественные точки на Google Map

Множественные точки на Google Map

Добавим на карту Google множество точек с описаниями.

Карта на сайт

Карта на сайт

Для добавления интерактивной карты в раздел контакты, нужно поместить в страницу или шаблон сгенерированный код Yandex карты, Google Map, или 2GIS. На данной странице я собрал популярные решения по добавлению Читать далее »

API Яндекс.Карт

API Яндекс.Карт

Если нам нужно кастомизировать карту Яндекс, то будет не достаточно подключить ее через iframe, т.к. в нем не будет никаких настроек. Необходимо подключить API Яндекс.Карт Подключаем API Яндекс.Карт На данный Читать далее »

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

Пока нет комментариев. Будь первым!

Посты — метки на карте Посты — метки на карте Посты — метки на карте
Доработка сортировки постов
Рекомендации для васДоработка сортировки постовOpttour.ru
Спасибо! Наш менеджер свяжется с Вами в течении 5 минут.