In this advanced tutorial we’re going to walk through the process of creating a simple short code to display Google Maps. The concept is simple, but we’ll be using advanced techniques and tools for displaying our maps. All maps will be cached using transients and all requests to Google’s API services will be done with the WordPress HTTP API.

There are a few key techniques utilized to write this plugin:

1. WordPress Short Code API

Most likely you are already familiar with how to register short codes, but just in case you aren’t, the video walks you through how the short code, including several parameters, is setup.

2. Transients API

The WordPress transients API is a really simple caching system that lets you easily store data in the database. It’s great to use when doing remote requests (such as Google Maps) so that you are not forced to perform the request every time the page is loaded.

3. WordPress HTTP API

The WordPress HTTP API provides us with an excellent set of tools for performing remote requests. We can send data remotely, retrieve data remotely, and more. In the scope of this tutorial, we’re using it to send an address to Google and retrieve a set of longitude/latitude coordinates back as a response. This is by far one of my favorite APIs in WordPress.

The maps displayed with the short code we’re writing in this tutorial will look like this screenshot:

The complete code written in the video can be seen below. A further improved version of this plugin will be available in a few days, and it will be free to all premium members.

NOTE: Due to Google deprecating version 2 of their maps API, the code below has been updated and is slightly different than shown in the video.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
<?php
/*
Plugin Name: Simple Google Map Short Codes
Plugin URL: https://pippinsplugins.com/simple-google-map-short-codes
Description: Plain and simple Google Maps via a Short Code
Version: 1.0
Author: Pippin Williamson
Author URI: https://pippinsplugins.com
Contributors: mordauk
*/
 
 
 
/**
 * Displays the map
 *
 * @access      private
 * @since       1.0
 * @return      void
*/
 
function pw_map_shortcode( $atts ) {
 
	$atts = shortcode_atts(
		array(
			'address' 	=> false,
			'width' 	=> '100%',
			'height' 	=> '400px'
		),
		$atts
	);
 
	$address = $atts['address'];
 
	if( $address ) :
 
		wp_print_scripts( 'google-maps-api' );
 
		$coordinates = pw_map_get_coordinates( $address );
 
		if( !is_array( $coordinates ) )
			return;
 
		$map_id = uniqid( 'pw_map_' ); // generate a unique ID for this map
 
		ob_start(); ?>
		<div class="pw_map_canvas" id="<?php echo esc_attr( $map_id ); ?>" style="height: <?php echo esc_attr( $atts['height'] ); ?>; width: <?php echo esc_attr( $atts['width'] ); ?>"></div>
	    <script type="text/javascript">
			var map_<?php echo $map_id; ?>;
			function pw_run_map_<?php echo $map_id ; ?>(){
				var location = new google.maps.LatLng("<?php echo $coordinates['lat']; ?>", "<?php echo $coordinates['lng']; ?>");
				var map_options = {
					zoom: 15,
					center: location,
					mapTypeId: google.maps.MapTypeId.ROADMAP
				}
				map_<?php echo $map_id ; ?> = new google.maps.Map(document.getElementById("<?php echo $map_id ; ?>"), map_options);
				var marker = new google.maps.Marker({
				position: location,
				map: map_<?php echo $map_id ; ?>
				});
			}
			pw_run_map_<?php echo $map_id ; ?>();
		</script>
		<?php
	endif;
	return ob_get_clean();
}
add_shortcode( 'pw_map', 'pw_map_shortcode' );
 
 
/**
 * Loads Google Map API
 *
 * @access      private
 * @since       1.0
 * @return      void
*/
 
function pw_map_load_scripts() {
	wp_register_script( 'google-maps-api', 'http://maps.google.com/maps/api/js?sensor=false' );
}
add_action( 'wp_enqueue_scripts', 'pw_map_load_scripts' );
 
 
 
/**
 * Retrieve coordinates for an address
 *
 * Coordinates are cached using transients and a hash of the address
 *
 * @access      private
 * @since       1.0
 * @return      void
*/
 
function pw_map_get_coordinates( $address, $force_refresh = false ) {
 
    $address_hash = md5( $address );
 
    $coordinates = get_transient( $address_hash );
 
    if ($force_refresh || $coordinates === false) {
 
    	$args       = array( 'address' => urlencode( $address ), 'sensor' => 'false' );
    	$url        = add_query_arg( $args, 'http://maps.googleapis.com/maps/api/geocode/json' );
     	$response 	= wp_remote_get( $url );
 
     	if( is_wp_error( $response ) )
     		return;
 
     	$data = wp_remote_retrieve_body( $response );
 
     	if( is_wp_error( $data ) )
     		return;
 
		if ( $response['response']['code'] == 200 ) {
 
			$data = json_decode( $data );
 
			if ( $data->status === 'OK' ) {
 
			  	$coordinates = $data->results[0]->geometry->location;
 
			  	$cache_value['lat'] 	= $coordinates->lat;
			  	$cache_value['lng'] 	= $coordinates->lng;
			  	$cache_value['address'] = (string) $data->results[0]->formatted_address;
 
			  	// cache coordinates for 3 months
			  	set_transient($address_hash, $cache_value, 3600*24*30*3);
			  	$data = $cache_value;
 
			} elseif ( $data->status === 'ZERO_RESULTS' ) {
			  	return __( 'No location found for the entered address.', 'pw-maps' );
			} elseif( $data->status === 'INVALID_REQUEST' ) {
			   	return __( 'Invalid request. Did you enter an address?', 'pw-maps' );
			} else {
				return __( 'Something went wrong while retrieving your map, please ensure you have entered the short code correctly.', 'pw-maps' );
			}
 
		} else {
		 	return __( 'Unable to contact Google API service.', 'pw-maps' );
		}
 
    } else {
       // return cached results
       $data = $coordinates;
    }
 
    return $data;
}
  1. FxB

    Just an amazing tutorial, love the way you explain clearly, i’m really glad to be a member…

    • Pippin

      Great to hear, and great to have you as a member 🙂

  2. jgalea

    Excellent tutorial as usual Pippin, an amazing resource for all those who are learning how to write plugins.

  3. yellowhousedesign

    Great tut Pippin! Explanation is always key and was able to follow everything you did; found myself talking to my screen when I saw a syntax mistake 😉

    Not sure if you have it installed, but http://wbond.net/sublime_packages/package_control is a great add-on for Sublime – the WP add-on is pretty awesome-balls as well

    • Pippin

      I didn’t have that installed, but dang, that’s sweet. And yes, the WP add-on is fantastic!

  4. Antoine Divay

    Hello Pippin, thanks for the plugin, Is there any php code I can write into my single.php and display a map automatically with my address in the “echo $long_title;”.
    ”,
    ‘width’ => 700 ,
    ‘height’ => 480
    ));
    }

    ?>

    Thanks a lot for your help !

  5. Antoine Divay

    Does something like work to use your shortcode in my page ?
    ID, ’emls_property_address’, true);
    echo do_shortcode(‘[pw_map address=$meta]’);

    ?>

    THanks a lot for your help

    • Pippin

      Yes it does!

  6. orionrush

    You mention that this is going to be a downloadable plugin “in a few days”. Are plans still in the works for this? I assume you wanted to flush it out a bit. By the way, your fly through of the Transients API was very useful for me. Thanks!

  7. orionrush

    Pipin, any reason in particular you chose to use XML vs JSON in the wp_remote_get for coordinates? Most of the maps js I’ve worked with uses JSON so I was thinking of trying to convert what you’ve done just to learn.

    • Pippin

      No, that’s just the format I had available at the time. I personally prefer json.

    • Pippin

      I just updated the code since Google deprecated v2 of their API. Now it uses json 🙂

  8. orionrush

    Pipin, I was diggin into how you went about setting transients for this plugin and noted that in addition to lat, lag etc, you’re also gathering icon, formatted_phone_number, and webiste when you parse the json — I cant seem to get an address that returns any of these values, and I cant seem to find any documentation that specifically mentions these returns from the geocoding api – are these a hangover from V2 api or perhaps the places api?

    • Pippin

      They most likely are.

Leave a Reply