Acf Google Map et catégories multiples

Acf Google Map et catégories multiples

Après avoir vu comment créer des cartes google map avec ACF avec de multiples marqueurs, chaque marqueur étant un article, dans ce tuto nous allons voir comment créer des cartes pour nos catégories.Au clic sur une catégorie de la liste, on afficherait pour chaque catégorie une carte différente avec tous nos articles

Nous allons donc partir du même design que pour le précédent article.

Il y a dans le principe plusieurs manières de faire.On pourrait imaginer une liste de catégories, avec une seule carte,et on ferait apparaître/disparaître les marqueurs correspondants sur la carte, en fonction de la catégorie sélectionnée. on trouve de nombreux exemples, notamment sur fiddle .

On a d’autres exemples, ou au clic sur une catégorie de la liste , on fait apparaître/disparaître chaque carte correspondante.On a un bel exemple sur ce site .Ce dernier utilise ACF, et explique dans le forum d’ACF  comment il parvient à ce résultat.

Dans l’exemple qui va suivre, j’utilise bootstrap et les tabs, et ACF(version gratuite).On va reprendre la même structure que pour les précédents tuto sur le sujet, et lister chaque étape

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 selectionne 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.on reseigne ici sa clé API

Création des fonctions JS

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($) {

/*
* new_map
*
* This function will render a Google Map onto the selected jQuery element
*
* @type function
* @date 8/11/2013
* @since 4.3.0
*
* @param $el (jQuery element)
* @return n/a
*/

function new_map( $el ) {

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


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


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


// add a markers reference
map.markers = [];


// add markers
$markers.each(function(){

add_marker( $(this), map );

});


// center map
center_map( map );


// return
return map;

}

/*
* add_marker
*
* This function will add a marker to the selected Google Map
*
* @type function
* @date 8/11/2013
* @since 4.3.0
*
* @param $marker (jQuery element)
* @param map (Google Map object)
* @return n/a
*/

function add_marker( $marker, map ) {

// var
var latlng = new google.maps.LatLng( $marker.attr('data-lat'), $marker.attr('data-lng') );

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

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

// if marker contains HTML, add it to an infoWindow
if( $marker.html() )
{
// 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 );

});
}

}

/*
* center_map
*
* This function will center the map, showing all markers attached to this map
*
* @type function
* @date 8/11/2013
* @since 4.3.0
*
* @param map (Google Map object)
* @return n/a
*/

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
map.setCenter( bounds.getCenter() );
map.setZoom( 16 );
}
else
{
// fit to bounds
map.fitBounds( bounds );
}

}

/*
* document ready
*
* This function will render each map when the document is ready (page has loaded)
*
* @type function
* @date 8/11/2013
* @since 5.0.0
*
* @param n/a
* @return n/a
*/
// global var
var map = null;

$(document).ready(function(){

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

// create map
map = new_map( $(this) );

});

});

})(jQuery);

Ces deux bouts de code sont ceux proposés par défaut dans la documentation d’ACF, il ne s »agit là que de simples copier-coller, le code est commenté pour mieux comprendre à quoi sert chaque fonction.

L’appel aux scripts

Il faut ensuite relier tout ca, 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 );

Ici aussi, il faut renseigner sa clé API à l’endroit indiqué.

Maintenant, dans chaque page d’édition d’article, je retrouve une nouvelle meta box avec ma carte google map.

map-in-post

ACF est tellement bien fait qu’il suffit juste de cliquer sur un endroit de la carte, ou d’insérer une adresse, pour que le marqueur se positionne et renvoie une adresse dans le champ.A l’enregistrement de l’article, la carte garde le marqueur en mémoire.

 

Il ne reste plus qu’à créer toute une série d’articles avec des adresses renseignées dans notre nouvelle metabox google map.On relie également chaque article à une catégorie

Création du custom field taxonomy

Maintenant, dans ACF on va :

  • créer un champ pour nos catégorie dans ACF (un champ taxonomy)
  • décider d’un emplacement ou l’on veut afficher ces catégories,
  • selectionner les catégories souhaitées dans la page.

Création du champ taxonomy

Dans un groupe de champ ou pas, on crée un nouveau champ « taxonomy »

 

objetjtere

Assigner un emplacement

On décide de l’emplacement de ce nouveau champ, ici je le place dans ma page d’accueil.Le but étant de créer une boucle qui me ramène les catégories selectionnée dans une section de ma page d’accueil

groupe de champ

Selection des catégories

Dans l’édition de ma page d’accueil, dans mon nouveau champ acf, je sélectionne les catégories que je veux afficher dan ma boucle.La selection multiple me permet d’en selectionner plusieurs.

ateg

Tout ceci fait, on  a maintenant l’essentiel. On a tous nos articles et leur carte, avec des positions latitude, longitude définies sur une carte, et on a nos catégories selectionnées.Il va donc falloir relier le tout.

Voici donc le code que j’insère dans une section de ma page home.php

<section id="categories">
<div class="tab-content">
<?php

$terms = get_field('categories_select');//je récupère mes catégories selectionnées
if( $terms ): ?>
<?php $i = 1; //ce compteur sert à incrémenter la classe active de bootstrap?>
<?php foreach( $terms as $term ): //pour chacune de mes catégories?>

<?php
$args = array(
'post_type' => 'post', //je recrée une deuxième boucle à l'intérieur pour me ramener cette fois tous les marqueurs de mes articles
'posts_per_page' => -1,
'category__in' => $term
);
$the_query = new WP_Query($args); // j'insère ma boucle dans ma div acf map, la classe active est ajoutée à la premiere div,l'id change en fonction du nom de ma catégori
;?>
<div class="acf-map tab-pane <?php if ($i == 1) echo 'active';?> fade in" id="<?php echo $term->slug ;?>">
<?php
while ( $the_query->have_posts() ) : $the_query->the_post();
$location = get_field('google_maps');?>

<?php
if( !empty($location) ) { // je crée l'apparence de mes infowindows
?>
<div class="marker" data-lat="<?php echo $location['lat']; ?>" data-lng="<?php echo $location['lng']; ?>">
<?php the_post_thumbnail('thumbnail');?>
<h4><a href="<?php the_permalink(); ?>" rel="bookmark"> <?php the_title(); ?></a></h4>
<p class="address"><?php echo $location['address']; ?></p>
</div>
<?php
}
endwhile;
;?>
</div>
<?php
wp_reset_postdata();
$i++;endforeach ;?>

<?php endif; ?>
</div>

<?php
$terms = get_field('categories_select');//deuxième bloc, pour la liste, je recupère mes catégories
if( $terms ): // je crée plus bas des fleches down et up pour sur lesquels on pourra cliquer pour faire défiler les catégories ;?>
<div id="list">
<div class="down">
<span class="glyphicon glyphicon-chevron-down"></span>
</div>
<div id="listdata"> <?php // cette fois ma liste est composée de tabs bootstrap ;?>
<ul clas="nav nav-tabs tabs-right" id="myModal">
<?php $i = 1; //j'incremente ici aussi pour la class active ?>
<?php foreach( $terms as $term ):?>
<li class="<?php if ($i == 1) echo 'active';?>">
<a href="#<?php echo $term->slug ;?>" class="linkage" data-toggle="tab">
<?php $category_image = get_field('categImg', $term); //ici je recupère l'image de ma catégorie que je recupère d'un custom field crée au préalable
$image = $category_image['url']; ?>
<img src="<?php echo $image ;?>" alt="" />
<h3><?php echo $term->name; ?></h3>
</a>
</li>
<?php $i++; endforeach; ?>
<?php wp_reset_postdata(); ?>
</ul>
</div>
<div class="up">
<span class="glyphicon glyphicon-chevron-up"></span>
</div>
</div>
<?php endif; ?>
</div>
</section>

j’ai commenté le code pour explication.J’utilise donc le code par défaut des tabs de bootstrap, à l’intérieur duquel j’ai placé mes boucles.

Problème de comptabilité

Maintenant, petit problème.Les tabs de bootstrap et google map ont un problème de compatibilité.En gros, chaque tab cachée est en display: none, ce qui signigie que google map est incapable dans une élément caché de définir une taille pour la carte.Si bien qu’au chargement de chaque carte, on se retrouve soit avec des cartes trop petites, tronquées, voir aucune carte.Il faut donc quelque part redimmensionner la carte lorsqu’elle s’affiche.

Pour pallier à ce problème, bootstrap donne une piste.

On trouve énormément de topic sur ce sujet, aucun ne convenait à mon problème, lié à ACF et google map..et bootstrap

voici donc le code à modifier dans le fichier google.js. On remplace la précédente fonction add_marker par celle ci

function add_marker( $marker, map ) {

// var
var latlng = new google.maps.LatLng( $marker.attr('data-lat'), $marker.attr('data-lng') );

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

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

// if marker contains HTML, add it to an infoWindow
if( $marker.html() )
{

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



$('a[data-toggle="tab"]').on("shown.bs.tab", function(e) {

google.maps.event.trigger(map, "resize");
map.setCenter(latlng);
map.setZoom( 6 );


});


// fermer l'infowindow au clic sur une autre infowindow
google.maps.event.addListener(marker, 'click', function() {
if (typeof( window.infoopened ) != 'undefined') infoopened.close();
infowindow.open(map,marker);
infoopened = infowindow;

});

}

}

on remplace la précédente fonction add_marker par celle ci.A l’intérieur de la fonction proposée par bootstrap :

$('a[data-toggle="tab"]').on('shown.bs.tab', function (e) {

})

on va donc rajouter une fonction de redimmensionnement, on va recentrer la carte en reprenant la variable latlng créee plus haut dans le code, et on va rezoomer.Dans mon exemple, sans le zoom, la carte reste tronquée..

Voilà donc le début d’une piste pour afficher des catétorie et des cartes contenant les articles liés.

Le css

en bonus un bout de css pour styliser le tout

.locations{
width:100%;


}

.acf-map {
width: 69%;
height: 450px;
float: left;
vertical-align: top;

}
#list{

width:31%;
display: inline-block;
position:relative;
}

#listdata {
overflow:hidden;
height: 450px;
}

#listdata ul{
margin:0;
padding:0;
}
#listdata ul li{
display:block;
float:none;
}
.linkage {
cursor: pointer;
border-bottom: 1px solid #ddd;
}
.linkage h3{
margin:0;
padding:10px;
}


.down{
cursor:pointer;
text-align: center;
padding:10px;
width:100%;
background-color:rgba(0,0,0,0.5);
position:absolute;
top:0;
color:#fff;
}

.up{cursor:pointer;
text-align: center;
padding:10px;
width:100%;
background-color:rgba(0,0,0,0.5);
position:absolute;
bottom: 0;
color:#fff;
}