If you own a chain restaurant, coffee shop, store, or even a company that has different branches in different cities, then you may want to markup all of them on a single map, and show this network on your website. Meta Box will give you an easy way to find exactly what you need!

I created a map like that.

Listings on the map displayed at the same time

There are several listings on the map displayed at the same time. They are all the restaurants in a chain. Each one of them has a custom marker icon. When clicking on the marker, a popup is displayed with the restaurant name and address.

Video Version

Before Getting Started

To have each restaurant displayed in each place, we should save the information about each restaurant in a post of a custom post type, and, obviously, include its location. In this practice, I use custom fields for the location.

We should have the Meta Box core plugin to have a framework to create a custom post type for the listings and custom fields for the locations. You can download it directly from wordpress.org.

We also need some Meta Box extensions to have advanced features. Here are the extensions that we will use in this practice:

  • MB Custom Post Type: to create a custom post type for the listings;
  • Meta Box Builder: to have a UI in the back end to create custom fields easily;
  • MB Views (optional): to create a page template for displaying the listings on the map. In another way, you can add code to the theme’s files instead of using this extension. You can choose one of these ways which I’m going to provide you in this practice.

You can install them individually or just use Meta Box AIO for all.

Create a New Custom Post Type

Go to Meta Box and create a new post type for your listings. It can be restaurants, company branches, coffee shops, or fashion stores, etc.

Create a new post type for your listings

After publishing, you will see a new menu displayed. It's your new post type.

A new post type displayed on tha dashboard

Create Custom Fields

As mentioned, I’m going to create these three fields. Maybe you want more fields for more information, just add them as you go. But for demonstration purposes, I just use these ones.

The fields that I created for the practice

Go to Meta Box and create the fields.

Go to Meta Box and create the fields

Choose the Text field for the address.

Choose the Text field for the address

I’ll use the Open Street Maps field for the map.

Use the Open Street Maps field for the map

I have the Address field above where I input the location in text. To autocomplete the address when you type some text in the Address field and connect it with the map, we should fill in the ID of the Address field into the settings of the map field.

Fill in the ID of the Address field into the settings of the map field

Then, you can type some text to the Address field and choose one from the suggested list, or just click on the map, drag and drop the marker to set the location. To know more about this field type, please dig in our documentation for more detail.

For the marker icon, I choose a URL field to save the icon link.

After creating all the fields, move to the Settings tab. Remember to choose the Location as Post type and select Restaurant to apply these fields to it.

Choose the Location as Post type and select Restaurant to apply these fields

Go to the post editor, you will see the created custom fields.

The created custom fields

Display the Map and Listings

I’m going to have a page for the map only. In your case, you might want to add some content to the page, but I’ll skip it to keep this practice simple.

Create a new page

I’ll create a template for the page using both two ways:

  1. Adding code to the theme’s files: you should add some files to the theme’s folder as well as add code to several different files.
  2. Using the MB Views extension of Meta Box: just work on a place only for all. Besides that, the template will not be affected when you change the theme.

You should experiment yourself to find which makes sense to you.

Method 1: Add PHP Code to the Theme

Add Files

Go to your theme folder, and add a new PHP file for the page template. You can name it another way as you want.

Add a new PHP file for the page template

We’ll use some JavaScript for the map, so go to the JS folder, and add a new file.

Go to the JS folder

Add a new file

Add Template

Now, go to the created PHP file and add some code.

<?php
/**
* Template Name: Listing on a map
*/
get_header();
?>
<div id="map_ID" style="width: 100%; height: 600px"></div>
<?php get_footer(); ?>

Go to the created PHP file and add some code

In there:

get_header(); and <?php get_footer(); ?> are to load the header and footer just like any other pages in your theme.

This codes is to load the header and footer just like any other pages in your theme

<div id="map" style="width: 100%; height: 600px"></div>   is the main content area of the page, it simply shows a Div with a specific width and height. The Div will be used to display the map via this HTML ID: id="map" .

Show a Div with a specific width and height

Now, go to the created page. Choose the template that we have just created.

Choose the template that we have just created

Get Data

Next, to regulate which content will be displayed on the page, go to add code to the functions.php file.

Go to add code to the functions.php file

add_action( 'wp_enqueue_scripts', function() {
    if ( is_page_template( 'tbl-listings-map.php' ) ) {
        wp_enqueue_style( 'leaflet', 'https://unpkg.com/[email protected]/dist/leaflet.css', [], '1.5.1' );
        wp_enqueue_script( 'leaflet', 'https://unpkg.com/[email protected]/dist/leaflet.js', [], '1.5.1', true );

        wp_enqueue_script( 'list', get_parent_theme_file_uri( 'js/list.js' ), ['jquery', 'leaflet'], '1.0', true );

        $locations = [];
        $query = new WP_Query( [
            'post_type' => 'restaurant',
        ] );
        foreach ( $query->posts as $post ) {
            $location = rwmb_get_value( 'location', '', $post->ID );
            $location['title'] = $post->post_title;
            $location['address'] = rwmb_get_value( 'address', '', $post->ID );
            $location['icon'] = rwmb_get_value( 'icon_url', '', $post->ID );
            $locations[] = $location;
        }
        wp_localize_script( 'list', 'Locations', $locations );
    }
} );

Add code to the functions.php file

In there:

if ( is_page_template( 'tbl-listings-map.php' ) ) { is to check if the current page is using the created template, the below lines of code will be applied.

Check if the current page is using the created template, the below lines of code will be applied

'tbl-listings-map.php' is the name of the PHP file that I have just created, you should replace it with your own.

The name of the PHP file that I have just created

wp_enqueue_style( 'leaflet', 'https://unpkg.com/[email protected]/dist/leaflet.css', [], '1.5.1' );
wp_enqueue_script( 'leaflet', 'https://unpkg.com/[email protected]/dist/leaflet.js', [], '1.5.1', true );

I’m going to use the Leaflet library for CSS and JS to have the map with a beautiful look. So those lines are to enqueue the libraries.

Those lines are to enqueue the libraries

wp_enqueue_script( 'list', get_parent_theme_file_uri( 'js/list.js' ), ['jquery', 'leaflet'], '1.0', true );

This is to enqueue the created file in the JS folder.

Enqueue the created file in the JS folder

I created an array to store all the data about the locations.

The array to store all the data about the locations

$query = new WP_Query( [
'post_type' => 'restaurant',
] );

This line of code is the query to get data from the wanted post type. And, restaurant is the ID of the post type of the restaurants that I’m using.

The query to get data from the wanted post type

There will be multiple posts since there are multiple locations, so we have a loop.

We have a loop

Inside the loop, these are the associative arrays to get data of each element of the location.

The associative arrays to get data of each element of the location

We use the rwmb_get_value function to get data from the custom fields. 'location' , 'address' , and 'icon_url' are the ID of the fields.

The function to get data from the custom fields

rwmb_get_value('location','',post->ID) will return values from the Location field which is the Open Street Map. They include both the latitude and longitude.

This codes will return values from the Location field which is the Open Street Map

$post->post_title; is to get the title of the post, it’s also the restaurant name.

Get the title of the post, it’s also the restaurant name

rwmb_get_value( 'address', '', $post->ID ); is to get the address in text from the Address field.

Get the address in text from the Address field

rwmb_get_value( 'icon_url', '', $post->ID ); is to get the icon for the marker.

Get the icon for the marker

All of that data will be transferred to the created array by this: $locations[] = $location;

wp_localize_script( 'list', 'Locations', $locations ); is to pass the values from the $locations array to a JavaScript Object that has named Locations.

Pass the values from the $locations array to a JavaScript Object that has named Locations

We’ll use this object in the created JS file to display all the locations on the map.

Display Data Using JavaScript

We just got the data so far and haven't displayed them yet.

To do it, go to the created JS file to add code.

( function ( document, Locations, L ) {

    // Set the first location.
    var First_Location_Point = L.latLng( Locations[ 0 ].latitude, Locations[ 0 ].longitude );

    // Map options.
    var map_options = {
        center: First_Location_Point,
        zoom: 13
    };

    // Initialize the map.
    var mapObject = L.map( document.querySelector( '#map_ID' ), map_options );

    // Set tile layer for Open Street Map.
    var tileLayer = L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
        attribution: '© <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'
    });
        mapObject.addLayer( tileLayer );

        // // Show marker for each location.
        Locations.forEach( function ( location_on_map ) {
            // Marker options.
            var marker_options = {
                title: location_on_map.title,
                icon: L.icon( {
                    iconUrl: location_on_map.icon
                } )
        };
        var Location_Point = L.latLng( location_on_map.latitude, location_on_map.longitude );
        var marker = L.marker( Location_Point, marker_options ).addTo( mapObject );

        // Show name of the restaurant when click on the icon.
        marker.bindPopup( '<b>' + location_on_map.title + '</b><br>' + location_on_map.address ).openPopup();
    } );

} )( document, Locations, L );

Go to the created JS file to add code

( function ( document, Locations, L ) { is to get data from the created JavaScript object.

Get data from the created JavaScript object

When someone goes to the page and looks at the map for the first time, the map should be fixed at a specific point. So, I created a point via this line:

var First_Location_Point = L.latLng( Locations[ 0 ].latitude, Locations[ 0 ].longitude );

This point will be regulated based on the first set of values in the stored value string.

This point will be regulated based on the first set of values in the stored value string

This part is to set the options for the map.

Set the options for the map

The center point of the map shows for the first time when a user looks at it will be set as the first location.

Show for the first time when a user looks at it will be set as the first location

var mapObject = L.map( document.querySelector( '#map_ID' ), options );

This is to initialize the map. It also means to display the map. The map will be displayed in the place where this HTML ID was set. We did it in the php file for the page template.

Initialize the map

The map will have settings as the options as we set.

The map will have settings as the options as we set

This part is to set a tile layer, and copyright for the map.

Set a tile layer, and copyright for the map

The next part is the main one of this practice to show all the markers on the map at the same time.

The main one of this practice to show all the markers on the map at the same time

Locations.forEach( function ( location_on_map ) { } );

This is a loop to get all the data from this object.

A loop to get all the data from this object

I created two variables to store the data about each location.

I created two variables to store the data about each location

Then transfer all of them to the mapObject variable. This variable is the one we use to initialize the map above. It also means that we finished adding markers to the map.

Transfer all of them to the mapObject variable

To have a popup to show the detailed information of each marker when clicking on each one,  I have this:

marker.bindPopup( '<b>' + location_on_map.title + '</b><br>' + location_on_map.address ).openPopup();

A popup to show the detailed information of each marker when clicking on each one

Now, go to the page on the frontend. If nothing goes wrong, here's what you'll see.

Listings on a map page

For each marker, display a popup when click on the icon of each restaurant. The popup will show the title and address of the restaurant in detail.

In the case that you don’t want to touch the theme files, let’s go ahead to see another way with MB Views.

Method 2: Use MB Views

Go to Views in Meta Box and create a new template.

Go to Views in Meta Box and create a new template

Add Template

I’m going to add code to the Template tab. The code will be quite the same as what we added in both php files in the first method.

<link rel="stylesheet" href="https://unpkg.com/[email protected]/dist/leaflet.css" />
<div id="map" style="width: 100%; height: 600px"></div>
{% set args = { post_type: 'restaurant' } %}
{% set posts = mb.get_posts( args ) %}
{% set restaurantsArray = [] %}
{% for post in posts %}
{% set restaurantsArray = restaurantsArray|merge( 
      [
         { 
            'longitude':
            'latitude':
            'address':
            'title':
            'icon':
         }
      ] ) %}
{% endfor %}
<div class="restaurants-list" data-items='{{restaurantsArray|json_encode()}}'></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.7.1/jquery.slim.min.js"></script>
<script src="https://unpkg.com/[email protected]/dist/leaflet.js"></script>

Add code to the Template tab

You can see that there is not much difference in code between the two methods.

<link rel="stylesheet" href="https://unpkg.com/[email protected]/dist/leaflet.css" /> is to register the Leaflet CSS Library.

Register the Leaflet CSS Library

<div id="map" style="width: 100%; height: 600px"></div> is to display the map. We also use JavaScript later and use id='map_ID' of the map.

Display the map

We have {% set args = { post_type: 'restaurant' } %} to query data from the restaurant post type.

Query data from the restaurant post type

We use the mb.get_posts( args ) function to get posts.

The function to get posts

I’m also creating a new empty array to get data about the location from each post. You can name the array as any name as you want.

Create a new empty array to get data about the location from each post

And then, have a loop to get data from all the posts, and assign them to the array using this:
{% set restaurantsArray = restaurantsArray|merge( .

Have a loop to get data from all the posts, and assign them to the array

These are the keys of the data we’re getting from posts. They are saved in some fields of the post, so we will insert a corresponding field for each one of them.

Insert a corresponding field for each one of them

Click on the Insert Field button, and choose a field from the list.

Click on the Insert Field button, and choose a field from the list

The longitude is the data saved in the Open Street Map field. It is named Location, so choose it.

he longitude is the data saved in the Open Street Map field. It is named Location

There will be some options of the map for the output data, just choose Longitude.

Choose Longitude

After removing the curly braces, the generated code will be like this.

After removing the curly braces, the generated code will be like this

Do likewise for the latitude. Remember that these data are compulsory to locate a position on the map.

Insert the latitude data

Next, insert the Address fields.

Insert the Address fields

Add the Post title.

Add the Post title

And, we also have a field for marker icons.

We also have a field for marker icons

In the first method, WordPress has the wp_localize_script) function to convert data from PHP to JavaScript. But with MB Views, we do not use it. Instead of that, we use the class="restaurants-list" HTML class and transfer all the values from the restaurantsArray array to this class.

We use the class="restaurants-list" HTML class and transfer all the values from the restaurantsArray array to this class

This line of code is to declare the Leaflet JavaScript library.

This line of code is to declare the Leaflet JavaScript library

That’s all for the template.

Add JavaScript

Still in the view, move to the JavaScript tab, and use the code that we use in the JS file in the first way.

Use the code that we use in the JS file in the first way

There will be a difference in the first part since we use HTML class to store data:

(function (document, L) {

      const Locations = $('.restaurants-list').data('items')

})(document, L);

Use HTML class to store data

All the following lines of code are exactly the same with the script we use in the JS file in the first method. So, I’ll not dig into them anymore.

Apply Template to the Page

Go to the Settings section of the view, and set the type as Singular.

Go to the Settings section of the view, and set the type as Singular

Then add a rule to set the location as the created page.

Add a rule to set the location as the created page

Go to the page, the map and all the markers also displayed.

Listings on the map displayed at the same time

Last Words

There is not much difference between the two methods, I pointed to those ones that you can compare and see how we should do in both ways. In personal thinking and experience, I choose MB Views. So, what do you choose? Let’s try and enjoy each! If you want to suggest any topic for tutorials, feel free to leave a comment and keep track of our blog. Thanks!

Other case studies you might be interested in

  1. Create A Dynamic Landing Page in WordPress Using Custom Field
  2. Create a Filter to Find Hotels by Location
  3. Create an OTA Website Like Booking.com with Meta Box Plugin - P1: Create a Page to Introduce Hotel Rooms
  4. Create an OTA Website Like Booking.com with Meta Box Plugin - P2: Create Filters on the Archive Page
  5. Create an OTA Website Like Booking.com with Meta Box Plugin - P3: Create Filters for Single Hotel Pages
  6. Create Dynamic Favicon in WordPress using Meta Box plugin
  7. Create Posts Series in WordPress Using Meta Box
  8. Display The Latest Products Section - P2 - Using Meta Box and Elementor
  9. Display The Latest Products Section - P3 - Using Meta Box And Oxygen
  10. How to Add Custom Fields for WooCommerce - P2 - Using MB Views
  11. How to Add Custom Fields to Display Banners using Meta Box Plugin
  12. How to Add Guest Authors and Guest Posts - Using Meta Box
  13. How to Add Related Posts - Using Custom Fields
  14. How to Build a Hotel Booking Website Using Meta Box - P1
  15. How to Build a Hotel Booking Website Using Meta Box - P2 - Booking Page in Backend
  16. How to Build a Hotel Booking Website Using Meta Box - P4 - Booking Management Page
  17. How to Build a Hotel Booking Website Using Meta Box – P3 – Booking Page for Customer
  18. How to Create a Classified Ads Website using Meta Box
  19. How to create a FAQs page - P5 - Using Meta Box and Breakdance
  20. How to Create a Product Page - P2 - Using Meta Box and Oxygen
  21. How to Create a Product Page - P3 - Using Meta Box and Bricks
  22. How to Create a Product Page - P4 - Using Meta Box and Elementor
  23. How to Create a Product Page - P5 - Using Meta Box and Gutenberg
  24. How to Create a Product Page - P6 -Using Meta Box and Breakdance
  25. How to Create a Product Page - P7 - Using Meta Box + Kadence
  26. How to Create a Product Page - P8 - Using Meta Box and Brizy
  27. How to Create a Product Page - P9 - Using Meta Box and Divi
  28. How to Create a Product Page using Meta Box Plugin
  29. How to Create a Recipe - P2 - Using Meta Box and Oxygen
  30. How to Create a Recipe - P3 - Using Meta Box and Elementor
  31. How to Create a Recipe - P4 - Using Meta Box and Bricks
  32. How to Create a Recipe - P5 - Using Meta Box and Zion
  33. How to Create a Recipe - P6 - Using Meta Box and Brizy
  34. How to Create a Recipe - P7 - Using Meta Box and Breakdance
  35. How to Create a Recipe - P8 - Using Meta Box and Kadence
  36. How to Create a Recipe - P9 - Using Meta Box and Divi
  37. How to Create a Recipe with Meta Box Plugin
  38. How to Create a Simple Listing - P2 - Using Meta Box and Bricks
  39. How to Create a Simple Listing - P3 - Using Meta Box and Breakdance
  40. How to Create a Simple Listing - P4 - Using Meta Box and Elementor
  41. How to Create a Team Members Page - P1- Using Meta Box and Elementor
  42. How to Create a Team Members Page - P2 - Using Meta Box and Oxygen
  43. How to Create a Team Members Page - P3 - Using Meta Box and Bricks
  44. How to Create a Team Members Page - P4 - Just Meta Box
  45. How to Create a Team Members Page - P6 - using Meta Box and Breakdance
  46. How to Create a Team Members Page - P7 - Using Meta Box and Kadence
  47. How to Create a Video Gallery Page - P2 - Using Meta Box + Bricks
  48. How to Create a Video Gallery Page - P3 - Using Meta Box and Breakdance
  49. How to Create a Video Gallery Page - P4 - Using Meta Box + Elementor
  50. How to Create a Video Gallery Page - P5 - Using MB Views
  51. How to Create a Video Gallery Page - P6 - Using Meta Box and Zion
  52. How to Create a Video Gallery Page Using Meta Box + Oxygen
  53. How to Create ACF Flexible Content Field with Meta Box
  54. How to Create an Auto-Updated Cheat Sheet in WordPress
  55. How to Create an FAQs Page - P1 - Using Meta Box and Elementor
  56. How to create an FAQs page - P2 - Using Meta Box and Oxygen
  57. How to create an FAQs page - P4 - Using Meta Box and Bricks
  58. How to Create an FAQs Page - P6 - Using MB Views
  59. How to Create an FAQs Page - P7 - Using Meta Box and Divi
  60. How to Create an FAQs Page - P8 - Using Meta Box and Kadence
  61. How to Create an FAQs Page -P3- Using Meta Box
  62. How to Create Buttons with Dynamic Link using Custom Fields
  63. How to Create Category Thumbnails & Featured Images Using Custom Fields
  64. How to Create Download and Preview Buttons - P1 - Using Meta Box and Bricks
  65. How to Create Download and Preview Buttons - P2 - Using Meta Box and Oxygen
  66. How to Create Download and Preview Buttons - P3 - Using MB Views
  67. How to Create Download Buttons in WordPress - Using Custom Fields
  68. How to Create Dynamic Landing Page in WordPress - P1 - Using Meta Box and Elementor
  69. How to Create Dynamic Landing Page in WordPress - P2 - Using Meta Box and Bricks
  70. How to Create Menus for Restaurants - P1 - Using Meta Box and Elementor
  71. How to Create Menus for Restaurants - P2- Using Meta Box and Bricks
  72. How to Create Notification Using Custom HTML Field
  73. How to Create Online Admission Form for School or University
  74. How to Create Online Reservation Form for Restaurants using Meta Box
  75. How to Create Relationships - P1 - Using Meta Box and Oxygen
  76. How to Create Relationships - P2 - Using Meta Box and Bricks
  77. How to Create Relationships - P3 - Using MB Views
  78. How to Create Relationships - P4 - Using Meta Box and Breakdance
  79. How to Create Taxonomy Thumbnails & Featured Images - P2 - Using Meta Box and Oxygen
  80. How to Create Taxonomy Thumbnails & Featured Images - P3 - Using Meta Box and Bricks
  81. How to Create Taxonomy Thumbnails & Featured Images - P4 - Using MB Views
  82. How to Create YouTube Video Timestamps on WordPress Website - P1 - Using MB Views
  83. How To Display All Listings On A Map With Meta Box
  84. How to Display Author Bio in WordPress - P1 - Using Meta Box and Bricks
  85. How to Display Images from Cloneable Fields - P1 - with Gutenberg
  86. How to Display Images from Cloneable Fields - P2 - Using Meta Box and Oxygen
  87. How to Display Images from Cloneable Fields - P3 - with Elementor
  88. How to Display Images from Cloneable Fields - P4 - with Bricks
  89. How to Display Opening Hours for Restaurants - P1 - Using Meta Box + Gutenberg
  90. How to Display Opening Hours for Restaurants - P2 - Using Meta Box and Oxygen
  91. How to Display Product Variations - P1 - Using Meta Box and Gutenberg
  92. How to Display Product Variations - P2 - Using Meta Box and Oxygen
  93. How to Display Product Variations - P3 - Using Meta Box and Bricks
  94. How to Display the Dynamic Banners - P2 - Using Meta Box and Bricks
  95. How to Display The Latest Products - P5 - Using Meta Box and Bricks
  96. How to Display the Latest Products - P6 - using Meta Box and Breakdance
  97. How to Display the Latest Products - P7 - Using Meta Box + Kadence
  98. How to Display the Latest Products Section - P4 - Using Meta Box + Zion
  99. How to Display the Most Viewed Posts - P1 - using MB Views

13 thoughts on “How To Display All Listings On A Map With Meta Box

  1. Perfect!
    Do you have a plan to write about creating filters for this page also? So people can sort, search by fields, categories...?

  2. Hi! It looks like the OSM field no longer exists, is this correct?

    I would like to make use of another Maps solution that was not Google Maps.

    Thanks!

    1. Hi Steve,

      In the View, you can just add the HTML code

      <div id="map" style="width: 100%; height: 600px"></div>

      and assign to the specific page as the template.

  3. This works well for me. I'm wondering if there is a way to do this while using the leaflet.markercluster plugin so that the locations cluster when zoomed out. Anyone know about this?

  4. As many have commented over the past 3 years, it would be EXTREMELY helpful to be able to 1) filter/facet posts based on what is shown in the map when you pan and zoom and 2) filter the map's pins for what has been filtered by search/facet tools on the page.

    I recognize that this might be able to be done with 3rd party plugins, like facet wp, but I'd like to do it with just Meta Box. Some instructions, such as those you created here (https://metabox.io/create-ota-website-with-meta-box-p2/) would be very helpful.

    In fact, this is the single factor that is preventing me from moving to Meta Box from Toolset.

  5. Is it possible to build a Storelocator with Metabox?
    For this it would be necessary that you can search e.g. in a radius of 50 miles around a location and all stores are displayed. In addition, the possibility to select by filters, whether the stores are displayed, for example, Chinese food or Italian or Mexican...

    With the possibility that the stores themselves can then edit their own data using frontend editing, but only certain ones, the rest should be displayed reading, this would be the absolute best store locator on the market and a killer feature for using Metabox.

    Based on the comments, it seems that the feature promised four years ago has unfortunately not yet been implemented. Is it still in the planning stages? Anyway, it would be fantastic if it came in a timely manner.

Leave a Reply

Your email address will not be published. Required fields are marked *