Meta box : trouvez des coordonnées GPS

Parmi les informations que l’on a fréquemment besoin d’associer à un contenu dans WordPress, il y a les coordonnées GPS.

Elles nous servent à situer un évènement, à placer un centre d’intérêt à proximité, à créer un annuaire géographique et plein de trucs encore…

Ce petit tutoriel va vous permettre de concevoir une meta box pour récupérer automatiquement ces données à partir d’une adresse.

Une carte google map avec une metabox WordPress
Une meta box pour récupérer des coordonnées GPS

Mais avant de voir ce que l’on peut faire avec, je vous propose de rentrer dans le gras… Commençons par coder cette petite boite ^^

Réalisation de la meta box

La structure de la meta box

La structure de base est très simple. Il nous faut un petit bout de code pour initialiser la metabox , avec la fonction add_meta_box(). Ici je défini qu’elle s’intitulera “Adresse” et qu’elle s’affichera dans la colonne de droite de la rubrique d’édition des articles.

Ensuite il faut la construire. Nous avons besoin de deux champs pour l’instant :

  1. Un textarea pour contenir l’adresse postale
  2. Un champ texte en disable pour afficher les coordonnées GPS retournées (… et pouvoir les contrôler)

// Initialisons la Metabox
add_action( 'add_meta_boxes', 'mes_metaboxes' );
function mes_metaboxes() {
  add_meta_box( 'metabox_adresse', 'Adresse', 'metabox_adresse', 'post', 'side', 'core' );
}

// Construisons la Metabox
function metabox_adresse( $post ){
  $adresse = get_post_meta( $post->ID, '_event_adresse', true );
  ?>
  <em>Renseignez une adresse postale précise</em>
  <textarea id="" style="width: 250px;" name="event_adress"><?php echo $adresse; ?></textarea>
  <input id="gps_coords" style="width: 250px;" type="text" name="event_coords" value="" disabled="disabled" />
  <?php
}

// sauvegarde de la metabox
add_action( 'save_post', 'save_adresse' );
function save_adresse( $post_id ) {
  if( isset( $_POST['event_adress'] ) ) {
    $adresse = wp_strip_all_tags( $_POST[ 'event_adress' ] );
    update_post_meta( $post_id, '_event_adresse', $adresse );
  }
}

Pour terminer, on nettoie et on sauvegarde la valeur de “adresse”.

Bien sûr il ne faut pas oublier de récupérer la précédente adresse enregistrée afin de l’afficher dans le textarea, sinon elle sera perdue à chaque rechargement.

Récupérer les coordonnées en PHP

Vous avez du remarquer, pour l’instant ma metabox n’a pas prévue de sauvegarder les coordonnées GPS. C’est tout simplement parce qu’il va falloir les récupérer avant de les enregistrer…

Pour ce faire j’utilise l’API geocode de Google Maps. Il suffit de lui envoyer une adresse URL-encodée pour qu’elle nous retourne un tas d’informations à son sujet, sous la forme souhaitée.

Faites donc le test en visitant cette URL : http://maps.google.com/maps/api/geocode/json?address=2+boulevard+jean+moulin+44000+nantes&sensor=false

Ça nous retourne un joli JSON, contenant entre autres les coordonnées GPS (dans results->geometry->location). Exactement ce qu’il nous faut !

Donc il faut ajouter, lors de la sauvegarde de la meta box, quelques lignes de PHP pour récupérer/sauvegarder tout ça.

add_action('save_post','save_adresse');
function save_adresse($post_id){
  // Code déjà présent ↓
  if( isset( $_POST[ 'event_adress' ] ) ) {
    $adresse = wp_strip_all_tags( $_POST[ 'event_adress' ] );
    update_post_meta( $post_id, '_event_adresse', $adresse );

    // Ajout ↓
    // 1 . je construit une fonction pour récup' les coords
    function get_coords($a){
      // je construit une URL avec l'adresse
      $map_url = 'http://maps.google.com/maps/api/geocode/json?address=' . urlencode( $a ) . '&sensor=false';
      // je récupère ça
      $request = wp_remote_get( $map_url );
      $json = wp_remote_retrieve_body( $request );

      // si c'est vide, je kill...
      if( empty( $json ) )
      return false;

      // je parse et je choppe la latitude et la longitude
      $json = json_decode( $json );
      $lat = $json->results[ 0 ]->geometry->location->lat;
      $long = $json->results[ 0 ]->geometry->location->lng;
      // je retourne les valeurs sous forme de tableau
      return compact( 'lat', 'long' );
    }

    // 2. je lance ma fonction, l'adresse en parametre
    $coords = get_coords( $adresse );
    // 3. si j'ai récupéré des coordonnées, je sauvegarde
    if( $coords != '' )
      update_post_meta( $post_id, '_event_coords', $coords );
  }
}

Il faut aussi penser à retourner les valeurs, dans la fonction metabox_adresse() qui ressemblera maintenant à ça :

function metabox_adresse( $post ){
  $adresse = get_post_meta( $post->ID, '_event_adresse', true );
  $coords = get_post_meta( $post->ID, '_event_coords', true );
  ?>
  <em>Renseignez une adresse postale précise</em>
  <textarea id="" style="width: 250px;" name="event_adress"><?php echo $adresse; ?></textarea>
  <input id="gps_coords" style="width: 250px;" type="text" name="event_coords" value="<?php echo $coords['lat'].' , '.$coords['long']; ?>" disabled="disabled" />
  <?php
}

Si vous testez cette metabox maintenant, tout devrait bien se passer. Elle est fonctionnelle. Cependant…

Renseigner manuellement les coordonnées GPS

… cependant si vous avez (comme à mon agence) des clients avec une adresse aussi précise que « D125 – 44120 – Vertou-les-boudins », il se peut que les coordonnées manquent de précisions.

Il faudrait alors, pour situer au mieux l’élément, pouvoir renseigner directement la latitude et la longitude.

Notre meta box ne nous le permet pas pour le moment (le champ Coordonnées est en disable, et de toute façon il est recalculé à chaque fois…). Nous allons remédier à ça en ajoutant une checkbox. Si celle-ci est coché, les coordonnées seront modifiables, et notre script sera shunté à la sauvegarde du contenu.

Le programme

  1. Ajouter un input:checkbox et son label
  2. Récupérer/sauvegarder la valeur de celui-ci (pour ne pas avoir besoin de le re-cocher à chaque fois)
  3. Construire un script qui ajoute ou enlève l’attribut disabled sur le input[event_coords]
  4. Shunter (ou pas) notre fonction de récupération des coordonnées GPS

Ce qui donne au final…

L’intégralité du code de la meta box, repris depuis le début :

// Initialisons la Metabox
add_action( 'add_meta_boxes', 'mes_metaboxes' );
function mes_metaboxes() {
  add_meta_box( 'metabox_adresse', 'Adresse', 'metabox_adresse', 'post', 'side', 'core' );
}

// Construisons la Metabox
function metabox_adresse( $post ) {
  $adresse = get_post_meta( $post->ID, '_event_adresse', true );
  $coords = get_post_meta( $post->ID, '_event_coords', true );
  $coordonnes_definies = get_post_meta( $post->ID, '_defined_coords', true );
  ?>
  <em>Renseignez une adresse postale précise</em>
  <textarea id="" style="width: 250px;" name="event_adress"><?php echo $adresse; ?></textarea>
  <input id="gps_coords" style="width: 250px;" type="text" name="event_coords" value="<?php echo $coords['lat'].' , '.$coords['long']; ?>" disabled="disabled" />

  <input type="checkbox" name="defined_coords" checked="checked" /> value="1" id="defined_coords"> <label for="defined_coords">Coordonnées définies manuellement</label>
  <script type="text/javascript">// <![CDATA[
    jQuery(document).ready(function($){
      var $gps_man = $('#defined_coords');
      function test_manual_coords(){
        if($gps_man.prop("checked")==true){
          $('#gps_coords').prop("disabled",false);
        }else{
          $('#gps_coords').prop("disabled",true);
        }
      }
      $gps_man.on('click',test_manual_coords);
      test_manual_coords();
    });

  // ]]></script>
  <?php
}

// sauvegarde de la metabox
add_action( 'save_post', 'save_adresse' );
function save_adresse( $post_id ) {
  if( isset( $_POST[ 'event_adress' ] ) ) {
    $adresse = wp_strip_all_tags( $_POST[ 'event_adress' ] );
    update_post_meta( $post_id, '_event_adresse', $adresse );
    function get_coords( $a ) {
      $map_url = 'http://maps.google.com/maps/api/geocode/json?address='.urlencode($a).'&sensor=false';
      $request = wp_remote_get( $map_url );
      $json = wp_remote_retrieve_body( $request );

      if( empty( $json ) )
        return false;

      $json = json_decode( $json );
      $lat = $json->results[ 0 ]->geometry->location->lat;
      $long = $json->results[ 0 ]->geometry->location->lng;
      return compact( 'lat', 'long' );
    }

    //je récupère ma checkbox
    $coordonnes_definies = $_POST[ 'defined_coords' ];
    if( $coordonnes_definies == 1 ) { //si checkbox cochée...
      // je sauvegarde sa valeur
      update_post_meta( $post_id, '_defined_coords', 1 );
      //je construis un tableu à partir des coordonnées de l'utilisateur
      $user_coords = explode( ',', trim( $_POST[ 'event_coords' ] ) );
      $coords = array( 'lat' => $user_coords[ 0 ], 'long' => $user_coords[ 1 ] );
      // j'update les coordonnées définies par l'utilisateur
      update_post_meta( $post_id, '_event_coords', $coords );
    }else{ // sinon...
      //j'update sa valeur
      update_post_meta( $post_id, '_defined_coords', 0 );
      // je fais le taf' normal
      $coords = get_coords( $adresse );
      if( $coords != '' )
        update_post_meta( $post_id, '_event_coords', $coords );
    }
  }
}

Voilà notre code tout beau tout propre qui nous permet au choix de trouver les coordonnées, ou bien de les rentrer manuellement.

Exemples d’utilisation

À partir de là on peut imaginer beaucoup d’utilisations. La plus basique est sans doute d’afficher une carte dans l’article, avec un curseur sur le lieu ciblé.

Mais on peut aussi imaginer pleins de trucs tordus, que ce soit juste pour afficher des infos géographiques relatives à un contenu, ou bien pour trier/afficher du contenu selon une donnée géographique.

Afficher une google map pour spécifier où à lieu un évènement

Pour afficher une petite google map, c’est plutôt simple, il suffit d’utiliser un shortcode.

Il reprend les coordonnées GPS relatives à l’article en cours, ainsi que l’adresse, puis il les insère dans le code iframe de Google Maps. Il s’utilise via [lieu].

add_shortcode( 'lieu', 'ma_google_map' );
function ma_google_map() {
  global $post;
  $coords = get_post_meta( $post->ID, '_event_coords', true );
  $adresse = get_post_meta( $post->ID, '_event_adresse', true );

  return '<iframe src="https://maps.google.fr/maps?q='.$adresse.'&num=1&t=v&ie=UTF8&z=14&ll='.$coords['lat'].','.$coords['long'].'&output=embed" frameborder="0" marginwidth="0" marginheight="0" scrolling="no" width="425" height="350"></iframe>
  <small><a style="color: #0000ff; text-align: left;" href="https://maps.google.fr/maps?q='.$adresse.'&num=1&t=v&ie=UTF8&z=14&ll='.$coords['lat'].','.$coords['long'].'&source=embed">Agrandir le plan</a></small>'
}

Une carte interactive

Je ne vais pas détailler le code ici (ce serait un peu long), mais on peut aussi, en reprenant l’idée du dernier article, créer un Custom Post Type « Lieux ».

Celui-ci supportera les champs habituels ainsi que notre meta box flambant neuve.

À partir de là on peut tout à fait imaginer concevoir une carte qui recense tous ces lieux. Par exemple un clic sur un marqueur irait ouvrir la page single de cet élément, affichant davantage d’informations…

Enfin bref. J’ai fait un petit plugin pour ça… mais là je déborde du thème des metaboxes donc on en reparlera peut-être une autre fois…

4 commentaires

  1. Par Rahe — Il y a 3 années
    Sympa comme tutoriel :)

    Par contre il serait pas mal d’utiliser add_query_arg() quand tu construis ton URL pour appeler Gmaps, ça te permettrait d’ajouter plus facilement des arguments si l’envie s’en fait ressentir ;).

    Sinon tu peux utiliser une partie de l’API google maps v3 pour trouver ton adresse sans avoir à recharger ta page elle te permet de faire du géocoding ( pas de clef gmaps à avoir à ma connaissance )
    https://developers.google.com/maps/documentation/javascript/reference#Geocoder et c’est assez simple à mettre en place, ça fait même la recherche des lieux

  2. Par Screenfeed — Il y a 3 années
    Joli l’accès au géocoding avec php, je ne connaissais pas la méthode (de mon côté j’ai opté pour la version JS).

    Bel article, merci :)

  3. Par Willy Bahuaud — Il y a 3 années
    Oui, c’est vrai… pas conpour le add_query_arg… je n’y avait pas pensé.
    Pour l’API geocoder en JS j’ai déjà testé un peu. C’est vrai qu’elle fonctionne super bien, j’aurais pu l’utiliser ici pareil.

    j’utilise aussi celle en javascript la plupart du temps. Ici le php me semblait plus adapté, mais à y repenser… je sais pas… peut importe je crois.

  4. Par Screenfeed — Il y a 3 années

    Ta version en php est peut-être plus simple que via JS. Perso j’avais opté pour JS parce que je n’avais pas envie d’intégrer toute un framework php lourd, mais tu viens de démontrer qu’on peut s’en passer et faire ça simplement.
    Au final ce sera une question de gout et/ou de connaissance des méthodes respectives.

Commenter