This add-on adds a Map facet type, which displays a Google map on the page. The generated map shows markers which represent geocoded results from a FacetWP-enabled listing on the page. These markers can be filtered by other facets, for example by a Proximity facet. The map will automatically update its zoom/pan to include only the filtered posts.

If enabled, the map’s viewport itself can also act as a facet and filter the results in the listing, by panning or zooming the map manually.

How it works

To get a clear mental picture of how the Map add-on works, it is important to understand that the map is not a listing, but a facet. It may look like a listing, as it shows posts (a marker for each), and those posts/markers will be filtered when using other facets, but it is still technically a facet.

For any facet to work, there needs to be a FacetWP-enabled listing on the page. Without it, the map (its markers) and other facets will just not show up, because FacetWP does not have a query to “latch onto”. This listing can be a Listing Builder listing or any of the other supported listing template types. If you don’t want a visible listing, you can hide it with CSS, but it still needs to be on the page for the map to function.

So, the map facet always needs a listing, it will show a marker for each post in this listing, and these posts/markers can be filtered by using other facets. How then is the map considered a facet? The answer is that it is not by default, but it can be. As soon as the Enable map filtering button is enabled, the map’s viewport becomes the facet filter. By panning and/or zooming the map, the listing will instantly be refreshed to only display the posts that are in the current map viewport. This feature can also be disabled, by hiding “Enable map filtering” button.

Combine a Map facet with a Proximity facet

A Map facet can be combined with any other facet to filter the posts/markers on the map. A specifically useful facet in combination with a map is the Proximity facet, which returns results within a chosen radius from a specified location.

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.
Map design Choose a design / style / color scheme for the map. See the Advanced Maps customizations page to learn how to use your own map styles.
Enable filtering button The button text of the “Enable map filtering” button. Note: the default or changed text can be translated with the facetwp_i18n hook, with a translation plugin, or with a gettext filter.
Reset button The button text of the “Reset” button, which appears after clicking the “Enable map filtering” button. Note: the default or changed text can be translated with the facetwp_i18n hook, with a translation plugin, or with a gettext filter.
Marker clustering This option will group markers that are close to each other into marker clusters, from a certain zoom level. See the Advanced Maps customizations page for ways to customize marker clustering behavior.
Ajax marker content Enable to dynamically load marker content via AJAX. Works best for maps with many markers, since it prevents all the marker content from loading all at once.
Marker limit
  • Show all results – will show all markers that match the results
  • Show current page results – will only display markers matching the results on the current page of paginated results. Note: this only works with a Pager facet of type “Page numbers”. It does not work with “Load more” pagination.
Map width / height Width and height of map. Without units, px is assumed: e.g. 300 is the same as 300px. Use other CSS units if needed, e.g. 100% for responsive full width of the parent container. Note: don’t use 100% for the height if the map’s container does not have a fixed height, else the map will have no height and will not show.
Zoom min / max Set the minimum and maximum zoom level. The values must be a number between 1 (minimum zoom) and 20 (maximum zoom).
Fallback lat / lng / zoom: Set a fallback location (lat/lng) and/or zoom level. The zoom level must be a number between 1 (minimum zoom) and 20 (maximum zoom). These settings are only used when no results/markers are found. If you leave these fields empty, the default lat/lng is 0,0 and the default zoom level is 1.

With some customization, this setting can also be used to set a default custom center and zoom level on load of the map.

Marker content Enter display code (HTML and/or PHP) to create the content that displays in an info window popup when a marker is selected. For an example, see below

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 sources for the Map 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 always choose the field under the “ACF” heading in the Data Source dropdown.

Note that if you want to retrieve content from other custom fields within the repeater field, to display in the marker/location’s info window, you cannot do that with the Marker content setting. In this setting field only post data can be retrieved, not the data for the separate locations within the repeater. The solution is to use the facetwp_map_marker_args hook.

Google Maps API key

Generate a Google Maps API key

The Map 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 Map / Proximity 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 Map facet and the Proximity facet use this key.

Besides in FacetWP’s settings, the API key can also be set with a constant in wp-config.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

define( 'GMAPS_API_KEY', 'your-api-key' );

Or with a hook in 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

add_filter( 'facetwp_gmaps_api_key', function( $api_key) { return 'your-api-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

Add marker content

The “Marker content” setting can be used to create the content of the info window popup that displays when a marker is selected. The setting’s field accepts HTML and PHP code, and is aware of the marker’s post data. You can use data from $post, like $post->ID.

The following example outputs the title, link, and excerpt:

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

<h3> <a href="<?php the_permalink(); ?>" title="<?php the_title_attribute(); ?>"> <?php the_title(); ?> </a> </h3> <?php the_excerpt(); ?>

If the “Marker content” field is too limiting, or if you can’t reach certain data with it, you can use the facetwp_map_marker_args hook to output/overwrite the marker infowindow content.

Style marker content

If you want to style the custom marker content with CSS, just add a container <div> with a custom class, and use that to target your elements in the info window:

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

<div class="infowindow"> <h3> <a href="<?php the_permalink(); ?>" title="<?php the_title_attribute(); ?>"> <?php the_title(); ?> </a> </h3> <?php the_excerpt(); ?> </div>

For example, to style the <h3>:

How to use custom CSS?

CSS code can be placed in your (child) theme's style.css file. Alternatively, you can add it manually between <style> tags in the <head> section, in your (child) theme's header.php file. You can also load it with a hook in your (child) theme's functions.php file, or in the Custom Hooks add-on. To load the code only on pages with facets, use the facetwp_scripts hook. To load it on all pages, use wp_head or wp_footer. Or you can use a code snippets plugin. More info

.facetwp-type-map .infowindow h3 { font-size: 18px; font-weight: bold; }

Alternatively, you can use the gm-style-iw class of the parent info window element:

Change the marker info window width or height

To change the marker info window’s width and/or height, you can use the gm-style-iw class.

The following example sets it to a fixed width of 300px and a min-height of 150px. Add the CSS directly to your theme CSS, or 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

add_action( 'wp_head', function() { ?> <style> .gm-style-iw { width: 300px; min-height: 150px; } </style> <?php }, 100 );

If you want to keep the info window’s width flexible and use max-width instead of width, you’ll need to override the map’s default inline CSS value with !important. The same is true for min-width and max-height:

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( 'wp_head', function() { ?> <style> .gm-style-iw { max-width: 300px !important; /* Override the inline CSS value set by Google */ /* if needed: */ /* min-width: 200px !important; */ /* max-height: 150px !important; */ } </style> <?php }, 100 );

Customize or overwrite the marker infowindow content

The marker infowindow content can be created in the “Marker content” setting field.

If this field is too limiting, or if you can’t reach certain data with it, you can use the facetwp_map_marker_args hook to output the marker infowindow content. Note that this will overwrite anything you have in the “Marker content” setting.

As $post_id is available in this hook, you can create or overwrite the content conditionally, only for specific posts:

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_map_marker_args', function( $args, $post_id ){ if ( $post_id == 5647 ) { // Optionally add a condition to check for specific post IDs $args['content'] = "my custom marker content"; // Create your custom marker infowindow content } return $args; }, 10, 2 );

One use case for this is if you use ACF Repeater fields to support multiple locations per post. With the “Marker content” field you can only get post data, but not the data for the separate locations within the repeater. This snippet shows how to get and output the repeater field data with the facetwp_map_marker_args hook.

Add marker content from ACF custom fields

If your posts have custom fields made with Advanced Custom Fields, you can get the custom field contents with ACF’s get_field() function, and echo it.

The following example displays the full_address, phone and email fields under the linked post title. The email address is displayed as an email link, only if it is available:

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

<h4> <a href="<?php the_permalink(); ?>" title="<?php the_title_attribute(); ?>"> <?php the_title(); ?> </a> </h4> <?php $address = get_field('full_address'); $phone = get_field('phone'); $email = get_field('email'); if ( !empty( $address ) ) { echo '<p>' . $address . '</p>'; } if ( !empty( $email ) ) { $email_address = ' | <a href="mailto:' . $email .'">' . $email . '</a>'; } if ( !empty( $phone ) || !empty( $email_address ) ) { echo '<p>' . $phone . $email_address . '</p>'; }

Add marker content from ACF repeater fields

If you are using ACF repeater fields to index and display multiple locations per post, you may also want to retrieve content from other custom fields within the repeater field, to display in the marker/location’s info window.

If you try to do this with the Marker content setting, you’ll run into trouble, because there only post data can be retrieved, not the data for the separate locations within the repeater.

Fortunately, there is the facetwp_map_marker_args hook, with which you can set the marker content dynamically. Be aware that this overwrites anything you have set in the Marker content setting:

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

// Change 'map-repeaterfield' to the name of the ACF repeater field // Change 'map-repeaterfield-location' to the name of Google Map field within the repeater field. // This field should be chosen as the Map facet's 'Data source' setting. Make sure to choose the field under the “ACF” heading in the Data Source dropdown. // Change 'map-repeaterfield-name' to the name of another field within the repeater field // Add other fields or content as needed to $args['content'] add_filter( 'facetwp_map_marker_args', function( $args, $post_id ){ // Get the marker's 'lat' value. $latitude = $args['position']['lat']; // Get the post's repeater field values. $locations = get_field( 'map-repeaterfield', $post_id ); foreach ( $locations AS $location ) { // Check if the 'lat' value of one of the repeater locations matches the marker's 'lat' value. if ( (string)$location['map-repeaterfield-location']['lat'] == (string)$latitude ) { // If so, get the value of another field within that repeater field. // $args['content'] is the string representing the marker content. $args['content'] = $location['map-repeaterfield-name']; // Add more fields data to $args['content'] if needed. break; } } return $args; }, 10, 2 );

Display the post distance in the marker content

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 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.

The “Enable map filtering” button

When the “Enable map filtering” button is enabled, the map’s viewport will behave like a facet filter: the results in the listing will be instantly updated whenever the map is zoomed or panned by the user. So after clicking the button, then zooming and/or panning the map, only those results (markers) that are within the map’s current viewport are shown in the filtered listing. You can see this in action in the State Parks map demo.

To understand how map filtering works exactly, you can think of the rectangular viewport of the map acting as a facet filter. When map filtering is enabled, you’ll see that the map viewport’s bottom-left, and top-right lat/lng coordinates are present in FacetWP’s URL variables as the active values of the map facet. These coordinates are updated when manually panning or zooming the map, just like any other facet updates its URL variables when making selections.

Hide the “Enable map filtering” button

Currently, there is no setting to disable the ‘Enable map filtering’ button/functionality. If you don’t want this button to show, you can hide the button with CSS:

How to use custom CSS?

CSS code can be placed in your (child) theme's style.css file. Alternatively, you can add it manually between <style> tags in the <head> section, in your (child) theme's header.php file. You can also load it with a hook in your (child) theme's functions.php file, or in the Custom Hooks add-on. To load the code only on pages with facets, use the facetwp_scripts hook. To load it on all pages, use wp_head or wp_footer. Or you can use a code snippets plugin. More info

.facetwp-map-filtering { display: none; }

Translate the “Enable map filtering” and “Reset” button text

The text of the “Enable map filtering”, and “Reset” buttons can be changed with a setting.

Both texts can be changed or translated with a translation plugin, with the facetwp_i18n hook, or with a WordPress gettext filter:

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( 'gettext', function( $translated_text, $untranslated_text, $domain ) { if ( 'facetwp-map-facet' == $domain ) { if ( $translated_text == 'Enable map filtering' ) { $translated_text = 'Use map as filter'; } if ( $translated_text == 'Reset' ) { $translated_text = 'Disable map as filter'; } } return $translated_text; }, 10, 3 );

Enable map filtering on load of the map

It’s possible to enable map filtering by default on load of the map, with the following code.

However, be aware that having map filtering enabled will prevent other facets – like a Proximity facet – from automatically zooming or panning the map. This can be confusing for users, even more so if it is unclear that map filtering is enabled. So it’s not a good idea to combine this with hiding the “Enable map filtering” button.

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-loaded', function() { if ('undefined' === typeof FWP_MAP) { return; } var filterButton = $(".facetwp-map-filtering"); if (!filterButton.hasClass('enabled') && 'undefined' == typeof FWP_MAP.enableFiltering) { filterButton.text(FWP_JSON['map']['resetText']); FWP_MAP.is_filtering = true; filterButton.addClass('enabled'); FWP_MAP.enableFiltering = true; } }); })(fUtil); </script> <?php }, 100);

Reset the “Enable map filtering” button

When using a Reset facet or a User Selections facet to reset facets, Map filtering is not reset by default.

Add the following code to your (child) theme’s function.php to reset the “Enable map filtering” button when the Map facet is reset:

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($) { FWP.hooks.addAction('facetwp/reset', function() { $.each(FWP.facet_type, function(type, name) { if ('map' === type) { var $button = $('.facetwp-map-filtering'); $button.text(FWP_JSON['map']['filterText']); FWP_MAP.is_filtering = false; $button.toggleClass('enabled'); } }); }); })(fUtil); </script> <?php }, 100);

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, you can use this code.

Common issues with “Enable map filtering”

If the “Enable map filtering” button is not working, make sure you have not disabled auto_refresh. That also disables the map from auto-refreshing.

Hide the listing

The Map facet always needs a listing on the page to function properly. If you don’t want a visible listing, you can easily hide it with CSS:

How to use custom CSS?

CSS code can be placed in your (child) theme's style.css file. Alternatively, you can add it manually between <style> tags in the <head> section, in your (child) theme's header.php file. You can also load it with a hook in your (child) theme's functions.php file, or in the Custom Hooks add-on. To load the code only on pages with facets, use the facetwp_scripts hook. To load it on all pages, use wp_head or wp_footer. Or you can use a code snippets plugin. More info

.facetwp-template { display: none; }

Be aware that this will hide all FacetWP listings on all pages. If you need it to only hide on a specific page, you need to adapt the CSS selector. For example, to hide the listing only on the page with the ID 68436, you can use the page-id-68436 body class. Check the body classes of your page to find the correct class to use.

How to use custom CSS?

CSS code can be placed in your (child) theme's style.css file. Alternatively, you can add it manually between <style> tags in the <head> section, in your (child) theme's header.php file. You can also load it with a hook in your (child) theme's functions.php file, or in the Custom Hooks add-on. To load the code only on pages with facets, use the facetwp_scripts hook. To load it on all pages, use wp_head or wp_footer. Or you can use a code snippets plugin. More info

body.page-id-68436 .facetwp-template { display: none; }

Advanced map customizations

Don’t miss our page with advanced map customizations, among which:

Changelog

1.1

  • New visual code editor support for the `Marker Content` input

1.0.5

  • Improved button label `facetwp_i18n` support

1.0.4

  • New added settings to customize the "Reset" and "Enable map filtering" button labels

1.0.3

  • Fixed Prevent need to double-click custom markers
  • Fixed PHP8 deprecation notices

1.0.2

  • Fixed "Google Maps JavaScript API without a callback is not supported" JS error

1.0.1

  • New added `facetwp_gmaps_url` hook for customizing the GMaps script URL
  • Improved changed the admin UI label from "Other data source" to "Longitude" for clarification

1.0

  • Improved refactored the "Enable map filtering" logic slightly
  • Improved support changing the spiderfier init arguments
  • Improved updated (and patched) markerclusterer.js
  • Improved renamed "Default lat / lng" to "Fallback lat / lng / zoom" for clarification
  • Fixed cleared up google `addDomListener` console warnings
  • Fixed make sure lat / lng aren't empty during indexing

0.9.3

  • Improved FacetWP 3.9 compatibility

0.9.2

  • Improved removed jQuery dependency

0.9.1

  • New added "Ajax marker content" UI option to choose between ajax-loaded and preloaded markers
  • Fixed switched from `init` to `facetwp_init` hook to prevent timing issues

0.9

  • Improved significant performance boost (esp. for maps with many markers)

0.8.1

  • Fixed issue causing "maxZoom" JS error

0.8

  • Changed use `FWP()->filtered_post_ids` if available
  • Fixed prevent infinite refresh when "Enable map filtering" is on

0.7.1

  • Fixed only load posts if the "Marker Content" box is filled (performance boost)

0.7

  • New `facetwp_map/fit_bounds` JS hook to disable fitBounds and manually center the map
  • Improved immediately trigger a refresh when the "Enable filtering" button is clicked
  • Improved replaced GMaps "scrollWheel" setting with "gestureHandling"

See also

Last updated: August 19, 2024