From a9654f00c8fbc9934289d761843ddd071025013f Mon Sep 17 00:00:00 2001
From: Jake Vanderwerf <get@jakevanderwerf.ca>
Date: Fri, 28 Aug 2026 17:20:28 +0000
Subject: [PATCH] =PHPStorm Code Inspection: fixed class reference errors (from getting rid of JVB() and replacing with direct class::getInstance; as well as general code sniffing, etc

---
 inc/integrations/services/GoogleMaps.php |  985 +++++++++++++++------------------------------------------
 1 files changed, 264 insertions(+), 721 deletions(-)

diff --git a/inc/integrations/services/GoogleMaps.php b/inc/integrations/services/GoogleMaps.php
index 6477a0d..adfa358 100644
--- a/inc/integrations/services/GoogleMaps.php
+++ b/inc/integrations/services/GoogleMaps.php
@@ -5,8 +5,10 @@
  */
 
 namespace JVBase\integrations\services;
+use JVBase\integrations\Admin;
+use JVBase\Instance;
 use JVBase\integrations\Integrations;
-use JVBase\registrar\Registrar;
+use JVBase\integrations\Requests;
 
 if (!defined('ABSPATH')) {
 	exit;
@@ -14,468 +16,101 @@
 
 class GoogleMaps extends Integrations
 {
-	private string $public_key;
-	private string $private_key;
-	private string $map_id;
-	private array $enabled_apis = [];
-
-	// Edmonton default coordinates
-	private const DEFAULT_LAT = 53.5461;
-	private const DEFAULT_LNG = -113.4938;
-	private const DEFAULT_ZOOM = 11; // City-wide view
-	private const DEFAULT_MAP_ID = '873aed4ca260b4203e45b6e3';
-
-	protected static self $instance;
-	public static function getInstance():self
-	{
-
-		if (!isset(self::$instance)) {
-			self::$instance = new self();
-		}
-		return self::$instance;
-	}
-
+	use Admin, Instance, Requests;
 	protected function __construct()
 	{
 		$this->service_name = 'maps';
 		$this->title = 'Google Maps';
 		$this->icon = 'map-pin';
+
 		$this->apiBase = 'https://maps.googleapis.com/maps/api/';
-		$this->apiEndpoints = [
-			'geocode/json',
-			'place/details/json',
-			'place/nearbysearch/json',
-			'distancematrix/json',
-			'js'
-		];
+		$this->defineFields();
+		$this->defineInstructions();
+		$this->defineActions();
 
-		$this->fields = [
-			'public_key' => [
-				'type'	=> 'text',
-				'subtype' => 'password',
-				'label'	=> 'Maps Platform API Key (Referrer-Restricted)',
-				'hint'	=> 'Restrict this key by <b>HTTP referrers</b> for security. Used for displaying maps in browsers.',
-				'required'	=> true,
-			],
-			'private_key' => [
-				'type'	=> 'text',
-				'subtype'	=> 'password',
-				'label'	=> 'Geocoding & Places API Key (IP-Restricted)',
-				'hint'	=> 'Restrict this key by <br>IP Addresses</b>. Used for geocoding and server-side operations.',
-				'required'	=> true,
-			]
-		];
-		$this->advanced = [
-			'map_id'	=> [
-				'type'	=> 'text',
-				'label'	=> 'Map ID',
-				'hint'	=> 'Required for custom styling. Create a Map ID in <a href="https://console.cloud.google.com/google/maps-apis/studio/maps" target="_blank">Google Cloud Console → Maps → Map Management</a>'
-			],
-			'default_zoom'	=> [
-				'type'	=> 'text',
-				'subtype'	=> 'number',
-				'min'	=> 1,
-				'max'	=> 20,
-				'label'	=> 'Default Zoom',
-				'default'	=> 11
-			],
-		];
-		$this->instructions = [
-			'Create two API keys in <a href="https://console.cloud.google.com/apis/credentials" target="_blank">Google Cloud Console</a>',
-			'Enable <strong>Geocoding API + Places API</strong> for frontend key, restricted by your server IP address',
-			'Enable <strong>Maps Platform API</strong> for server key, restricted by your website domain',
-		];
-		$this->defaults = [
-
-		];
 		parent::__construct();
-
-		$this->actions = array_merge(
-			$this->actions,
-			[
-				'reverse_geocode' => 'processReverseGeocode',
-				'geocode' => 'processGeocode'
-			]
-		);
 		// Auto-enqueue maps script when needed
 		add_action('wp_enqueue_scripts', [$this, 'maybeEnqueueMapsScript']);
-//		add_action('admin_enqueue_scripts', [$this, 'maybeEnqueueMapsScript']);
 	}
+		protected function defineFields():void
+		{
+			$pub = $this->addField('public_key', 'Maps Platform API Key', 'text', 'manage_options');
+				$pub->setHint('Restrict this key by HTTP referrers for security. Used for displaying maps in browsers.');
+				$pub->setSubType('password');
+				$pub->setRequired();
 
+			$priv = $this->addField('private_key', 'Geocoding & Places API Key', 'text', 'manage_options');
+				$priv->setHint('Restrict this key by IP Addresses. Used for geocoding and server-side operations.');
+				$priv->setRequired();
+				$priv->setSubType('password');
+
+			$map_id = $this->addField('map_id', 'Map ID', 'text', 'manage_options');
+				$map_id->setHint('Required for custom styling. Create a Map ID in Google Cloud Console -> Maps -> Map Management.');
+
+			$zoom = $this->addField('default_zoom', 'Default Zoom', 'text', 'manage_options');
+				$zoom->setSubType('number');
+				$zoom->setDefault(11);
+				$zoom->setMin(1);
+				$zoom->setMax(20);
+
+			$lng = $this->addField('default_lng', 'Default Longitude', 'text', 'manage_options');
+				$lng->setSubType('number');
+				$lng->setDefault(-113.4938);
+
+			$lat = $this->addField('default_lat', 'Default Latitude', 'text', 'manage_options');
+				$lng->setSubType('number');
+				$lng->setDefault(53.5461);
+		}
+
+		protected function defineInstructions():void
+		{
+			$this->instructions = [
+				'Create two API keys in <a href="https://console.cloud.google.com/apis/credentials" target="_blank">Google Cloud Console</a>',
+				'Enable <strong>Geocoding API + Places API</strong> for frontend key, restricted by your server IP address',
+				'Enable <strong>Maps Platform API</strong> for server key, restricted by your website domain',
+			];
+		}
+
+		protected function defineActions():void
+		{
+			$this->addAction(
+				'reverse_geocode',
+				[$this, 'processReverseGeocode']
+			);
+
+			$this->addAction(
+				'geocode',
+				[$this, 'processGeocode']
+			);
+		}
+			public function processReverseGeocode(array $data):array
+			{
+				if (!array_key_exists('lat', $data) || !array_key_exists('lng', $data)) {
+					return $this->response(false, 'Invalid coordinates provided', $data);
+				}
+				$lat = floatval($data['lat']);
+				$lng = floatval($data['lng']);
+
+				$result = $this->reverseGeocode($lat, $lng);
+				if ($result) {
+					return $this->response(true, 'Successfully reversed Geocode', ['data'=> $result]);
+				}
+				return $this->response(false, 'Reverse geocoding failed');
+			}
+
+			public function processGeocode(array $data):array
+			{
+				if (!array_key_exists('address', $data)) {
+					return $this->response(false, 'No address provided');
+				}
+				$result = $this->geocodeAddress(sanitize_text_field($data['address']));
+				if ($result) {
+					return $this->response(true, 'Successfully geocoded address', ['data' => $result]);
+				}
+				return $this->response(false, 'Geocoding failed');
+			}
 	protected function initialize(): void
 	{
-		$this->private_key = $this->credentials['private_key'] ?? '';
-		$this->public_key = $this->credentials['public_key'] ?? '';
-		$this->map_id = $this->credentials['map_id'] ?? self::DEFAULT_MAP_ID;
-		$this->rate_limits = ['min_interval' => 0]; // Google Maps has generous limits
-	}
-
-	/**
-	 * Get service description
-	 */
-	public function getServiceDescription(): string
-	{
-		return "Enable location features and embedded maps throughout your site.";
-	}
-
-	/**
-	 * Get request headers (required by base class)
-	 */
-	protected function getRequestHeaders(): array
-	{
-		// Google Maps API uses API key in URL params, not headers
-		return [
-			'Accept' => 'application/json',
-			'Content-Type' => 'application/json'
-		];
-	}
-
-
-	/**
-	 * Process test connection request
-	 */
-	protected function performConnectionTest(): bool
-	{
-		if (!$this->isSetUp()) {
-			return false;
-		}
-
-		// Test with a simple geocoding request
-		$test_address = 'Edmonton, Alberta, Canada';
-		$result = $this->geocodeAddress($test_address);
-
-		return $result !== null;
-	}
-
-	/**
-	 * Process reverse geocode request
-	 */
-	private function processReverseGeocode(array $data): WP_Error|array
-	{
-		$lat = floatval($data['lat'] ?? 0);
-		$lng = floatval($data['lng'] ?? 0);
-
-		if (!$lat || !$lng) {
-			return new WP_Error('invalid_coordinates', 'Invalid coordinates provided');
-		}
-
-		$result = $this->reverseGeocode($lat, $lng);
-
-		if ($result) {
-			return ['success' => true, 'data' => $result];
-		}
-
-		return new WP_Error('geocoding_failed', 'Reverse geocoding failed');
-	}
-
-	/**
-	 * Process geocode request
-	 */
-	private function processGeocode(array $data): WP_Error|array
-	{
-		$address = sanitize_text_field($data['address'] ?? '');
-
-		if (empty($address)) {
-			return new WP_Error('invalid_address', 'No address provided');
-		}
-
-		$result = $this->geocodeAddress($address);
-
-		if ($result) {
-			return ['success' => true, 'data' => $result];
-		}
-
-		return new WP_Error('geocoding_failed', 'Geocoding failed');
-	}
-
-	/**
-	 * Geocode an address to coordinates
-	 */
-	public function geocodeAddress(string $address): ?array
-	{
-		if (!$this->isSetUp()) {
-			return null;
-		}
-
-		$params = [
-			'address' => $address,
-			'key' => $this->private_key
-		];
-
-		$key = $this->cache->generateKey(['geocode', $address]);
-		$cached = $this->cache->get($key);
-		if ($cached) {
-			return $cached;
-		}
-
-		$url = $this->apiBase . 'geocode/json?' . http_build_query($params);
-		$response = wp_remote_get($url);
-
-		if (is_wp_error($response)) {
-			$this->logError('Geocoding request failed', [
-				'error' => $response->get_error_message(),
-				'address' => $address
-			]);
-			return null;
-		}
-
-		$data = json_decode(wp_remote_retrieve_body($response), true);
-
-		if ($data['status'] === 'OK' && !empty($data['results'])) {
-			$result = $data['results'][0];
-			$result = [
-				'lat' => $result['geometry']['location']['lat'],
-				'lng' => $result['geometry']['location']['lng'],
-				'formatted_address' => $result['formatted_address'],
-				'place_id' => $result['place_id'] ?? '',
-				'components' => $this->parseAddressComponents($result['address_components'] ?? [])
-			];
-			$this->cache->set($key, $result);
-		} else {
-			$this->logError('Google Maps API error', [
-				'status' => $data['status'] ?? 'unknown',
-				'address' => $address
-			], 'warning');
-			$result = null;
-		}
-
-		return $result;
-	}
-
-	/**
-	 * Reverse geocode coordinates to address
-	 */
-	public function reverseGeocode(float $lat, float $lng): ?array
-	{
-		if (!$this->isSetUp()) {
-			return null;
-		}
-
-		$params = [
-			'latlng' => "{$lat},{$lng}",
-			'key' => $this->private_key
-		];
-
-		$key = $this->cache->generateKey(['reverse', $lat, $lng]);
-		$cached = $this->cache->get($key);
-		if ($cached) {
-			return $cached;
-		}
-
-		$url = $this->apiBase . 'geocode/json?' . http_build_query($params);
-		$response = wp_remote_get($url);
-
-		if (is_wp_error($response)) {
-			$this->logError('Reverse geocoding request failed', [
-				'error' => $response->get_error_message(),
-				'lat' => $lat,
-				'lng' => $lng
-			]);
-			return null;
-		}
-
-		$data = json_decode(wp_remote_retrieve_body($response), true);
-
-		if ($data['status'] === 'OK' && !empty($data['results'])) {
-			$result = $data['results'][0];
-			$return = [
-				'formatted_address' => $result['formatted_address'],
-				'place_id' => $result['place_id'] ?? '',
-				'components' => $this->parseAddressComponents($result['address_components'] ?? [])
-			];
-			$this->cache->set($key, $return);
-			return $return;
-		}
-
-		return null;
-	}
-
-	/**
-	 * Get place details by place ID
-	 */
-	public function getPlaceDetails(string $place_id, array $fields = []): ?array
-	{
-		if (!$this->isSetUp()) {
-			return null;
-		}
-
-		$default_fields = ['name', 'formatted_address', 'geometry', 'rating', 'formatted_phone_number'];
-		$fields = empty($fields) ? $default_fields : $fields;
-
-		$key = $this->cache->generateKey(['place', $place_id, $fields]);
-		$cached = $this->cache->get($key);
-		if ($cached) {
-			return $cached;
-		}
-
-		$params = [
-			'place_id' => $place_id,
-			'fields' => implode(',', $fields),
-			'key' => $this->private_key
-		];
-
-		$url = $this->apiBase . 'place/details/json?' . http_build_query($params);
-		$response = wp_remote_get($url);
-
-		if (is_wp_error($response)) {
-			$this->logError('Place details request failed', [
-				'error' => $response->get_error_message(),
-				'place_id' => $place_id
-			]);
-			return null;
-		}
-
-		$data = json_decode(wp_remote_retrieve_body($response), true);
-
-		if ($data['status'] === 'OK' && !empty($data['result'])) {
-			$result = $data['result'];
-			$this->cache->set($key, $result);
-			return $result;
-		}
-
-		return null;
-	}
-
-	/**
-	 * Search for places nearby
-	 */
-	public function searchNearby(float $lat, float $lng, int $radius = 1000, string $type = ''): array
-	{
-		if (!$this->isSetUp()) {
-			return [];
-		}
-
-		$params = [
-			'location' => "{$lat},{$lng}",
-			'radius' => $radius,
-			'key' => $this->private_key
-		];
-
-		if (!empty($type)) {
-			$params['type'] = $type;
-		}
-
-		$key = $this->cache->generateKey(['nearby', $lat, $lng, $radius, $type]);
-		$cached = $this->cache->get($key);
-		if ($cached) {
-			return $cached;
-		}
-
-		$url = $this->apiBase . 'place/nearbysearch/json?' . http_build_query($params);
-		$response = wp_remote_get($url);
-
-		if (is_wp_error($response)) {
-			$this->logError('Nearby search request failed', [
-				'error' => $response->get_error_message(),
-				'lat' => $lat,
-				'lng' => $lng,
-				'radius' => $radius
-			]);
-			return [];
-		}
-
-		$data = json_decode(wp_remote_retrieve_body($response), true);
-
-		if ($data['status'] === 'OK' && !empty($data['results'])) {
-			$return = $data['results'];
-			$this->cache->set($key, $return);
-			return $return;
-		}
-
-		return [];
-	}
-
-	/**
-	 * Calculate distance between two points
-	 */
-	public function calculateDistance(array $origin, array $destination, string $mode = 'driving'): ?array
-	{
-		if (!$this->isSetUp()) {
-			return null;
-		}
-
-		// Handle different input formats
-		$origin_str = is_array($origin) ? "{$origin['lat']},{$origin['lng']}" : $origin;
-		$dest_str = is_array($destination) ? "{$destination['lat']},{$destination['lng']}" : $destination;
-
-		$params = [
-			'origins' => $origin_str,
-			'destinations' => $dest_str,
-			'mode' => $mode,
-			'units' => 'metric',
-			'key' => $this->private_key
-		];
-
-		$key = $this->cache->generateKey(['distance', $origin_str, $dest_str, $mode]);
-		$cached = $this->cache->get($key);
-		if ($cached) {
-			return $cached;
-		}
-
-		$url = $this->apiBase . 'distancematrix/json?' . http_build_query($params);
-		$response = wp_remote_get($url);
-
-		if (is_wp_error($response)) {
-			$this->logError('Distance calculation request failed', [
-				'error' => $response->get_error_message(),
-				'origin' => $origin_str,
-				'destination' => $dest_str
-			]);
-			return null;
-		}
-
-		$data = json_decode(wp_remote_retrieve_body($response), true);
-
-		if ($data['status'] === 'OK' && !empty($data['rows'][0]['elements'][0])) {
-			$element = $data['rows'][0]['elements'][0];
-			if ($element['status'] === 'OK') {
-				$return = [
-					'distance' => $element['distance'],
-					'duration' => $element['duration'],
-					'mode' => $mode
-				];
-				$this->cache->set($key, $return);
-				return $return;
-			}
-		}
-
-		return null;
-	}
-
-	/**
-	 * Get the JavaScript API URL with key
-	 */
-	public function getJavaScriptApiUrl(array $libraries = ['places', 'marker', 'geometry']): string
-	{
-		if (empty($this->public_key)) {
-			return '';
-		}
-
-		$params = [
-			'key' => $this->public_key,
-			'libraries' => implode(',', $libraries),
-			'callback' => 'initGoogleMaps',
-		];
-
-		return $this->apiBase . 'js?' . http_build_query($params);
-	}
-
-	/**
-	 * Enqueue Google Maps script when needed
-	 */
-	public function maybeEnqueueMapsScript(): void
-	{
-		// Only enqueue if we're on a page that needs maps
-		if (!$this->shouldEnqueueMaps()) {
-			return;
-		}
-
-		if (!$this->isSetUp()) {
-			return;
-		}
-
-		$this->ensureInitialized();
-
 		// Register Google Maps API
 		wp_register_script(
 			'google-maps-api',
@@ -499,36 +134,69 @@
 				'strategy' => 'defer'
 			]
 		);
+	}
+		public function getJavaScriptApiUrl(array $libraries = ['places', 'marker', 'geometry']): string
+		{
+			if (empty($this->getPublicKey())) {
+				return '';
+			}
+
+			$params = [
+				'key' => $this->getPublicKey(),
+				'libraries' => implode(',', $libraries),
+				'callback' => 'initGoogleMaps',
+			];
+
+			return $this->apiBase . 'js?' . http_build_query($params);
+		}
+
+
+	public function maybeEnqueueMapsScript():void
+	{
+		if (!$this->isSetUp()) {
+			return;
+		}
+		if (!$this->shouldEnqueueMaps()) {
+			return;
+		}
 
 		// Add initialization script
-		wp_add_inline_script('google-maps-api', '
-		// Set map defaults
-		window.jvbMapDefaults = {
-			lat: ' . self::DEFAULT_LAT . ',
-			lng: ' . self::DEFAULT_LNG . ',
-			zoom: ' . self::DEFAULT_ZOOM . ',
-			mapId: "' . esc_js($this->map_id) . '"
-		};
+		wp_add_inline_script('google-maps-api',
+			sprintf(
+			'
+				// Set map defaults
+				window.jvbMapDefaults = {
+					lat: %s,
+					lng: %s,
+					zoom: %s,
+					mapId: "%s"
+				};
 
-		// Google Maps initialization callback
-		window.initGoogleMaps = function() {
-			// Dispatch ready event
-			document.dispatchEvent(new Event("googleMapsReady"));
+				// Google Maps initialization callback
+				window.initGoogleMaps = function() {
+					// Dispatch ready event
+					document.dispatchEvent(new Event("googleMapsReady"));
 
-			// Call any registered callbacks
-			if (window.googleMapsCallbacks && Array.isArray(window.googleMapsCallbacks)) {
-				window.googleMapsCallbacks.forEach(function(callback) {
-					if (typeof callback === "function") {
-						callback();
+					// Call any registered callbacks
+					if (window.googleMapsCallbacks && Array.isArray(window.googleMapsCallbacks)) {
+						window.googleMapsCallbacks.forEach(function(callback) {
+							if (typeof callback === "function") {
+								callback();
+							}
+						});
+						window.googleMapsCallbacks = [];
 					}
-				});
-				window.googleMapsCallbacks = [];
-			}
-		};
+				};
 
-		// Initialize callback queue
-		window.googleMapsCallbacks = window.googleMapsCallbacks || [];
-		', 'before');
+				// Initialize callback queue
+				window.googleMapsCallbacks = window.googleMapsCallbacks || [];
+				',
+				$this->getDefaultLat(),
+				$this->getDefaultLng(),
+				$this->getDefaultZoom(),
+				esc_js($this->getMapID())
+			),
+			'before');
 
 		// Enqueue scripts
 		wp_enqueue_script('google-maps-api');
@@ -541,134 +209,53 @@
 			'service' => $this->service_name
 		]);
 	}
-
-	/**
-	 * Check if maps should be enqueued on current page
-	 */
-	private function shouldEnqueueMaps(): bool
-	{
-		// Check for shortcodes
-		if (is_singular() && get_post_meta(get_the_ID(), BASE . 'has_map', true) === true) {
-			return true;
-		}
-
-		if (!empty(Registrar::withFeature('is_content', 'term')) && get_term_meta(get_queried_object_id(), BASE . 'has_map', true) === true) {
-			return true;
-		}
-
-		// Check for specific page templates or post types
-		if (is_singular(['shop', 'artist', 'location'])) {
-			return true;
-		}
-
-		// Check for admin pages that need maps
-		if (is_admin()) {
-			$screen = get_current_screen();
-			if ($screen && in_array($screen->post_type, ['shop', 'artist', 'location'])) {
+		protected function shouldEnqueueMaps():bool
+		{
+			//See if it's a singular post/page that has the map feature flagged
+			if (is_singular() && get_post_meta(get_the_ID(), BASE.'has_map', true) === true) {
 				return true;
 			}
+			if (is_tax() && get_term_meta(get_queried_object_id(), BASE . 'has_map', true) === true) {
+				return true;
+			}
+
+			// Allow filtering
+			return apply_filters('jvb_should_enqueue_maps', false);
 		}
 
-		// Allow filtering
-		return apply_filters('jvb_should_enqueue_maps', false);
-	}
-
-	/**
-	 * Parse address components from Google response
-	 */
-	private function parseAddressComponents(array $components): array
+	public function getServiceDescription():string
 	{
-		$parsed = [
-			'street_number' => '',
-			'street' => '',
-			'city' => '',
-			'province' => '',
-			'country' => '',
-			'postal_code' => ''
-		];
-
-		foreach ($components as $component) {
-			$types = $component['types'];
-
-			if (in_array('street_number', $types)) {
-				$parsed['street_number'] = $component['long_name'];
-			}
-			if (in_array('route', $types)) {
-				$parsed['street'] = $component['long_name'];
-			}
-			if (in_array('locality', $types)) {
-				$parsed['city'] = $component['long_name'];
-			}
-			if (in_array('administrative_area_level_1', $types)) {
-				$parsed['province'] = $component['short_name'];
-			}
-			if (in_array('country', $types)) {
-				$parsed['country'] = $component['short_name'];
-			}
-			if (in_array('postal_code', $types)) {
-				$parsed['postal_code'] = $component['long_name'];
-			}
-		}
-
-		// Combine street number and street name
-		if ($parsed['street_number'] && $parsed['street']) {
-			$parsed['street'] = $parsed['street_number'] . ' ' . $parsed['street'];
-		}
-
-		return $parsed;
+		return 'Allows for a map field, utilizing Google Maps';
 	}
-
-	/**
-	 * Get Map ID
-	 */
-	public function getMapId(): string
+	/**********************************************************************
+	 * UTILITY
+	**********************************************************************/
+	protected function getPrivateKey():string|false
 	{
-		return $this->map_id;
+		return $this->loadCredentials()['private_key']??false;
 	}
-
-	/**
-	 * Get default map settings
-	 */
-	public function getDefaultMapSettings(): array
+	protected function getPublicKey():string|false
 	{
-		return [
-			'center' => [
-				'lat' => self::DEFAULT_LAT,
-				'lng' => self::DEFAULT_LNG
-			],
-			'zoom' => $this->credentials['default_zoom'] ?? self::DEFAULT_ZOOM,
-			'mapId' => $this->map_id,
-			'styles' => $this->getMapStyles()
-		];
+		return $this->loadCredentials()['public_key']??false;
 	}
 
-	/**
-	 * Get map styles based on theme
-	 */
-	private function getMapStyles(): array
+	protected function getMapID():string|false
 	{
-		$theme = $this->credentials['theme'] ?? 'default';
-
-		switch ($theme) {
-			case 'dark':
-				return [
-					['elementType' => 'geometry', 'stylers' => [['color' => '#242f3e']]],
-					['elementType' => 'labels.text.fill', 'stylers' => [['color' => '#746855']]],
-					['elementType' => 'labels.text.stroke', 'stylers' => [['color' => '#242f3e']]],
-					['featureType' => 'road', 'elementType' => 'geometry', 'stylers' => [['color' => '#38414e']]],
-					['featureType' => 'water', 'elementType' => 'geometry', 'stylers' => [['color' => '#17263c']]]
-				];
-
-			case 'minimal':
-				return [
-					['featureType' => 'poi', 'stylers' => [['visibility' => 'off']]],
-					['featureType' => 'transit', 'stylers' => [['visibility' => 'off']]]
-				];
-
-			default:
-				return [];
-		}
+		return $this->loadCredentials()['map_id']??false;
 	}
+	protected function getDefaultZoom():string|false
+	{
+		return $this->loadCredentials()['default_zoom']??false;
+	}
+	protected function getDefaultLng():string|false
+	{
+		return $this->loadCredentials()['default_lng']??false;
+	}
+	protected function getDefaultLat():string|false
+	{
+		return $this->loadCredentials()['default_lat']??false;
+	}
+
 
 	/**
 	 * Generate map application links
@@ -683,152 +270,108 @@
 			'waze' => "https://waze.com/ul?ll={$lat},{$lng}&navigate=yes"
 		];
 	}
-
-	/**
-	 * Render a frontend display map
-	 */
-	public function renderDisplayMap(array $location, array $options = []): string
+	private function parseAddressComponents(array $components):array
 	{
-		if (!$this->isSetUp() || empty($location['lat']) || empty($location['lng'])) {
-			return '';
-		}
-
-		$map_id = 'map-' . uniqid();
-		$lat = (float)$location['lat'];
-		$lng = (float)$location['lng'];
-		$address = $location['address'] ?? '';
-
-		$map_options = array_merge([
-			'height' => '250px',
-			'zoom' => 15,
-			'show_marker' => true,
-			'show_info_window' => true,
-			'info_content' => $address,
-			'interactive' => true
-		], $options);
-
-		ob_start();
-		?>
-		<div id="<?= esc_attr($map_id); ?>"
-			 class="jvb-location-map-display"
-			 style="height: <?= esc_attr($map_options['height']); ?>; border-radius: 8px; overflow: hidden;">
-		</div>
-
-		<script>
-			document.addEventListener('DOMContentLoaded', function() {
-				function initDisplayMap() {
-					if (!window.jvbMaps || !window.jvbMaps.ready) {
-						setTimeout(initDisplayMap, 100);
-						return;
-					}
-
-					window.jvbMaps.createDisplayMap('<?= esc_js($map_id); ?>', {
-						lat: <?= $lat; ?>,
-						lng: <?= $lng; ?>,
-						zoom: <?= intval($map_options['zoom']); ?>,
-						show_marker: <?= $map_options['show_marker'] ? 'true' : 'false'; ?>,
-						show_info_window: <?= $map_options['show_info_window'] ? 'true' : 'false'; ?>,
-						info_content: <?= json_encode($map_options['info_content']); ?>,
-						interactive: <?= $map_options['interactive'] ? 'true' : 'false'; ?>
-					});
+		$parsed = [];
+		$check = [
+			'street_number' => 'long_name',
+			'street' 		=> 'long_name',
+			'city' 			=> 'long_name',
+			'province' 		=> 'short_name',
+			'country'		=> 'short_name',
+			'postal_code'	=> 'long_name'
+		];
+		foreach ($components as $c) {
+			$types = $c['types'];
+			foreach ($check as $ch => $index) {
+				if (in_array($ch, $types)) {
+					$parsed[$ch] = $c[$index];
 				}
-
-				if (typeof google !== 'undefined' && google.maps) {
-					initDisplayMap();
-				} else {
-					document.addEventListener('googleMapsReady', initDisplayMap);
-				}
-			});
-		</script>
-		<?php
-
-		return ob_get_clean();
-	}
-
-	/**
-	 * Render map application links
-	 */
-	public function renderMapLinks(float $lat, float $lng, ?string $address = null, array $options = []): string
-	{
-		$links = $this->generateMapLinks($lat, $lng, $address);
-
-		$link_options = array_merge([
-			'show_icons' => true,
-			'style' => 'buttons', // 'buttons' or 'text'
-			'include' => ['google', 'apple'], // which links to show
-			'target' => '_blank'
-		], $options);
-
-		$output = '<div class="jvb-map-links' . ($link_options['style'] === 'buttons' ? ' button-style' : ' text-style') . '">';
-
-		foreach ($link_options['include'] as $provider) {
-			if (!isset($links[$provider])) continue;
-
-			$icon = '';
-			$label = '';
-
-			switch ($provider) {
-				case 'google':
-					$icon = $link_options['show_icons'] ? jvbIcon('google') : '';
-					$label = 'Google Maps';
-					break;
-				case 'apple':
-					$icon = $link_options['show_icons'] ? jvbIcon('apple') : '';
-					$label = 'Apple Maps';
-					break;
-				case 'waze':
-					$icon = $link_options['show_icons'] ? jvbIcon('waze') : '';
-					$label = 'Waze';
-					break;
 			}
-
-			$output .= sprintf(
-				'<a href="%s" target="%s" class="map-link %s-maps-link">%s<span>%s</span></a>',
-				esc_url($links[$provider]),
-				esc_attr($link_options['target']),
-				esc_attr($provider),
-				$icon,
-				esc_html($label)
-			);
 		}
-
-		$output .= '</div>';
-
-		return $output;
+		if (!empty($parsed['street_number']) && !empty($parsed['street'])) {
+			$parsed['street'] = $parsed['street_number'] . ' ' . $parsed['street'];
+		}
+		return $parsed;
 	}
 
-	/**
-	 * Format address for display
-	 */
-	public function formatAddress(array $location, string $format = 'full'): string
+	public function reverseGeocode(float $lat, float $lng):array|false
 	{
-		if (!empty($location['address'])) {
-			return $location['address'];
+		if (!$this->isSetUp()) {
+			return false;
+		}
+		$params = [
+			'latlng'	=> "{$lat},{$lng}",
+			'key'		=> $this->getPrivateKey()
+		];
+		return $this->getRequest(
+			sprintf(
+				'%s/geocode/json',
+				$this->apiBase,
+			),
+			$params
+		);
+	}
+		protected function handleGeocodeResponse(array $data, string $method):array
+		{
+			if (!array_key_exists('status', $data) || $data['status'] !== 'OK' || !array_key_exists('results', $data) || empty($data['results'])) {
+				return $this->response(false, 'Invalid response provided');
+			}
+			$result = $data['results'][0];
+			return $this->response(true, 'Successfully reversed geocode',[
+				'lat'				=> $result['geometry']['location']['lat'],
+				'lng'				=> $result['geometry']['location']['lng'],
+				'formatted_address'	=> $result['formatted_address'],
+				'place_id'			=> $result['place_id']??'',
+				'components'		=> $this->parseAddressComponents($result['address_compenents']??[])
+			]);
 		}
 
-		// Build address from components if no formatted address
-		$parts = [];
+	public function geocodeAddress(string $address):array|false
+	{
+		if (!$this->isSetUp()) {
+			return false;
+		}
+		$params = [
+			'address'	=> $address,
+			'key'		=> $this->getPrivateKey()
+		];
+		return $this->getRequest(
+			sprintf(
+				'%s/geocode/json',
+				$this->apiBase
+			)
+		);
+	}
 
-		switch ($format) {
-			case 'full':
-				if (!empty($location['street'])) $parts[] = $location['street'];
-				if (!empty($location['city'])) $parts[] = $location['city'];
-				if (!empty($location['province'])) $parts[] = $location['province'];
-				if (!empty($location['postal_code'])) $parts[] = $location['postal_code'];
-				if (!empty($location['country'])) $parts[] = $location['country'];
-				break;
+	protected function getRequestHeaders(): array
+	{
+		return [
+			'Accept' => 'application/json',
+			'Content-Type' => 'application/json'
+		];
+	}
 
-			case 'compact':
-				if (!empty($location['city']) && !empty($location['province'])) {
-					$parts[] = $location['city'] . ', ' . $location['province'];
-				}
-				break;
+	protected function handleResponse(\WP_Error|array $response, string $method, string $endpoint): array
+	{
+		if (is_wp_error($response) && $response->get_error_message() === 'rate_limit_exceeded') {
+			return $this->response(false, 'Rate limit exceeded');
+		}
+		$endpoint = str_replace($this->apiBase, '', $endpoint);
+		return  match ($endpoint) {
+			'/geocode/json'	=> $this->handleGeocodeResponse($response, $method),
+			default => $this->response(false, 'Unhandled response for '.$endpoint.' endpoint, with method: '.$method),
+		};
+	}
 
-			case 'city_only':
-				if (!empty($location['city'])) $parts[] = $location['city'];
-				break;
+	protected function performConnectionTest():bool
+	{
+		if (!$this->isSetUp()) {
+			return false;
 		}
 
-		return implode(', ', $parts);
+		$test = 'Edmonton, Alberta, Canada';
+		$result = $this->geocodeAddress($test);
+		return $result['success'];
 	}
 }

--
Gitblit v1.10.0