Building Responsive Maps
with WordPress
Presented by

Alicia Duffy & Ben Bond
Norfolk, VA

Saturday, November 23, 13
Alicia Duffy
Designer & Front-End Developer
@bedsheet / aliciad@petaf.org

Ben Bond
PHP Developer
@benniestacks / bennyb@petaf.org

Norfolk, VA / www.peta.org

Saturday, November 23, 13
THE CATALYST:

peta2's Vegan Campus Map
Project
Requirements:
• Each school is a
WordPress post
• School provides
their address
• Color-coded map
by ranking
• Must be responsive
and mobile-friendly

Saturday, November 23, 13
Screenshot of custom post type + meta + taxonomy

Saturday, November 23, 13
Zip Code -> Coordinates
PHP
add_action('load-post.php', 'generic_map_admin_init');
add_action('load-post-new.php', 'generic_map_admin_init');!
function generic_map_admin_init() {
$screen = get_current_screen();
wp_register_script( 'googlemaps', 'http://
maps.googleapis.com/maps/api/js?
v=3&key=API_KEY&sensor=false' );
wp_register_script( 'field-geocode', 'field-geocode.js',
array( 'jquery', 'googlemaps' ), '', true );
! ! ! ! ! ! !
! ! !
if ( $screen->id == 'location' ) { ! !
!
! wp_enqueue_script( 'googlemaps' ); ! !
! wp_enqueue_script( 'field-geocode' );
}
} !

Saturday, November 23, 13
Find zip code meta, get coordinates
Javascript / field-geocode.js
jQuery.fn.codeAddress = function () {
! var geocoder = new google.maps.Geocoder();
! var zip = $'input[name="zip_code"]').attr('value');
! if(zip != '') {
! ! geocoder.geocode( { 'address': zip},
function(results, status) {
!
if (status == google.maps.GeocoderStatus.OK) {
var coordinates =
results[0].geometry.location.lng() + ", " +
results[0].geometry.location.lat();
$'input[name="coordinates"]').attr('value',
coordinates);
!
} else {
!
! alert("Geocode failed: " + status);
!
}
});
! }
}$(document).codeAddress();

Saturday, November 23, 13
After ZIP is entered, get coordinates
Javascript / field-geocode.js (..continued)
var typingTimer;
Text
var doneTypingInterval = 1000; // 1 second
!
$("input#zip_code").keyup(function(){
typingTimer = setTimeout(function() {
$(document).codeAddress();
}, doneTypingInterval);
});
$("input#zip_code").keydown(function(){
clearTimeout(typingTimer);
});!

Saturday, November 23, 13
LeafletJS

https://github.com/Leaflet/Leaflet

Open Source + HTML5 + Supports IE7+
Very Customizable

Saturday, November 23, 13
Add Leaflet to WordPress
wp_register_style( 'leaflet_style', 'leaflet-0.6.3.css',
'', '0.6.3' );
wp_register_script( 'leaflet-js', 'leaflet-0.6.3.js',
'', '0.6.3', true );
wp_register_script( 'leaflet-config', 'leafletconfig.js', '', '', true );
wp_enqueue_style( 'leaflet_style' );
// Register shortcode
add_shortcode('leaflet-map', 'generic_map_shortcode');
function generic_map_shortcode($atts) {
! wp_enqueue_script( 'leaflet-js' );
! wp_enqueue_script( 'leaflet-config' );
! echo '<div class="map-inner" style="width: 100%;
height: 500px;"><div id="map" style="width: 100%;
height: 100%;"></div></div>';
}
Saturday, November 23, 13
Basic Leaflet Map
Javascript / leaflet-config.js
var map = L.map('map').setView([51.505, -0.09], 13);
L.tileLayer('http://{s}.tile.cloudmade.com/API-KEY/1/256/
{z}/{x}/{y}.png', {
! attribution: 'Map data &copy; 2013 OpenStreetMap
contributors, Imagery &copy; 2013 CloudMade',
! key: 'API-KEY'
}).addTo(map);
! !
L.marker([51.5, -0.09]).addTo(map)
.bindPopup('A pretty CSS3 popup. <br> Easily
customizable.')
.openPopup();!

*See https://github.com/leaflet-extras/leaflet-providers
for more map choices.

Saturday, November 23, 13
Screenshot of custom post type + meta + taxonomy

Saturday, November 23, 13
How to map 1000+ posts?
Output all the posts as a geoJSON object
var locationMap = {
! "type": "FeatureCollection",
! "features": [{
"geometry": {
"type": "Point",
"coordinates": [-78.72000000000003, 35.81]
},
"type": "Feature",
"properties": {
"name": "WordCamp Raleigh",
"link": "http://localhost:8888/location/17/",
"symbol": "star"
},
"id": 1
}]
};

Saturday, November 23, 13
Generate the GeoJSON file
query_posts($query_string.'&order=DEC&posts_per_page=2000');
if( isset($_REQUEST['geo']) ) {
if( have_posts() ) {
while( have_posts() ) {
! ! the_post();
! ! $output[]=array(
! ! ! 'title' => get_the_title(),
! ! ! 'meta' => get_post_custom(),
! ! ! 'id'
=> get_the_id()
! ! );
}
}
}
$upload_dir = wp_upload_dir();
$theFile = $upload_dir['basedir'].'/geojson.php';
$expiration_date = strtotime("+1 day");
$now = strtotime("now");
Saturday, November 23, 13
Check File Expiration
$expiration_date = '.$expiration_date.';
$now = strtotime("now");
! !
if ( $expiration_date < $now ) {
! $refresh_file = file_get_contents("'.$callFile.'");
! if ( $refresh_file ) {
! ! echo file_get_contents("'.$cacheFile.'");
! }
} else {
//Display new cache file

Saturday, November 23, 13
foreach ($output as $key => $value) {
! $terms = get_the_terms($value['id'], 'location_symbol');
! $term = array_pop($terms);
! $fileContents .='
! ! {
! ! ! "geometry": {
! ! ! ! "type": "Point",
! ! ! ! "coordinates": [' . $value['meta']
['coordinates'][0] . ']
! ! ! },
! ! ! "type": "Feature",
! ! ! "properties": {
! ! ! ! "name": "' . $value['title'] . '",
! ! ! ! "link": "' . get_permalink($value['id']) . '",
! ! ! ! "symbol": "' . $term‐>name . '"
! ! ! },
! ! "id": ' . $count . '
! ! },
! ';
! ! $count++;
! }

Saturday, November 23, 13
Map each location
PHP
wp_register_script( 'geojson', get_site_url() . '/wpcontent/uploads/geojson.php', array( 'jquery' ), '', true );
Javascript / leaflet-config.js
L.geoJson(locationMap, {
! pointToLayer: function(feature, coordinates) {
! ! return L.marker(coordinates);
! },
! onEachFeature: onEachFeature
}).addTo(map);
function onEachFeature(feature, layer) {
! var popupContent = "<h4><a href='" +
feature.properties.link + "'>" + feature.properties.name +
"</a></h4>";
! layer.bindPopup(popupContent, {maxWidth:200});!
}

Saturday, November 23, 13
Screenshot of custom post type + meta + taxonomy

Saturday, November 23, 13
Customize Map Markers

• Awesome Leaflet Markers

https://github.com/lvoogdt/
Leaflet.awesome-markers

• Colorful & retina-proof markers for Leaflet
• Can use a taxonomy or meta field to
differentiate markers

• Uses web fonts for the icons

Saturday, November 23, 13
Icon-ize our Markers
PHP
wp_register_style( 'font_awesome', 'font-awesome.min.css');
wp_register_style( 'leaflet_markers', 'leaflet.awesome-markers.css');
wp_register_script( 'leaflet-awesome-markers', 'leaflet.awesome-markers.js', '',
'', true );

Javascript
L.geoJson(locationMap, {
!
pointToLayer: function(feature, coordinates) {
!
!
return L.marker(coordinates, {icon: L.AwesomeMarkers.icon({icon:
feature.properties.symbol, prefix: 'fa', markerColor:
randomColor(feature.properties.symbol)}) });
!
},
!
onEachFeature: onEachFeature
}).addTo(map);
function randomColor() {
!
var colors = Array('red', 'darkred', 'orange', 'green', 'darkgreen', 'blue',
'purple', 'darkpuple', 'cadetblue');
!
var color = colors[Math.floor(Math.random()*colors.length)];
!
return color;
}

Saturday, November 23, 13
Screenshot of custom post type + meta + taxonomy

Saturday, November 23, 13
Generic Map Plugin
A starting off point for making maps in WordPress
https://github.com/aliciaduffy/generic-map

•
•

Creates location post type and custom taxonomy

•

Generates an updated geoJSON object daily, w/
option to manually refresh

•

Adds a [leaflet-map] shortcode to easily drop the
map onto any page

Adds ZIP code and latitude/longitude custom meta
fields

Saturday, November 23, 13

Responsive Maps in WordPress

  • 1.
    Building Responsive Maps withWordPress Presented by Alicia Duffy & Ben Bond Norfolk, VA Saturday, November 23, 13
  • 2.
    Alicia Duffy Designer &Front-End Developer @bedsheet / aliciad@petaf.org Ben Bond PHP Developer @benniestacks / bennyb@petaf.org Norfolk, VA / www.peta.org Saturday, November 23, 13
  • 3.
    THE CATALYST: peta2's VeganCampus Map Project Requirements: • Each school is a WordPress post • School provides their address • Color-coded map by ranking • Must be responsive and mobile-friendly Saturday, November 23, 13
  • 4.
    Screenshot of custompost type + meta + taxonomy Saturday, November 23, 13
  • 5.
    Zip Code ->Coordinates PHP add_action('load-post.php', 'generic_map_admin_init'); add_action('load-post-new.php', 'generic_map_admin_init');! function generic_map_admin_init() { $screen = get_current_screen(); wp_register_script( 'googlemaps', 'http:// maps.googleapis.com/maps/api/js? v=3&key=API_KEY&sensor=false' ); wp_register_script( 'field-geocode', 'field-geocode.js', array( 'jquery', 'googlemaps' ), '', true ); ! ! ! ! ! ! ! ! ! ! if ( $screen->id == 'location' ) { ! ! ! ! wp_enqueue_script( 'googlemaps' ); ! ! ! wp_enqueue_script( 'field-geocode' ); } } ! Saturday, November 23, 13
  • 6.
    Find zip codemeta, get coordinates Javascript / field-geocode.js jQuery.fn.codeAddress = function () { ! var geocoder = new google.maps.Geocoder(); ! var zip = $'input[name="zip_code"]').attr('value'); ! if(zip != '') { ! ! geocoder.geocode( { 'address': zip}, function(results, status) { ! if (status == google.maps.GeocoderStatus.OK) { var coordinates = results[0].geometry.location.lng() + ", " + results[0].geometry.location.lat(); $'input[name="coordinates"]').attr('value', coordinates); ! } else { ! ! alert("Geocode failed: " + status); ! } }); ! } }$(document).codeAddress(); Saturday, November 23, 13
  • 7.
    After ZIP isentered, get coordinates Javascript / field-geocode.js (..continued) var typingTimer; Text var doneTypingInterval = 1000; // 1 second ! $("input#zip_code").keyup(function(){ typingTimer = setTimeout(function() { $(document).codeAddress(); }, doneTypingInterval); }); $("input#zip_code").keydown(function(){ clearTimeout(typingTimer); });! Saturday, November 23, 13
  • 8.
    LeafletJS https://github.com/Leaflet/Leaflet Open Source +HTML5 + Supports IE7+ Very Customizable Saturday, November 23, 13
  • 9.
    Add Leaflet toWordPress wp_register_style( 'leaflet_style', 'leaflet-0.6.3.css', '', '0.6.3' ); wp_register_script( 'leaflet-js', 'leaflet-0.6.3.js', '', '0.6.3', true ); wp_register_script( 'leaflet-config', 'leafletconfig.js', '', '', true ); wp_enqueue_style( 'leaflet_style' ); // Register shortcode add_shortcode('leaflet-map', 'generic_map_shortcode'); function generic_map_shortcode($atts) { ! wp_enqueue_script( 'leaflet-js' ); ! wp_enqueue_script( 'leaflet-config' ); ! echo '<div class="map-inner" style="width: 100%; height: 500px;"><div id="map" style="width: 100%; height: 100%;"></div></div>'; } Saturday, November 23, 13
  • 10.
    Basic Leaflet Map Javascript/ leaflet-config.js var map = L.map('map').setView([51.505, -0.09], 13); L.tileLayer('http://{s}.tile.cloudmade.com/API-KEY/1/256/ {z}/{x}/{y}.png', { ! attribution: 'Map data &copy; 2013 OpenStreetMap contributors, Imagery &copy; 2013 CloudMade', ! key: 'API-KEY' }).addTo(map); ! ! L.marker([51.5, -0.09]).addTo(map) .bindPopup('A pretty CSS3 popup. <br> Easily customizable.') .openPopup();! *See https://github.com/leaflet-extras/leaflet-providers for more map choices. Saturday, November 23, 13
  • 11.
    Screenshot of custompost type + meta + taxonomy Saturday, November 23, 13
  • 12.
    How to map1000+ posts? Output all the posts as a geoJSON object var locationMap = { ! "type": "FeatureCollection", ! "features": [{ "geometry": { "type": "Point", "coordinates": [-78.72000000000003, 35.81] }, "type": "Feature", "properties": { "name": "WordCamp Raleigh", "link": "http://localhost:8888/location/17/", "symbol": "star" }, "id": 1 }] }; Saturday, November 23, 13
  • 13.
    Generate the GeoJSONfile query_posts($query_string.'&order=DEC&posts_per_page=2000'); if( isset($_REQUEST['geo']) ) { if( have_posts() ) { while( have_posts() ) { ! ! the_post(); ! ! $output[]=array( ! ! ! 'title' => get_the_title(), ! ! ! 'meta' => get_post_custom(), ! ! ! 'id' => get_the_id() ! ! ); } } } $upload_dir = wp_upload_dir(); $theFile = $upload_dir['basedir'].'/geojson.php'; $expiration_date = strtotime("+1 day"); $now = strtotime("now"); Saturday, November 23, 13
  • 14.
    Check File Expiration $expiration_date= '.$expiration_date.'; $now = strtotime("now"); ! ! if ( $expiration_date < $now ) { ! $refresh_file = file_get_contents("'.$callFile.'"); ! if ( $refresh_file ) { ! ! echo file_get_contents("'.$cacheFile.'"); ! } } else { //Display new cache file Saturday, November 23, 13
  • 15.
    foreach ($output as$key => $value) { ! $terms = get_the_terms($value['id'], 'location_symbol'); ! $term = array_pop($terms); ! $fileContents .=' ! ! { ! ! ! "geometry": { ! ! ! ! "type": "Point", ! ! ! ! "coordinates": [' . $value['meta'] ['coordinates'][0] . '] ! ! ! }, ! ! ! "type": "Feature", ! ! ! "properties": { ! ! ! ! "name": "' . $value['title'] . '", ! ! ! ! "link": "' . get_permalink($value['id']) . '", ! ! ! ! "symbol": "' . $term‐>name . '" ! ! ! }, ! ! "id": ' . $count . ' ! ! }, ! '; ! ! $count++; ! } Saturday, November 23, 13
  • 16.
    Map each location PHP wp_register_script('geojson', get_site_url() . '/wpcontent/uploads/geojson.php', array( 'jquery' ), '', true ); Javascript / leaflet-config.js L.geoJson(locationMap, { ! pointToLayer: function(feature, coordinates) { ! ! return L.marker(coordinates); ! }, ! onEachFeature: onEachFeature }).addTo(map); function onEachFeature(feature, layer) { ! var popupContent = "<h4><a href='" + feature.properties.link + "'>" + feature.properties.name + "</a></h4>"; ! layer.bindPopup(popupContent, {maxWidth:200});! } Saturday, November 23, 13
  • 17.
    Screenshot of custompost type + meta + taxonomy Saturday, November 23, 13
  • 18.
    Customize Map Markers •Awesome Leaflet Markers https://github.com/lvoogdt/ Leaflet.awesome-markers • Colorful & retina-proof markers for Leaflet • Can use a taxonomy or meta field to differentiate markers • Uses web fonts for the icons Saturday, November 23, 13
  • 19.
    Icon-ize our Markers PHP wp_register_style('font_awesome', 'font-awesome.min.css'); wp_register_style( 'leaflet_markers', 'leaflet.awesome-markers.css'); wp_register_script( 'leaflet-awesome-markers', 'leaflet.awesome-markers.js', '', '', true ); Javascript L.geoJson(locationMap, { ! pointToLayer: function(feature, coordinates) { ! ! return L.marker(coordinates, {icon: L.AwesomeMarkers.icon({icon: feature.properties.symbol, prefix: 'fa', markerColor: randomColor(feature.properties.symbol)}) }); ! }, ! onEachFeature: onEachFeature }).addTo(map); function randomColor() { ! var colors = Array('red', 'darkred', 'orange', 'green', 'darkgreen', 'blue', 'purple', 'darkpuple', 'cadetblue'); ! var color = colors[Math.floor(Math.random()*colors.length)]; ! return color; } Saturday, November 23, 13
  • 20.
    Screenshot of custompost type + meta + taxonomy Saturday, November 23, 13
  • 21.
    Generic Map Plugin Astarting off point for making maps in WordPress https://github.com/aliciaduffy/generic-map • • Creates location post type and custom taxonomy • Generates an updated geoJSON object daily, w/ option to manually refresh • Adds a [leaflet-map] shortcode to easily drop the map onto any page Adds ZIP code and latitude/longitude custom meta fields Saturday, November 23, 13