checkbox.php
3 weeks ago
date.php
3 weeks ago
datetime.php
3 weeks ago
field.php
3 weeks ago
gallery.php
3 weeks ago
map.php
3 weeks ago
media-url.php
3 weeks ago
media.php
3 weeks ago
number.php
3 weeks ago
post.php
3 weeks ago
radio.php
3 weeks ago
repeater.php
3 weeks ago
select.php
3 weeks ago
switcher.php
3 weeks ago
text.php
3 weeks ago
time.php
3 weeks ago
toggle.php
3 weeks ago
user.php
3 weeks ago
map.php
234 lines
| 1 | <?php |
| 2 | |
| 3 | namespace Wpai\AddonAPI; |
| 4 | |
| 5 | if ( ! defined( 'ABSPATH' ) ) exit; |
| 6 | |
| 7 | abstract class PMXI_Addon_Map_Provider_Field extends PMXI_Addon_Field { |
| 8 | abstract public function getGeocodeProviderName(); |
| 9 | |
| 10 | abstract public function getGeoCodeProviderSlug(); |
| 11 | |
| 12 | abstract public function getLanguage($custom_language = null); |
| 13 | |
| 14 | abstract public function getRegion($custom_region = null); |
| 15 | |
| 16 | abstract public function getApiKey( $use_custom = false, $custom_key = null ); |
| 17 | |
| 18 | abstract public function getLocationData( $logger, $apiKey, $address = null, $lat = null, $lng = null ); |
| 19 | |
| 20 | /** |
| 21 | * @param mixed $value |
| 22 | * @param "string"|"array"|"address" $format |
| 23 | * |
| 24 | * @return mixed |
| 25 | */ |
| 26 | abstract public function formatValue( $value, string $format ); |
| 27 | } |
| 28 | |
| 29 | class PMXI_Addon_Map_Field extends PMXI_Addon_Map_Provider_Field { |
| 30 | |
| 31 | private $baseUrl = 'https://maps.googleapis.com/maps/api/geocode/json'; |
| 32 | private $table = 'pmxi_geocoding'; |
| 33 | |
| 34 | public function getGeocodeProviderName() { |
| 35 | return 'Google Maps'; |
| 36 | } |
| 37 | |
| 38 | public function getGeoCodeProviderSlug() { |
| 39 | return 'google_maps'; |
| 40 | } |
| 41 | |
| 42 | public function getLanguage( $custom_language = null ) { |
| 43 | return $custom_language ?? ''; |
| 44 | } |
| 45 | |
| 46 | public function getRegion( $custom_region = null ) { |
| 47 | return $custom_region ?? ''; |
| 48 | } |
| 49 | |
| 50 | public function getApiKey( $use_custom = false, $custom_key = null ) { |
| 51 | return $use_custom ? $custom_key : ''; // It's up to the add-on to provide the API key |
| 52 | } |
| 53 | |
| 54 | private function buildApiUrl( $apiKey, $address = null, $lat = null, $lng = null, $params = [] ) { |
| 55 | $queryArgs = [ 'key' => $apiKey ]; |
| 56 | |
| 57 | if ( $address ) { |
| 58 | $queryArgs['address'] = urlencode( $address ); |
| 59 | } elseif ( $lat && $lng ) { |
| 60 | $queryArgs['latlng'] = "{$lat},{$lng}"; |
| 61 | } else { |
| 62 | return null; |
| 63 | } |
| 64 | |
| 65 | $params = array_filter( $params ); |
| 66 | $queryArgs = array_merge( $queryArgs, $params ); |
| 67 | |
| 68 | return add_query_arg( $queryArgs, $this->baseUrl ); |
| 69 | } |
| 70 | |
| 71 | public function getCachedData( $address = null, $lat = null, $lng = null ) { |
| 72 | global $wpdb; |
| 73 | $table = $wpdb->prefix . $this->table; |
| 74 | |
| 75 | if ( $address ) { |
| 76 | $query = $wpdb->prepare( |
| 77 | // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared -- $table is an internal plugin table name composed from $wpdb->prefix. |
| 78 | "SELECT * FROM $table WHERE address = %s LIMIT 1", |
| 79 | $address |
| 80 | ); |
| 81 | } else if ( $lat && $lng ) { |
| 82 | $query = $wpdb->prepare( |
| 83 | // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared -- $table is an internal plugin table name composed from $wpdb->prefix. |
| 84 | "SELECT * FROM $table WHERE latitude = %s AND longitude = %s LIMIT 1", |
| 85 | $lat, |
| 86 | $lng |
| 87 | ); |
| 88 | } else { |
| 89 | return null; |
| 90 | } |
| 91 | |
| 92 | // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared, WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching -- $query was built with $wpdb->prepare() above. |
| 93 | $row = $wpdb->get_row( $query ); |
| 94 | |
| 95 | return $row ? json_decode( $row->raw_data, true ) : null; |
| 96 | } |
| 97 | |
| 98 | public function cacheData( $data, $address = null, $lat = null, $lng = null ) { |
| 99 | global $wpdb; |
| 100 | $table = $wpdb->prefix . $this->table; |
| 101 | |
| 102 | if ( ! isset( $address ) && ! isset( $lat ) && ! isset( $lng ) ) { |
| 103 | return false; |
| 104 | } |
| 105 | |
| 106 | // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching |
| 107 | $wpdb->insert( $table, [ |
| 108 | 'address' => $address, |
| 109 | 'latitude' => $lat, |
| 110 | 'longitude' => $lng, |
| 111 | 'raw_data' => json_encode( $data ), |
| 112 | 'provider' => $this->getGeoCodeProviderSlug(), |
| 113 | 'created_at' => gmdate( 'Y-m-d H:i:s' ) |
| 114 | ] ); |
| 115 | |
| 116 | return true; |
| 117 | } |
| 118 | |
| 119 | public function getLocationData( $logger, $apiKey, $address = null, $lat = null, $lng = null, $params = [] ) { |
| 120 | $url = $this->buildApiUrl( $apiKey, $address, $lat, $lng, $params ); |
| 121 | $lookup_value = $address ?? $lat . ',' . $lng; |
| 122 | |
| 123 | if ( ! $url ) { |
| 124 | $logger and call_user_func( $logger, '- <b>WARNING</b>: You must provide either an address or latitude and longitude.' ); |
| 125 | return null; |
| 126 | } |
| 127 | |
| 128 | // Check if data is already cached |
| 129 | $cachedData = $this->getCachedData( $address, $lat, $lng ); |
| 130 | |
| 131 | if ( $cachedData ) { |
| 132 | $logger and call_user_func( $logger, '- Google Maps Geocoding: Using cached data for ' . $lookup_value ); |
| 133 | return $cachedData['results'][0]; |
| 134 | } |
| 135 | |
| 136 | if(empty($apiKey)){ |
| 137 | $logger and call_user_func( $logger, '- <b>WARNING</b>: You must provide a Google Maps Geocoding API Key.' ); |
| 138 | return null; |
| 139 | } |
| 140 | |
| 141 | // Fetch data from API |
| 142 | $response = wp_remote_get( $url ); |
| 143 | if ( is_wp_error( $response ) ) { |
| 144 | $logger and call_user_func( $logger, '- <b>WARNING</b>: Google Maps Geocoding: ' . $lookup_value . ' - ' . $response->get_error_message() ); |
| 145 | |
| 146 | return null; |
| 147 | } |
| 148 | |
| 149 | $logger and call_user_func( $logger, '- Google Maps Geocoding: Searching geolocation data for: ' . $lookup_value ); |
| 150 | |
| 151 | $body = wp_remote_retrieve_body( $response ); |
| 152 | $data = json_decode( $body, true ); |
| 153 | |
| 154 | if ( $data['status'] !== 'OK' ) { |
| 155 | $message = isset($data['error_message']) ? ' - ' . $data['error_message'] : ''; |
| 156 | $logger and call_user_func( $logger, '- <b>WARNING</b>: Error fetching geocoding data for: ' . $lookup_value . ' - ' . $data['status'] . $message ); |
| 157 | |
| 158 | return null; |
| 159 | } |
| 160 | |
| 161 | $this->cacheData( $data, $address, $lat, $lng ); |
| 162 | |
| 163 | $logger and call_user_func( $logger, '- Google Maps Geocoding: Found geolocation data for ' . $lookup_value ); |
| 164 | |
| 165 | return $data['results'][0]; |
| 166 | } |
| 167 | |
| 168 | public function formatValue( $value, $format = null ) { |
| 169 | if ( ! $value ) { |
| 170 | return null; |
| 171 | } |
| 172 | |
| 173 | $geometry = $value['geometry']['location']; |
| 174 | |
| 175 | if ( $format === 'string' ) { |
| 176 | return $geometry['lat'] . ',' . $geometry['lng']; |
| 177 | } elseif ( $format === 'address' ) { |
| 178 | return $value['formatted_address']; |
| 179 | } elseif ( $format === 'array' ) { |
| 180 | $geometry['address'] = $value['formatted_address']; |
| 181 | |
| 182 | return $geometry; |
| 183 | } else { |
| 184 | return $value; |
| 185 | } |
| 186 | } |
| 187 | |
| 188 | public function beforeImport( $postId, $value, $data, $logger, $rawData ) { |
| 189 | |
| 190 | // Short circuit if we don't have the data to process further. |
| 191 | if(('by_address' === $value['search_logic'] && empty($value['address'])) || ('by_coordinates' === $value['search_logic'] && (empty($value['lat']) || empty($value['lng'])))){ |
| 192 | return ''; |
| 193 | } |
| 194 | |
| 195 | $search_by = $value['search_logic'] ?? 'by_address'; |
| 196 | $value_format = $this->args['value_format'] ?? null; |
| 197 | $api_key = $this->getApiKey( $value['use_custom_api_key'] ?? false, $value['custom_api_key'] ?? null ); |
| 198 | $region = $this->getRegion( $value['custom_region'] ?? null ); |
| 199 | $language = $this->getLanguage( $value['custom_language'] ?? null ); |
| 200 | |
| 201 | $params = [ |
| 202 | 'region' => $region, |
| 203 | 'language' => $language |
| 204 | ]; |
| 205 | |
| 206 | if ( $search_by === 'manual' ) { |
| 207 | $geo_data = [ |
| 208 | 'geometry' => [ |
| 209 | 'location' => [ |
| 210 | 'lat' => $value['manual_lat'] ?? '', |
| 211 | 'lng' => $value['manual_lng'] ?? '' |
| 212 | ] |
| 213 | ], |
| 214 | 'formatted_address' => $value['manual_location'] ?? '' |
| 215 | ]; |
| 216 | |
| 217 | return $this->formatValue($geo_data, $value_format); |
| 218 | } |
| 219 | |
| 220 | switch ( $search_by ) { |
| 221 | case 'by_address': |
| 222 | $location_data = $this->getLocationData( $logger, $api_key, $value['address'], null, null, $params ); |
| 223 | break; |
| 224 | case 'by_coordinates': |
| 225 | $location_data = $this->getLocationData( $logger, $api_key, null, $value['lat'], $value['lng'], $params ); |
| 226 | break; |
| 227 | default: |
| 228 | return $value; |
| 229 | } |
| 230 | |
| 231 | return $this->formatValue( $location_data, $value_format ); |
| 232 | } |
| 233 | } |
| 234 |