Geoposicionador de cosas
This commit is contained in:
@@ -0,0 +1,280 @@
|
||||
<?php
|
||||
/**
|
||||
* Proveedor de datos para el mapa
|
||||
*
|
||||
* @package FP_Geo_Content
|
||||
*/
|
||||
|
||||
if (!defined('ABSPATH')) {
|
||||
exit;
|
||||
}
|
||||
|
||||
class FP_Geo_Data_Provider {
|
||||
|
||||
/**
|
||||
* Obtener marcadores para el mapa
|
||||
*
|
||||
* @param array $args Argumentos de configuración
|
||||
* @return array
|
||||
*/
|
||||
public static function get_markers($args = []) {
|
||||
$options = get_option('fp_geo_content_options', []);
|
||||
|
||||
$defaults = [
|
||||
'post_types' => $options['post_types'] ?? [],
|
||||
'lat_field' => $options['lat_field'] ?? 'latitud',
|
||||
'lng_field' => $options['lng_field'] ?? 'longitud',
|
||||
'taxonomies' => [],
|
||||
'terms' => [],
|
||||
'filter_combine' => $options['filter_combine'] ?? 'OR',
|
||||
];
|
||||
|
||||
$args = wp_parse_args($args, $defaults);
|
||||
|
||||
if (empty($args['post_types'])) {
|
||||
return [];
|
||||
}
|
||||
|
||||
// Query args
|
||||
$query_args = [
|
||||
'post_type' => $args['post_types'],
|
||||
'posts_per_page' => -1,
|
||||
'post_status' => 'publish',
|
||||
'meta_query' => [
|
||||
'relation' => 'AND',
|
||||
[
|
||||
'key' => $args['lat_field'],
|
||||
'compare' => 'EXISTS',
|
||||
],
|
||||
[
|
||||
'key' => $args['lng_field'],
|
||||
'compare' => 'EXISTS',
|
||||
],
|
||||
[
|
||||
'key' => $args['lat_field'],
|
||||
'value' => '',
|
||||
'compare' => '!=',
|
||||
],
|
||||
[
|
||||
'key' => $args['lng_field'],
|
||||
'value' => '',
|
||||
'compare' => '!=',
|
||||
],
|
||||
],
|
||||
];
|
||||
|
||||
// Filtros por taxonomía
|
||||
if (!empty($args['terms']) && is_array($args['terms'])) {
|
||||
$tax_query = ['relation' => $args['filter_combine']];
|
||||
|
||||
foreach ($args['terms'] as $taxonomy => $term_slugs) {
|
||||
if (!empty($term_slugs)) {
|
||||
$tax_query[] = [
|
||||
'taxonomy' => $taxonomy,
|
||||
'field' => 'slug',
|
||||
'terms' => (array) $term_slugs,
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
if (count($tax_query) > 1) {
|
||||
$query_args['tax_query'] = $tax_query;
|
||||
}
|
||||
}
|
||||
|
||||
$query = new WP_Query($query_args);
|
||||
$markers = [];
|
||||
|
||||
if ($query->have_posts()) {
|
||||
while ($query->have_posts()) {
|
||||
$query->the_post();
|
||||
$post = get_post();
|
||||
|
||||
$marker = self::prepare_marker($post, $args);
|
||||
if ($marker) {
|
||||
$markers[] = $marker;
|
||||
}
|
||||
}
|
||||
wp_reset_postdata();
|
||||
}
|
||||
|
||||
return $markers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Preparar datos de un marcador
|
||||
*
|
||||
* @param WP_Post $post
|
||||
* @param array $args
|
||||
* @return array|null
|
||||
*/
|
||||
private static function prepare_marker($post, $args) {
|
||||
// Obtener coordenadas
|
||||
$lat = get_field($args['lat_field'], $post->ID);
|
||||
$lng = get_field($args['lng_field'], $post->ID);
|
||||
|
||||
// Si no hay coordenadas, intentar con get_post_meta
|
||||
if (!$lat) {
|
||||
$lat = get_post_meta($post->ID, $args['lat_field'], true);
|
||||
}
|
||||
if (!$lng) {
|
||||
$lng = get_post_meta($post->ID, $args['lng_field'], true);
|
||||
}
|
||||
|
||||
// Validar coordenadas
|
||||
if (!$lat || !$lng || !is_numeric($lat) || !is_numeric($lng)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Datos básicos
|
||||
$marker = [
|
||||
'id' => $post->ID,
|
||||
'title' => html_entity_decode(get_the_title($post), ENT_QUOTES, 'UTF-8'),
|
||||
'lat' => (float) $lat,
|
||||
'lng' => (float) $lng,
|
||||
'url' => get_permalink($post),
|
||||
'post_type' => $post->post_type,
|
||||
'excerpt' => wp_trim_words(get_the_excerpt($post), 20),
|
||||
'thumbnail' => get_the_post_thumbnail_url($post, 'medium'),
|
||||
];
|
||||
|
||||
// Obtener taxonomías
|
||||
$options = get_option('fp_geo_content_options', []);
|
||||
$filter_taxonomies = $options['filter_taxonomies'] ?? [];
|
||||
|
||||
$marker['taxonomies'] = [];
|
||||
foreach ($filter_taxonomies as $taxonomy) {
|
||||
$terms = wp_get_post_terms($post->ID, $taxonomy);
|
||||
if (!is_wp_error($terms) && !empty($terms)) {
|
||||
$marker['taxonomies'][$taxonomy] = [];
|
||||
foreach ($terms as $term) {
|
||||
$term_data = [
|
||||
'id' => $term->term_id,
|
||||
'name' => $term->name,
|
||||
'slug' => $term->slug,
|
||||
];
|
||||
|
||||
// Obtener campos ACF del término si existen (icono y color)
|
||||
if (function_exists('get_field')) {
|
||||
$icono = get_field('icono', $term);
|
||||
$color = get_field('color', $term);
|
||||
if ($icono) $term_data['icono'] = $icono;
|
||||
if ($color) $term_data['color'] = $color;
|
||||
}
|
||||
|
||||
$marker['taxonomies'][$taxonomy][] = $term_data;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Campo es_piloto del post (para actuaciones)
|
||||
$es_piloto = get_field('es_piloto', $post->ID);
|
||||
if (!$es_piloto) {
|
||||
$es_piloto = get_post_meta($post->ID, 'es_piloto', true);
|
||||
}
|
||||
if ($es_piloto) {
|
||||
$marker['es_piloto'] = true;
|
||||
}
|
||||
|
||||
// Campos adicionales comunes
|
||||
$additional_fields = ['direccion', 'localidad', 'telefono', 'email', 'web'];
|
||||
foreach ($additional_fields as $field) {
|
||||
$value = get_field($field, $post->ID);
|
||||
if (!$value) {
|
||||
$value = get_post_meta($post->ID, $field, true);
|
||||
}
|
||||
if ($value) {
|
||||
$marker[$field] = $value;
|
||||
}
|
||||
}
|
||||
|
||||
// Permitir filtrar los datos del marcador
|
||||
return apply_filters('fp_geo_marker_data', $marker, $post);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handler AJAX para obtener marcadores
|
||||
*/
|
||||
public static function ajax_get_markers() {
|
||||
check_ajax_referer('fp_geo_nonce', 'nonce');
|
||||
|
||||
$post_types = isset($_POST['post_types']) ? array_map('sanitize_text_field', (array) $_POST['post_types']) : [];
|
||||
$terms = isset($_POST['terms']) ? $_POST['terms'] : [];
|
||||
|
||||
// Sanitizar términos
|
||||
$sanitized_terms = [];
|
||||
if (is_array($terms)) {
|
||||
foreach ($terms as $taxonomy => $slugs) {
|
||||
$taxonomy = sanitize_text_field($taxonomy);
|
||||
$sanitized_terms[$taxonomy] = array_map('sanitize_text_field', (array) $slugs);
|
||||
}
|
||||
}
|
||||
|
||||
$markers = self::get_markers([
|
||||
'post_types' => $post_types,
|
||||
'terms' => $sanitized_terms,
|
||||
]);
|
||||
|
||||
wp_send_json_success(['markers' => $markers]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtener términos disponibles para filtros
|
||||
*
|
||||
* @param array $post_types
|
||||
* @param array $taxonomies
|
||||
* @return array
|
||||
*/
|
||||
public static function get_filter_terms($post_types = [], $taxonomies = []) {
|
||||
$result = [];
|
||||
|
||||
foreach ($taxonomies as $taxonomy) {
|
||||
$tax_obj = get_taxonomy($taxonomy);
|
||||
if (!$tax_obj) continue;
|
||||
|
||||
// Verificar que la taxonomía está asociada a alguno de los post types
|
||||
$associated = false;
|
||||
foreach ($post_types as $pt) {
|
||||
if (in_array($pt, $tax_obj->object_type)) {
|
||||
$associated = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!$associated) continue;
|
||||
|
||||
$terms = get_terms([
|
||||
'taxonomy' => $taxonomy,
|
||||
'hide_empty' => true,
|
||||
]);
|
||||
|
||||
if (!is_wp_error($terms) && !empty($terms)) {
|
||||
$result[$taxonomy] = [
|
||||
'label' => $tax_obj->label,
|
||||
'terms' => [],
|
||||
];
|
||||
|
||||
foreach ($terms as $term) {
|
||||
$term_data = [
|
||||
'id' => $term->term_id,
|
||||
'name' => $term->name,
|
||||
'slug' => $term->slug,
|
||||
'count' => $term->count,
|
||||
];
|
||||
|
||||
// Campos ACF del término (icono y color)
|
||||
if (function_exists('get_field')) {
|
||||
$icono = get_field('icono', $term);
|
||||
$color = get_field('color', $term);
|
||||
if ($icono) $term_data['icono'] = $icono;
|
||||
if ($color) $term_data['color'] = $color;
|
||||
}
|
||||
|
||||
$result[$taxonomy]['terms'][] = $term_data;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,357 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Renderizador del mapa
|
||||
*
|
||||
* @package FP_Geo_Content
|
||||
*/
|
||||
|
||||
if (!defined('ABSPATH')) {
|
||||
exit;
|
||||
}
|
||||
|
||||
class FP_Geo_Map_Renderer
|
||||
{
|
||||
|
||||
/**
|
||||
* Contador de instancias para IDs únicos
|
||||
*/
|
||||
private static $instance_count = 0;
|
||||
|
||||
/**
|
||||
* Shortcode: [fp-geo-map]
|
||||
*
|
||||
* Atributos:
|
||||
* - post_types: tipos de contenido separados por coma (usa config si no se especifica)
|
||||
* - taxonomies: taxonomías para filtros separadas por coma
|
||||
* - height: altura del mapa (default: 600px)
|
||||
* - lat: latitud centro (usa config si no se especifica)
|
||||
* - lng: longitud centro
|
||||
* - zoom: nivel de zoom inicial
|
||||
* - filters: true|false - mostrar filtros
|
||||
* - detail: sidebar|modal - cómo mostrar el detalle
|
||||
* - sidebar_position: left|right - posición del sidebar
|
||||
* - legend: true|false - mostrar leyenda
|
||||
* - show_detail_btn: true|false - mostrar botón de detalle
|
||||
* - detail_btn_text: texto del botón
|
||||
* - class: clases CSS adicionales
|
||||
*/
|
||||
public static function render_shortcode($atts)
|
||||
{
|
||||
$options = get_option('fp_geo_content_options', []);
|
||||
|
||||
$atts = shortcode_atts([
|
||||
'post_types' => implode(',', $options['post_types'] ?? []),
|
||||
'taxonomies' => implode(',', $options['filter_taxonomies'] ?? []),
|
||||
'height' => '600px',
|
||||
'lat' => $options['default_lat'] ?? '40.4168',
|
||||
'lng' => $options['default_lng'] ?? '-3.7038',
|
||||
'zoom' => $options['default_zoom'] ?? 12,
|
||||
'filters' => 'true',
|
||||
'detail' => $options['detail_display'] ?? 'sidebar',
|
||||
'cluster' => $options['cluster_enabled'] ?? true,
|
||||
'sidebar_position' => $options['sidebar_position'] ?? 'right',
|
||||
'legend' => isset($options['show_legend']) ? ($options['show_legend'] ? 'true' : 'false') : 'false',
|
||||
'show_detail_btn' => isset($options['show_detail_button']) ? ($options['show_detail_button'] ? 'true' : 'false') : 'true',
|
||||
'detail_btn_text' => $options['detail_button_text'] ?? __('Ver detalle', 'fp-geo-content'),
|
||||
'class' => '',
|
||||
], $atts, 'fp-geo-map');
|
||||
|
||||
// Parsear valores
|
||||
$post_types = array_filter(array_map('trim', explode(',', $atts['post_types'])));
|
||||
$taxonomies = array_filter(array_map('trim', explode(',', $atts['taxonomies'])));
|
||||
$show_filters = filter_var($atts['filters'], FILTER_VALIDATE_BOOLEAN);
|
||||
$use_cluster = filter_var($atts['cluster'], FILTER_VALIDATE_BOOLEAN);
|
||||
$show_legend = filter_var($atts['legend'], FILTER_VALIDATE_BOOLEAN);
|
||||
$show_detail_btn = filter_var($atts['show_detail_btn'], FILTER_VALIDATE_BOOLEAN);
|
||||
$sidebar_position = $atts['sidebar_position'];
|
||||
|
||||
if (empty($post_types)) {
|
||||
return '<p class="fp-geo-error">' . __('No se han configurado tipos de contenido para el mapa.', 'fp-geo-content') . '</p>';
|
||||
}
|
||||
|
||||
// Incrementar contador de instancias
|
||||
self::$instance_count++;
|
||||
$map_id = 'fp-geo-map-' . self::$instance_count;
|
||||
|
||||
// Cargar assets
|
||||
wp_enqueue_style('fp-geo-content');
|
||||
wp_enqueue_script('fp-geo-content');
|
||||
|
||||
// Obtener marcadores
|
||||
$markers = FP_Geo_Data_Provider::get_markers([
|
||||
'post_types' => $post_types,
|
||||
]);
|
||||
|
||||
// Obtener términos para filtros
|
||||
$filter_terms = [];
|
||||
if ($show_filters && !empty($taxonomies)) {
|
||||
$filter_terms = FP_Geo_Data_Provider::get_filter_terms($post_types, $taxonomies);
|
||||
}
|
||||
|
||||
// Obtener configuración de tiles
|
||||
$tile_provider = $options['tile_provider'] ?? 'carto_light';
|
||||
$tile_providers = FP_Geo_Settings::get_tile_providers();
|
||||
$tile_config = $tile_providers[$tile_provider] ?? $tile_providers['carto_light'];
|
||||
|
||||
// Obtener icono personalizado si existe
|
||||
$marker_icon_id = $options['marker_icon'] ?? 0;
|
||||
$marker_icon_url = $marker_icon_id ? wp_get_attachment_image_url($marker_icon_id, 'full') : '';
|
||||
|
||||
// Obtener etiquetas de los post types
|
||||
$post_type_labels = [];
|
||||
foreach ($post_types as $pt) {
|
||||
$pt_obj = get_post_type_object($pt);
|
||||
if ($pt_obj) {
|
||||
$post_type_labels[$pt] = [
|
||||
'singular' => $pt_obj->labels->singular_name,
|
||||
'plural' => $pt_obj->labels->name,
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
// Obtener datos de leyenda si está habilitada
|
||||
$legend_data = [];
|
||||
$legend_taxonomy = $options['legend_taxonomy'] ?? '';
|
||||
if ($show_legend && !empty($legend_taxonomy) && isset($filter_terms[$legend_taxonomy])) {
|
||||
// Verificar si hay marcadores piloto (es_piloto está en los posts, no en los términos)
|
||||
$has_pilot_markers = false;
|
||||
foreach ($markers as $marker) {
|
||||
if (isset($marker['es_piloto']) && $marker['es_piloto']) {
|
||||
$has_pilot_markers = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
$legend_data = [
|
||||
'taxonomy' => $legend_taxonomy,
|
||||
'label' => $filter_terms[$legend_taxonomy]['label'],
|
||||
'items' => $filter_terms[$legend_taxonomy]['terms'],
|
||||
'has_pilots' => $has_pilot_markers,
|
||||
];
|
||||
}
|
||||
|
||||
// Configuración del mapa
|
||||
$map_config = [
|
||||
'mapId' => $map_id,
|
||||
'center' => [(float) $atts['lat'], (float) $atts['lng']],
|
||||
'zoom' => (int) $atts['zoom'],
|
||||
'minZoom' => (int) ($options['min_zoom'] ?? 5),
|
||||
'maxZoom' => (int) ($options['max_zoom'] ?? 18),
|
||||
'markers' => $markers,
|
||||
'filters' => $filter_terms,
|
||||
'filterCombine' => $options['filter_combine'] ?? 'OR',
|
||||
'detailDisplay' => $atts['detail'],
|
||||
'clusterEnabled' => $use_cluster,
|
||||
'tileUrl' => $tile_config['url'],
|
||||
'tileAttribution' => $tile_config['attribution'],
|
||||
'tileSubdomains' => $tile_config['subdomains'],
|
||||
'defaultIcon' => FP_GEO_PLUGIN_URL . 'assets/img/marker-icon.png',
|
||||
'ajaxUrl' => admin_url('admin-ajax.php'),
|
||||
'nonce' => wp_create_nonce('fp_geo_nonce'),
|
||||
'postTypes' => $post_types,
|
||||
'postTypeLabels' => $post_type_labels,
|
||||
// Nuevas opciones de marcadores
|
||||
'markerIcon' => $marker_icon_url,
|
||||
'markerDefaultColor' => $options['marker_default_color'] ?? '#F97316',
|
||||
'useCategoryColors' => isset($options['use_category_colors']) && $options['use_category_colors'],
|
||||
'legendTaxonomy' => $legend_taxonomy,
|
||||
// Nuevas opciones de scroll
|
||||
'scrollWheelZoom' => $options['scroll_wheel_zoom'] ?? 'ctrl',
|
||||
// Nuevas opciones de display
|
||||
'sidebarPosition' => $sidebar_position,
|
||||
'showLegend' => $show_legend,
|
||||
'legendData' => $legend_data,
|
||||
'showDetailButton' => $show_detail_btn,
|
||||
'detailButtonText' => $atts['detail_btn_text'],
|
||||
'i18n' => [
|
||||
'loading' => __('Cargando...', 'fp-geo-content'),
|
||||
'noResults' => __('No se encontraron resultados', 'fp-geo-content'),
|
||||
'viewMore' => $atts['detail_btn_text'],
|
||||
'close' => __('Cerrar', 'fp-geo-content'),
|
||||
'clearFilters' => __('Limpiar filtros', 'fp-geo-content'),
|
||||
'scrollZoomHint' => __('Usa Ctrl + scroll para hacer zoom', 'fp-geo-content'),
|
||||
],
|
||||
];
|
||||
|
||||
// Pasar configuración al JS
|
||||
wp_localize_script('fp-geo-content', 'fpGeoConfig_' . self::$instance_count, $map_config);
|
||||
|
||||
ob_start();
|
||||
$wrapper_classes = [
|
||||
'fp-geo-wrapper',
|
||||
'fp-geo-detail-' . esc_attr($atts['detail']),
|
||||
'fp-geo-sidebar-' . esc_attr($sidebar_position),
|
||||
esc_attr($atts['class']),
|
||||
];
|
||||
?>
|
||||
<div id="<?php echo esc_attr($map_id); ?>-wrapper"
|
||||
class="<?php echo esc_attr(implode(' ', array_filter($wrapper_classes))); ?>"
|
||||
data-instance="<?php echo esc_attr(self::$instance_count); ?>">
|
||||
|
||||
<?php if ($show_filters && !empty($filter_terms)): ?>
|
||||
<?php echo self::render_filters($map_id, $filter_terms); ?>
|
||||
<?php endif; ?>
|
||||
|
||||
<div class="fp-geo-map-container">
|
||||
<div id="<?php echo esc_attr($map_id); ?>"
|
||||
class="fp-geo-map"
|
||||
style="height: <?php echo esc_attr($atts['height']); ?>;"></div>
|
||||
|
||||
<?php if ($show_legend && !empty($legend_data)): ?>
|
||||
<?php echo self::render_legend($map_id, $legend_data); ?>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php echo self::render_detail_panel($map_id, $atts['detail'], $show_detail_btn, $atts['detail_btn_text']); ?>
|
||||
</div>
|
||||
</div>
|
||||
<?php
|
||||
|
||||
return ob_get_clean();
|
||||
}
|
||||
|
||||
/**
|
||||
* Renderizar panel de filtros
|
||||
*/
|
||||
private static function render_filters($map_id, $filter_terms)
|
||||
{
|
||||
ob_start();
|
||||
?>
|
||||
<div class="fp-geo-filters" data-map="<?php echo esc_attr($map_id); ?>">
|
||||
<div class="fp-geo-filters-inner">
|
||||
<?php foreach ($filter_terms as $taxonomy => $data): ?>
|
||||
<div class="fp-geo-filter-group" data-taxonomy="<?php echo esc_attr($taxonomy); ?>">
|
||||
<label class="fp-geo-filter-label"><?php echo esc_html($data['label']); ?>:</label>
|
||||
<div class="fp-geo-filter-buttons">
|
||||
<?php foreach ($data['terms'] as $term): ?>
|
||||
<button type="button"
|
||||
class="fp-geo-filter-btn"
|
||||
data-slug="<?php echo esc_attr($term['slug']); ?>"
|
||||
data-taxonomy="<?php echo esc_attr($taxonomy); ?>"
|
||||
style="<?php echo isset($term['color']) ? '--filter-color: ' . esc_attr($term['color']) . ';' : ''; ?>">
|
||||
<?php if (isset($term['icono'])): ?>
|
||||
<img src="<?php echo esc_url($term['icono']); ?>" alt="" class="fp-geo-filter-icon">
|
||||
<?php endif; ?>
|
||||
<span><?php echo esc_html($term['name']); ?></span>
|
||||
</button>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
</div>
|
||||
<?php endforeach; ?>
|
||||
|
||||
<div class="fp-geo-filters-footer">
|
||||
<span class="fp-geo-results-count">
|
||||
<?php _e('Mostrando', 'fp-geo-content'); ?>
|
||||
<strong class="fp-geo-results-number">0</strong>
|
||||
<span class="fp-geo-results-label"><?php _e('resultados', 'fp-geo-content'); ?></span>
|
||||
</span>
|
||||
<button type="button" class="fp-geo-clear-filters">
|
||||
<?php _e('Limpiar filtros', 'fp-geo-content'); ?>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<?php
|
||||
return ob_get_clean();
|
||||
}
|
||||
|
||||
/**
|
||||
* Renderizar leyenda
|
||||
*/
|
||||
private static function render_legend($map_id, $legend_data)
|
||||
{
|
||||
if (empty($legend_data['items'])) {
|
||||
return '';
|
||||
}
|
||||
|
||||
$has_pilots = isset($legend_data['has_pilots']) && $legend_data['has_pilots'];
|
||||
|
||||
ob_start();
|
||||
?>
|
||||
<div id="<?php echo esc_attr($map_id); ?>-legend" class="fp-geo-legend">
|
||||
<div class="fp-geo-legend-title"><?php _e('Leyenda', 'fp-geo-content'); ?></div>
|
||||
|
||||
<div class="fp-geo-legend-section">
|
||||
<div class="fp-geo-legend-section-title"><?php _e('Iniciativas', 'fp-geo-content'); ?></div>
|
||||
<div class="fp-geo-legend-items">
|
||||
<?php foreach ($legend_data['items'] as $item):
|
||||
$color = isset($item['color']) ? $item['color'] : '#F97316';
|
||||
?>
|
||||
<div class="fp-geo-legend-item">
|
||||
<span class="fp-geo-legend-marker" style="background-color: <?php echo esc_attr($color); ?>;"></span>
|
||||
<span class="fp-geo-legend-label"><?php echo esc_html($item['name']); ?></span>
|
||||
</div>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?php if ($has_pilots): ?>
|
||||
<div class="fp-geo-legend-section fp-geo-legend-pilot-section">
|
||||
<div class="fp-geo-legend-items">
|
||||
<div class="fp-geo-legend-item fp-geo-legend-pilot">
|
||||
<span class="fp-geo-legend-marker-pilot" aria-hidden="true">
|
||||
<svg width="22" height="28" viewBox="0 0 36 48">
|
||||
<circle cx="18" cy="18" r="15" fill="#888" stroke="white" stroke-width="3"/>
|
||||
<polygon points="18,42 24,30 12,30" fill="#888" stroke="white" stroke-width="2" stroke-linejoin="round"/>
|
||||
<text x="18" y="22" text-anchor="middle" fill="white" font-size="14" font-weight="bold">★</text>
|
||||
</svg>
|
||||
</span>
|
||||
<span class="fp-geo-legend-label"><?php _e('Bloque Piloto', 'fp-geo-content'); ?></span>
|
||||
</div>
|
||||
<p class="fp-geo-legend-pilot-desc">
|
||||
<?php _e('Actuación piloto (transversal a cualquier iniciativa)', 'fp-geo-content'); ?>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
<?php
|
||||
return ob_get_clean();
|
||||
}
|
||||
|
||||
/**
|
||||
* Renderizar panel de detalle
|
||||
*/
|
||||
private static function render_detail_panel($map_id, $display_type, $show_button = true, $button_text = '')
|
||||
{
|
||||
$class = $display_type === 'modal' ? 'fp-geo-modal' : 'fp-geo-sidebar';
|
||||
$button_text = $button_text ?: __('Ver más', 'fp-geo-content');
|
||||
|
||||
ob_start();
|
||||
?>
|
||||
<div id="<?php echo esc_attr($map_id); ?>-detail" class="fp-geo-detail <?php echo esc_attr($class); ?>">
|
||||
<button class="fp-geo-detail-close" aria-label="<?php _e('Cerrar', 'fp-geo-content'); ?>">×</button>
|
||||
|
||||
<div class="fp-geo-detail-content">
|
||||
<div class="fp-geo-detail-header">
|
||||
<div class="fp-geo-detail-taxonomies"></div>
|
||||
</div>
|
||||
|
||||
<div class="fp-geo-detail-thumbnail"></div>
|
||||
|
||||
<h2 class="fp-geo-detail-title"></h2>
|
||||
|
||||
<div class="fp-geo-detail-excerpt"></div>
|
||||
|
||||
<div class="fp-geo-detail-meta">
|
||||
<div class="fp-geo-detail-location"></div>
|
||||
<div class="fp-geo-detail-contact"></div>
|
||||
</div>
|
||||
|
||||
<?php if ($show_button): ?>
|
||||
<div class="fp-geo-detail-footer">
|
||||
<a href="#" class="fp-geo-detail-link fp-geo-btn" target="_blank">
|
||||
<?php echo esc_html($button_text); ?>
|
||||
</a>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?php if ($display_type === 'modal'): ?>
|
||||
<div id="<?php echo esc_attr($map_id); ?>-overlay" class="fp-geo-overlay"></div>
|
||||
<?php endif; ?>
|
||||
<?php
|
||||
return ob_get_clean();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,765 @@
|
||||
<?php
|
||||
/**
|
||||
* Configuración del plugin
|
||||
*
|
||||
* @package FP_Geo_Content
|
||||
*/
|
||||
|
||||
if (!defined('ABSPATH')) {
|
||||
exit;
|
||||
}
|
||||
|
||||
class FP_Geo_Settings {
|
||||
|
||||
/**
|
||||
* Registrar settings
|
||||
*/
|
||||
public static function register() {
|
||||
// Nada que hacer en init por ahora
|
||||
}
|
||||
|
||||
/**
|
||||
* Registrar ajustes de WordPress
|
||||
*/
|
||||
public static function register_settings() {
|
||||
register_setting('fp_geo_content_options', 'fp_geo_content_options', [
|
||||
'sanitize_callback' => [__CLASS__, 'sanitize_options'],
|
||||
]);
|
||||
|
||||
// Sección: Tipos de contenido
|
||||
add_settings_section(
|
||||
'fp_geo_content_types',
|
||||
__('Tipos de Contenido', 'fp-geo-content'),
|
||||
[__CLASS__, 'section_content_types'],
|
||||
'fp-geo-content'
|
||||
);
|
||||
|
||||
add_settings_field(
|
||||
'post_types',
|
||||
__('Tipos de contenido a mostrar', 'fp-geo-content'),
|
||||
[__CLASS__, 'field_post_types'],
|
||||
'fp-geo-content',
|
||||
'fp_geo_content_types'
|
||||
);
|
||||
|
||||
add_settings_field(
|
||||
'lat_field',
|
||||
__('Campo de Latitud', 'fp-geo-content'),
|
||||
[__CLASS__, 'field_lat'],
|
||||
'fp-geo-content',
|
||||
'fp_geo_content_types'
|
||||
);
|
||||
|
||||
add_settings_field(
|
||||
'lng_field',
|
||||
__('Campo de Longitud', 'fp-geo-content'),
|
||||
[__CLASS__, 'field_lng'],
|
||||
'fp-geo-content',
|
||||
'fp_geo_content_types'
|
||||
);
|
||||
|
||||
// Sección: Configuración del mapa
|
||||
add_settings_section(
|
||||
'fp_geo_map_settings',
|
||||
__('Configuración del Mapa', 'fp-geo-content'),
|
||||
[__CLASS__, 'section_map_settings'],
|
||||
'fp-geo-content'
|
||||
);
|
||||
|
||||
add_settings_field(
|
||||
'default_center',
|
||||
__('Centro por defecto', 'fp-geo-content'),
|
||||
[__CLASS__, 'field_default_center'],
|
||||
'fp-geo-content',
|
||||
'fp_geo_map_settings'
|
||||
);
|
||||
|
||||
add_settings_field(
|
||||
'zoom_levels',
|
||||
__('Niveles de zoom', 'fp-geo-content'),
|
||||
[__CLASS__, 'field_zoom_levels'],
|
||||
'fp-geo-content',
|
||||
'fp_geo_map_settings'
|
||||
);
|
||||
|
||||
add_settings_field(
|
||||
'tile_provider',
|
||||
__('Proveedor de tiles', 'fp-geo-content'),
|
||||
[__CLASS__, 'field_tile_provider'],
|
||||
'fp-geo-content',
|
||||
'fp_geo_map_settings'
|
||||
);
|
||||
|
||||
add_settings_field(
|
||||
'cluster_enabled',
|
||||
__('Agrupar marcadores', 'fp-geo-content'),
|
||||
[__CLASS__, 'field_cluster'],
|
||||
'fp-geo-content',
|
||||
'fp_geo_map_settings'
|
||||
);
|
||||
|
||||
add_settings_field(
|
||||
'scroll_wheel_zoom',
|
||||
__('Zoom con scroll', 'fp-geo-content'),
|
||||
[__CLASS__, 'field_scroll_wheel_zoom'],
|
||||
'fp-geo-content',
|
||||
'fp_geo_map_settings'
|
||||
);
|
||||
|
||||
// Sección: Marcadores
|
||||
add_settings_section(
|
||||
'fp_geo_markers',
|
||||
__('Marcadores', 'fp-geo-content'),
|
||||
[__CLASS__, 'section_markers'],
|
||||
'fp-geo-content'
|
||||
);
|
||||
|
||||
add_settings_field(
|
||||
'marker_icon',
|
||||
__('Icono personalizado', 'fp-geo-content'),
|
||||
[__CLASS__, 'field_marker_icon'],
|
||||
'fp-geo-content',
|
||||
'fp_geo_markers'
|
||||
);
|
||||
|
||||
add_settings_field(
|
||||
'marker_default_color',
|
||||
__('Color por defecto', 'fp-geo-content'),
|
||||
[__CLASS__, 'field_marker_default_color'],
|
||||
'fp-geo-content',
|
||||
'fp_geo_markers'
|
||||
);
|
||||
|
||||
add_settings_field(
|
||||
'use_category_colors',
|
||||
__('Colores por categoría', 'fp-geo-content'),
|
||||
[__CLASS__, 'field_use_category_colors'],
|
||||
'fp-geo-content',
|
||||
'fp_geo_markers'
|
||||
);
|
||||
|
||||
add_settings_field(
|
||||
'show_legend',
|
||||
__('Mostrar leyenda', 'fp-geo-content'),
|
||||
[__CLASS__, 'field_show_legend'],
|
||||
'fp-geo-content',
|
||||
'fp_geo_markers'
|
||||
);
|
||||
|
||||
// Sección: Filtros
|
||||
add_settings_section(
|
||||
'fp_geo_filters',
|
||||
__('Filtros', 'fp-geo-content'),
|
||||
[__CLASS__, 'section_filters'],
|
||||
'fp-geo-content'
|
||||
);
|
||||
|
||||
add_settings_field(
|
||||
'filter_taxonomies',
|
||||
__('Taxonomías para filtrar', 'fp-geo-content'),
|
||||
[__CLASS__, 'field_filter_taxonomies'],
|
||||
'fp-geo-content',
|
||||
'fp_geo_filters'
|
||||
);
|
||||
|
||||
add_settings_field(
|
||||
'filter_combine',
|
||||
__('Combinación de filtros', 'fp-geo-content'),
|
||||
[__CLASS__, 'field_filter_combine'],
|
||||
'fp-geo-content',
|
||||
'fp_geo_filters'
|
||||
);
|
||||
|
||||
// Sección: Visualización
|
||||
add_settings_section(
|
||||
'fp_geo_display',
|
||||
__('Visualización', 'fp-geo-content'),
|
||||
[__CLASS__, 'section_display'],
|
||||
'fp-geo-content'
|
||||
);
|
||||
|
||||
add_settings_field(
|
||||
'detail_display',
|
||||
__('Mostrar detalle en', 'fp-geo-content'),
|
||||
[__CLASS__, 'field_detail_display'],
|
||||
'fp-geo-content',
|
||||
'fp_geo_display'
|
||||
);
|
||||
|
||||
add_settings_field(
|
||||
'sidebar_position',
|
||||
__('Posición del panel lateral', 'fp-geo-content'),
|
||||
[__CLASS__, 'field_sidebar_position'],
|
||||
'fp-geo-content',
|
||||
'fp_geo_display'
|
||||
);
|
||||
|
||||
add_settings_field(
|
||||
'show_detail_button',
|
||||
__('Botón "Ver detalle"', 'fp-geo-content'),
|
||||
[__CLASS__, 'field_show_detail_button'],
|
||||
'fp-geo-content',
|
||||
'fp_geo_display'
|
||||
);
|
||||
|
||||
add_settings_field(
|
||||
'detail_button_text',
|
||||
__('Texto del botón', 'fp-geo-content'),
|
||||
[__CLASS__, 'field_detail_button_text'],
|
||||
'fp-geo-content',
|
||||
'fp_geo_display'
|
||||
);
|
||||
|
||||
// Sección: CSS Personalizado
|
||||
add_settings_section(
|
||||
'fp_geo_custom_css',
|
||||
__('CSS Personalizado', 'fp-geo-content'),
|
||||
[__CLASS__, 'section_custom_css'],
|
||||
'fp-geo-content'
|
||||
);
|
||||
|
||||
add_settings_field(
|
||||
'custom_css',
|
||||
__('Estilos CSS', 'fp-geo-content'),
|
||||
[__CLASS__, 'field_custom_css'],
|
||||
'fp-geo-content',
|
||||
'fp_geo_custom_css'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sanitizar opciones
|
||||
*/
|
||||
public static function sanitize_options($input) {
|
||||
$sanitized = [];
|
||||
|
||||
// Post types
|
||||
$sanitized['post_types'] = isset($input['post_types']) && is_array($input['post_types'])
|
||||
? array_map('sanitize_text_field', $input['post_types'])
|
||||
: [];
|
||||
|
||||
// Campos de lat/lng
|
||||
$sanitized['lat_field'] = sanitize_text_field($input['lat_field'] ?? 'latitud');
|
||||
$sanitized['lng_field'] = sanitize_text_field($input['lng_field'] ?? 'longitud');
|
||||
|
||||
// Centro por defecto
|
||||
$sanitized['default_lat'] = floatval($input['default_lat'] ?? 40.4168);
|
||||
$sanitized['default_lng'] = floatval($input['default_lng'] ?? -3.7038);
|
||||
|
||||
// Zoom
|
||||
$sanitized['default_zoom'] = intval($input['default_zoom'] ?? 12);
|
||||
$sanitized['min_zoom'] = intval($input['min_zoom'] ?? 5);
|
||||
$sanitized['max_zoom'] = intval($input['max_zoom'] ?? 18);
|
||||
|
||||
// Cluster
|
||||
$sanitized['cluster_enabled'] = isset($input['cluster_enabled']);
|
||||
|
||||
// Tile provider
|
||||
$sanitized['tile_provider'] = sanitize_text_field($input['tile_provider'] ?? 'carto_light');
|
||||
|
||||
// Filtros
|
||||
$sanitized['filter_taxonomies'] = isset($input['filter_taxonomies']) && is_array($input['filter_taxonomies'])
|
||||
? array_map('sanitize_text_field', $input['filter_taxonomies'])
|
||||
: [];
|
||||
$sanitized['filter_combine'] = in_array($input['filter_combine'] ?? 'OR', ['OR', 'AND'])
|
||||
? $input['filter_combine']
|
||||
: 'OR';
|
||||
|
||||
// Display
|
||||
$sanitized['detail_display'] = in_array($input['detail_display'] ?? 'sidebar', ['sidebar', 'modal'])
|
||||
? $input['detail_display']
|
||||
: 'sidebar';
|
||||
|
||||
// Scroll wheel zoom
|
||||
$sanitized['scroll_wheel_zoom'] = sanitize_text_field($input['scroll_wheel_zoom'] ?? 'ctrl');
|
||||
|
||||
// Marcadores
|
||||
$sanitized['marker_icon'] = isset($input['marker_icon']) ? absint($input['marker_icon']) : 0;
|
||||
$sanitized['marker_default_color'] = sanitize_hex_color($input['marker_default_color'] ?? '#F97316');
|
||||
$sanitized['use_category_colors'] = isset($input['use_category_colors']);
|
||||
$sanitized['show_legend'] = isset($input['show_legend']);
|
||||
$sanitized['legend_taxonomy'] = sanitize_text_field($input['legend_taxonomy'] ?? '');
|
||||
|
||||
// Sidebar position
|
||||
$sanitized['sidebar_position'] = in_array($input['sidebar_position'] ?? 'right', ['left', 'right'])
|
||||
? $input['sidebar_position']
|
||||
: 'right';
|
||||
|
||||
// Detail button
|
||||
$sanitized['show_detail_button'] = isset($input['show_detail_button']);
|
||||
$sanitized['detail_button_text'] = sanitize_text_field($input['detail_button_text'] ?? __('Ver detalle', 'fp-geo-content'));
|
||||
|
||||
// Custom CSS - sanitizar pero permitir CSS válido
|
||||
$sanitized['custom_css'] = isset($input['custom_css']) ? wp_strip_all_tags($input['custom_css']) : '';
|
||||
|
||||
return $sanitized;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sección: Tipos de contenido
|
||||
*/
|
||||
public static function section_content_types() {
|
||||
echo '<p>' . __('Selecciona los tipos de contenido que tienen campos de geolocalización y que quieres mostrar en el mapa.', 'fp-geo-content') . '</p>';
|
||||
}
|
||||
|
||||
/**
|
||||
* Campo: Post types
|
||||
*/
|
||||
public static function field_post_types() {
|
||||
$options = get_option('fp_geo_content_options', []);
|
||||
$selected = $options['post_types'] ?? [];
|
||||
|
||||
// Obtener todos los post types públicos
|
||||
$post_types = get_post_types(['public' => true], 'objects');
|
||||
|
||||
echo '<fieldset>';
|
||||
foreach ($post_types as $pt) {
|
||||
if ($pt->name === 'attachment') continue;
|
||||
|
||||
$checked = in_array($pt->name, $selected) ? 'checked' : '';
|
||||
printf(
|
||||
'<label style="display:block;margin-bottom:8px;"><input type="checkbox" name="fp_geo_content_options[post_types][]" value="%s" %s> %s <code>(%s)</code></label>',
|
||||
esc_attr($pt->name),
|
||||
$checked,
|
||||
esc_html($pt->label),
|
||||
esc_html($pt->name)
|
||||
);
|
||||
}
|
||||
echo '</fieldset>';
|
||||
echo '<p class="description">' . __('Solo se mostrarán los posts que tengan coordenadas de latitud y longitud.', 'fp-geo-content') . '</p>';
|
||||
}
|
||||
|
||||
/**
|
||||
* Campo: Latitud
|
||||
*/
|
||||
public static function field_lat() {
|
||||
$options = get_option('fp_geo_content_options', []);
|
||||
$value = $options['lat_field'] ?? 'latitud';
|
||||
|
||||
printf(
|
||||
'<input type="text" name="fp_geo_content_options[lat_field]" value="%s" class="regular-text">',
|
||||
esc_attr($value)
|
||||
);
|
||||
echo '<p class="description">' . __('Nombre del campo ACF o meta que contiene la latitud.', 'fp-geo-content') . '</p>';
|
||||
}
|
||||
|
||||
/**
|
||||
* Campo: Longitud
|
||||
*/
|
||||
public static function field_lng() {
|
||||
$options = get_option('fp_geo_content_options', []);
|
||||
$value = $options['lng_field'] ?? 'longitud';
|
||||
|
||||
printf(
|
||||
'<input type="text" name="fp_geo_content_options[lng_field]" value="%s" class="regular-text">',
|
||||
esc_attr($value)
|
||||
);
|
||||
echo '<p class="description">' . __('Nombre del campo ACF o meta que contiene la longitud.', 'fp-geo-content') . '</p>';
|
||||
}
|
||||
|
||||
/**
|
||||
* Sección: Configuración del mapa
|
||||
*/
|
||||
public static function section_map_settings() {
|
||||
echo '<p>' . __('Configura el comportamiento y apariencia del mapa.', 'fp-geo-content') . '</p>';
|
||||
}
|
||||
|
||||
/**
|
||||
* Campo: Centro por defecto
|
||||
*/
|
||||
public static function field_default_center() {
|
||||
$options = get_option('fp_geo_content_options', []);
|
||||
$lat = $options['default_lat'] ?? '40.4168';
|
||||
$lng = $options['default_lng'] ?? '-3.7038';
|
||||
|
||||
printf(
|
||||
'<label>Latitud: <input type="text" name="fp_geo_content_options[default_lat]" value="%s" style="width:120px;"></label> ',
|
||||
esc_attr($lat)
|
||||
);
|
||||
printf(
|
||||
'<label>Longitud: <input type="text" name="fp_geo_content_options[default_lng]" value="%s" style="width:120px;"></label>',
|
||||
esc_attr($lng)
|
||||
);
|
||||
echo '<p class="description">' . __('Coordenadas del centro inicial del mapa (por defecto: Madrid).', 'fp-geo-content') . '</p>';
|
||||
}
|
||||
|
||||
/**
|
||||
* Campo: Niveles de zoom
|
||||
*/
|
||||
public static function field_zoom_levels() {
|
||||
$options = get_option('fp_geo_content_options', []);
|
||||
$default = $options['default_zoom'] ?? 12;
|
||||
$min = $options['min_zoom'] ?? 5;
|
||||
$max = $options['max_zoom'] ?? 18;
|
||||
|
||||
printf(
|
||||
'<label>Por defecto: <input type="number" name="fp_geo_content_options[default_zoom]" value="%s" min="1" max="20" style="width:60px;"></label> ',
|
||||
esc_attr($default)
|
||||
);
|
||||
printf(
|
||||
'<label>Mínimo: <input type="number" name="fp_geo_content_options[min_zoom]" value="%s" min="1" max="20" style="width:60px;"></label> ',
|
||||
esc_attr($min)
|
||||
);
|
||||
printf(
|
||||
'<label>Máximo: <input type="number" name="fp_geo_content_options[max_zoom]" value="%s" min="1" max="20" style="width:60px;"></label>',
|
||||
esc_attr($max)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Campo: Proveedor de tiles
|
||||
*/
|
||||
public static function field_tile_provider() {
|
||||
$options = get_option('fp_geo_content_options', []);
|
||||
$value = $options['tile_provider'] ?? 'carto_light';
|
||||
|
||||
$providers = [
|
||||
'osm' => 'OpenStreetMap (estándar)',
|
||||
'carto_light' => 'CartoDB Positron (claro)',
|
||||
'carto_dark' => 'CartoDB Dark Matter (oscuro)',
|
||||
'carto_voyager' => 'CartoDB Voyager (colores)',
|
||||
'stamen_toner' => 'Stamen Toner (B/N)',
|
||||
'stamen_watercolor' => 'Stamen Watercolor (acuarela)',
|
||||
];
|
||||
|
||||
echo '<select name="fp_geo_content_options[tile_provider]">';
|
||||
foreach ($providers as $key => $label) {
|
||||
printf(
|
||||
'<option value="%s" %s>%s</option>',
|
||||
esc_attr($key),
|
||||
selected($value, $key, false),
|
||||
esc_html($label)
|
||||
);
|
||||
}
|
||||
echo '</select>';
|
||||
}
|
||||
|
||||
/**
|
||||
* Campo: Cluster
|
||||
*/
|
||||
public static function field_cluster() {
|
||||
$options = get_option('fp_geo_content_options', []);
|
||||
$checked = isset($options['cluster_enabled']) && $options['cluster_enabled'] ? 'checked' : '';
|
||||
|
||||
printf(
|
||||
'<label><input type="checkbox" name="fp_geo_content_options[cluster_enabled]" value="1" %s> %s</label>',
|
||||
$checked,
|
||||
__('Agrupar marcadores cercanos en clusters', 'fp-geo-content')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sección: Filtros
|
||||
*/
|
||||
public static function section_filters() {
|
||||
echo '<p>' . __('Configura qué taxonomías se pueden usar como filtros en el mapa.', 'fp-geo-content') . '</p>';
|
||||
}
|
||||
|
||||
/**
|
||||
* Campo: Taxonomías para filtrar
|
||||
*/
|
||||
public static function field_filter_taxonomies() {
|
||||
$options = get_option('fp_geo_content_options', []);
|
||||
$selected = $options['filter_taxonomies'] ?? [];
|
||||
|
||||
// Obtener todas las taxonomías públicas
|
||||
$taxonomies = get_taxonomies(['public' => true], 'objects');
|
||||
|
||||
echo '<fieldset>';
|
||||
foreach ($taxonomies as $tax) {
|
||||
if (in_array($tax->name, ['post_format'])) continue;
|
||||
|
||||
$checked = in_array($tax->name, $selected) ? 'checked' : '';
|
||||
printf(
|
||||
'<label style="display:block;margin-bottom:8px;"><input type="checkbox" name="fp_geo_content_options[filter_taxonomies][]" value="%s" %s> %s <code>(%s)</code></label>',
|
||||
esc_attr($tax->name),
|
||||
$checked,
|
||||
esc_html($tax->label),
|
||||
esc_html($tax->name)
|
||||
);
|
||||
}
|
||||
echo '</fieldset>';
|
||||
}
|
||||
|
||||
/**
|
||||
* Campo: Combinación de filtros
|
||||
*/
|
||||
public static function field_filter_combine() {
|
||||
$options = get_option('fp_geo_content_options', []);
|
||||
$value = $options['filter_combine'] ?? 'OR';
|
||||
|
||||
echo '<select name="fp_geo_content_options[filter_combine]">';
|
||||
printf('<option value="OR" %s>%s</option>', selected($value, 'OR', false), __('OR - Mostrar si cumple cualquier filtro', 'fp-geo-content'));
|
||||
printf('<option value="AND" %s>%s</option>', selected($value, 'AND', false), __('AND - Mostrar solo si cumple todos los filtros', 'fp-geo-content'));
|
||||
echo '</select>';
|
||||
}
|
||||
|
||||
/**
|
||||
* Sección: Visualización
|
||||
*/
|
||||
public static function section_display() {
|
||||
echo '<p>' . __('Configura cómo se muestra la información de cada marcador.', 'fp-geo-content') . '</p>';
|
||||
}
|
||||
|
||||
/**
|
||||
* Campo: Mostrar detalle
|
||||
*/
|
||||
public static function field_detail_display() {
|
||||
$options = get_option('fp_geo_content_options', []);
|
||||
$value = $options['detail_display'] ?? 'sidebar';
|
||||
|
||||
echo '<select name="fp_geo_content_options[detail_display]">';
|
||||
printf('<option value="sidebar" %s>%s</option>', selected($value, 'sidebar', false), __('Panel lateral sobre el mapa', 'fp-geo-content'));
|
||||
printf('<option value="modal" %s>%s</option>', selected($value, 'modal', false), __('Ventana modal/popup', 'fp-geo-content'));
|
||||
echo '</select>';
|
||||
echo '<p class="description">' . __('Cómo mostrar la ficha de detalle al hacer clic en un marcador.', 'fp-geo-content') . '</p>';
|
||||
}
|
||||
|
||||
/**
|
||||
* Campo: Scroll wheel zoom
|
||||
*/
|
||||
public static function field_scroll_wheel_zoom() {
|
||||
$options = get_option('fp_geo_content_options', []);
|
||||
$value = $options['scroll_wheel_zoom'] ?? 'ctrl';
|
||||
|
||||
echo '<select name="fp_geo_content_options[scroll_wheel_zoom]">';
|
||||
printf('<option value="ctrl" %s>%s</option>', selected($value, 'ctrl', false), __('Solo con Ctrl + scroll (recomendado)', 'fp-geo-content'));
|
||||
printf('<option value="always" %s>%s</option>', selected($value, 'always', false), __('Siempre activo', 'fp-geo-content'));
|
||||
printf('<option value="disabled" %s>%s</option>', selected($value, 'disabled', false), __('Desactivado', 'fp-geo-content'));
|
||||
echo '</select>';
|
||||
echo '<p class="description">' . __('Controla si el scroll del ratón hace zoom en el mapa. "Solo con Ctrl" permite hacer scroll en la página sin hacer zoom accidentalmente.', 'fp-geo-content') . '</p>';
|
||||
}
|
||||
|
||||
/**
|
||||
* Sección: Marcadores
|
||||
*/
|
||||
public static function section_markers() {
|
||||
echo '<p>' . __('Personaliza la apariencia de los marcadores en el mapa.', 'fp-geo-content') . '</p>';
|
||||
}
|
||||
|
||||
/**
|
||||
* Campo: Icono personalizado
|
||||
*/
|
||||
public static function field_marker_icon() {
|
||||
$options = get_option('fp_geo_content_options', []);
|
||||
$image_id = $options['marker_icon'] ?? 0;
|
||||
$image_url = $image_id ? wp_get_attachment_image_url($image_id, 'thumbnail') : '';
|
||||
|
||||
echo '<div class="fp-geo-media-upload">';
|
||||
printf(
|
||||
'<input type="hidden" name="fp_geo_content_options[marker_icon]" id="fp_geo_marker_icon" value="%s">',
|
||||
esc_attr($image_id)
|
||||
);
|
||||
printf(
|
||||
'<div id="fp_geo_marker_icon_preview" class="fp-geo-image-preview" style="%s">',
|
||||
$image_url ? '' : 'display:none;'
|
||||
);
|
||||
if ($image_url) {
|
||||
printf('<img src="%s" alt="" style="max-width: 60px; height: auto;">', esc_url($image_url));
|
||||
}
|
||||
echo '</div>';
|
||||
printf(
|
||||
'<button type="button" class="button fp-geo-upload-btn" data-target="fp_geo_marker_icon">%s</button>',
|
||||
__('Subir icono', 'fp-geo-content')
|
||||
);
|
||||
printf(
|
||||
'<button type="button" class="button fp-geo-remove-btn" data-target="fp_geo_marker_icon" style="%s">%s</button>',
|
||||
$image_id ? '' : 'display:none;',
|
||||
__('Eliminar', 'fp-geo-content')
|
||||
);
|
||||
echo '</div>';
|
||||
echo '<p class="description">' . __('Opcional: Sube un icono personalizado para los marcadores. Si no se sube, se usarán círculos de color. Tamaño recomendado: 40x50px.', 'fp-geo-content') . '</p>';
|
||||
}
|
||||
|
||||
/**
|
||||
* Campo: Color por defecto
|
||||
*/
|
||||
public static function field_marker_default_color() {
|
||||
$options = get_option('fp_geo_content_options', []);
|
||||
$value = $options['marker_default_color'] ?? '#F97316';
|
||||
|
||||
printf(
|
||||
'<input type="color" name="fp_geo_content_options[marker_default_color]" value="%s" class="fp-geo-color-picker">',
|
||||
esc_attr($value)
|
||||
);
|
||||
echo '<p class="description">' . __('Color por defecto para los marcadores cuando no tienen color de categoría asignado.', 'fp-geo-content') . '</p>';
|
||||
}
|
||||
|
||||
/**
|
||||
* Campo: Usar colores por categoría
|
||||
*/
|
||||
public static function field_use_category_colors() {
|
||||
$options = get_option('fp_geo_content_options', []);
|
||||
$checked = isset($options['use_category_colors']) && $options['use_category_colors'] ? 'checked' : '';
|
||||
$legend_taxonomy = $options['legend_taxonomy'] ?? '';
|
||||
|
||||
printf(
|
||||
'<label><input type="checkbox" name="fp_geo_content_options[use_category_colors]" value="1" %s> %s</label>',
|
||||
$checked,
|
||||
__('Usar colores de las categorías de los filtros (si tienen campo ACF "color")', 'fp-geo-content')
|
||||
);
|
||||
|
||||
// Selector de taxonomía para los colores
|
||||
$taxonomies = get_taxonomies(['public' => true], 'objects');
|
||||
echo '<div class="fp-geo-category-color-options" style="margin-top: 10px; margin-left: 25px;">';
|
||||
echo '<label>' . __('Taxonomía para colores:', 'fp-geo-content') . ' ';
|
||||
echo '<select name="fp_geo_content_options[legend_taxonomy]">';
|
||||
echo '<option value="">' . __('-- Seleccionar --', 'fp-geo-content') . '</option>';
|
||||
foreach ($taxonomies as $tax) {
|
||||
if (in_array($tax->name, ['post_format'])) continue;
|
||||
printf(
|
||||
'<option value="%s" %s>%s</option>',
|
||||
esc_attr($tax->name),
|
||||
selected($legend_taxonomy, $tax->name, false),
|
||||
esc_html($tax->label)
|
||||
);
|
||||
}
|
||||
echo '</select></label>';
|
||||
echo '<p class="description">' . __('Selecciona la taxonomía cuyos colores quieres usar para los marcadores.', 'fp-geo-content') . '</p>';
|
||||
echo '</div>';
|
||||
}
|
||||
|
||||
/**
|
||||
* Campo: Mostrar leyenda
|
||||
*/
|
||||
public static function field_show_legend() {
|
||||
$options = get_option('fp_geo_content_options', []);
|
||||
$checked = isset($options['show_legend']) && $options['show_legend'] ? 'checked' : '';
|
||||
|
||||
printf(
|
||||
'<label><input type="checkbox" name="fp_geo_content_options[show_legend]" value="1" %s> %s</label>',
|
||||
$checked,
|
||||
__('Mostrar leyenda de colores sobre el mapa', 'fp-geo-content')
|
||||
);
|
||||
echo '<p class="description">' . __('Muestra una leyenda con los colores de las categorías en la esquina del mapa.', 'fp-geo-content') . '</p>';
|
||||
}
|
||||
|
||||
/**
|
||||
* Campo: Posición del sidebar
|
||||
*/
|
||||
public static function field_sidebar_position() {
|
||||
$options = get_option('fp_geo_content_options', []);
|
||||
$value = $options['sidebar_position'] ?? 'right';
|
||||
|
||||
echo '<select name="fp_geo_content_options[sidebar_position]">';
|
||||
printf('<option value="right" %s>%s</option>', selected($value, 'right', false), __('Derecha', 'fp-geo-content'));
|
||||
printf('<option value="left" %s>%s</option>', selected($value, 'left', false), __('Izquierda', 'fp-geo-content'));
|
||||
echo '</select>';
|
||||
echo '<p class="description">' . __('Posición del panel lateral cuando se muestra el detalle (solo aplica al modo sidebar).', 'fp-geo-content') . '</p>';
|
||||
}
|
||||
|
||||
/**
|
||||
* Campo: Mostrar botón detalle
|
||||
*/
|
||||
public static function field_show_detail_button() {
|
||||
$options = get_option('fp_geo_content_options', []);
|
||||
// Por defecto activado si no existe la opción
|
||||
$checked = !isset($options['show_detail_button']) || $options['show_detail_button'] ? 'checked' : '';
|
||||
|
||||
printf(
|
||||
'<label><input type="checkbox" name="fp_geo_content_options[show_detail_button]" value="1" %s> %s</label>',
|
||||
$checked,
|
||||
__('Mostrar botón para ir al detalle del contenido', 'fp-geo-content')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Campo: Texto del botón
|
||||
*/
|
||||
public static function field_detail_button_text() {
|
||||
$options = get_option('fp_geo_content_options', []);
|
||||
$value = $options['detail_button_text'] ?? __('Ver detalle', 'fp-geo-content');
|
||||
|
||||
printf(
|
||||
'<input type="text" name="fp_geo_content_options[detail_button_text]" value="%s" class="regular-text">',
|
||||
esc_attr($value)
|
||||
);
|
||||
echo '<p class="description">' . __('Texto del botón que enlaza al contenido completo. Ejemplos: "Ver detalle", "Ver más", "Ir al contenido"...', 'fp-geo-content') . '</p>';
|
||||
}
|
||||
|
||||
/**
|
||||
* Sección: CSS Personalizado
|
||||
*/
|
||||
public static function section_custom_css() {
|
||||
echo '<p>' . __('Añade CSS personalizado para sobreescribir los estilos base del mapa. Estos estilos se cargarán después de los estilos base del plugin.', 'fp-geo-content') . '</p>';
|
||||
}
|
||||
|
||||
/**
|
||||
* Campo: CSS Personalizado
|
||||
*/
|
||||
public static function field_custom_css() {
|
||||
$options = get_option('fp_geo_content_options', []);
|
||||
$value = $options['custom_css'] ?? '';
|
||||
|
||||
printf(
|
||||
'<textarea name="fp_geo_content_options[custom_css]" rows="20" class="large-text code" style="font-family: monospace; font-size: 13px;">%s</textarea>',
|
||||
esc_textarea($value)
|
||||
);
|
||||
echo '<p class="description">' . __('Introduce CSS válido para personalizar el aspecto del mapa. No incluyas etiquetas <style>.', 'fp-geo-content') . '</p>';
|
||||
|
||||
// Mostrar clases disponibles
|
||||
echo '<details style="margin-top: 15px;">';
|
||||
echo '<summary style="cursor: pointer; font-weight: 500;">' . __('Ver clases CSS disponibles', 'fp-geo-content') . '</summary>';
|
||||
echo '<div style="background: #f5f5f5; padding: 15px; margin-top: 10px; border-radius: 4px; font-size: 13px;">';
|
||||
echo '<code>.fp-geo-wrapper</code> - Contenedor principal<br>';
|
||||
echo '<code>.fp-geo-filters</code> - Barra de filtros<br>';
|
||||
echo '<code>.fp-geo-filter-group</code> - Grupo de filtros<br>';
|
||||
echo '<code>.fp-geo-filter-label</code> - Etiqueta del grupo<br>';
|
||||
echo '<code>.fp-geo-filter-btn</code> - Botón de filtro<br>';
|
||||
echo '<code>.fp-geo-filter-btn.active</code> - Botón activo<br>';
|
||||
echo '<code>.fp-geo-clear-filters</code> - Botón limpiar<br>';
|
||||
echo '<code>.fp-geo-map</code> - Contenedor del mapa<br>';
|
||||
echo '<code>.fp-geo-legend</code> - Leyenda<br>';
|
||||
echo '<code>.fp-geo-legend-item</code> - Item de leyenda<br>';
|
||||
echo '<code>.fp-geo-legend-marker</code> - Marcador en leyenda<br>';
|
||||
echo '<code>.fp-geo-detail</code> - Panel de detalle<br>';
|
||||
echo '<code>.fp-geo-sidebar</code> - Panel lateral<br>';
|
||||
echo '<code>.fp-geo-modal</code> - Modal<br>';
|
||||
echo '<code>.fp-geo-detail-header</code> - Cabecera del detalle<br>';
|
||||
echo '<code>.fp-geo-detail-title</code> - Título<br>';
|
||||
echo '<code>.fp-geo-detail-excerpt</code> - Extracto<br>';
|
||||
echo '<code>.fp-geo-btn</code> - Botones<br>';
|
||||
echo '<code>.fp-geo-circle-marker</code> - Marcadores circulares<br>';
|
||||
echo '<code>.marker-cluster</code> - Clusters<br>';
|
||||
echo '</div>';
|
||||
echo '</details>';
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtener proveedores de tiles
|
||||
*/
|
||||
public static function get_tile_providers() {
|
||||
return [
|
||||
'osm' => [
|
||||
'url' => 'https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png',
|
||||
'attribution' => '© <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a>',
|
||||
'subdomains' => 'abc',
|
||||
],
|
||||
'carto_light' => [
|
||||
'url' => 'https://{s}.basemaps.cartocdn.com/light_all/{z}/{x}/{y}{r}.png',
|
||||
'attribution' => '© <a href="https://carto.com/">CARTO</a>',
|
||||
'subdomains' => 'abcd',
|
||||
],
|
||||
'carto_dark' => [
|
||||
'url' => 'https://{s}.basemaps.cartocdn.com/dark_all/{z}/{x}/{y}{r}.png',
|
||||
'attribution' => '© <a href="https://carto.com/">CARTO</a>',
|
||||
'subdomains' => 'abcd',
|
||||
],
|
||||
'carto_voyager' => [
|
||||
'url' => 'https://{s}.basemaps.cartocdn.com/rastertiles/voyager/{z}/{x}/{y}{r}.png',
|
||||
'attribution' => '© <a href="https://carto.com/">CARTO</a>',
|
||||
'subdomains' => 'abcd',
|
||||
],
|
||||
'stamen_toner' => [
|
||||
'url' => 'https://tiles.stadiamaps.com/tiles/stamen_toner/{z}/{x}/{y}{r}.png',
|
||||
'attribution' => '© <a href="https://stadiamaps.com/">Stadia Maps</a>',
|
||||
'subdomains' => '',
|
||||
],
|
||||
'stamen_watercolor' => [
|
||||
'url' => 'https://tiles.stadiamaps.com/tiles/stamen_watercolor/{z}/{x}/{y}.jpg',
|
||||
'attribution' => '© <a href="https://stadiamaps.com/">Stadia Maps</a>',
|
||||
'subdomains' => '',
|
||||
],
|
||||
];
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user