PluginProbe ʕ •ᴥ•ʔ
Advanced Custom Fields (ACF®) / 6.8.7
Advanced Custom Fields (ACF®) v6.8.7
6.8.9 6.8.8 6.8.7 6.8.6 6.8.5 6.8.4 6.8.3 6.8.2 6.8.1 5.8.5 5.8.6 5.8.7 5.8.8 5.8.9 5.9.0 5.9.1 5.9.2 5.9.3 5.9.4 5.9.5 5.9.6 5.9.7 5.9.8 5.9.9 6.0.0 6.0.1 6.0.2 6.0.3 6.0.4 6.0.5 6.0.6 6.0.7 6.1.0 6.1.1 6.1.2 6.1.3 6.1.4 6.1.5 6.1.6 6.1.7 6.1.8 6.2.0 6.2.1 6.2.2 6.2.3 6.2.4 6.2.5 6.2.6 6.2.6.1 6.2.7 6.2.8 6.2.9 6.3.0 6.3.1 6.3.10.2 6.3.11 6.3.12 6.3.2 6.3.3 6.3.4 6.3.5 6.3.6 6.3.6.1 6.4.0 6.4.0.1 6.4.1 6.4.2 6.4.3 6.5.0 6.5.1 6.6.0 6.6.1 6.6.2 6.7.0 6.7.1 6.7.2 6.8.0 trunk 1.0.0 1.0.2 1.0.3 1.0.5 1.1.0 1.1.1 1.1.2 1.1.3 1.1.4 2.0.0 2.0.1 2.0.2 2.0.3 2.0.4 2.0.5 2.1.1 2.1.3 2.1.4 3.0.0 3.0.1 3.0.2 3.0.3 3.0.4 3.0.6 3.0.7 3.1.0 3.1.1 3.1.2 3.1.3 3.1.4 3.1.5 3.1.6 3.1.7 3.1.8 3.1.9 3.2.0 3.2.2 3.2.3 3.2.4 3.2.5 3.2.6 3.2.7 3.2.8 3.2.9 3.3.0 3.3.1 3.3.2 3.3.3 3.3.4 3.3.5 3.3.6 3.3.7 3.3.8 3.3.9 3.4.0 3.4.1 3.4.2 3.4.3 3.5.0 3.5.1 3.5.2 3.5.3 3.5.4 3.5.5 3.5.6 3.5.7 3.5.8 4.0.0 4.0.1 4.0.2 4.0.3 4.1.0 4.1.1 4.1.2 4.1.3 4.1.4 4.1.5 4.1.6 4.1.8 4.2.0 4.2.1 4.2.2 4.3.0 4.3.1 4.3.2 4.3.3 4.3.4 4.3.5 4.3.6 4.3.7 4.3.8 4.3.9 4.4.0 4.4.1 4.4.10 4.4.11 4.4.12 4.4.2 4.4.3 4.4.4 4.4.5 4.4.6 4.4.7 4.4.8 4.4.9 5.10 5.10.1 5.10.2 5.11 5.11.1 5.11.2 5.11.3 5.11.4 5.12 5.12.1 5.12.2 5.12.3 5.12.4 5.12.5 5.12.6 5.6.10 5.6.2 5.6.3 5.6.4 5.6.5 5.6.6 5.6.7 5.6.8 5.6.9 5.7.0 5.7.1 5.7.10 5.7.12 5.7.13 5.7.2 5.7.3 5.7.4 5.7.5 5.7.6 5.7.7 5.7.8 5.7.9 5.8.0 5.8.1 5.8.10 5.8.11 5.8.12 5.8.13 5.8.14 5.8.2 5.8.3 5.8.4
advanced-custom-fields / includes / fields / class-acf-field-google-map.php
advanced-custom-fields / includes / fields Last commit date
class-acf-field-accordion.php 5 months ago class-acf-field-button-group.php 5 months ago class-acf-field-checkbox.php 2 months ago class-acf-field-color_picker.php 5 months ago class-acf-field-date_picker.php 5 months ago class-acf-field-date_time_picker.php 5 months ago class-acf-field-email.php 5 months ago class-acf-field-file.php 5 months ago class-acf-field-google-map.php 5 months ago class-acf-field-group.php 5 months ago class-acf-field-icon_picker.php 6 months ago class-acf-field-image.php 1 month ago class-acf-field-link.php 5 months ago class-acf-field-message.php 6 months ago class-acf-field-number.php 5 months ago class-acf-field-oembed.php 2 months ago class-acf-field-output.php 6 months ago class-acf-field-page_link.php 1 month ago class-acf-field-password.php 5 months ago class-acf-field-post_object.php 1 month ago class-acf-field-radio.php 2 months ago class-acf-field-range.php 5 months ago class-acf-field-relationship.php 1 month ago class-acf-field-select.php 2 months ago class-acf-field-separator.php 6 months ago class-acf-field-tab.php 6 months ago class-acf-field-taxonomy.php 2 months ago class-acf-field-text.php 5 months ago class-acf-field-textarea.php 5 months ago class-acf-field-time_picker.php 5 months ago class-acf-field-true_false.php 5 months ago class-acf-field-url.php 5 months ago class-acf-field-user.php 2 months ago class-acf-field-wysiwyg.php 5 months ago class-acf-field.php 5 months ago index.php 2 years ago
class-acf-field-google-map.php
541 lines
1 <?php
2 /**
3 * @package ACF
4 * @author WP Engine
5 *
6 * © 2026 Advanced Custom Fields (ACF®). All rights reserved.
7 * "ACF" is a trademark of WP Engine.
8 * Licensed under the GNU General Public License v2 or later.
9 * https://www.gnu.org/licenses/gpl-2.0.html
10 */
11
12 if ( ! class_exists( 'acf_field_google_map' ) ) :
13 class acf_field_google_map extends acf_field {
14
15
16 /**
17 * This function will setup the field type data
18 *
19 * @type function
20 * @date 5/03/2014
21 * @since 5.0.0
22 *
23 * @param n/a
24 * @return n/a
25 */
26 function initialize() {
27
28 // vars
29 $this->name = 'google_map';
30 $this->label = __( 'Google Map', 'acf' );
31 $this->category = 'advanced';
32 $this->description = __( 'An interactive UI for selecting a location using Google Maps. Requires a Google Maps API key and additional configuration to display correctly.', 'acf' );
33 $this->preview_image = acf_get_url() . '/assets/images/field-type-previews/field-preview-google-map.png';
34 $this->doc_url = acf_add_url_utm_tags( 'https://www.advancedcustomfields.com/resources/google-map/', 'docs', 'field-type-selection' );
35 $this->defaults = array(
36 'height' => '',
37 'center_lat' => '',
38 'center_lng' => '',
39 'zoom' => '',
40 );
41 $this->default_values = array(
42 'height' => '400',
43 'center_lat' => '-37.81411',
44 'center_lng' => '144.96328',
45 'zoom' => '14',
46 );
47 }
48
49
50 /**
51 * description
52 *
53 * @type function
54 * @date 16/12/2015
55 * @since 5.3.2
56 *
57 * @param $post_id (int)
58 * @return $post_id (int)
59 */
60 function input_admin_enqueue_scripts() {
61
62 // localize
63 acf_localize_text(
64 array(
65 'Sorry, this browser does not support geolocation' => __( 'Sorry, this browser does not support geolocation', 'acf' ),
66 )
67 );
68
69 // bail early if no enqueue
70 if ( ! acf_get_setting( 'enqueue_google_maps' ) ) {
71 return;
72 }
73
74 // vars
75 $api = array(
76 'key' => acf_get_setting( 'google_api_key' ),
77 'client' => acf_get_setting( 'google_api_client' ),
78 'libraries' => 'places',
79 'ver' => 3,
80 'callback' => 'Function.prototype',
81 'language' => acf_get_locale(),
82 );
83
84 // filter
85 $api = apply_filters( 'acf/fields/google_map/api', $api );
86
87 // remove empty
88 if ( empty( $api['key'] ) ) {
89 unset( $api['key'] );
90 }
91 if ( empty( $api['client'] ) ) {
92 unset( $api['client'] );
93 }
94
95 // construct url
96 $url = add_query_arg( $api, 'https://maps.googleapis.com/maps/api/js' );
97
98 // localize
99 acf_localize_data(
100 array(
101 'google_map_api' => $url,
102 )
103 );
104 }
105
106
107 /**
108 * Create the HTML interface for your field
109 *
110 * @param $field - an array holding all the field's data
111 *
112 * @type action
113 * @since 3.6
114 * @date 23/01/13
115 */
116 function render_field( $field ) {
117
118 // Apply defaults.
119 foreach ( $this->default_values as $k => $v ) {
120 if ( ! $field[ $k ] ) {
121 $field[ $k ] = $v;
122 }
123 }
124
125 // Attrs.
126 $attrs = array(
127 'id' => $field['id'],
128 'class' => "acf-google-map {$field['class']}",
129 'data-lat' => $field['center_lat'],
130 'data-lng' => $field['center_lng'],
131 'data-zoom' => $field['zoom'],
132 );
133
134 $search = '';
135 if ( $field['value'] ) {
136 $attrs['class'] .= ' -value';
137 $search = $field['value']['address'];
138 } else {
139 $field['value'] = '';
140 }
141
142 ?>
143 <div <?php echo acf_esc_attrs( $attrs ); ?>>
144
145 <?php
146 acf_hidden_input(
147 array(
148 'name' => $field['name'],
149 'value' => $field['value'],
150 )
151 );
152 ?>
153
154 <div class="title">
155
156 <input class="search" type="text" placeholder="<?php esc_attr_e( 'Search for address...', 'acf' ); ?>" value="<?php echo esc_attr( $search ); ?>" />
157
158 <div class="acf-actions -hover">
159 <button type="button" data-name="search" class="acf-icon -search grey" aria-label="<?php esc_attr_e( 'Search', 'acf' ); ?>"></button>
160 <button type="button" data-name="clear" class="acf-icon -cancel grey" aria-label="<?php esc_attr_e( 'Clear location', 'acf' ); ?>"></button>
161 <button type="button" data-name="locate" class="acf-icon -location grey" aria-label="<?php esc_attr_e( 'Find current location', 'acf' ); ?>"></button>
162 </div>
163
164 <i class="acf-loading"></i>
165
166 </div>
167
168 <div class="canvas" style="<?php echo esc_attr( 'height: ' . $field['height'] . 'px' ); ?>"></div>
169
170 </div>
171 <?php
172 }
173
174
175 /**
176 * Create extra options for your field. This is rendered when editing a field.
177 * The value of $field['name'] can be used (like bellow) to save extra data to the $field
178 *
179 * @type action
180 * @since 3.6
181 * @date 23/01/13
182 *
183 * @param $field - an array holding all the field's data
184 */
185 function render_field_settings( $field ) {
186
187 // center_lat
188 acf_render_field_setting(
189 $field,
190 array(
191 'label' => __( 'Center', 'acf' ),
192 'hint' => __( 'Center the initial map', 'acf' ),
193 'type' => 'text',
194 'name' => 'center_lat',
195 'prepend' => 'lat',
196 'placeholder' => $this->default_values['center_lat'],
197 )
198 );
199
200 // center_lng
201 acf_render_field_setting(
202 $field,
203 array(
204 'label' => __( 'Center', 'acf' ),
205 'hint' => __( 'Center the initial map', 'acf' ),
206 'type' => 'text',
207 'name' => 'center_lng',
208 'prepend' => 'lng',
209 'placeholder' => $this->default_values['center_lng'],
210 '_append' => 'center_lat',
211 )
212 );
213
214 // zoom
215 acf_render_field_setting(
216 $field,
217 array(
218 'label' => __( 'Zoom', 'acf' ),
219 'instructions' => __( 'Set the initial zoom level', 'acf' ),
220 'type' => 'text',
221 'name' => 'zoom',
222 'placeholder' => $this->default_values['zoom'],
223 )
224 );
225
226 // allow_null
227 acf_render_field_setting(
228 $field,
229 array(
230 'label' => __( 'Height', 'acf' ),
231 'instructions' => __( 'Customize the map height', 'acf' ),
232 'type' => 'text',
233 'name' => 'height',
234 'append' => 'px',
235 'placeholder' => $this->default_values['height'],
236 )
237 );
238 }
239
240 /**
241 * load_value
242 *
243 * Filters the value loaded from the database.
244 *
245 * @date 16/10/19
246 * @since 5.8.1
247 *
248 * @param mixed $value The value loaded from the database.
249 * @param mixed $post_id The post ID where the value is saved.
250 * @param array $field The field settings array.
251 * @return (array|false)
252 */
253 function load_value( $value, $post_id, $field ) {
254
255 // Ensure value is an array.
256 if ( $value ) {
257 return wp_parse_args(
258 $value,
259 array(
260 'address' => '',
261 'lat' => 0,
262 'lng' => 0,
263 )
264 );
265 }
266
267 // Return default.
268 return false;
269 }
270
271
272 /**
273 * This filter is appied to the $value before it is updated in the db
274 *
275 * @type filter
276 * @since 3.6
277 * @date 23/01/13
278 *
279 * @param $value - the value which will be saved in the database
280 * @param $post_id - the post_id of which the value will be saved
281 * @param $field - the field array holding all the field options
282 *
283 * @return $value - the modified value
284 */
285 function update_value( $value, $post_id, $field ) {
286
287 // decode JSON string.
288 if ( is_string( $value ) ) {
289 $value = json_decode( wp_unslash( $value ), true );
290 }
291
292 // Ensure value is an array.
293 if ( $value ) {
294 return (array) $value;
295 }
296
297 // Return default.
298 return false;
299 }
300
301 /**
302 * Return the schema array for the REST API.
303 *
304 * @param array $field
305 * @return array
306 */
307 public function get_rest_schema( array $field ) {
308 return array(
309 'type' => array( 'object', 'null' ),
310 'required' => ! empty( $field['required'] ),
311 'properties' => array(
312 'address' => array(
313 'type' => 'string',
314 ),
315 'lat' => array(
316 'type' => array( 'string', 'float' ),
317 ),
318 'lng' => array(
319 'type' => array( 'string', 'float' ),
320 ),
321 'zoom' => array(
322 'type' => array( 'string', 'int' ),
323 ),
324 'place_id' => array(
325 'type' => 'string',
326 ),
327 'name' => array(
328 'type' => 'string',
329 ),
330 'street_number' => array(
331 'type' => array( 'string', 'int' ),
332 ),
333 'street_name' => array(
334 'type' => 'string',
335 ),
336 'street_name_short' => array(
337 'type' => 'string',
338 ),
339 'city' => array(
340 'type' => 'string',
341 ),
342 'state' => array(
343 'type' => 'string',
344 ),
345 'state_short' => array(
346 'type' => 'string',
347 ),
348 'post_code' => array(
349 'type' => array( 'string', 'int' ),
350 ),
351 'country' => array(
352 'type' => 'string',
353 ),
354 'country_short' => array(
355 'type' => 'string',
356 ),
357 ),
358 );
359 }
360
361 /**
362 * Apply basic formatting to prepare the value for default REST output.
363 *
364 * @param mixed $value
365 * @param string|integer $post_id
366 * @param array $field
367 * @return mixed
368 */
369 public function format_value_for_rest( $value, $post_id, array $field ) {
370 if ( ! $value ) {
371 return null;
372 }
373
374 return acf_format_numerics( $value );
375 }
376
377 /**
378 * Returns an array of JSON-LD Property output types that are supported by this field type.
379 *
380 * @since 6.8
381 *
382 * @return string[]
383 */
384 public function get_jsonld_output_types(): array {
385 return array( 'Place', 'GeoCoordinates', 'PostalAddress' );
386 }
387
388 /**
389 * Formats the field value for JSON-LD output.
390 *
391 * @since 6.8.0
392 *
393 * @param mixed $value The value of the field.
394 * @param integer|string $post_id The ID of the post.
395 * @param array $field The field array.
396 * @return mixed
397 */
398 public function format_value_for_jsonld( $value, $post_id, $field ) {
399 if ( empty( $value ) || ! is_array( $value ) ) {
400 return null;
401 }
402
403 // Get output format with fallback.
404 $output_format = $field['schema_output_format'] ?? '';
405 if ( empty( $output_format ) ) {
406 $property = $field['schema_property'] ?? '';
407 $output_format = \ACF\AI\GEO\Schema::get_default_output_format( $this->name, $property );
408 }
409
410 // Default to Place if no format determined.
411 if ( empty( $output_format ) ) {
412 $output_format = 'Place';
413 }
414
415 switch ( $output_format ) {
416 case 'GeoCoordinates':
417 return $this->format_geo_coordinates( $value );
418
419 case 'PostalAddress':
420 return $this->format_postal_address( $value );
421
422 case 'Place':
423 default:
424 return $this->format_place( $value );
425 }
426 }
427
428 /**
429 * Format value as GeoCoordinates.
430 *
431 * @since 6.8.0
432 *
433 * @param array $value The google map value array.
434 * @return array|null
435 */
436 private function format_geo_coordinates( $value ) {
437 if ( empty( $value['lat'] ) || empty( $value['lng'] ) ) {
438 return null;
439 }
440
441 return array(
442 '@type' => 'GeoCoordinates',
443 'latitude' => (float) $value['lat'],
444 'longitude' => (float) $value['lng'],
445 );
446 }
447
448 /**
449 * Format value as PostalAddress.
450 *
451 * @since 6.8.0
452 *
453 * @param array $value The google map value array.
454 * @return array|null
455 */
456 private function format_postal_address( $value ) {
457 $address = array(
458 '@type' => 'PostalAddress',
459 );
460
461 // Build street address from components.
462 $street_parts = array();
463 if ( ! empty( $value['street_number'] ) ) {
464 $street_parts[] = $value['street_number'];
465 }
466 if ( ! empty( $value['street_name'] ) ) {
467 $street_parts[] = $value['street_name'];
468 }
469 if ( ! empty( $street_parts ) ) {
470 $address['streetAddress'] = implode( ' ', $street_parts );
471 }
472
473 if ( ! empty( $value['city'] ) ) {
474 $address['addressLocality'] = $value['city'];
475 }
476
477 if ( ! empty( $value['state'] ) ) {
478 $address['addressRegion'] = $value['state'];
479 }
480
481 if ( ! empty( $value['post_code'] ) ) {
482 $address['postalCode'] = (string) $value['post_code'];
483 }
484
485 if ( ! empty( $value['country'] ) ) {
486 $address['addressCountry'] = $value['country'];
487 }
488
489 // Only return if we have at least one address property beyond @type.
490 if ( count( $address ) > 1 ) {
491 return $address;
492 }
493
494 return null;
495 }
496
497 /**
498 * Format value as Place.
499 *
500 * @since 6.8.0
501 *
502 * @param array $value The google map value array.
503 * @return array|null
504 */
505 private function format_place( $value ) {
506 $place = array(
507 '@type' => 'Place',
508 );
509
510 // Add name if available.
511 if ( ! empty( $value['name'] ) ) {
512 $place['name'] = $value['name'];
513 }
514
515 // Add full address as formatted string.
516 if ( ! empty( $value['address'] ) ) {
517 $place['address'] = $value['address'];
518 }
519
520 // Add geo coordinates.
521 $geo = $this->format_geo_coordinates( $value );
522 if ( $geo ) {
523 $place['geo'] = $geo;
524 }
525
526 // Only return if we have meaningful data beyond @type.
527 if ( count( $place ) > 1 ) {
528 return $place;
529 }
530
531 return null;
532 }
533 }
534
535
536 // initialize
537 acf_register_field_type( 'acf_field_google_map' );
538 endif; // class_exists check
539
540 ?>
541