Create Multiple Marker Map from ACF Google Map Location Field from a CPT

Here is a rundown on how to get a multiple marker Google map on a page that contains markers for a business dealer that has it’s own Custom Post Type (CPT). Each dealer has it’s own CPT with an individual map location marker and also another agnostic page that has all the dealers map markers in a multimarker map.

The guide uses Genesis hooks to insert content but can easily be adapted to other themes by using native theme hooks or shortcode I have added a shortcode alternative in the code snippets that can be added anywhere.

acf-multiple-marker-map-dealer

 

Set Up Your CPT

Create your CPT this example uses dealer. I use a CPT code gist I am familiar with for CPTs, a plugin alternative option which is excellent is WebDev CPTui.

Create ACF Field Group

acf-goole-map-field-type-location

Get ACF Pro and create a new field group, in the group add your required fields for the CPT and include the location field as a Google Map field type.

acf-field-group-dealer-cpt

Set the ACF field group to appear on the dealer CPT.

Get Your Google Map API

Get a Google API Map Key – click on Get a Key

Once you have the API add it via your functions.php

add_action('acf/init', 'my_acf_init');
/* Google Maps API */

function my_acf_init() {

acf_update_setting('google_api_key', 'xxxxxxx');
}

This is for ACF PRO – if you have regular ACF use this function instead.

Create your ACF Google Map Javascript Code

Add a JS file in your /js theme folder – this example uses dealer.js

(function($) {
/*
* new_map
*
* This function will render a Google Map onto the selected jQuery element
*
* @type function
* @date 8/11/2013
* @since 4.3.0
*
* @param $el (jQuery element)
* @return n/a
*/
function new_map( $el ) {
// var
var $markers = $el.find('.marker');
// vars
var args = {
zoom : 16,
center : new google.maps.LatLng(0, 0),
mapTypeId : google.maps.MapTypeId.ROADMAP
};
// create map
var map = new google.maps.Map( $el[0], args);
// add a markers reference
map.markers = [];
// add markers
$markers.each(function(){
add_marker( $(this), map );
});
// center map
center_map( map );
// return
return map;
}
/*
* add_marker
*
* This function will add a marker to the selected Google Map
*
* @type function
* @date 8/11/2013
* @since 4.3.0
*
* @param $marker (jQuery element)
* @param map (Google Map object)
* @return n/a
*/
function add_marker( $marker, map ) {
// var
var latlng = new google.maps.LatLng( $marker.attr('data-lat'), $marker.attr('data-lng') );
// create marker
var marker = new google.maps.Marker({
position : latlng,
map : map
});
// add to array
map.markers.push( marker );
// if marker contains HTML, add it to an infoWindow
if( $marker.html() )
{
// create info window
var infowindow = new google.maps.InfoWindow({
content : $marker.html()
});
// show info window when marker is clicked
google.maps.event.addListener(marker, 'click', function() {
infowindow.open( map, marker );
});
}
}
/*
* center_map
*
* This function will center the map, showing all markers attached to this map
*
* @type function
* @date 8/11/2013
* @since 4.3.0
*
* @param map (Google Map object)
* @return n/a
*/
function center_map( map ) {
// vars
var bounds = new google.maps.LatLngBounds();
// loop through all markers and create bounds
$.each( map.markers, function( i, marker ){
var latlng = new google.maps.LatLng( marker.position.lat(), marker.position.lng() );
bounds.extend( latlng );
});
// only 1 marker?
if( map.markers.length == 1 )
{
// set center of map
map.setCenter( bounds.getCenter() );
map.setZoom( 16 );
}
else
{
// fit to bounds
map.setCenter( bounds.getCenter() );
map.setZoom( 2 ); // Change the zoom value as required
//map.fitBounds( bounds ); // This is the default setting which I have uncommented to stop the World Map being repeated
}
}
/*
* document ready
*
* This function will render each map when the document is ready (page has loaded)
*
* @type function
* @date 8/11/2013
* @since 5.0.0
*
* @param n/a
* @return n/a
*/
// global var
var map = null;
jQuery(document).ready(function($){
$('.acf-map').each(function(){
// create map
map = new_map( $(this) );
});
});
})(jQuery);
view raw acf-js.js hosted with ❤ by GitHub

Original JS from ACF here. Mine is slightly modified.

Set Up ACF JS and API Dependencies

You need to enqueue the ACF JS and Goole Map API files for output to render.

<?php //<~ don't add me in
// Add in your functions.php
add_action( 'wp_enqueue_scripts', 'themeprefix_google_map_script' ); // Firing the JS and API
// Enqueue Google Map scripts
function themeprefix_google_map_script() {
wp_enqueue_script( 'google-map', get_stylesheet_directory_uri() . '/js/dealer.js', array( 'jquery' ), '1.0.0', true );
wp_enqueue_script( 'google-api', 'https://maps.googleapis.com/maps/api/js?key=AIzaSyDp1yayYfK-qOod7Kpt2x8u3Q8ZiuxMybc', null, null, true); // Add in your key
}
view raw acf-map-js.php hosted with ❤ by GitHub

Add a bit of CSS

.acf-map {
	width: 100%;
	height: 400px;
	border: #ccc solid 1px;
	margin: 20px 0;
}

/* fixes potential theme css conflict */
.acf-map img {
   max-width: inherit !important;
}

 

Display Single CPT Map Field

So first if you are also displaying the Google Map as a single map on the dealer CPT you’ll need to output the custom location map field and fire the JS and API files – here I am adding this code directly in the CPT template – so in my single-dealer.php

<?php //<~ don't add me in
add_action( 'genesis_entry_content', 'themeprefix_add_marker' ); // Hook in the field
// ACF Google Map Single Map Output
function themeprefix_add_marker() {
$location = get_field('location'); // Set the ACF location field to a variable
if( !empty($location) ) {
?>
<div class="acf-map">
<div class="marker" data-lat="<?php echo $location['lat']; ?>" data-lng="<?php echo $location['lng']; ?>">
<h4><a href="<?php the_permalink(); ?>" rel="bookmark"> <?php the_title(); ?></a></h4> <!-- Output the title -->
<p class="address"><?php echo $location['address']; ?></p> <!-- Output the address -->
</div>
</div>
<?php
}
}
view raw single-map.php hosted with ❤ by GitHub

 

Display Multiple Markers in one map for all CPT dealer posts

I have created a custom page page-all-dealers.php which I am outputting one map with all the markers using a while loop

<?php //<~ don't add me in
add_action( 'genesis_entry_content', 'themeprefix_add_marker_loop' );
// Output all dealers via a custom loop of the Dealer CPT and show the title and address field in the marker and link that to the Dealer CPT
function themeprefix_add_marker_loop() {
$args = array(
'post_type' => 'dealer',
'posts_per_page' => -1,
);
$the_query = new WP_Query($args);
echo "<div class='map-container'><div class='wrap'><div class='acf-map'>";
while ( $the_query->have_posts() ) : $the_query->the_post();
$location = get_field('location');
$title = get_the_title(); // Get the title
if( !empty($location) ) {
?>
<div class="marker" data-lat="<?php echo $location['lat']; ?>" data-lng="<?php echo $location['lng']; ?>">
<h4><a href="<?php the_permalink(); ?>" rel="bookmark"> <?php the_title(); ?></a></h4>
<p class="address"><?php echo $location['address']; ?></p>
</div>
<?php
}
endwhile;
echo '</div></div></div>';
wp_reset_postdata();
}
view raw all-markers.php hosted with ❤ by GitHub

The cool thing here is you can add what you want in between the .marker div and this will appear in the pop up when you click the marker, here I have added the_permalink() so when clicked will go to the original post!

Having a Zoomed out Map with Multiple Markers

If you have a more localised spread of locations, you may want to set the zoom level a bit more zoomed in. This is controlled in the javascript Google map code previously enqueued in the center_map function under the else statement for multiple markers – try a value between 10 – 14

function center_map( map ) {

	// vars
	var bounds = new google.maps.LatLngBounds();

	// loop through all markers and create bounds
	$.each( map.markers, function( i, marker ){

		var latlng = new google.maps.LatLng( marker.position.lat(), marker.position.lng() );

		bounds.extend( latlng );

	});

	// only 1 marker?
	if( map.markers.length == 1 )
	{
		// set center of map
	    map.setCenter( bounds.getCenter() );
	    map.setZoom( 16 );
	}
	else
	{
		// fit to bounds
		map.setCenter( bounds.getCenter() );
	   	map.setZoom( 11 ); // Change the zoom value as required
		//map.fitBounds( bounds ); // This is the default setting which I have uncommented to stop the World Map being repeated
	}

}

Shortcodes for Map Output

Single shortcode [themeprefix_single_marker]

<?php //<~ don't add me in
add_shortcode( 'themeprefix_single_marker', 'themeprefix_single_marker' ); // Create shortcode [themeprefix_single_marker]
// ACF Google Map Single Map Output
function themeprefix_single_marker() {
ob_start();
$location = get_field('location'); // Set the ACF location field to a variable
if( !empty($location) ) {
?>
<div class="acf-map">
<div class="marker" data-lat="<?php echo $location['lat']; ?>" data-lng="<?php echo $location['lng']; ?>">
<h4><a href="<?php the_permalink(); ?>" rel="bookmark"> <?php the_title(); ?></a></h4> <!-- Output the title -->
<p class="address"><?php echo $location['address']; ?></p> <!-- Output the address -->
</div>
</div>
<?php
}
return ob_get_clean();
}

 

Multiple shortcode [themeprefix_multiple_marker]

<?php //<~ don't add me in
add_shortcode( 'themeprefix_multiple_marker', 'themeprefix_multiple_marker' ); // Create shortcode [themeprefix_multiple_marker]
// Output all dealers via a custom loop of the Dealer CPT and show the title and address field in the marker and link that to the Dealer CPT
function themeprefix_multiple_marker() {
ob_start();
$args = array(
'post_type' => 'dealer',
'posts_per_page' => -1,
);
$the_query = new WP_Query($args);
echo "<div class='map-container'><div class='wrap'><div class='acf-map'>";
while ( $the_query->have_posts() ) : $the_query->the_post();
$location = get_field('location');
$title = get_the_title(); // Get the title
if( !empty($location) ) {
?>
<div class="marker" data-lat="<?php echo $location['lat']; ?>" data-lng="<?php echo $location['lng']; ?>">
<h4><a href="<?php the_permalink(); ?>" rel="bookmark"> <?php the_title(); ?></a></h4>
<p class="address"><?php echo $location['address']; ?></p>
</div>
<?php
}
endwhile;
echo '</div></div></div>';
wp_reset_postdata();
return ob_get_clean();
}

15 Comments

  1. Mauro on April 18, 2019 at 5:34 pm

    Sorry! I solved… I make an error in your zoom plugin.
    Thank you very much!

  2. Mauro on April 18, 2019 at 5:08 pm

    Very helpfull!
    I’ve only one question. I would like more zoom…
    Now your solution shows a world map… I would like to show only one city.
    How can I solve this problem?
    Many thanks!!

  3. Nathan Boaldin on March 19, 2019 at 3:46 pm

    Thank you so much for this.

  4. Alexandra on March 5, 2019 at 10:46 am

    So sad ! Thanks for the answer :)

  5. Alexandra on February 24, 2019 at 12:53 pm

    Hi, great this tutorial works ! Thanks you so much.
    Unfortunatly I can’t modify it to add cluster markers. I have followed other tuto , but I certainly did something wrong. Do you plan to purpose another tuto to add cluster ?

    • Neil Gowran on February 26, 2019 at 7:27 am

      Not at this point, not had a reason to – yet

  6. Andriy on February 16, 2019 at 6:19 pm

    It works great, thank a lot. I’m also trying to incorporate some custom style from Snazzy Maps. Having trouble with a adding those styles to your code. Where is the right place to add “styles: [my styles here]”

  7. Andriy on February 12, 2019 at 2:30 am

    Can’t get this to work. I created a custom post type “Store”, added the some posts with ACF Google Maps Location to it. Then created this custom page template:
    https://pastebin.com/807WEJ7v

    “This page isn’t working”
    Error 500

    Any ideas what I’m doing wrong?

    • Neil Gowran on February 12, 2019 at 2:59 am

      You have extra opening php tag above get_footer – and you are missing opening php tag above add_shortcode

      • Andriy on February 16, 2019 at 6:16 pm

        Thanks! It works!

  8. Ivan on January 22, 2019 at 4:56 pm

    Wow, that works really nice! Thanks a lot for sharing, I would not have built this so nicely myself :]

  9. Jesse on December 13, 2018 at 7:16 pm

    This well-written and EXACTLY what I need, except I can’t get it to work. Is it outdated at this point? I’m running WordPress 5.0.

    • Neil Gowran on December 28, 2018 at 9:47 am

      No it’s still valid – I have updated the code to make it easier – I am using it on WP5.0 sites

  10. Greg on February 4, 2018 at 10:55 am

    Thanks for this tutorial. Would be nice if you can share code for the search function :)

    • Dave on June 21, 2018 at 12:58 pm

      I was also hoping to see that, but I agree… great tutorial.

Leave a Comment