For years, I’ve geo-tagged my photos on my photography site, 75CentralPhotography. In fact, I one wrote about my geotagging workflow over there…the workflow is a bit outdated, but still works and is still relevant.
Recently, I was thinking about ways to enhance the browsing/user experience of the site, when I hit upon the idea of including a map with each photo showing where the photos was taken, since I already had all this GPS metadata embedded in each photo.
The first step was figuring out how to extract the GPS data from the photo’s embedded metadata. Luckily, the site is built on WordPress and WordPress is built using PHP. And PHP has a built-in function for extracting EXIF and IPTC metadata from a given image, exif_read_data(), so I just needed to pass in an image path and it would return the full image metadata, then parse that to extract the longitude and latitude of where the photo is geotagged, which I could then use to place the photo’s location on a map.
The code I used to get the GPS coordinates
Explained
- First, I needed to get the attachment ID for the photo. Since I only post one photo for each blog post, I knew I could use the handy catch_that_image() function that returns the id of the first image in a post when called from within a post:
- However, since catch_that_image() only returns the attachment ID and exif_read_data() needs a relative path to the image file, I needed to get the path to the file from the attachment ID. Luckily, WordPress offers the get_attached_file() function to do just that:
- Now that we have the relative path, we can finally pass that to the exif_read_data() PHP function to get the EXIF data back as arrays.
- Finally, we can extract the latitude and longitude from the EXIF data using a custom getGPS() function:
Now that we’ve successfully extracted the embedded GPS coordinate’s from the photo’s EXIF data, we can use the leaflet.js Javascript library to display it.
Before we can display the map, we do three things:
- Check to make sure that the photo actually has GPS data (as extracted in the previous step)
- Add these coordinates to custom post metadata in WordPress
- Check to see if a custom zoom level has been defined for a particular image in custom post metadata, else set the default zoom level of the map.
- We do this as for some photos, there may not be any contextual information available for a map to display, such as a photo taken in the middle of the ocean, which would result in a blank map.
The code that does this is some simple PHP:
Now that we have that, we can embed the leaflet.js map:
Explained
- First, we use an HTML <div> tag to set the display <div> for the map:
<div id=”mapid” ></div> - Next, we define the map and set the view and zoom level:
var mymap = L.map(‘mapid’, {scrollWheelZoom: false}).setView([<?php echo $lat ?>, <?php echo $lon ?>], <?php echo $zoom[0] ?>); - Add the zoom controls to the map:
L.control.scale({position: ‘topright’}).addTo(mymap); - Add the map tiles from a custom map in MapBox, as well as the custom icon or pin we created to pinpoint the photo’s location:
L.tileLayer(‘https://api.mapbox.com/styles/v1/75central/{id}/tiles/{z}/{x}/{y}?access_token=SECRET_TOKEN’, {
attribution: ‘Map data © <a href=”https://www.openstreetmap.org/copyright”>OpenStreetMap</a> contributors, Imagery © <a href=”https://www.mapbox.com/”>Mapbox</a>. Some photo locations may be <a href=”https://www.75centralphotography.com/location-information/”>inaccurate or obfuscated</a>.’,
maxZoom: 20,
id: ‘SECRET_ID’,
tileSize: 512,
zoomOffset: -1,
accessToken: ‘SECRET_TOKEN’
}).addTo(mymap);
var LeafIcon = L.Icon.extend({
options: {
iconSize: [50, 50],
iconAnchor: [22, 50],
popupAnchor: [-3, -76]
}
});
var greenIcon = new LeafIcon({iconUrl: ‘https://www.75centralphotography.com/assets/camera.png’});
window.dispatchEvent(new Event(‘resize’)); - And, finally, add the defined marker/pin to the map:
var marker = L.marker([<?php echo $lat ?>, <?php echo $lon ?>], {icon: greenIcon}).addTo(mymap);
And, voila, we have a map with the photo’s location on each photo on 75CentralPhotography: