├── .gitignore ├── README.md ├── acf-Autocomplete.php ├── assets └── js │ └── input.js ├── fields └── class-LQ-acf-field-Autocomplete.php └── images ├── field-in-use.png └── repeater-field.png /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled source # 2 | ################### 3 | *.com 4 | *.class 5 | *.dll 6 | *.so 7 | *.swp 8 | *.swo 9 | **/*.sw[abcdefghijklmnop] 10 | .sass-cache 11 | 12 | # Packages # 13 | ############ 14 | fuel/app/logs/*/*/* 15 | fuel/app/cache/*/* 16 | *.7z 17 | *.dmg 18 | *.iso 19 | *.rar 20 | *.zip 21 | *.psd 22 | .idea 23 | .idea/tasks.xml 24 | node_modules 25 | bower_components 26 | 27 | # Logs and databases # 28 | ###################### 29 | *.log 30 | 31 | # OS generated files # 32 | ###################### 33 | .DS_Store 34 | .DS_Store? 35 | ._* 36 | .Spotlight-V100 37 | .Trashes 38 | ehthumbs.db 39 | Thumbs.db 40 | 41 | # Wordpress Specific Ignores 42 | 43 | vendor 44 | sql 45 | 46 | # Theme Ignores 47 | .svn 48 | .cvs 49 | 50 | 51 | # wordpress specific 52 | wp-config.php 53 | wp-content/uploads/ 54 | wp-content/blogs.dir/ 55 | wp-content/upgrade/* 56 | wp-content/backup-db/* 57 | wp-content/advanced-cache.php 58 | wp-content/wp-cache-config.php 59 | wp-content/cache/* 60 | wp-content/cache/supercache/* 61 | 62 | # wpengine specific 63 | .smushit-status 64 | .gitattributes 65 | _wpeprivate 66 | wp-content/object-cache.php 67 | wp-content/mu-plugins/mu-plugin.php 68 | wp-content/mu-plugins/slt-force-strong-passwords.php 69 | wp-content/mu-plugins/limit-login-attempts 70 | wp-content/mu-plugins/wpengine-common 71 | wp-content/mysql.sql 72 | 73 | # wp core (as of 3.4.1) 74 | /db-config.php 75 | /index.php 76 | /license.txt 77 | /readme.html 78 | /wp-activate.php 79 | /wp-app.php 80 | /wp-atom.php 81 | /wp-blog-header.php 82 | /wp-comments-post.php 83 | /wp-commentsrss2.php 84 | /wp-config-sample.php 85 | /wp-cron.php 86 | /wp-feed.php 87 | /wp-links-opml.php 88 | /wp-load.php 89 | /wp-login.php 90 | /wp-mail.php 91 | /wp-rdf.php 92 | /wp-rss.php 93 | /wp-rss2.php 94 | /wp-pass.php 95 | /wp-register.php 96 | /wp-settings.php 97 | /wp-signup.php 98 | /wp-trackback.php 99 | /xmlrpc.php 100 | /wp-admin 101 | /wp-includes 102 | /wp-content/index.php 103 | /wp-content/themes/twentyten 104 | /wp-content/themes/index.php 105 | /wp-content/plugins/index.php 106 | 107 | # large/disallowed file types 108 | # a CDN should be used for these 109 | *.hqx 110 | *.deb 111 | *.img 112 | *.msi 113 | *.msp 114 | *.msm 115 | *.mid 116 | *.midi 117 | *.kar 118 | *.mp3 119 | *.ogg 120 | *.m4a 121 | *.ra 122 | *.3gpp 123 | *.3gp 124 | *.mp4 125 | *.mpeg 126 | *.mpg 127 | *.mov 128 | *.webm 129 | *.flv 130 | *.m4v 131 | *.mng 132 | *.asx 133 | *.asf 134 | *.wmv 135 | *.avi 136 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ACF GoogleMaps Autocomplete 2 | 3 | Adds a new field type to ACF so you can use Google Maps Autocomplete anywhere inside your admin area without displaying the full ACF map component. 4 | 5 | Useful for long lists of locations etc. 6 | 7 | ## Installation 8 | 9 | - Copy the folder into your wp-content/plugins folder 10 | - Make sure you have included the standard ACF call to your Google Map API key in your functions.php file 11 | - Activate ACF and this plugin 12 | - Create the new ACF field, selecting the new GoogleMaps Autocomplete field type, under jQuery 13 | - Enter, and pull the data out to the Front-End 14 | 15 | This plugin will add 3 fields to be saved within your ACF data - address, lat, lng 16 | 17 | It is up to you to decide how to display them on the Front-End and send the information to the map; I recommend using data attributes. 18 | 19 | ### Include this in your functions.php file 20 | 21 | ```php 22 | function my_acf_init() { 23 | acf_update_setting('google_api_key', '**your_map_key_here**' ); 24 | } 25 | 26 | add_action('acf/init', 'my_acf_init'); 27 | ``` 28 | 29 | ## Screenshot 30 | 31 | ![](images/field-in-use.png) 32 | 33 | ## Helped you out? Buy me a coffee! 34 | 35 | Buy Me A Coffee 36 | -------------------------------------------------------------------------------- /acf-Autocomplete.php: -------------------------------------------------------------------------------- 1 | settings = array( 20 | 'version' => '1.0.0', 21 | 'url' => plugin_dir_url( __FILE__ ), 22 | 'path' => plugin_dir_path( __FILE__ ), 23 | 'enqueue_google_maps' => true, 24 | ); 25 | 26 | add_action('acf/include_field_types', array($this, 'include_field')); // v5 27 | } 28 | 29 | function include_field( $version = false ) { 30 | include_once(plugin_dir_path( __FILE__ ) . 'fields/class-LQ-acf-field-Autocomplete.php'); 31 | } 32 | 33 | } 34 | 35 | new LQ_acf_plugin_Autocomplete(); 36 | 37 | endif; 38 | 39 | ?> 40 | -------------------------------------------------------------------------------- /assets/js/input.js: -------------------------------------------------------------------------------- 1 | document.autocompleteField = function() { 2 | // Has user pressed the down key to navigate autocomplete options? 3 | let hasDownBeenPressed = false; 4 | 5 | const inputHandling = function(searchInput) { 6 | // options 7 | const options = { 8 | componentRestrictions: { country: 'gb' } 9 | }; 10 | // Google Maps Autocomplete Method 11 | const autocomplete = new google.maps.places.Autocomplete(searchInput, options); 12 | google.maps.event.trigger(autocomplete, 'place_changed'); 13 | // Default listener outside to stop nested loop returning odd results 14 | searchInput.addEventListener('keydown', e => { 15 | if (e.keyCode === 40) { 16 | hasDownBeenPressed = true; 17 | } 18 | }); 19 | 20 | // GoogleMaps API custom eventlistener method 21 | google.maps.event.addDomListener(searchInput, 'keydown', e => { 22 | // Maps API e.stopPropagation(); 23 | e.cancelBubble = true; 24 | 25 | // If enter key, or tab key 26 | if (e.keyCode === 13 || e.keyCode === 9) { 27 | // If user isn't navigating using arrows and this hasn't ran yet 28 | if (!hasDownBeenPressed && !e.hasRanOnce) { 29 | e.preventDefault(); 30 | google.maps.event.trigger(e.target, 'keydown', { 31 | keyCode: 40, 32 | hasRanOnce: true 33 | }); 34 | } 35 | } 36 | }); 37 | 38 | // Clear the input on focus, reset hasDownBeenPressed 39 | searchInput.addEventListener('focus', () => { 40 | hasDownBeenPressed = false; 41 | searchInput.value = ''; 42 | }); 43 | 44 | // place_changed GoogleMaps listener when we do submit 45 | google.maps.event.addListener(autocomplete, 'place_changed', function() { 46 | // Get the place info from the autocomplete Api 47 | const place = autocomplete.getPlace(); 48 | 49 | //If we can find the place lets go to it 50 | if (typeof place.address_components !== 'undefined') { 51 | // reset hasDownBeenPressed in case they don't unfocus 52 | hasDownBeenPressed = false; 53 | // 🤢 😷 54 | const hiddenInputs = Array.from(searchInput.parentNode.parentNode.children.item(0).children); 55 | hiddenInputs.forEach(function(input) { 56 | switch (input.dataset.name) { 57 | case 'address': 58 | input.value = place.formatted_address; 59 | break; 60 | case 'lat': 61 | input.value = place.geometry.location.lat(); 62 | break; 63 | case 'lng': 64 | input.value = place.geometry.location.lng(); 65 | break; 66 | } 67 | }); 68 | } 69 | }); 70 | }; 71 | 72 | // search input 73 | 74 | const readyExistingFields = function() { 75 | const searchInput = Array.from(document.querySelectorAll('input[data-maps-autocomplete]')); 76 | searchInput.forEach(input => { 77 | inputHandling(input); 78 | }); 79 | }; 80 | 81 | const readyNewFields = function(input) { 82 | inputHandling(input); 83 | }; 84 | 85 | if (typeof acf.add_action !== 'undefined') { 86 | acf.add_action('ready', readyExistingFields); 87 | acf.add_action('append', function(parent) { 88 | var input = parent[0].querySelector('.search'); 89 | if (!input) return; 90 | readyNewFields(input); 91 | }); 92 | } 93 | }; 94 | -------------------------------------------------------------------------------- /fields/class-LQ-acf-field-Autocomplete.php: -------------------------------------------------------------------------------- 1 | name = 'autocomplete'; 12 | $this->label = __("Google Autocomplete",'acf'); 13 | $this->category = 'jquery'; 14 | $this->defaults = array( 15 | 'center_lat' => '', 16 | 'center_lng' => '' 17 | ); 18 | 19 | $this->settings = $settings; 20 | // do not delete! 21 | parent::__construct(); 22 | } 23 | 24 | function input_admin_enqueue_scripts() { 25 | 26 | // localize 27 | acf_localize_text(array( 28 | 'Sorry, this browser does not support geolocation' => __('Sorry, this browser does not support geolocation', 'acf'), 29 | )); 30 | 31 | if( !acf_get_setting('enqueue_google_maps') ) { 32 | return; 33 | } 34 | 35 | $url = $this->settings['url']; 36 | $version = $this->settings['version']; 37 | 38 | wp_register_script('autocomplete', "{$url}assets/js/input.js", $version); 39 | wp_enqueue_script('autocomplete'); 40 | 41 | $api = array( 42 | 'key' => acf_get_setting('google_api_key'), 43 | 'client' => acf_get_setting('google_api_client'), 44 | 'libraries' => 'places', 45 | 'ver' => 3, 46 | 'callback' => 'document.autocompleteField' 47 | ); 48 | 49 | $api = apply_filters('acf/fields/google_map/api', $api); 50 | 51 | if( empty($api['key']) ) unset($api['key']); 52 | if( empty($api['client']) ) unset($api['client']); 53 | 54 | $api_path = add_query_arg($api, 'https://maps.googleapis.com/maps/api/js'); 55 | 56 | wp_register_script( 'google_maps', $api_path, false, '3' ); 57 | wp_enqueue_script( 'google_maps' ); 58 | 59 | } 60 | 61 | function render_field( $field ) { 62 | // validate value 63 | if( empty($field['value']) ) { 64 | $field['value'] = array(); 65 | } 66 | 67 | //var_dump($field); 68 | 69 | $field['value'] = wp_parse_args($field['value'], array( 70 | 'address' => '', 71 | 'lat' => '', 72 | 'lng' => '' 73 | )); 74 | 75 | $atts = array( 76 | 'id' => $field['id'], 77 | 'class' => "acf-google-map {$field['class']}", 78 | 'data-lat' => $field['center_lat'], 79 | 'data-lng' => $field['center_lng'], 80 | ); 81 | 82 | if( $field['value']['address'] ) { 83 | $atts['class'] .= ' -value'; 84 | } 85 | 86 | ?> 87 | 88 |
> 89 | 90 |
91 | $v ): 92 | acf_hidden_input(array( 'name' => $field['name'].'['.$k.']', 'value' => $v, 'data-name' => $k )); 93 | endforeach; ?> 94 |
95 | 96 |
97 | " 102 | value="" 103 | /> 104 |
105 | 106 |
107 | settings ); 133 | 134 | endif; 135 | 136 | ?> 137 | -------------------------------------------------------------------------------- /images/field-in-use.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mt-deva/ACF-GoogleMaps-autocomplete/497c6894b00f9a507b84f994c13ba84fa022b2ef/images/field-in-use.png -------------------------------------------------------------------------------- /images/repeater-field.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mt-deva/ACF-GoogleMaps-autocomplete/497c6894b00f9a507b84f994c13ba84fa022b2ef/images/repeater-field.png --------------------------------------------------------------------------------