Automatisch Google Maps kaartje bij een WordPress post

Google Map

Zou het niet mooi zijn om bij het invoeren van een bericht in WordPress ook een bijbehorend adres in te voeren, waarna op de website automatisch een kaartje van Google Maps wordt getoond, inclusief een marker naar het adres. Zo kun je bij een bericht of pagina aan de bezoeker meteen een routekaartje laten zien.

Zoals onderaan de pagina van Modevakschool Avanti op de WordPress site Modevakschool.net of zoals bij de adresgegevens van BS Sennenhonden op Doggo.nl

Google geeft gelukkig veel mogelijkheden om dit te maken en te automatiseren. Hierbij de beschrijving van de stappen die je kunt uitvoeren als je zelf toegang hebt tot de programmatuur en de database. Geef een gil in de comment section below als je behoefte hebt aan een kant en klare plugin. Bij veel belangstelling zal ik er een maken.

[UPDATE]: Plugin is klaar en te downloaden op: RRWD Single Google Map WordPress plugin

De opzet en volgorde

  • Per post kun je bij de “extra velden” (custom fields) een adres ingeven, bijvoorbeeld
    Saal van Zwanenbergweg 11, 5026 RM, Tilburg, Nederland
    Maar 5026 RM, Nederland kan ook. Hoe gedetailleerder het adres, hoe nauwkeuriger de geo-coördinaten.
  • Na opslaan of wijzigen van het bericht worden bij Google de geografische coördinaten opgehaald en in de database gezet.
  • Als een bezoeker het bericht bekijkt, worden de geo-coördinaten uit de database gevist en het kaartje gemaakt. Geen coördinaten, geen kaarten. Anders wel dus.

Stapsgewijs heb ik dat als volgt opgezet:

1. Maak in de MySQL database een tabel aan prefix_geo

Vul voor prefix de waarde in van je WordPress installatie, in mijn voorbeeld is dat wp.

CREATE TABLE IF NOT EXISTS `wp_geo` (
`geo_id` int(11) NOT NULL auto_increment,
`post_id` int(11) NOT NULL,
`geo_latitude` varchar(255) NOT NULL,
`geo_longitude` varchar(255) NOT NULL,
PRIMARY KEY  (`geo_id`)
) ENGINE=MyISAM;

Hierin worden per post de latitude en longitude opgeslagen die Google Maps gebruikt om het kaartje te maken.

2. Conversie adres naar coördinaten (admin-gedeelte)

Bij het opslaan van het bericht wordt het custom field ‘address” uitgelezen in de functie mvs_save_post en het adres omgezet naar geo-coordinaten via de functie mvs_get_coordinates_form_address en deze worden in de database geschreven. De functies worden aangeroepen met de add_action hook save_post.

Voeg hiervoor aan functions.php de volende code toe:

// set up hooks for WordPress
add_action( 'save_post', 'mvs_save_post' );

function mvs_save_post($post_id) {
  global $wpdb;
  global $table_prefix;
  $coordinatenArray= array();
  unset($my_custom_field);
  unset($geo_id);

  // get addresss form custom field
  $my_custom_field =  get_post_meta($post_id, 'address', true);

  // if found: add or update
  if ($my_custom_field !="") {
    // convert address into geo coordinates
    $coordinatenArray = mvs_get_coordinates_form_address($my_custom_field);
    $geo_latitude = $coordinatenArray[0];
    $geo_longitude = $coordinatenArray[1];

    // find record for this post in database
    $geo_id = $wpdb->get_var($wpdb->prepare("SELECT geo_id FROM ".$table_prefix."geo WHERE post_id='$post_id'"));
    if ($geo_id) {
      // update geo-coordinates in database
      $result = $wpdb->query( "UPDATE ".$table_prefix."geo SET geo_latitude= '$geo_latitude', geo_longitude= '$geo_longitude' WHERE geo_id='$geo_id'") or die(mysql_error());
    } else {
       // insert geo-coordinates in database
       $result = $wpdb->query( "INSERT INTO ".$table_prefix."geo VALUES (NULL, '$post_id', '$geo_latitude', '$geo_longitude')") or die(mysql_error());
    }
  }  else {    // if not found delete if found
     // find geo-coordinates for this post in database
     $geo_id = $wpdb->get_var($wpdb->prepare("SELECT geo_id FROM ".$table_prefix."geo WHERE post_id='$post_id'"));
     // delete geo-coordinates in database if found
     if($geo_id) $result = $wpdb->query("DELETE FROM ".$table_prefix."geo WHERE geo_id='$geo_id'") or die(mysql_error());
  }
}

function mvs_get_coordinates_form_address($adres, $timeout=10){
  // Roep Google Maps aan met het adres en de soort output
  $adres = urlencode($adres);
  $url = "http://maps.google.com/maps/geo?q=".$adres."&output=xml";

  // defineer een header
  $parts = parse_url($url);
  $host = $parts['host'];
  $path = $parts['path'];
  $query = $parts['query'];
  $header = "GET $path"."?"."$query HTTP/1.0\r\n";
  $header .= "Host: $host\r\n";
  $header .= "User-Agent: {$_SERVER['SERVER_NAME']}{$_SERVER['REQUEST_URI']} - RRWD\r\n\r\n";

  // open socket naar Google en lees output in
  if (gethostbyname($host) != $host) {
    $socket = @fsockopen($host, 80, $errno, $errstr, $timeout);
    if ($socket) {
      fwrite($socket, $header);
      unset($http_response);
      while (!feof($socket)) {
        $http_response .= fread($socket, 256);
      }
      fclose($socket);
      if (strpos($http_response, "200 OK")) {
        // mik de header weer weg
        $pos1 = stripos($http_response, "<?xml");
        $http_response = substr("$http_response",$pos1);
        // lees de xml in en pik de coordinates eruit
        $xml = new SimpleXMLElement($http_response);
        $coordinatenArray = array();
        $coordinaten =  $xml->Response->Placemark->Point->coordinates;
        $coordinatenArray = explode(",", $coordinaten);
        return $coordinatenArray;
      }
    }
  }
}

3. Kaartje bij het bericht tonen (uitvoer-gedeelte)

In de header van het bericht worden twee JavaScripts aangeroepen. Een extern script van Google om het kaartje aan te roepen en een intern script met de gegevens over het kaartje.

Via de hook wp_head worden de scripts in de head sectie van de single.php gezet.
de functie mvs_get_gingle_google_map haalt de geo-coördinaten van het bericht op. De functie mvs_get_single_google_map_js en schrijft de javascript om het kaartje te vullen met de benodigde gegevens en functie mvs_body_js voegt de onload toe aan de body-tag voor de JavaScripts.

Voeg hiervoor aan functions.php de volende code toe:

add_action('wp_head', 'mvs_get_single_google_map_js');
function mvs_get_single_google_map_js() {
  global $wpd;
  $coordinatenArray= array();
  if (is_single()) {
    $coordinatenArray = mvs_get_single_google_map();
    if ($coordinatenArray[0]) {
      ?>
      <script type="text/javascript" src="http://maps.google.com/maps/api/js?sensor=false"></script>
      <script type="text/javascript">
      function initialize() {
        var myLatlng = new google.maps.LatLng(<?php echo $coordinatenArray[1].",".$coordinatenArray[0] ?>);
        var myOptions = {
        zoom: 12,
        center: myLatlng,
        mapTypeId: google.maps.MapTypeId.ROADMAP
      }
      var map = new google.maps.Map(document.getElementById("map_canvas"), myOptions);
      var marker = new google.maps.Marker({
          position: myLatlng,
          map: map,
          title:"<?php echo get_the_title(); ?>"
      });
      var contentString = '<div id="contentgm">'+
                          '<p><?php echo get_the_title(); ?></p>'+
                          '</div>';
      var infowindow = new google.maps.InfoWindow({
          content: contentString
      });
      google.maps.event.addListener(marker, 'click', function() {
        infowindow.open(map,marker);
      });
     }
     </script>
     <?php
    } else {
     ?> <script type="text/javascript">function initialize() {} </script> <?php
    }
  }
}
function mvs_body_js() {
  global $wpd;
  if (is_single()) echo "onload=\"initialize()\"";
}
function mvs_get_single_google_map() {
  global $wpd, $wpdb, $table_prefix, $post;
  $post_id = $post->ID;
  // kijk of er coordinaten zijn in het custom field
  $my_custom_field =  get_post_meta($post_id, 'address', true);
  if ($my_custom_field !="") {
  $geo_array[0] = $wpdb->get_var($wpdb->prepare("SELECT geo_latitude  FROM ".$table_prefix."geo WHERE post_id='$post_id'"));
  $geo_array[1] = $wpdb->get_var($wpdb->prepare("SELECT geo_longitude FROM ".$table_prefix."geo WHERE post_id='$post_id'"));
  return $geo_array;
  }
}

4. Kaartjes bij berichten opgeven

Voeg bij elk bericht waar je een kaartje wilt laten zien een extra veld toe bij “Extra velden” of “Custom fields”: address en geef als invoer het adres zoals Google dat wil hebben voor Google Maps, bijvoorbeeld: Saal van Zwanenbergweg 11, 5026 RM, Tilburg, Nederland

custom fieldsLees zonodig de korte handleiding voor het toevoegen van custom fields in WordPress op Hiranthi’s weblog.

Bronnen

Advertisements

Author: Rian Rietveld

WordPress Engineer focussing on accessibility

10 thoughts on “Automatisch Google Maps kaartje bij een WordPress post”

  1. Nice!

    Kan stap 1 niet vervangen worden door het opslaan van de longitude en latitude in een (hidden) custom field? Dan zit de informatie direct samen bij de post in de table en beperkt de aanpassing zich tot het bewerken van functions.php. Zo kan je de volledige functionaliteit in je theme inwerken.

    Waarom heeft deze oplossing geen google API key nodig? Bij andere tutorials die ik vond is dat meestal wel nodig.

    Like

    1. Beste Koen,
      Bedankt voor het compliment.

      Het invullen van de latitude/longitude in de custom fields kan ook, maar dan moet je deze voor elk adres eerst zelf opzoeken, en nu doet de software het voor je. Een plugin is in de maak, zodra die klaar is geef ik je een gil, de plugin doet dan verder alles voor je, zoals het aanmaken van de tabel. Je hoeft dan alleen de div voor het kaartje in de template-files te zetten

      Sinds versie 2 van de Google API hoef je geen key meer mee te geven. Zie http://code.google.com/intl/nl-NL/apis/maps/documentation/staticmaps/
      Scheelt weer 🙂

      Like

      1. Heb de code net aangepast en het werkt wel met custom fields. Opzoeken hoeft niet, kan op dezelfde manier gebeuren als jij nu doet, namelijk adres invullen en script doet de rest, met deze aanpassingen:


        // if found: add or update
        if (!empty($my_custom_field)) {
        // convert address into geo coordinates
        $coordinatenArray = mvs_get_coordinates_form_address($my_custom_field);
        get_post_meta($post_id, 'address', true);
        //update hiddencustom fields ipv database oplossing
        update_post_meta($post_id, '_geo_latitude', $coordinatenArray[0]);
        update_post_meta($post_id, '_geo_longitude', $coordinatenArray[1]);
        /** DIT DEEL WERD VERVANGEN DOOR DE CUSTOM FIELDS HIERBOVEN
        $geo_latitude = $coordinatenArray[0];
        $geo_longitude = $coordinatenArray[1];

        // find record for this post in database
        $geo_id = $wpdb->get_var($wpdb->prepare("SELECT geo_id FROM ".$table_prefix."geo WHERE post_id='$post_id'"));
        if ($geo_id) {
        // update geo-coordinates in database
        $result = $wpdb->query( "UPDATE ".$table_prefix."geo SET geo_latitude= '$geo_latitude', geo_longitude= '$geo_longitude' WHERE geo_id='$geo_id'") or die(mysql_error());
        } else {
        // insert geo-coordinates in database
        $result = $wpdb->query( "INSERT INTO ".$table_prefix."geo VALUES (NULL, '$post_id', '$geo_latitude', '$geo_longitude')") or die(mysql_error());
        } *** EINDE VERVANGING*/
        }
        else {
        // als custom field terug leeg is, delete de longitude en latitude
        update_post_meta($post_id, '_geo_latitude', '');
        update_post_meta($post_id, '_geo_longitude', '');
        /***
        // if not found delete if found
        // find geo-coordinates for this post in database
        $geo_id = $wpdb->get_var($wpdb->prepare("SELECT geo_id FROM ".$table_prefix."geo WHERE post_id='$post_id'"));
        // delete geo-coordinates in database if found
        if($geo_id) $result = $wpdb->query("DELETE FROM ".$table_prefix."geo WHERE geo_id='$geo_id'") or die(mysql_error());
        ***/
        }

        en onder deel 3 vvordt de functie mvs_get_single_google_map() dan dit:

        function mvs_get_single_google_map() {
        global $wpd, $wpdb, $table_prefix, $post;
        $post_id = $post->ID;
        // kijk of er coordinaten zijn in het custom field
        $my_custom_field = get_post_meta($post_id, 'address', true);
        if (!empty($my_custom_field)) {
        $geo_array[0] = get_post_meta($post_id, '_geo_latitude', true);
        $geo_array[1] = get_post_meta($post_id, '_geo_longitude', true);
        return $geo_array;

        Mijn enige probleem dat ik nu nog heb (cruciaal wel :)): de kaartje verschijnen niet! Ik zie in de header wel de javascript, maar verschijnt niet in de body. Ik gebruik een twenty ten child theme.

        Like

      2. Hoi Koen,

        Ja, zo kan het ook, mooie oplossing voor als je geen nieuwe tabel wilt gebruiken. 🙂
        Een nadeel vind ik wel dat je nu 3 custom fields ziet in plaats van 1 in de admin, en ik hou alles graag voor de gebruiker zo simpel mogelijk, niet teveel ballast, het CMS heeft nu al zoveel toeters en bellen.

        Wat betreft je tweede punt:
        Zet in het template bestand single.php op de plek waar je het kaartje wilt hebben een div met het id map_canvas, en zet in de body-tag in de header.php de call naar de functie mvs_body_js() erbij

        Like

  2. door een underscore aan de naam van de customfield toe te voegen wordt die onzichtbaar in het admin gedeelte, dus de _geo_latitude en _geo_longitude zie ik nu ook niet hoor 🙂 enkel als je in de database gaat zoeken vind je die nog.

    De instructies voor de template snap ik niet goed. Volgens mij is hier een stukje code verloren gegaan in de comment?

    Bedankt alvast!

    Like

  3. Koen:

    door een underscore aan de naam van de customfield toe te voegen wordt die onzichtbaar in het admin gedeelte, dus de _geo_latitude en _geo_longitude zie ik nu ook niet hoor enkel als je in de database gaat zoeken vind je die nog.

    Thanks 🙂 weer wat geleerd.

    Zet in het template bestand single.php op de plek waar je het kaartje wilt hebben een div met het id map_canvas, en zet in de body-tag in de header.php de call naar de functie mvs_body_js() erbij

    Like

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s