专业WordPress插件,用于管理和显示具有高级功能的Google地图上多个商店位置
<?php /** * Plugin Name: BDFG Map Multi Locations * Plugin URI: https://beiduofengou.net/2024/04/15/bdfg-map-multi-locations/ * Description: Professional WordPress plugin for managing and displaying multiple store locations on Google Maps with advanced features * Version: 2.3.1 * Author: beiduofengou * Author URI: https://beiduofengou.net * License: GPL v2 or later * Text Domain: bdfg-map-locations * Domain Path: /languages * * @package BDFG_Map_Locations * @author beiduofengou <[email protected]> * @copyright 2024 beiduofengou.net */ // Prevent direct access to this file if (!defined('ABSPATH')) { exit('Direct access denied.'); } // Define plugin constants define('BDFG_MAP_VERSION', '2.3.1'); define('BDFG_MAP_PLUGIN_DIR', plugin_dir_path(__FILE__)); define('BDFG_MAP_PLUGIN_URL', plugin_dir_url(__FILE__)); define('BDFG_MAP_CACHE_TIME', 3600); // Cache lifetime in seconds /** * Main plugin class */ class BDFG_Map_Locations { /** * Singleton instance * * @var BDFG_Map_Locations */ private static $instance = null; /** * Store locations array * * @var array */ private $locations = []; /** * Plugin settings * * @var array */ private $settings = []; /** * Get singleton instance * * @return BDFG_Map_Locations */ public static function get_instance() { if (null === self::$instance) { self::$instance = new self(); } return self::$instance; } /** * Constructor */ private function __construct() { // Core initialization add_action('init', [$this, 'init']); add_action('plugins_loaded', [$this, 'load_language_files']); // Admin hooks add_action('admin_menu', [$this, 'add_admin_menu']); add_action('admin_enqueue_scripts', [$this, 'admin_enqueue_scripts']); add_action('admin_init', [$this, 'register_settings']); // Frontend hooks add_action('wp_enqueue_scripts', [$this, 'frontend_enqueue_scripts']); // Shortcodes add_shortcode('bdfg_map', [$this, 'map_shortcode']); add_shortcode('bdfg_location_list', [$this, 'location_list_shortcode']); // Ajax handlers add_action('wp_ajax_bdfg_save_location', [$this, 'ajax_save_location']); add_action('wp_ajax_bdfg_delete_location', [$this, 'ajax_delete_location']); add_action('wp_ajax_nopriv_bdfg_get_locations', [$this, 'ajax_get_locations']); add_action('wp_ajax_bdfg_get_locations', [$this, 'ajax_get_locations']); // REST API add_action('rest_api_init', [$this, 'register_rest_routes']); } /** * Initialize plugin */ public function init() { // Load locations from cache or database $this->locations = $this->get_cached_locations(); // Register location taxonomy $this->register_location_taxonomy(); // Load plugin settings $this->settings = get_option('bdfg_map_settings', [ 'api_key' => '', 'default_zoom' => 12, 'default_lat' => 40.7128, 'default_lng' => -74.0060, 'enable_clustering' => true, 'analytics_enabled' => true ]); } /** * Register location taxonomy */ public function register_location_taxonomy() { $labels = [ 'name' => __('Location Categories', 'bdfg-map-locations'), 'singular_name' => __('Location Category', 'bdfg-map-locations'), 'search_items' => __('Search Categories', 'bdfg-map-locations'), 'all_items' => __('All Categories', 'bdfg-map-locations'), 'parent_item' => __('Parent Category', 'bdfg-map-locations'), 'parent_item_colon' => __('Parent Category:', 'bdfg-map-locations'), 'edit_item' => __('Edit Category', 'bdfg-map-locations'), 'update_item' => __('Update Category', 'bdfg-map-locations'), 'add_new_item' => __('Add New Category', 'bdfg-map-locations'), 'new_item_name' => __('New Category Name', 'bdfg-map-locations'), 'menu_name' => __('Categories', 'bdfg-map-locations'), ]; $args = [ 'hierarchical' => true, 'labels' => $labels, 'show_ui' => true, 'show_admin_column' => true, 'query_var' => true, 'rewrite' => ['slug' => 'location-category'], ]; register_taxonomy('bdfg_location_category', null, $args); } /** * Add admin menu items */ public function add_admin_menu() { add_menu_page( __('BDFG Map Locations', 'bdfg-map-locations'), __('BDFG Maps', 'bdfg-map-locations'), 'manage_options', 'bdfg-map-locations', [$this, 'admin_page'], 'dashicons-location', 30 ); add_submenu_page( 'bdfg-map-locations', __('Settings', 'bdfg-map-locations'), __('Settings', 'bdfg-map-locations'), 'manage_options', 'bdfg-map-settings', [$this, 'settings_page'] ); add_submenu_page( 'bdfg-map-locations', __('Import/Export', 'bdfg-map-locations'), __('Import/Export', 'bdfg-map-locations'), 'manage_options', 'bdfg-map-import-export', [$this, 'import_export_page'] ); } /** * Enqueue admin scripts and styles */ public function admin_enqueue_scripts($hook) { if (!strpos($hook, 'bdfg-map')) { return; } // Admin styles wp_enqueue_style( 'bdfg-admin-style', BDFG_MAP_PLUGIN_URL . 'assets/css/admin.css', [], BDFG_MAP_VERSION ); // Google Maps with places library wp_enqueue_script( 'google-maps', 'https://maps.googleapis.com/maps/api/js?key=' . $this->get_api_key() . '&libraries=places', [], BDFG_MAP_VERSION, true ); // Admin scripts wp_enqueue_script( 'bdfg-admin-script', BDFG_MAP_PLUGIN_URL . 'assets/js/admin.js', ['jquery', 'google-maps'], BDFG_MAP_VERSION, true ); wp_localize_script('bdfg-admin-script', 'bdfgMapParams', [ 'ajaxUrl' => admin_url('admin-ajax.php'), 'nonce' => wp_create_nonce('bdfg_map_nonce'), 'strings' => [ 'confirmDelete' => __('Are you sure you want to delete this location?', 'bdfg-map-locations'), 'locationSaved' => __('Location saved successfully!', 'bdfg-map-locations'), 'locationDeleted' => __('Location deleted successfully!', 'bdfg-map-locations'), 'error' => __('An error occurred. Please try again.', 'bdfg-map-locations') ] ]); } /** * Get API key from settings */ private function get_api_key() { return $this->settings['api_key'] ?? ''; } /** * Get cached locations */ private function get_cached_locations() { $cached = wp_cache_get('bdfg_map_locations'); if (false === $cached) { $cached = get_option('bdfg_map_locations', []); wp_cache_set('bdfg_map_locations', $cached, '', BDFG_MAP_CACHE_TIME); } return $cached; } /** * Map shortcode handler */ public function map_shortcode($atts) { $atts = shortcode_atts([ 'height' => '400px', 'zoom' => $this->settings['default_zoom'], 'category' => '', 'clustering' => $this->settings['enable_clustering'] ], $atts); // Filter locations by category if specified $locations = $this->locations; if (!empty($atts['category'])) { $locations = array_filter($locations, function($location) use ($atts) { return isset($location['category']) && $location['category'] === $atts['category']; }); } // Add schema markup for SEO $schema_markup = ''; foreach ($locations as $location) { $schema_markup .= $this->add_location_schema($location); } ob_start(); include BDFG_MAP_PLUGIN_DIR . 'templates/map.php'; return ob_get_clean(); } // Add remaining methods here (ajax_save_location, ajax_delete_location, etc.) // ... } // Initialize the plugin function bdfg_map_locations_init() { BDFG_Map_Locations::get_instance(); } add_action('plugins_loaded', 'bdfg_map_locations_init'); // Activation hook register_activation_hook(__FILE__, 'bdfg_map_locations_activate'); function bdfg_map_locations_activate() { // Create necessary database tables and options if (!get_option('bdfg_map_locations')) { add_option('bdfg_map_locations', []); } if (!get_option('bdfg_map_settings')) { add_option('bdfg_map_settings', [ 'api_key' => '', 'default_zoom' => 12, 'default_lat' => 40.7128, 'default_lng' => -74.0060, 'enable_clustering' => true, 'analytics_enabled' => true ]); } // Clear any existing caches wp_cache_delete('bdfg_map_locations'); // Create custom capabilities $role = get_role('administrator'); $role->add_cap('manage_bdfg_locations'); } // Deactivation hook register_deactivation_hook(__FILE__, 'bdfg_map_locations_deactivate'); function bdfg_map_locations_deactivate() { // Clean up caches wp_cache_delete('bdfg_map_locations'); // Optional: Remove capabilities $role = get_role('administrator'); $role->remove_cap('manage_bdfg_locations'); }
includes/class-bdfg-locations-api.php
相关文章: WooCommerce 自定义”加入购物车”按钮
<?php /** * BDFG Map Locations API Handler * * @package BDFG_Map_Locations * @author beiduofengou <[email protected]> * @copyright 2025 beiduofengou.net */ if (!defined('ABSPATH')) { exit('Direct access denied.'); } class BDFG_Locations_API { /** * Register REST API routes */ public function register_routes() { register_rest_route('bdfg-map/v1', '/locations', [ [ 'methods' => WP_REST_Server::READABLE, 'callback' => [$this, 'get_locations'], 'permission_callback' => '__return_true', ], [ 'methods' => WP_REST_Server::CREATABLE, 'callback' => [$this, 'create_location'], 'permission_callback' => [$this, 'check_admin_permission'], ] ]); } /** * Check if user has admin permissions */ public function check_admin_permission() { return current_user_can('manage_options'); } /** * Get all locations */ public function get_locations($request) { $locations = get_option('bdfg_map_locations', []); if (empty($locations)) { return new WP_REST_Response([], 200); } return new WP_REST_Response($locations, 200); } /** * Create new location */ public function create_location($request) { $params = $request->get_params(); $location = [ 'id' => uniqid('bdfg_loc_'), 'name' => sanitize_text_field($params['name']), 'address' => sanitize_text_field($params['address']), 'lat' => (float) $params['lat'], 'lng' => (float) $params['lng'], 'description' => wp_kses_post($params['description']), 'category' => sanitize_text_field($params['category'] ?? ''), 'created_at' => current_time('mysql'), 'created_by' => get_current_user_id() ]; $locations = get_option('bdfg_map_locations', []); $locations[] = $location; update_option('bdfg_map_locations', $locations); wp_cache_delete('bdfg_map_locations'); return new WP_REST_Response($location, 201); } }
includes/class-bdfg-locations-importer.php
<?php /** * BDFG Map Locations Importer * * @package BDFG_Map_Locations * @author beiduofengou <[email protected]> * @copyright 2025 beiduofengou.net */ if (!defined('ABSPATH')) { exit('Direct access denied.'); } class BDFG_Locations_Importer { /** * Import locations from CSV file */ public function import_from_csv($file) { if (!current_user_can('manage_options')) { return new WP_Error('permission_denied', __('Permission denied', 'bdfg-map-locations')); } if (!file_exists($file)) { return new WP_Error('file_not_found', __('Import file not found', 'bdfg-map-locations')); } $csv = array_map('str_getcsv', file($file)); array_shift($csv); // Remove headers $locations = get_option('bdfg_map_locations', []); $imported = 0; foreach ($csv as $row) { if (count($row) < 4) continue; $locations[] = [ 'id' => uniqid('bdfg_loc_'), 'name' => sanitize_text_field($row[0]), 'address' => sanitize_text_field($row[1]), 'lat' => (float)$row[2], 'lng' => (float)$row[3], 'description' => wp_kses_post($row[4] ?? ''), 'category' => sanitize_text_field($row[5] ?? ''), 'created_at' => current_time('mysql'), 'created_by' => get_current_user_id() ]; $imported++; } update_option('bdfg_map_locations', $locations); wp_cache_delete('bdfg_map_locations'); return $imported; } }
assets/js/admin.js
相关文章: Woocommerce强大的购物车管理扩展
/** * BDFG Map Locations Admin JavaScript * * @package BDFG_Map_Locations * @author beiduofengou <[email protected]> */ (function($) { 'use strict'; const BDFGMapAdmin = { map: null, marker: null, geocoder: null, init: function() { this.initMap(); this.bindEvents(); this.initAutocomplete(); }, initMap: function() { const mapElement = document.getElementById('bdfg-admin-map'); if (!mapElement) return; this.map = new google.maps.Map(mapElement, { zoom: 12, center: { lat: 40.7128, lng: -74.0060 }, styles: this.getMapStyles() }); this.geocoder = new google.maps.Geocoder(); }, bindEvents: function() { $('#bdfg-location-form').on('submit', this.handleFormSubmit.bind(this)); $('.bdfg-delete-location').on('click', this.handleDelete.bind(this)); $('#bdfg-search-address').on('change', this.handleAddressSearch.bind(this)); }, initAutocomplete: function() { const input = document.getElementById('bdfg-search-address'); if (!input) return; const autocomplete = new google.maps.places.Autocomplete(input); autocomplete.addListener('place_changed', () => { const place = autocomplete.getPlace(); if (!place.geometry) return; this.updateMarker(place.geometry.location); this.map.setCenter(place.geometry.location); $('#bdfg-lat').val(place.geometry.location.lat()); $('#bdfg-lng').val(place.geometry.location.lng()); }); }, updateMarker: function(location) { if (this.marker) { this.marker.setMap(null); } this.marker = new google.maps.Marker({ map: this.map, position: location, draggable: true, animation: google.maps.Animation.DROP }); google.maps.event.addListener(this.marker, 'dragend', (event) => { $('#bdfg-lat').val(event.latLng.lat()); $('#bdfg-lng').val(event.latLng.lng()); }); }, handleFormSubmit: function(e) { e.preventDefault(); const form = $(e.target); $.ajax({ url: bdfgMapParams.ajaxUrl, type: 'POST', data: { action: 'bdfg_save_location', nonce: bdfgMapParams.nonce, ...form.serializeArray().reduce((obj, item) => { obj[item.name] = item.value; return obj; }, {}) }, success: (response) => { if (response.success) { alert(bdfgMapParams.strings.locationSaved); location.reload(); } else { alert(bdfgMapParams.strings.error); } }, error: () => alert(bdfgMapParams.strings.error) }); }, handleDelete: function(e) { e.preventDefault(); if (!confirm(bdfgMapParams.strings.confirmDelete)) return; const btn = $(e.target); $.ajax({ url: bdfgMapParams.ajaxUrl, type: 'POST', data: { action: 'bdfg_delete_location', nonce: bdfgMapParams.nonce, location_id: btn.data('id') }, success: (response) => { if (response.success) { btn.closest('tr').fadeOut(); } else { alert(bdfgMapParams.strings.error); } }, error: () => alert(bdfgMapParams.strings.error) }); }, getMapStyles: function() { return [ { "featureType": "administrative", "elementType": "geometry", "stylers": [{"visibility": "simplified"}] }, { "featureType": "poi", "stylers": [{"visibility": "simplified"}] } // Add more custom styles as needed ]; } }; $(document).ready(() => BDFGMapAdmin.init()); })(jQuery);
assets/js/frontend.js
/** * BDFG Map Locations Frontend JavaScript * * @package BDFG_Map_Locations * @author beiduofengou <[email protected]> */ (function($) { 'use strict'; const BDFGMapFrontend = { map: null, markers: [], infoWindow: null, markerCluster: null, init: function() { $('.bdfg-map-container').each((i, element) => { this.initMap(element); }); }, initMap: function(element) { const mapOptions = { zoom: parseInt($(element).data('zoom')) || 12, styles: this.getMapStyles(), mapTypeControl: true, streetViewControl: true, fullscreenControl: true }; this.map = new google.maps.Map(element, mapOptions); this.infoWindow = new google.maps.InfoWindow(); this.loadLocations(); }, loadLocations: function() { $.ajax({ url: bdfgMapParams.ajaxUrl, data: { action: 'bdfg_get_locations', nonce: bdfgMapParams.nonce }, success: (response) => { if (response.success && response.data) { this.addMarkers(response.data); } } }); }, addMarkers: function(locations) { const bounds = new google.maps.LatLngBounds(); locations.forEach(location => { const position = new google.maps.LatLng(location.lat, location.lng); const marker = new google.maps.Marker({ position: position, map: this.map, title: location.name, animation: google.maps.Animation.DROP }); bounds.extend(position); this.markers.push(marker); marker.addListener('click', () => { this.showInfoWindow(marker, location); }); }); if (locations.length > 1) { this.map.fitBounds(bounds); } else if (locations.length === 1) { this.map.setCenter(bounds.getCenter()); this.map.setZoom(15); } if (bdfgMapParams.enableClustering) { this.initMarkerClusterer(); } }, showInfoWindow: function(marker, location) { const content = ` <div class="bdfg-info-window"> <h3>${location.name}</h3> <p>${location.address}</p> ${location.description ? `<p>${location.description}</p>` : ''} <p> <a href="https://www.google.com/maps/dir/?api=1&destination=${location.lat},${location.lng}" target="_blank" rel="noopener noreferrer"> ${bdfgMapParams.strings.getDirections} </a> </p> </div> `; this.infoWindow.setContent(content); this.infoWindow.open(this.map, marker); }, initMarkerClusterer: function() { if (typeof MarkerClusterer !== 'undefined') { this.markerCluster = new MarkerClusterer(this.map, this.markers, { imagePath: bdfgMapParams.clusterImagePath }); } }, getMapStyles: function() { return [ { "featureType": "administrative", "elementType": "geometry", "stylers": [{"visibility": "simplified"}] }, { "featureType": "poi", "stylers": [{"visibility": "simplified"}] } // Add more custom styles as needed ]; } }; $(document).ready(() => BDFGMapFrontend.init()); })(jQuery);
assets/css/admin.css
相关文章: WooCommerce 快速下单插件
/** * BDFG Map Locations Admin Styles * * @package BDFG_Map_Locations * @author beiduofengou <[email protected]> */ .bdfg-admin-wrap { margin: 20px; max-width: 1200px; } .bdfg-admin-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 20px; padding-bottom: 10px; border-bottom: 1px solid #ccd0d4; } .bdfg-admin-title { margin: 0; padding: 0; font-size: 23px; font-weight: 400; color: #1d2327; } #bdfg-admin-map { width: 100%; height: 400px; margin-bottom: 20px; border: 1px solid #ccd0d4; border-radius: 4px; } .bdfg-form-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); gap: 20px; margin-bottom: 20px; } .bdfg-form-group { margin-bottom: 15px; } .bdfg-form-group label { display: block; margin-bottom: 5px; font-weight: 600; } .bdfg-form-group input[type="text"], .bdfg-form-group textarea { width: 100%; padding: 8px; border: 1px solid #8c8f94; border-radius: 4px; } .bdfg-locations-table { width: 100%; border-collapse: collapse; margin-top: 20px; background: #fff; box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1); } .bdfg-locations-table th { text-align: left; padding: 12px; border-bottom: 2px solid #0073aa; color: #1d2327; font-weight: 600; } .bdfg-locations-table td { padding: 12px; border-bottom: 1px solid #f0f0f1; vertical-align: middle; } .bdfg-locations-table tr:hover { background-color: #f6f7f7; } .bdfg-action-buttons { display: flex; gap: 10px; } .bdfg-button { display: inline-block; padding: 8px 12px; border-radius: 4px; cursor: pointer; text-decoration: none; border: 1px solid transparent; transition: all 0.2s ease; } .bdfg-button-primary { background: #0073aa; color: #fff; border-color: #006291; } .bdfg-button-primary:hover { background: #006291; } .bdfg-button-danger { background: #dc3232; color: #fff; border-color: #cc2929; } .bdfg-button-danger:hover { background: #cc2929; } .bdfg-settings-form { max-width: 600px; background: #fff; padding: 20px; border-radius: 4px; box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1); } .bdfg-api-key-field { position: relative; } .bdfg-api-key-toggle { position: absolute; right: 10px; top: 50%; transform: translateY(-50%); cursor: pointer; color: #0073aa; } .bdfg-import-export { display: grid; grid-template-columns: 1fr 1fr; gap: 30px; margin-top: 20px; }
assets/css/frontend.css
/** * BDFG Map Locations Frontend Styles * * @package BDFG_Map_Locations * @author beiduofengou <[email protected]> */ .bdfg-map-container { width: 100%; height: 500px; margin-bottom: 30px; border-radius: 8px; overflow: hidden; box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); } .bdfg-info-window { padding: 5px; max-width: 300px; } .bdfg-info-window h3 { margin: 0 0 10px; font-size: 16px; color: #333; } .bdfg-info-window p { margin: 0 0 8px; font-size: 14px; color: #666; } .bdfg-info-window a { color: #0073aa; text-decoration: none; font-weight: 500; } .bdfg-info-window a:hover { text-decoration: underline; } .bdfg-location-list { display: grid; grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); gap: 20px; margin: 20px 0; } .bdfg-location-card { background: #fff; border-radius: 8px; padding: 15px; box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); transition: transform 0.2s ease; } .bdfg-location-card:hover { transform: translateY(-2px); } .bdfg-location-card h3 { margin: 0 0 10px; color: #333; } .bdfg-location-card p { margin: 0 0 8px; color: #666; font-size: 14px; } .bdfg-directions-button { display: inline-block; padding: 8px 16px; background: #0073aa; color: #fff; text-decoration: none; border-radius: 4px; font-size: 14px; transition: background 0.2s ease; } .bdfg-directions-button:hover { background: #006291; text-decoration: none; color: #fff; }
templates/admin.php
<?php /** * Admin page template for BDFG Map Locations * * @package BDFG_Map_Locations * @author beiduofengou <[email protected]> */ if (!defined('ABSPATH')) { exit('Direct access denied.'); } ?> <div class="wrap bdfg-admin-wrap"> <div class="bdfg-admin-header"> <h1 class="bdfg-admin-title"> <?php _e('BDFG Map Locations', 'bdfg-map-locations'); ?> </h1> <a href="<?php echo admin_url('admin.php?page=bdfg-map-settings'); ?>" class="bdfg-button bdfg-button-primary"> <?php _e('Settings', 'bdfg-map-locations'); ?> </a> </div> <div class="bdfg-admin-content"> <div id="bdfg-admin-map"></div> <form id="bdfg-location-form" method="post"> <?php wp_nonce_field('bdfg_map_nonce'); ?> <div class="bdfg-form-grid"> <div class="bdfg-form-group"> <label for="bdfg-name"><?php _e('Location Name', 'bdfg-map-locations'); ?></label> <input type="text" id="bdfg-name" name="name" required> </div> <div class="bdfg-form-group"> <label for="bdfg-search-address"><?php _e('Search Address', 'bdfg-map-locations'); ?></label> <input type="text" id="bdfg-search-address" name="address" required> </div> <div class="bdfg-form-group"> <label for="bdfg-category"><?php _e('Category', 'bdfg-map-locations'); ?></label> <select id="bdfg-category" name="category"> <option value=""><?php _e('Select Category', 'bdfg-map-locations'); ?></option> <?php $categories = get_terms([ 'taxonomy' => 'bdfg_location_category', 'hide_empty' => false, ]); foreach ($categories as $category) { echo sprintf( '<option value="%s">%s</option>', esc_attr($category->slug), esc_html($category->name) ); } ?> </select> </div> </div> <div class="bdfg-form-group"> <label for="bdfg-description"><?php _e('Description', 'bdfg-map-locations'); ?></label> <textarea id="bdfg-description" name="description" rows="4"></textarea> </div> <input type="hidden" id="bdfg-lat" name="lat" required> <input type="hidden" id="bdfg-lng" name="lng" required> <button type="submit" class="bdfg-button bdfg-button-primary"> <?php _e('Add Location', 'bdfg-map-locations'); ?> </button> </form> <table class="bdfg-locations-table"> <thead> <tr> <th><?php _e('Name', 'bdfg-map-locations'); ?></th> <th><?php _e('Address', 'bdfg-map-locations'); ?></th> <th><?php _e('Category', 'bdfg-map-locations'); ?></th> <th><?php _e('Actions', 'bdfg-map-locations'); ?></th> </tr> </thead> <tbody> <?php foreach ($this->locations as $location): ?> <tr> <td><?php echo esc_html($location['name']); ?></td> <td><?php echo esc_html($location['address']); ?></td> <td><?php echo esc_html($location['category'] ?? ''); ?></td> <td class="bdfg-action-buttons"> <button class="bdfg-button bdfg-button-danger bdfg-delete-location" data-id="<?php echo esc_attr($location['id']); ?>"> <?php _e('Delete', 'bdfg-map-locations'); ?> </button> </td> </tr> <?php endforeach; ?> </tbody> </table> </div> </div>
templates/settings.php
<?php /** * Settings page template for BDFG Map Locations * * @package BDFG_Map_Locations * @author beiduofengou <[email protected]> */ if (!defined('ABSPATH')) { exit('Direct access denied.'); } $settings = get_option('bdfg_map_settings', []); ?> <div class="wrap bdfg-admin-wrap"> <h1 class="bdfg-admin-title"><?php _e('BDFG Map Settings', 'bdfg-map-locations'); ?></h1> <form method="post" action="options.php" class="bdfg-settings-form"> <?php settings_fields('bdfg_map_settings'); ?> <div class="bdfg-form-group"> <label for="bdfg_map_api_key"> <?php _e('Google Maps API Key', 'bdfg-map-locations'); ?> </label> <div class="bdfg-api-key-field"> <input type="password" id="bdfg_map_api_key" name="bdfg_map_settings[api_key]" value="<?php echo esc_attr($settings['api_key'] ?? ''); ?>" class="regular-text"> <span class="bdfg-api-key-toggle dashicons dashicons-visibility"></span> </div> <p class="description"> <?php _e('Enter your Google Maps API key. Get one from the Google Cloud Console.', 'bdfg-map-locations'); ?> </p> </div> <div class="bdfg-form-group"> <label for="bdfg_map_default_zoom"> <?php _e('Default Zoom Level', 'bdfg-map-locations'); ?> </label> <input type="number" id="bdfg_map_default_zoom" name="bdfg_map_settings[default_zoom]" value="<?php echo intval($settings['default_zoom'] ?? 12); ?>" min="1" max="20" class="small-text"> </div> <div class="bdfg-form-group"> <label> <input type="checkbox" name="bdfg_map_settings[enable_clustering]" value="1" <?php checked(($settings['enable_clustering'] ?? false), true); ?>> <?php _e('Enable Marker Clustering', 'bdfg-map-locations'); ?> </label> </div> <div class="bdfg-form-group"> <label> <input type="checkbox" name="bdfg_map_settings[analytics_enabled]" value="1" <?php checked(($settings['analytics_enabled'] ?? false), true); ?>> <?php _e('Enable Analytics', 'bdfg-map-locations'); ?> </label> </div> <?php submit_button(); ?> </form> </div>
templates/map.php
<?php /** * Frontend map template for BDFG Map Locations * * @package BDFG_Map_Locations * @author beiduofengou <[email protected]> */ if (!defined('ABSPATH')) { exit('Direct access denied.'); } ?> <div class="bdfg-map-container" id="bdfg-map-<?php echo esc_attr(uniqid()); ?>" data-zoom="<?php echo esc_attr($atts['zoom']); ?>" style="height: <?php echo esc_attr($atts['height']); ?>;"> </div> <?php echo $schema_markup; // Schema markup for SEO ?> <?php if (!empty($atts['show_list'])): ?> <div class="bdfg-location-list"> <?php foreach ($locations as $location): ?> <div class="bdfg-location-card"> <h3><?php echo esc_html($location['name']); ?></h3> <p><?php echo esc_html($location['address']); ?></p> <?php if (!empty($location['description'])): ?> <p><?php echo wp_kses_post($location['description']); ?></p> <?php endif; ?> <a href="https://www.google.com/maps/dir/?api=1&destination=<?php echo esc_attr($location['lat']); ?>,<?php echo esc_attr($location['lng']); ?>" class="bdfg-directions-button" target="_blank" rel="noopener noreferrer"> <?php _e('Get Directions', 'bdfg-map-locations'); ?> </a> </div> <?php endforeach; ?> </div> <?php endif; ?>