In this case study I’ll walk through how I was able to create a radius search from Google map data for a client.
It’s a bit technical if you just want to see the output, scroll down to the video for a demo of the front end.
My clients requirement was for a user to enter their Zip code and then for the code to search on a custom post type called location and return all locations within a 100 mile radius.
We had attached an ACF google map field to the custom post type so we could save the address data of the location on the post, I created a map and I could output all of the data points on the map, so far so good.
Problem One – Google Maps Latitude and Longitude Data Is Serialised
The data is serialised so it is very hard to search on an ACF google map, so I create two new fields (latitude and longitude) and upon save of the custom post type I grab the ACF field latitude and longitude and save them into their own fields.
function nm_update_lat_long($post_id){
$post_type = get_post_type( $post_id );
if ( 'location' == $post_type ) {
$xxx_map= get_field('xxx_google_map', $post_id);
$_POST["acf"]["field_65b8c2e984961"]=$xxx_map['lat'];
$_POST["acf"]["field_65b8c2fb84962"]=$xxx_map['lng'];
return $_POST;
}
}
add_action('acf/save_post', 'nm_update_lat_long',1);
Convert Zip Code TO Co-Ordinates
Using the Google maps API I can do a search using a zip code and return a set of latitude and longitude co-ordinates I can use to create my search are. The code looks like this.
function nm_get_coords_zip_code($zip){
$api_key=get_field('xxx_options_google_map_api_key','options');
$url = "https://maps.googleapis.com/maps/api/geocode/json?address=".$zip."&sensor=false&key=".$api_key;
$details=file_get_contents($url);
$result = json_decode($details,true);
$account_lat=$result['results'][0]['geometry']['location']['lat'];
$account_long=$result['results'][0]['geometry']['location']['lng'];
return array($account_lat,$account_long);
}
The Search Box
Using maths I’ve not used since school, I was able to return a box which is 100 miles radius of my zip code. Who am I kidding I found it on stack overflow.
function nm_getBoundingBox($lat_degrees,$lon_degrees,$distance_in_miles) {
$radius = 3963.1; // of earth in miles
// bearings - FIX
$due_north = deg2rad(0);
$due_south = deg2rad(180);
$due_east = deg2rad(90);
$due_west = deg2rad(270);
// convert latitude and longitude into radians
$lat_r = deg2rad($lat_degrees);
$lon_r = deg2rad($lon_degrees);
// find the northmost, southmost, eastmost and westmost corners $distance_in_miles away
// original formula from
// http://www.movable-type.co.uk/scripts/latlong.html
$northmost = asin(sin($lat_r) * cos($distance_in_miles/$radius) + cos($lat_r) * sin ($distance_in_miles/$radius) * cos($due_north));
$southmost = asin(sin($lat_r) * cos($distance_in_miles/$radius) + cos($lat_r) * sin ($distance_in_miles/$radius) * cos($due_south));
$eastmost = $lon_r + atan2(sin($due_east)*sin($distance_in_miles/$radius)*cos($lat_r),cos($distance_in_miles/$radius)-sin($lat_r)*sin($lat_r));
$westmost = $lon_r + atan2(sin($due_west)*sin($distance_in_miles/$radius)*cos($lat_r),cos($distance_in_miles/$radius)-sin($lat_r)*sin($lat_r));
$northmost = rad2deg($northmost);
$southmost = rad2deg($southmost);
$eastmost = rad2deg($eastmost);
$westmost = rad2deg($westmost);
// sort the lat and long so that we can use them for a between query
if ($northmost > $southmost) {
$lat1 = $southmost;
$lat2 = $northmost;
} else {
$lat1 = $northmost;
$lat2 = $southmost;
}
if ($eastmost > $westmost) {
$lon1 = $westmost;
$lon2 = $eastmost;
} else {
$lon1 = $eastmost;
$lon2 = $westmost;
}
return array($northmost, $southmost, $eastmost, $westmost);
}
The Query
I setup a query to search the data looking for locations within the bounds of the co-ordinates I had grabbed from the search box in the previous step. I saved those co-ordinates in an erray $distance_box. Here are the query arguments I used.
$args = array(
'post_type' => 'location',
'post_status' => 'publish',
'meta_query' => array(
'relation' => 'AND',
array(
'key' => 'xxx_latitude',
'value' => array($distance_box[1]),
'compare' => '>=',
'type' => 'NUMERIC',
),
array(
'key' => 'xxx_latitude',
'value' => array($distance_box[0]),
'compare' => '<=',
'type' => 'NUMERIC',
),
array(
'key' => 'xxx_longitude',
'value' => array($distance_box[2]),
'compare' => '<=',
'type' => 'NUMERIC',
),
array(
'key' => 'xxx_longitude',
'value' => array($distance_box[3]),
'compare' => '>=',
'type' => 'NUMERIC',
),
)
);
Video Demo
Here’s what it looks like on the front end.
Wrap Up – Radius Search ACF Google Map Field
So here’s my case study on how to search ACF google map fields via a 100 mile radius.
If you need help implementing Google maps on your site please get in touch.
Photo by José MartÃn RamÃrez Carrasco on Unsplash