Is there a way to display all my posts on a single Google Map?

I’d like to “geotag” all my posts and display them on a single Google map.

1
1

Can do this without any plugin, you need only the Google Maps API.

Please note that if you plan to have 20 markers or more on a single page, you have to geolocate posts using coordinates and not addresses.

To save coordinates from an address you can:

  1. manually use a service (something like this)
  2. call Google maps geocoding from WP admin when you create or update the post

How to implement the second option is not strictly related to the question, and I will not take it into account for my answer, but see this Maps API example to see how simple is retrieve coordinates from an address.

So I will assume in this answer that posts have a custom field ‘coords’ where coordinates are stored as a string of two comma separated values, someting like: '38.897683,-77.03649'.

I also assume that there is a page template saved in the file ‘page-google-map.php’.

Put the following code in functions.php

add_action( 'wp_enqueue_scripts', 'enqueue_gmap' );

function enqueue_gmap() {
    // script goes only in the map page template
    if ( ! is_page_template('page-google-map.php') ) return;

    wp_register_script( 'google-maps-api', '//maps.google.com/maps/api/js?sensor=false', false, false );
    wp_register_script( 'posts_map', get_template_directory_uri().'/js/mygmap.js', false, false, true );
    wp_enqueue_script( 'google-maps-api' );
    wp_enqueue_script( 'posts_map' );

    // use a custom field on the map page to setup the zoom
    global $post;
    $zoom = (int) get_post_meta( $post->ID, 'map_zoom', true );
    if ( ! $zoom ) $zoom = 6;

    $map_data = array( 
        'markers' => array(), 
        'center'  => array( 41.890262, 12.492310 ), 
        'zoom'    => $zoom,
    );
    $lats  = array();
    $longs = array();

    // put here your query args
    $map_query = new WP_Query( array( 'posts_per_page' => -1, ) );

    // Loop
    if ( $map_query->have_posts() ) : 
        while( $map_query->have_posts() ) : $map_query->the_post();
            $meta_coords = get_post_meta( get_the_ID(), 'coords', true );
            if ( $meta_coords ) {
                $coords = array_map('floatval', array_map( 'trim', explode( ",", $meta_coords) ) );
                $title = get_the_title();
                $link  = sprintf('<a href="https://wordpress.stackexchange.com/questions/18644/%s">%s</a>', get_permalink(), $title);
                $map_data['markers'][] = array(
                    'latlang' => $coords,
                    'title'   => $title,
                    'desc'    => '<h3 class="marker-title">'.$link.'</h3><div class="marker-desc">'.get_the_excerpt().'</div>',
                );
                $lats[]  = $coords[0];
                $longs[] = $coords[1];
            }
        endwhile;
        // auto calc map center
        if ( ! empty( $lats ) )
            $map_data['center'] = array( 
                ( max( $lats ) + min( $lats ) ) /2,
                ( max( $longs ) + min( $longs ) ) /2 
            );
    endif; // End Loop

    wp_reset_postdata;
    wp_localize_script( 'posts_map', 'map_data', $map_data );
}

As you can see, in the map page template, I enqueue

  • the google map api script
  • a script called mygmap.js located in ‘js’ subfolder of the theme

also, looping the posts, I populate an array $map_data and using wp_localize_script I pass this array to the js in the page.

Now, mygmap.js will contain:

function map_initialize() {
    var map_div     = document.getElementById( 'map' );
        map_markers = map_data.markers,
        map_center  = new google.maps.LatLng( map_data.center[0], map_data.center[1] ),
        map_zoom    = Number( map_data.zoom ),
        map         = new google.maps.Map( document.getElementById( 'map' ), {
            zoom      : map_zoom,
            center    : map_center,
            mapTypeId : google.maps.MapTypeId.ROADMAP
        } );

    if ( map_markers.length ) {
        var infowindow = new google.maps.InfoWindow(),
            marker, 
            i;
        for ( i = 0; i < map_markers.length; i++ ) {  
            marker = new google.maps.Marker( {
                position : new google.maps.LatLng(
                    map_markers[i]['latlang'][0], 
                    map_markers[i]['latlang'][1]
                ),
                title    : map_markers[i]['title'],
                map      : map
            } );
            google.maps.event.addListener( marker, 'click', ( function( marker, i ) {
                return function() {
                    infowindow.setContent( map_markers[i]['desc'] );
                    infowindow.open( map, marker );
                }
            } )( marker, i ) );
        }
    }
};
google.maps.event.addDomListener( window, 'load', map_initialize );

The javascript is not WP related, and I put here only to show the use of map_data var. I’m not a js developer and the code is more or less entirely taken from here

That’s all. Just create the page template and insert a div with the id ‘map’, something like:

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

Of course the div can be styled with css, and note that also the info windows of markers can be styled, too: in the css use h3.marker-title to style the info window title and div.marker-desc to style the content.

Note that the map center is automatically calculated and if you want to change the default zoom you have to put a custom field ‘map_zoom’ in the page assigned to the map page template.

Hope it helps.

Leave a Comment