Find results near a specified location

FacetWP Proximity facet - filter by distance to locationThe Proximity facet lets you find results near a specified location, entered manually, or by clicking the “Locate me” icon.

After entering a location, a radius can be chosen from a pre-defined list, with a dropdown or slider. Results within that radius from the set location are then displayed.

How it works

After entering a location, FacetWP uses Google to grab the latitude, longitude of that location’s central point. Results within the user-defined radius of that point are displayed.

Proximity facet radius and countries / regions
A Proximity search for the region “Lombardy, Italy” (with the red border and blue marker at its geographical center). When the radius is set to 40km, it does not return any results in its capital Milan.

It does not understand geographic / political boundaries. If you search for a country (e.g. “Italy”), the facet will return results extending from that country’s geographical center point (as defined by Google), which may include results from other countries if the chosen radius is large enough.

Be aware that this behavior is possibly confusing for users. For example, if a user searches for the region Lombardy (Italy), they may expect to see results within the whole region (including its capital Milan). They may even expect results with a radius extending from the border of the region, not the center point. The Lombardy region is about 220km from west to east. So if a user searches it with a radius set to 40km, the facet will only display results within a circle of 80km diameter around Lombardy’s center point, which covers only a small part of the region, and does not include its capital Milan.

Keep this behavior in mind when choosing radius options for your situation. If you expect users to often search for regions or even countries, it makes sense to offer higher radius settings that cover whole regions or countries. Also, setting the default radius to a higher value can make the initial results more intuitively correct.

Another approach would be to limit what “place types” are returned by the autocomplete results, and exclude regions and countries. And/or to limit results to a specific country.

Combine a Proximity facet with a Map facet

If you use a Proximity facet on its own, it will return results within the chosen radius from the specified location. But there is no map for the user to interact with, nor any other feedback that includes distances.

You can show the resulting posts’ distances to the specified location, and/or let users sort results by distance. But to give users visual feedback, a Proximity facet can very well be combined with a Map facet.

When a location and radius are set (or changed) with the Proximity facet, the map will automatically zoom in or out, showing the locations that are within the radius of the set location.

The default Proximity facet marker pin
The default Proximity facet marker pin.

If the Proximity facet is in use, it will display a yellow marker pin at the set location. This marker pin can be customized, disabled, or excluded from marker clustering behavior).

See our Advanced Map customization page for more things you can do with the map and the Proximity facet/marker.

Available options

Name Description
Data source The Data source should be a custom field containing a comma-separated latitude, longitude. Or – if you use a separate custom field for the longitude – only a latitude. See below for more info.
Longitude Choose a custom field to use for the longitude value, if stored separately from the latitude (optional). See below for more info.
Unit of measurement Miles or Kilometers
Radius UI The UI element to use for the radius selector (Dropdown, Slider or None)
Radius options A comma-separated list of radius choices. The values need to be integers. Default: “10, 25, 50, 100, 250”. These radius choices can be changed programmatically if needed.
Default radius The default radius to be shown in the radius selector. If left empty, the first radius option will be the default if the Radius UI is set to Dropdown, and the middle of the range will be the default if the Radius UI is set to Slider.
Placeholder text The placeholder text that appears within the input box (default: “Enter location”). Note: this text is translatable with the facetwp_i18n hook. The default text is also translatable with a translation plugin or a WordPress gettext filter (see this example).

Data source

The Data source should be a custom field containing a comma-separated latitude, longitude.

You can also use separate custom fields for the latitude and longitude, see the available options.

Other data sources

The following plugins and themes offer dedicated custom fields for latitude and longitude that can be used as data source for the Proximity facet. Click the links for specific instructions on using these fields:

Using multiple data sources / locations per post

To use an ACF Google Maps field in an ACF Repeater field, choose the Google Maps field as data source ('my_map' in this example).
To use an ACF Google Maps field in an ACF Repeater field, choose the Google Maps field as data source (my_map in this example).

It is possible to index multiple locations per post, by using a multi-value custom field, like an ACF repeater field, or for example a checkboxes/dropdown field (if you have a select number of locations to choose from).

If you use an ACF Repeater field with a Google Maps sub field, you need to choose the Google Maps sub field’s name from the Map facet’s Data Source dropdown (my_map in the example to the right).

Make sure to choose the field under the “ACF” heading in the Data Source dropdown.

Google Maps API key

Generate a Google Maps API key

The Proximity facet requires a valid Google Maps API key. To generate a key, you have to log into Google Cloud Console, set up a project, add an API key under API's & Services > Credentials, and enable the following three API services for the key:

  1. Maps JavaScript API: required for the Proximity / Map facets to work
  2. Geocoding API: required for the Proximity facet’s “Locate me” button
  3. Places API: required for the Proximity facet’s autocomplete box

To be able to use the key, you also need to set up a Billing Account in Google Cloud Console, and add your project to it. You will need a creditcard to set up billing. There is a free monthly credit of $200, which amounts to 28000+ map loads per month.

Add the Google Maps API key to FacetWP

After generating an API key, add it to: Settings > FacetWP > Settings > Google Maps API key.
Both the Proximity facet and the Map facet use this key.

Add the Google Maps API key to Advanced Custom Fields

If you are using the Advanced Custom Fields Google Map field as the data source, make sure you pass the same Google Maps API key into ACF. ACF needs the Google Maps API in the backend to geolocate the address entered for each post.

Add the Google Maps API key to Listify, Listable, WP Job Manager

If you are using Listify theme, Listable theme and/or the WP Job Manager plugin, make sure to also add the Google Maps API key to:
(Job) Listings > Settings > Google Maps API Key

The Listify theme itself has a second settings to enter the Google Maps API key, at:
Appearance > Customize > Listings > Map settings

Accuracy of the “Locate me” button

When the “Locate me” button is pressed, FacetWP attempts to determine the user’s location. FacetWP first makes a browser Geolocation API request, which returns an approximate latitude/longitude (based on the user’s IP address).

Then FacetWP performs a reverse lookup to determine the human-friendly physical address. This not an exact science, and occasionally the location can be off by several kilometers.

Limit autocomplete results to a specific country

It is possible to limit the autocomplete results to one or more countries with the “componentRestrictions” option. You can specify a single country, or an array of up to five country code strings. The country code needs to be a two-letter ISO 3166-1 Alpha-2 country code and is case insensitive.

This code example forces the autocomplete to show only choices in Germany and The Netherlands (country codes = de and nl):

How to use custom PHP code?

PHP code can be added to your (child) theme's functions.php file. Alternatively, you can use the Custom Hooks add-on, or a code snippets plugin. More info

<?php add_filter( 'facetwp_proximity_autocomplete_options', function( $options ) { $options['componentRestrictions'] = [ 'country' => ['de','nl'], // Limit to Germany and The Netherlands ]; return $options; });

Limit autocomplete results to specific place types

It is possible to limit the autocomplete results to certain “place types”, like countries, regions, cities, municipalities or postal codes. A list of available place types can be found in the Places API reference.

This code example limits autocomplete results to cities only:

How to use custom PHP code?

PHP code can be added to your (child) theme's functions.php file. Alternatively, you can use the Custom Hooks add-on, or a code snippets plugin. More info

<?php add_filter( 'facetwp_proximity_autocomplete_options', function( $options ) { $options['types'] = ['(cities)']; return $options; });

Bias autocomplete results towards a specific area

It is possible to bias the autocomplete prediction results towards a specific area by setting a location with lat/lng coordinates, and defining a “bounding box” surrounding that location.

The following example sets New York City as location and defines a bounding box with sides of approximately 10km away from the specified center.

The results will biased towards, but not restricted to to places within the bounding box. Unfortunately, restricting the results is currently not possible with the available options the Google Places API provides (but it could very well become possible in the future).

You can test this example code by entering “Amsterdam” in the Proximity facet’s field. The first prediction result will be a billiards club in New York with that name, and not the capital of the Netherlands, which would otherwise be the first.

How to use custom PHP code?

PHP code can be added to your (child) theme's functions.php file. Alternatively, you can use the Custom Hooks add-on, or a code snippets plugin. More info

<?php add_filter( 'facetwp_proximity_autocomplete_options', function( $options ) { // New York City. Test results with "Amsterdam" $mylocation = [ 'lat' => 40.6974034, 'lng' => -74.1197615 ]; // Create a bounding box with sides ~10km away from the location point $myBounds = [ 'north' => $mylocation['lat'] + 0.1, 'south' => $mylocation['lat'] - 0.1, 'east' => $mylocation['lng'] + 0.1, 'west' => $mylocation['lng'] - 0.1, ]; $options['bounds'] = $myBounds; return $options; } );

Fix issues with the number of autocomplete results

The Google Places API returns a maximum of 5 autocomplete results. Unfortunately, this number cannot be changed.

This may lead to issues where some search terms (like zip codes) do not show up in the dropdown because there are more than 5 results for it. A solution can be to limit autocomplete results to a specific country, or place type, like region, or bias them towards a specific area. This will narrow the search, leading to smaller number of autocomplete results.

Change the minimum character length and delay

This code example limits the minimum characters to 3 and sets the delay to 250 ms:

How to use custom PHP code?

PHP code can be added to your (child) theme's functions.php file. Alternatively, you can use the Custom Hooks add-on, or a code snippets plugin. More info

<?php add_filter( 'facetwp_assets', function( $assets ) { FWP()->display->json['proximity']['queryDelay'] = 250; // default = 250 milliseconds FWP()->display->json['proximity']['minLength'] = 3; // default = 3 characters return $assets; } );

Display the post distance

If you are using a Proximity facet, you can use the facetwp_get_distance() function to get each post’s distance from the user-specified location. When the facet is in use as a filter (when a location is entered in the facet field), the function will return the numeric distance, or FALSE otherwise.

The distance is calculated in the units specified in the Proximity facet’s “Unit of measurement” setting (miles or kilometers). Be aware that the distance output is a float value, which needs to be rounded before being displayed.

In your loop template code you can use it like this:

How to use custom PHP code?

PHP code can be added to your (child) theme's functions.php file. Alternatively, you can use the Custom Hooks add-on, or a code snippets plugin. More info

// Get the distance as a float value. $distance = facetwp_get_distance(); // Round distance to 2 decimals and append ' mi' or ' km'. if ( false !== $distance ) { echo round( $distance, 2 ) . ' mi'; }

To get the distance of a specific post only, you can pass a post_id:

How to use custom PHP code?

PHP code can be added to your (child) theme's functions.php file. Alternatively, you can use the Custom Hooks add-on, or a code snippets plugin. More info

// Get the distance as a float value. $distance = facetwp_get_distance( $post_id ); // Round distance to 2 decimals and append ' mi' or ' km'. if ( false !== $distance ) { echo round( $distance, 2 ) . ' km'; }

If your posts have multiple locations, the facetwp_get_distance() function will return the distance of the location that is closest to the user-specified location. And if you need to know which one that is, you can let FacetWP store that location’s lat/lng values, and retrieve them.

Display the post distance with the Listing Builder

If you want to display the post distance in a shortcode template made with the Listing Builder, you can create a custom dynamic tag that outputs the distance, with the help of the facetwp_builder_dynamic_tag_value hook.

Add the following to your (child) theme’s functions.php to create a {{ distance }} dynamic tag:

How to use custom PHP code?

PHP code can be added to your (child) theme's functions.php file. Alternatively, you can use the Custom Hooks add-on, or a code snippets plugin. More info

add_filter( 'facetwp_builder_dynamic_tag_value', function( $tag_value, $tag_name, $params ) { if ( 'distance' == $tag_name ) { $distance = facetwp_get_distance(); // Round distance to 2 decimals and append ' mi' or ' km'. if ( false !== $distance ) { $tag_value = round( $distance, 2 ) . ' mi'; } } return $tag_value; }, 10, 3 );
Display the post distance in the Listin Builder with a custom dynamic tag.
Display the post distance in the Listin Builder with a custom dynamic tag.

This tag can then be used in Listing Builder elements. You can for example create an HTML element and use the tag in its “Content” field, as shown in the image on the right.

Note that the distance will only be calculated and displayed when the Proximity facet is actually in use as a filter (when location is entered in its field).

Display the post distance with a custom shortcode

If you are using a page builder like Bricks, Beaver Builder or Elementor, or the WordPress block editor, the easiest way to display the post distance with each post is to add a Shortcode module/block to the individual post layout and use a custom shortcode.

First add the following code to your (child) theme’s functions.php to create the custom shortcode:

How to use custom PHP code?

PHP code can be added to your (child) theme's functions.php file. Alternatively, you can use the Custom Hooks add-on, or a code snippets plugin. More info

add_shortcode( 'fwp_distance', function() { $distance = facetwp_get_distance(); // Round distance to 2 decimals and append ' mi' or ' km'. if ( false !== $distance ) { return round( $distance, 2 ) . ' mi'; } return ''; } );
Display the post distance with a custom shortcode in a Bricks Shortcode block.
Display the post distance with a custom shortcode in a Bricks Shortcode block.

Then paste the [fwp_distance] shortcode into the Shortcode module/block. The image on the right shows an example for the Bricks Shortcode module.

You can also use this custom shortcode in your PHP loop template, using WP’s do_shortcode() function:

How to use custom PHP code?

PHP code can be added to your (child) theme's functions.php file. Alternatively, you can use the Custom Hooks add-on, or a code snippets plugin. More info

do_shortcode( '[fwp_distance]' );

Display the post distance in Brick with a dynamic data tag

If you are using Bricks, another way to display the post distance is with a dynamic data echo.

First, add the following function to your (child) theme’s functions.php, in the Custom Hooks add-on, or with a code snippets plugin:

How to use custom PHP code?

PHP code can be added to your (child) theme's functions.php file. Alternatively, you can use the Custom Hooks add-on, or a code snippets plugin. More info

function fwp_distance() { $distance = facetwp_get_distance(); // Round distance to 2 decimals and append ' mi' or ' km' if ( false !== $distance ) { return round( $distance, 2 ) . ' mi'; } return ''; }
Display the post distance in Bricks with a dynamic data tag.
Display the post distance in Bricks with a dynamic data tag.

Then you can use the dynamic data tag {echo: fwp_distance()} to echo the distance, in any element that supports dynamic data tags. The image on the right shows how to add it as a field in a Bricks “Posts” element.

Display the post distance in map marker info windows

If you are using a Proximity facet together with a Map facet, it is possible to show the post distance in the info window that appears when a map marker is clicked.

To do so, open your Map facet’s settings, and add the following PHP code to the Marker content text field:

How to use custom PHP code?

PHP code can be added to your (child) theme's functions.php file. Alternatively, you can use the Custom Hooks add-on, or a code snippets plugin. More info

<?php // Get the distance as a float value. $distance = facetwp_get_distance(); // Round distance to 2 decimals and append ' mi' or ' km'. if ( false !== $distance ) { echo round( $distance, 2 ) . ' mi'; } ?>

Note that the post distance will only display when it is available: when the Proximity facet is in use and has a location entered.

Customize the post distance output

If you need to customize the output of the facetwp_get_distance() function, for example doing some calculations, rounding, or prepending/appending a string, you can use the following hook. Be aware that the passed $distance is a float value:

How to use custom PHP code?

PHP code can be added to your (child) theme's functions.php file. Alternatively, you can use the Custom Hooks add-on, or a code snippets plugin. More info

<?php add_filter( 'facetwp_proximity_distance_output', function( $distance ) { $distance = "Distance: " . round( $distance,2 ) + 5.5 . ' km'; return $distance; }, 10, 2 );

Store and get the (closest) post location

Add the following hook to your (child) theme’s functions.php to let FacetWP dynamically store the lat and lng values of each post in the filtered listing:

How to use custom PHP code?

PHP code can be added to your (child) theme's functions.php file. Alternatively, you can use the Custom Hooks add-on, or a code snippets plugin. More info

add_filter( 'facetwp_proximity_store_latlng', '__return_true' );

With this hook in place, and the Proximity facet in use as a filter, you can dynamically get the lat and lng values for a specific post (or for each post in the listing’s loop), as follows:

How to use custom PHP code?

PHP code can be added to your (child) theme's functions.php file. Alternatively, you can use the Custom Hooks add-on, or a code snippets plugin. More info

$latlngposts = FWP()->facet->facet_types['proximity']->post_latlng; if ( ! empty( $latlngposts ) ) { $latlng = $latlngposts[THE_POST_ID]; // Replace "THE_POST_ID" with the post id. If used in the loop, you can use: get_the_ID() $lat = $latlng[0]; $lng = $latlng[1]; // do something with $lat and $lng }

If your posts have multiple locations that are indexed by FacetWP, only one location is dynamically stored: the one that is closest to the user-specified location. This is the same location that is used by the facetwp_get_distance() function to calculate the post’s distance from the user-specified location.

Sort results by distance

When a Proximity facet is in use as a filter (with a location entered), the post IDs are automatically re-sorted in the post__in argument of the query, from nearest to furthest. (See below for how to prevent this).

This makes it possible to sort results by distance if a Proximity facet is in use, by adding the following code to your (child) theme’s functions.php. This order is retained until/unless a Sort facet is also used, which then overrules the sort order. Make sure to replace yoursortfacet in line 10 with the name of your Sort facet:

How to use custom PHP code?

PHP code can be added to your (child) theme's functions.php file. Alternatively, you can use the Custom Hooks add-on, or a code snippets plugin. More info

<?php add_action( 'pre_get_posts', function( $query ) { if ( ! class_exists( 'FacetWP_Helper' ) ) { return; } $facets_in_use = FWP()->facet->facets; $prefix = FWP()->helper->get_setting( 'prefix' ); // replace 'yoursortfacet' with the name of your sort facet $using_sort = isset( FWP()->facet->http_params['get'][ $prefix . 'yoursortfacet' ] ); $is_main_query = false; if ( is_array( FWP()->facet->template ) ) { if ( 'wp' != FWP()->facet->template['name'] || true === $query->get( 'facetwp' ) ) { $is_main_query = true; } } if ( ! empty( $facets_in_use ) && ! $using_sort && $is_main_query ) { foreach ( $facets_in_use as $f ) { if ( 'proximity' == $f['type'] && ! empty( $f['selected_values'] ) ) { $query->set( 'orderby', array( 'post__in' => 'ASC' ) ); // or 'DESC' } } } }, 1000 );

Sort results by distance with a Sort facet

Sort by distance
Make sure sort options have unique names.

If you want to allow users to sort by distance as a sorting option in a Sort facet, create a new sort option and set its data source to post__in with ASC or DESC order.

If you make both a ASC and a DESC sort option, make sure each sort option has a unique technical name set.

Be aware that sorting by distance only works when a location has been entered in the Proximity facet.

Prevent ordering by distance of post__in argument

If you want to prevent the Proximity facet from re-ordering the post IDs within the post__in argument of the query, add the following code to your (child) theme’s functions.php:

How to use custom PHP code?

PHP code can be added to your (child) theme's functions.php file. Alternatively, you can use the Custom Hooks add-on, or a code snippets plugin. More info

<?php add_filter( 'facetwp_query_args', function ( $query_args ) { remove_filter( 'facetwp_filtered_post_ids', [ FWP()->helper->facet_types['proximity'], 'sort_by_distance' ] ); return $query_args; } );

Change the radius options programmatically

If you want to change the radius options programmatically, add the following code to your (child) theme’s functions.php. The first value will be the default radius:

How to use custom PHP code?

PHP code can be added to your (child) theme's functions.php file. Alternatively, you can use the Custom Hooks add-on, or a code snippets plugin. More info

add_filter( 'facetwp_proximity_radius_options', function( $radius_options ) { return array( 250, 500, 1000, 2500 ); // The first value is the default value }, 10, 2 );

Reset a Proximity facet when map filtering is used

If you are using a Map facet together with a Proximity facet, and you want to reset/clear the Proximity facet when the map itself is filtering (when the “Enable map filtering button” is enabled), add the following code to your (child) theme’s functions.php. Make sure to replace my_proximity_facet with the name of your Proximity facet:

How to use custom PHP code?

PHP code can be added to your (child) theme's functions.php file. Alternatively, you can use the Custom Hooks add-on, or a code snippets plugin. More info

add_action('facetwp_scripts', function () { ?> <script> (function($) { document.addEventListener('facetwp-refresh', function() { if ( 'undefined' != typeof FWP_MAP && true === FWP_MAP.is_filtering) { $('.facetwp-location').val(''); // resets the value of the input field $('.facetwp-lat').val(''); // reset hidden field $('.facetwp-lng').val(''); // reset hidden field $('.facetwp-radius option').each(function () { if (this.defaultSelected) { this.selected = true; return false; } // reset default radius if it is a dropdown }); FWP.facets['my_proximity_facet'] = []; // change 'my_proximity_facet' to name of your Proximity facet } }); })(fUtil); </script> <?php }, 100);

See also