Créer une carte Google Map avec ACF (wordpress) : version 2

Comment Créer une carte Google Map avec ACF (wordpress) : version 2

A la suite du précédent post sur ACF et les cartes google Map, on va dans ce tuto pousser un peu plus loin pour obtenir ce genre de résultat:

acf-google-map

 

Au clic sur l’une des vignettes à droite, une popup s’ouvre sur le marqueur concerné.La liste à droite qui liste tous mes articles ou j’ai renseigné une adresse, a une hauteur fixe et est en mode overflow-y: scroll, ce qui signifie qu’on peut rajouter autant d’articles que souhaité, un curseur permet de faire défiler la liste

Au préalable, je vous invite à suivre le premier tuto sur le sujet , vous aurez ainsi les bases.
Je retranscris néanmoins tout le code ici

En complément, voici les sources sur lesquelles je me suis largement appuyé pour parvenir à ce résultat

La différence majeure, est que je ne crée pas ici de custom post type, j’utilise un seul champ additionnel, et j’utilise la version gratuite d’ACF. La carte finale est placée sur ma page d’accueil et non une page de custom posts.

Télécharger ACF

Première étape bien sûr, il faut télécharger ACF.

Créer une clé API

Pour faire fonctionner google map dans ACF, il faut une clé API.La procédure peut faire peur au début, mais il suffit de suivre les étapes indiquées ici

Démarrer avec ACF

Une fois le tout effectué, on peut aller dans les paramètres du plugin et créer nos custom fields.

Ici on va créer un simple champ additionnel que l’on va nommer google maps. Dans le backoffice, on clique sur l’onglet « ACF« , puis dans « groupe de champs« , on clique sur « ajouter« .

On donne au Titre du champ le nom de Google Maps, le Nom de champ se remplit tout seul, puis on sélectionne google map en Type de champ. Le reste on n’y touche pas.

acf-google-map

Au bas de la page on définit l’emplacement de ce nouveau champ additionnel. Pour mon exemple, je vais partir sur les articles normaux.

assigner-acf

La documentation ACF

Maintenant dans le code, pour que tout cela fonctionne il faut insérer certaines fonctions, selon les recommandations d’ACF.

Dans functions.php, insérer le code suivant



function my_acf_google_map_api( $api ){
$api['key'] = 'VotreCléAPI';
return $api;
}

add_filter('acf/fields/google_map/api', 'my_acf_google_map_api');

Ce code est nécessaire pour que la carte s’affiche.

( A partir de là, le code change par rapport au premier tuto ).

On crée ensuite un fichier js, qu’on nomme par exemple, google.js. A l’intérieur on insère le code suivant:

(function($) {

function render_map( $el ) {

// var
var $markers = $(document).find('.marker');

// vars
var args = {
zoom : 16,
center : new google.maps.LatLng(0, 0),
mapTypeId : google.maps.MapTypeId.ROADMAP,
scrollwheel: false,
mapTypeControlOptions: {
mapTypeIds: [google.maps.MapTypeId.ROADMAP]
}
};

// create map
var map = new google.maps.Map( $el[0], args);

// add a markers reference
map.markers = [];
// add markers
index=0;
$markers.each(function(){
add_marker( $(this), map, index);
index++;
});

// center map
center_map( map );

}

function add_marker( $marker, map, index ) {

// var
var latlng = new google.maps.LatLng( $marker.attr('data-lat'), $marker.attr('data-lng') );
var image = new google.maps.MarkerImage("http://localhost/virtual_v2/wp-content/themes/virtualtrip2017/img/map-marker.png", null, null, null, new google.maps.Size(25,30));

// create marker
var marker = new google.maps.Marker({
position : latlng,
map : map,
icon : image
});

// add to array
map.markers.push( marker );


// if marker contains HTML, add it to an infoWindow
if( $marker.html() )
{
$('#listdata').append('<div class= "linkage" id="p'+index+'">'+$marker.html()+'</div>'); // change html here if you want but eave id intact!!

$(document).on('click', '#p'+index, function(){
infowindow.open(map, marker);
setTimeout(function () { infowindow.close(); }, 3000);
});

// create info window
var infowindow = new google.maps.InfoWindow({
content : $marker.html(),
});

// show info window when marker is clicked
google.maps.event.addListener(marker, 'click', function() {

infowindow.open( map, marker );

});

}

}

function center_map( map ) {

// vars
var bounds = new google.maps.LatLngBounds();

// loop through all markers and create bounds
$.each( map.markers, function( i, marker ){

var latlng = new google.maps.LatLng( marker.position.lat(), marker.position.lng() );

bounds.extend( latlng );

});

// only 1 marker?
if( map.markers.length == 1 )
{
// set center of map
alert(bounds);
map.setCenter( bounds.getCenter() );
map.setZoom( 16 );
}
else
{
// fit to bounds
map.fitBounds( bounds );
}

}

// Call it


$(document).ready(function(){

$('.acf-map').each(function(){

render_map( $(this) );

});

});


})(jQuery);

On voit ici notamment par rapport à la documentation ACF, la modification de la fonction add_marker : on va voir plus bas l’explication du code.

L’appel aux scripts

Il faut ensuite relier tout ça, en allant chercher les scripts de google et notre fichier js.

Dans functions.php, à l’intérieur de votre fonction d’appel aux scripts, placez le code suivant :

wp_enqueue_script( 'google-map', 'https://maps.googleapis.com/maps/api/js?key=votreCléApi', array(), '3', true );
wp_enqueue_script( 'google', get_template_directory_uri() . '/js/google.js', array('google-map', 'jquery'), '0.1', true );

Comme on le voit dans le premier tuto, on a désormais un champ additionnel dans chaque page d’édition d’article, avec la carte google map; On crée donc plusieurs articles et on renseigne une adresse pour chaque article.

Afficher la carte sur une page dédiée

Maintenant, j’affiche la carte et tous les marqueurs avec le code suivant. Plutôt que d’utiliser une boucle, comme dans le tuto cité en exemple, j’utilise le même foreach que dans le premier tuto:   pour mon exemple, je place ce code dans le fichier home.php, mais on peut le mettre ailleurs.

<?php 
$post_objects = get_posts( array(
'post_type' => 'post',
'posts_per_page' => -1
));

if( !empty($post_objects) ): ?>
<?php
echo '<div class="locations"><div class="acf-map"></div>';
echo '<div id="listdata"></div><div id="newdiv">';
foreach($post_objects as $post){
setup_postdata($post);

$location = get_field('google_maps');
if( !empty($location) ):
printf( '<div class="marker" data-lat="%s" data-lng="%s">
<h4 class="title">%s</h4>
<div class="address"><i class="fa fa-map-marker" aria-hidden="true"></i> %s
<a href="" target="_blank" class="website" title="%s"></a>
</div>
</div>',
$location['lat'],
$location['lng'],
get_the_title(),
$location['address'],
get_the_title());


endif;
}
echo '</div></div>';

/* Restore original Post Data */
wp_reset_postdata();?>
<?php endif; ?>

L’explication du code

Au niveau de la structure de notre bloc, on a à l’intérieur d’une div englobante .locations, d’un coté la carte, avec la div .acf-map, de l’autre coté, la liste avec la div #listdata. Comme on le voit les deux div sont vides.

A la suite, il crée le bloc des marqueurs dans un printf, afin de pouvoir récupérer tout ce code dans le fichier google.js précédemment crée. C’est le js qui avec toutes les données nécessaires va créer la carte dans la div acf-map, grace à la dernière fonction du fichier js

$('.acf-map').each(function(){

render_map( $(this) );

});

et au niveau de la fonction add_marker() :

$('#listdata').append('<div class= "linkage" id="p'+index+'">'+$marker.html()+'</div>'); 

Il injecte avec .append() tout le code html du printf dans une nouvelle div .linkage, dont il incrémente l’ID.

Dans la fonction suivante

$(document).on('click', '#p'+index, function(){
infowindow.open(map, marker);
setTimeout(function () { infowindow.close(); }, 3000);
});

au clic sur chaque div.linkage ciblée par son nouvel ID, il ouvre la fenêtre (ou le marqueur) correspondante sur la carte.

En fait, le code dans chaque bloc de notre liste, est l’identique réplique de ce qu’on a dans chaque infowindow (le code dans le printf).

Cette manière de faire peut ne pas convenir dans le sens où il est difficile ensuite d’afficher les éléments différemment : on pourrait par exemple n’afficher dans la liste que des titres, et dans l‘infowindow une image, un titre, un extrait..Or la on a deux fois la même chose .

Afficher les thumbnails sur les vignettes

acf-image

On continue néanmoins sur cette version, et pour un visuel plus sympa, on peut rajouter les images à la une des articles sur la colonne de droite et donc aussi à l’intérieur des ‘infowindow’ (les petites fenêtres qui apparaissent au clic).

Voici le code à modifier dans le fichier home.php :

<?php 
$post_objects = get_posts( array(
'post_type' => 'post',
'posts_per_page' => -1
));

if( !empty($post_objects) ): ?>
<?php
echo '<div class="locations"><div class="acf-map"></div>';
echo '<div id="listdata"></div><div id="newdiv">';
foreach($post_objects as $post){
setup_postdata($post);

$location = get_field('google_maps');


if( !empty($location) ): ?>

<?php
printf( '<div class="marker" data-lat="%s" data-lng="%s">
<div class="location-image"> '. get_the_post_thumbnail( $post_id, "thumbnail" ) .'</div>
<div class="text">
<h4 class="title">%s</h4>
<div class="address"><i class="fa fa-map-marker" aria-hidden="true"></i> %s
<a href="" target="_blank" class="website" title="%s"></a>
</div></div>
</div>',
$location['lat'],
$location['lng'],
get_the_title(),

$location['address'],
get_the_title());


endif;
}
echo '</div></div>';

/* Restore original Post Data */
wp_reset_postdata();?>
<?php endif; ?>

Je rajoute donc simplement le code <div class= »location-image »> ‘. get_the_post_thumbnail( $post_id, « thumbnail » ) .'</div> dans a fonction printf, qui est ainsi repris automatiquement dans l’infowindow grace au js.

Voici le code css entièrement pris sur le site alansari.io,  légèrement modifié :

/* fixes potential theme css conflict */
.acf-map img {
max-width: inherit !important;
}

.locations {
display: -webkit-box;
display: -ms-flexbox;
display: flex;
-ms-flex-flow: row wrap;
flex-flow: row wrap;
-webkit-box-pack: justify;
-ms-flex-pack: justify;
justify-content: space-between;
}

.locations *:nth-of-type(1) {
-ms-flex-preferred-size: 69%;
flex-basis: 69%;
}

.locations *:nth-of-type(2) {
-ms-flex-preferred-size: 29%;
flex-basis: 29%;
}

#newdiv {
display: none;
}

#listdata {
overflow-y: scroll;
overflow-x:hidden;
height: 600px;
}

.linkage {
cursor: pointer;
border-bottom: 1px solid #ddd;
padding: 30px 30px 30px 30px;
}

.linkage:nth-last-of-type(1) {
border: none;
}

.fa-map-marker {
color: #000;
}

.acf-map .location-image {
width:150px;
height:auto;


}

.marker{
display:table;
}

#listdata .location-image,
#listdata .text{
display:table-cell;
padding:10px;
vertical-align:top;
width:50%;
}
.acf-map .location-image,
.acf-map .text{
display:table-cell;
padding:10px;
vertical-align:top;
}

.text h4{
margin-top:0;
}

@media only screen and (max-width: 1024px) {
.locations *:nth-of-type(1),
.locations *:nth-of-type(2) {
-ms-flex-preferred-size: 100%;
flex-basis: 100%;
}

#listdata {
height: auto;
overflow: visible;
display: -webkit-box;
display: -ms-flexbox;
display: flex;
-ms-flex-flow: row wrap;
flex-flow: row wrap;
-webkit-box-pack: justify;
-ms-flex-pack: justify;
justify-content: space-between;
}

#listdata * {
-ms-flex-preferred-size: 49%;
flex-basis: 49%;
}

.linkage {
margin: 0;
padding: 40px 40px 0 20px;
}

.linkage:nth-last-of-type(2) {
border-bottom: none;
}
}

@media only screen and (max-width: 640px) {
#listdata * {
-ms-flex-preferred-size: 100%;
flex-basis: 100%;
}

.linkage:nth-last-of-type(2) {
border-bottom: 1px dashed;
}
}