I always liked sites that wrap in creative uses of maps, in particular, those which show Google Maps with Multiple Markers on the same map. Thankfully, the Google Maps API makes it easy (relatively) to pull posts and custom posts and display them on a custom Google Map.

In this tutorial, I’ll be sharing the code I used to create a custom Google Maps with Multiple Markers from a custom post type in WordPress, using the post’s featured image as a custom map marker. You can see a working example of what we’ll be doing in our maps demo site.

If you\’re too lazy to link over to the demo, here\’s an image of what we\’re doing:



What We’ll Cover in the Google Maps with Multiple Markers Tutorial

  • Custom script to hold the code to render the google map
  • Custom WordPress page template to populate Google Maps with multiple markers
  • Custom CSS to style map and markers


Housekeeping and Setup Notes

In this example, we’re using the popular Genesis Child Theme (AgentPress Pro – affiliate link*) with its recommended AgentPress Listings Plugin to add a custom post type for real estate listings. But rather than use the address fields available to us in that plugin we’re using Advanced Custom Fields Google Map Field. It’s much easier to use, easier to display single google maps, and easier to convert into geocode info usable with our multiple marker Google Map.

You can use the address fields already supplied by the listings plugin but you\’ll need to geocode them for use with Google Maps. You can view the Google Maps Geocoding documentation for information on how to wrap that into your code.

After reading it, I think you\’ll agree using something like ACF is easier. But that\’s personal preference. If you want to include this in your own plugin and don\’t want to offer ACF you\’ll need to go the geocoding route and work that code into your code.

Also, the code listed in this tutorial can work with just about any theme – it\’s not exclusive to the AgentPress Pro theme we use here. We chose that child theme because it does a nice job of showcasing listings, and this would be a good improvement for a real estate related theme – in my opinion.

If you wanted to use this code with other themes or even a basic WordPress installation it could be done by just moving around a few lines of code. That\’s beyond what we\’ll cover here, but send a note in comments and I\’ll try to point you in the right direction if I can.


Using the Google API

Before we start with the code you’ll need an API key from Google to make calls to the Google Maps API. It’s easy to get one and you can do that at the Google Developer Code Site.

You’ll need to login with a Google account. If you don’t have one you can stop reading now and go stick your head in the snow. Seriously.

Once logged-in you’ll be taken to the developer code console. If you’ve used this platform your projects will show up here and you’ll know what your’e doing and can thus skip this section. If not, just click the blue “Create Project” button.


You’ll create a project name and give it an id, and then agree to Google’s terms. You’ll have some options to boost the app, choose to Enable an API.

Google has a ton of APIs, they’re listed alphabetically, scroll down to “G” and enable the Google Maps APIs. There are a bunch. The one you’re really looking for is the Google Maps JavaScript API v3, but I like to enable them all just in case I decide to expand my code to offer different features sometime down the road. That way, they’re enabled and you don’t have to remember to come back to turn them on if you do add features that would require the expanded APIs.

Once that’s done, look over in the left admin panel underneath a section titled “APIs and Auth.” Select the link for CREDENTIALS. Then click the “Create New Key” button underneath the heading for Public API Access.

When the window pops asking you which key to use, choose Browser Key. When it asks you to enter information in the box about allowed referrers just leave that area blank and click the continue button.

You’ll then be shown your API credentials. You’re looking for the API Key, which will look something like this:


That’s not a real key, by the way, so don’t bother using it – it won’t make your map work. Without a key your map will NOT render, so do not skip this step. Google gives you the ability to get free keys with up to 1 million calls per day, which you’ll probably never hit, but you have to get the key for this to work – it goes into our code later.


Advanced Custom Fields Setup for Google Maps with Multiple Markers

The next step is to get Advanced Custom Fields (ACF) setup. This is relatively easy to do. ACF works on the freemium model – it has a free and a premium version. Thankfully, we can get everything done here using the free version of ACF in the repository.

Install ACF like any other plugin, activate it, and then look for a menu item in admin called “Custom Fields.” Click that.

Create a Google Map ACF Field Group

The base of operations in ACF is the field group. Since you’re just starting, click the blue button to create a new field group. The first field is the group title. We’ll enter Google Maps here.

You can set the location to any post type you like. In our case, we’re using the listings post type.

We leave the remaining settings as ACF sets them for us.

Now scroll back up and add a new field inside the field group. You’ll only need to edit the following fields:

Field Label: Google Maps
Field Name: google_maps
Field Type: Google Map (this is a select field)
Zoom: 14
Height: 400px

Here\’s what our ACF Google Maps settings look like:


Scroll to the top and click Publish to create your field group. This will put the google map meta box on the selected post. Our listing post now looks like this the image below. The Google Maps section is listed in the red box.


Remember, the AgentPress plugin adds an address field to this post type, but that’s not what we’re using for our map because it would require geocoding before it hits the google map code and we just don\’t want to mess with, especially when ACF does it for us.

Of course, you’ll have to go through a few sample posts and add addresses in those ACF google map fields so we have something to plot on our cool new map. Do that now.

Okay done?

Good. Let’s move on.


Create the Google Maps API Code

We’ve got the API key for the map, we’ve got the right plugins installed, and now we’ve got a few addresses entered. We’re ready to code.

Let’s start with the simple stuff: CSS.

It may seem weird we\’re doing the CSS first, but if we don\’t have the CSS in, when we view the map it will not render correctly, so let\’s just get this simple stuff done so that when we do finish the map code it will display correctly when we view our files on the front-end.

Google Maps CSS

Using your favorite FTP program or your IDE, create a CSS folder inside your child theme. Again, in our example, we’re using the AgentPress pro Child theme, and in it we create a CSS folder. Inside that folder, we create a CSS file called acfmap.css, with the following contents:


The first part of the CSS sets our map container width and height and gives it a slight border. The height will be required, otherwise the map will not display.

The second part ‘location-image’ has to do with the featured image we’ll be using in the marker. We’ll come to that shortly.

And the last part is a fix for a known issue that a specific element of the google maps location info windows have.

Okay, that’s out of the way, even thought we can’t really see anything yet.

Now let’s move onto the script.


Google Maps with Advanced Custom Fields JavaScript

The theme folder already has a js folder, so we don’t need to create one. If you\’re theme doesn\’t have a js folder you can create one now. Then create a JavaScript file called acfmap.js and put it in that folder. We’ll come back to this in a moment.

If you look at the Google Maps API, creating Google Maps with multiple markers can be done simply by breaking your code down into into the individual parts Google requires to render the different areas of the map.

Each map has a call to render the map itself somewhere in your html, then the map is populated with markers. In turn, the markers have specific data and styling so the map knows where to position the markers.

The map itself can be customized with colors, types, scale buttons, zooms, and other controls.

Then the info windows (boxes that display when someone clicks a marker) are built and then customized, and the whole thing sits on top of, and is rendered into, the specified container element in HTML.

The acfmap.js file we just created should have these contents:


The first function renders the google map with our map arguments. The arguments we can choose from are many. Again, see the Maps API code for all that you can do.

In our case, we’re zooming in at a level of 16, telling the map where to center itself, then telling it what type of map it should be with the mapTypeID. In our case, we’ve chosen a roadmap.

The next line tells Google Map not to zoom the map when we scroll while the map is active. That gets annoying on large maps that take up much of the screen real estate.

In the next section of the render function we’ve chosen to add some controls to the map in the form of MapTypeControls and ZoomControl. That\’s the stuff on the google map shown in the image below:



  • Line 43 actually creates the google map with our arguments and places it in the map variable.
  • Line 46 creates the marker array, line 50–54 adds the markers, and line 57 centers the map among the markers.
  • Lines 63–65 creates the info windows we’ll see when the map markers are clicked. We’ll get the actual content for those info windows from our HTML – in this case the page template we’ll be modifying.
  • Lines 81–114 handles the infobox events, in particular it does the following:
    • Line 84: Sets where the marker is placed on the map (according to Lat/Lng of marker from ACF field location)
    • Line 87: Sets the custom image used for the icon and stores it in a variable called $listImage
    • Lines 90–94: Creates the marker for each listing and sets the properties for each marker, including position on the map, which map to use, and the icon
    • Line 97: Adds the marker to the overall marker array
    • Lines 103–114: Controls how the info window reacts when a user clicks on it, or uses the X to close the window, or clicks off the window, or clicks on another marker, or back on the map

Centering the Map

Because we’re using multiple markers on the map we can’t just set the map center location, because the marker locations are dynamic.

  • Lines 134–159 will help us get the bounds of the marker locations and then set the center of the map to the geographic center of those locations. Thankfully, the google maps API has built-in functions for that based on our geocoded locations from the ACF maps fields.
  • Lines 149–153 says, if there is only 1 marker in the marker array, set the map center on that marker position and make the map zoom level 16. If there is more than 1 marker, the conditional moves to line 158, which says for multiple markers fit the map to the bounds of the markers and center on that.
  • Lines 176–186 renders the map when the page has loaded. The one thing to note here is line 178 which contains the container element of the map. You’d change that based on the class or id of the container you use to hold your google map. Here, we’re using .google-acfmap, but that can be anything you want. Whatever you decide to use, it will need to be mirrored in the html, which we’ll describe next.

Google Maps Markup

For the markers to render on the map we need to get the information from somewhere. Here, we’re getting it from the ACF google map custom meta inside the listing post type.

To display multiple markers we need to run through a loop. That’s pretty much done for us using the listing archive template in AgentPress, but we’re going to modify it slightly to get the address geocode information into the format we want.

Our entire archive-listings.php file is listed below.


This is an edited version of the normal archives-listing.php file that comes with AgentPress pro, which normally ends around line 96 of the file shown above. We’ve added lines 99–167, and an explanation of what that code does follows.

  • Lines 99 – 115: These are the scripts and styles we need to enqueue for the Google map to render properly on our site. The first is the custom CSS file we created. The second is the custom script file we described above. That will reside in the js folder that already exists on this child theme. The third is the call to the google maps API with your correct key inserted. Notice line 104 we’re making the google maps API a dependency of this file because it requires the google maps API to function properly.


  • Line 118+ is basically the code to add the marker markup. We create a custom loop to create the markers. We start by creating our class that will hold the google map. Here we use google-acfmap, but it can be anything you want. Just make sure to use that same element in the js file where noted, so it knows the HTML element on which to render the map.
  • On line 139, we run a simple loop that mirrors the loop used to get the listings used above by the listings plugin. That will ensure our markers are pulled only from the resultant listings generated by the original loop. This is important because AgentPress has a listing search functionality that uses this template, which can be placed in any area of the site via a widget. When people search on the front end they can filter the listing results which dumps us a list of listings displayed using the archive-listings.php template.
  • Line 143 populates a location variable with information from the ACF google map field on each listing.
  • Lines 149–156 is the html for each marker and its info window that will pop-up when we click on the marker. We use the .marker class, which we also call throughout the JavaScript file.

The marker itself needs just a latitude and longitude to be plotted on the map. We use the data-lat and data-lng elements to set latitude and longitude used to place each marker on the map. These elements are required by Google for the map to function properly. This is where ACF Google Maps field is superior to a simple address field as a text box in meta. ACF Google Maps field takes care of coding the lat/lng for us, and we pull that out of the location object by using $location[lat] and $location[lng].

Our map makes use of a custom image as the marker instead of the normal red pin that Google gives us, so we add a third element, data-icon, to hold the genesis featured image. For that, we created a separate image size in our functions file using this line of code:


Note: That code goes in the functions.php file, not here in the listings file we\’ve been discussing.

The Google Maps API requires a url to the image, so we use the featured image and pull the url using genesis_image with the arguments we need, namely ‘format’ to get the url of the image, and ‘size’ to call our special mapthumb image size.

The remainder of the html is what we see in the info window when we click a marker on the map. We are using a h4 heading and with the permalink and title to the particular listing. We call the genesis_image again to make the thumbnail image appear inside the info window as well. And then we echo out the string version of the address pulled as an element of the ACF field using $location[‘address’].

Make sure to save all your files and upload them to the correct folders. When all is said and done, my theme folder structure looks like this:


Remember, the listings plugins puts all the listings in a CPT archive /listings. Our demo site link is: http://acfmaps.demospring.com/listings/.

Your site might be something like www.YourSite.com/listings.  You may need to resave permalinks to be able to view the listings.

That’s it! You’ve got your map with multiple markers. Congratulations!

If you run into issues leave a note here and I\’ll try to help as I\’m able.

Like this article?