Skip to:

How to with Gabey D: Adding Location Filtering

  • Avatar of godavid33


    Hello all,

    I’ve seen some posts asking for this and never saw a full, complete guide on it so figure I’ll try again at making a contribution to the community. The below code is working for me with one caveat (that hopefully I’ll fix and post the solution to here).

    So first off, we need a unified way of assessing location. The least sensitive yet least prone to error that I’ve found is zip code. Before I get ahead of myself though, here are the steps.

    0. Make sure you have ‘geo_lat’ and ‘geo_meta’ keys set up. These are needed for the below code to work.
    1. Get Zip Code
    2. Get longitude and latitude from Zip Code using google geocoding API
    3. Store lat and long (everytime a user updates zip code it updates these values)
    4. Query database and order results by the distance from current user

    so here it is, all of this code is in functions.php:

    add_action( 'bp_members_directory_order_options', 'mycred_pro_add_sorting_options' );
    function mycred_pro_add_sorting_options() { ?>
    	<option value="points-asc">Distance: Closest to me</option>
    	<option value="points-desc">Distance: Farthest from me</option>
    add_action( 'bp_pre_user_query', 'mycred_pro_pre_user_query' );
    function mycred_pro_pre_user_query( $BP_User_Query ) {
    	// Only run this if one of our custom options is selected
    	if ( in_array( $BP_User_Query->query_vars['type'], array( 'points-asc', 'points-desc' ) ) ) {
    		global $wpdb, $scope;
    		// Adjust SELECT
    		$BP_User_Query->uid_clauses['select'] = "
    			select distinct um.user_id, um.meta_value as latitude, um2.meta_value as longitude
    			from wp_usermeta as um
    			left join wp_usermeta as um2 on um.user_id=um2.user_id and um2.meta_key = 'geo_long'
    		// Adjust WHERE
    		$BP_User_Query->uid_clauses['where'] = "WHERE um.meta_key='geo_lat'";
    		//Additional Custom WHERE
                        //You don't really need this part, I'm using it to make sure that my custom sort tabs don't stop working
    		$ids_to_include = explode("=", $scope);
    		$ids_to_include = explode(",",$ids_to_include[1]);
    		$ids_string = "";
    		$id_count = 0;
    		foreach($ids_to_include as $id){
    			if($id == ""){
    				if($id_count == 0)
    					$ids_string .= " AND (um.user_id = ".$id;
    					$ids_string .= " OR um.user_id = ".$id;		
    		if($ids_string != "")
    			$ids_string .= ")";	
    		$BP_User_Query->uid_clauses['where'] .= $ids_string;
    		// Adjust ORDER BY
    		$BP_User_Query->uid_clauses['orderby'] = "ORDER BY (((acos(sin((".get_user_meta(get_current_user_id(), "geo_lat",true)."*pi()/180)) * sin((latitude*pi()/180))+cos((".get_user_meta(get_current_user_id(), "geo_lat",true)."*pi()/180)) * cos((latitude*pi()/180)) * cos(((".get_user_meta(get_current_user_id(), "geo_long",true)."- longitude)*pi()/180))))*180/pi())*60*1.1515)";
    		// Adjust ORDER
    		$BP_User_Query->uid_clauses['order'] = ( $BP_User_Query->query_vars['type'] == 'points-asc' ) ? 'ASC' : 'DESC';
    		echo '<script>console.log("'.$BP_User_Query->uid_clauses['where'].'");</script>';
    function getDistanceBetweenPointsNew($latitude1, $longitude1, $latitude2, $longitude2, $unit = 'Mi') {
         $theta = $longitude1 - $longitude2;
         $distance = (sin(deg2rad($latitude1)) * sin(deg2rad($latitude2))) + (cos(deg2rad($latitude1)) * cos(deg2rad($latitude2)) * cos(deg2rad($theta)));
         $distance = acos($distance);
         $distance = rad2deg($distance);
         $distance = $distance * 60 * 1.1515; switch($unit) {
              case 'Mi': break; case 'Km' : $distance = $distance * 1.609344;
         return (round($distance,2));
    function set_lat_long( $field_id, $value ){
    	global $bp;
    	if($field_id == 36){
    	$url = "".$value."&sensor=false";
    	$response = wp_remote_get($url);
    	$geodata = json_decode($response['body'], true);
    	$lat = $geodata["results"][0]["geometry"]["location"]["lat"];
    	$long = $geodata["results"][0]["geometry"]["location"]["lng"];
    	update_user_meta($bp->displayed_user->id, "geo_lat", $lat);
    	update_user_meta($bp->displayed_user->id, "geo_long", $long);
    add_action( 'xprofile_profile_field_data_updated', 'set_lat_long', 1, 2 );

    Hopefully I didnt forget anything. Feel free to edit it as you will, let me know if it doesn’t work – I may have forgotten to include one of the functions needed to make this work.

    Also, as you can see the code that adds the filters to the drop down is from the MyCred author, Gabriel Merovingi so credit goes to him for that. I also found the data calculation somewhere online through google, don’t remember the exact author unfortunately :(


    If you figure out how to get the count (“Showing x out of y members”) let me know

Viewing 3 replies - 1 through 3 (of 3 total)
  • Avatar of erannou


    godavid you are the savior of the day ! thank you very much for sharing your code.

    It works perfectly for me, I just added something in order to be able to search a real address (with spaces between words) and not a single word:

    $url = ‘”‘.str_replace(” “,”+”, urlencode($new_station_value)).’”&sensor=false’;

    Without this, google was not able to locate a location like “tokyo station” with a space.

    Thx again.

    Avatar of godavid33


    Ah, great addition. I may end up making use of that myself.

    Glad that I could help!

    Avatar of chrisminnick


    Thank you so much for posting this. It works great, however, the pagination doesn’t work on my site when the distance from me sort option is applied. The first page comes up, but clicking on the next page always shows ‘no members found’. I’m using the custom community theme. Do you have any idea what the issue is or how I might work around it?

Viewing 3 replies - 1 through 3 (of 3 total)

You must be logged in to reply to this topic.