Matt Radford

Messing with links since <blink>

Embedding an Apple Map on a WordPress website using Mapkit JS

Published on 

Apple announced MapKit JS at WWDC recently, and there are already some great demos available:

But how can we integrate this with WordPress? I use Advanced Custom Fields Pro quite a lot, so my first thought was “How can I work MapKit JS into ACF and provide user-customisable maps to clients?” There is already a Google Maps field type in ACF, so perhaps I can piggyback on that? But I’m getting ahead of myself.

Pre-requisites

You thought it was just a matter of generating and adding an API key? Not so fast. Before you can embed a MapKit JS map, you will need:

  • an Apple developer account
  • your Apple developer Team ID
  • a maps identifier
  • a private key
  • a key identifier
  • a JWT (JSON Web Token)

Get an Apple Developer account if you don’t have one already. 9 to 5 Mac have a good guide to getting an account for free.

Then follow Apple’s Developer documentation here: https://help.apple.com/developer-account/#/dev4bb1cc12b?sub=devc240e1a83

To communicate with the MapKit JS, you’ll use a Maps private key to sign one or more developer tokens.

First register a Maps identifier to identify your app. Register a Maps identifier for each app that uses MapKit JS. Next create and download a private key with MapKit JS enabled and associate it with the Maps identifier. You can associate two keys with each Maps identifier.

Then get the key identifier (kid) to create a JSON web token (JWT) that you’ll use to communicate with the services you enabled.

Once you have a maps identifier, private key and key identifier, you can then generate a JWT.

Phew. This is starting to sound like a lot of work.

Especially as (ideally) Apple wants you to host a:

/services/jwt/ endpoint yourself. The endpoint should return a signed JWT-token which can then be used to authenticate against Apple endpoints.

See https://blog.rubeng.nl/getting-started-with-apples-mapkit-js/ for (many) more details. But as the author Ruben Gommers points out in that post, you can also generate a token that will last up to 10 years, and negate the need to run an endpoint for token generation. So that’s something. But you still have to generate the JWT.

[Update 2017-09-12] Ruben contacted me to point out he has created a tool to create long-lived tokens. It’s available here: https://mapkitjs.rubeng.nl

Thankfully, Thomas Schoffelen has already created MapKit JWT for PHP: https://github.com/includable/mapkit-jwt 🙂 You pass his function a private key, key identifier and maps identifier, and it returns a JWT. It’s this token that you use much like a Google Maps API key in order to authorise initialization of your map.

Now we are getting somewhere.

How do Mapkit JS embeds work?

Apple has demonstrated some embeds on its introductory page for developers: https://developer.apple.com/maps/mapkitjs/. Here’s the sample code for a simple embed:

<!DOCTYPE html>
        <html>
        <head>
        <meta charset="utf-8">
        
        <script src="https://cdn.apple-mapkit.com/mk/5.x.x/mapkit.js"></script>
        
        <style>
        #map {
            width: 100%;
            height: 600px;
        }
        </style>
        
        </head>
        
        <body>
        <div id="map"></div>
        
        <script>
        mapkit.init({
            authorizationCallback: function(done) {
                var xhr = new XMLHttpRequest();
                xhr.open("GET", "/services/jwt");
                xhr.addEventListener("load", function() {
                    done(this.responseText);
                });
                xhr.send();
            }
        });
        
        var Cupertino = new mapkit.CoordinateRegion(
            new mapkit.Coordinate(37.3316850890998, -122.030067374026),
            new mapkit.CoordinateSpan(0.167647972, 0.354985255)
        );
        var map = new mapkit.Map("map");
        map.region = Cupertino;
        </script>
        </body>
        </html>

Breaking this down, we have:

Link to the MapKit JS library

<script src="https://cdn.apple-mapkit.com/mk/5.x.x/mapkit.js"></script>

Define the map size

<style>
#map {
width: 100%;
height: 600px;
}
</style>

Give the map JS a target in the DOM

<div id="map"></div>

Initialise, set map parameters and attach it to the DOM element

 mapkit.init({
            authorizationCallback: function(done) {
                var xhr = new XMLHttpRequest();
                xhr.open("GET", "/services/jwt");
                xhr.addEventListener("load", function() {
                    done(this.responseText);
                });
                xhr.send();
            }
        });
        
        var Cupertino = new mapkit.CoordinateRegion(
            new mapkit.Coordinate(37.3316850890998, -122.030067374026),
            new mapkit.CoordinateSpan(0.167647972, 0.354985255)
        );
        var map = new mapkit.Map("map");
        map.region = Cupertino;

All in all, this looks a lot like the ACF documentation for adding a Google Map: https://www.advancedcustomfields.com/resources/google-map/.

WordPress integration

To get this integrated into a WordPress website I will:

  • add the MapKit JWT library
  • create a settings page to store Team ID, Key ID, Private Key and origin
  • store those in wp_options
  • generate a JWT and store that in wp_options as well
  • enqueue the MapKit JS CDN and custom map JS
  • initialise and display the map using a shortcode

And here’s the result:

Well it did show a live Apple Map. But I’ve deactivated the plugin now.

To do this I’ve created a plugin. It’s just a demo of a simple embed but does output an Apple Map 🙂  Even this was certainly more effort than using a Google Maps embed, and a lot more work than I was expecting. The next step will be to integrate custom markers, controlled using an ACF repeater. Any questions, please contact me on Twitter or raise an issue on Github.

You can get the plugin here: https://github.com/mattradford/apple-map-embed.