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 apparaitre/disparaitre les marqueurs correspondants sur la carte, en fonction de la catégorie selectionné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 apparaitre/disparaitre 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 struture 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;
}

2 thoughts on “Acf Google Map et catégories multiples

  1. chris

    SUper tuto, tout fonctionne chez moi.
    Par contre un point n’a pas été abordé. C’est le cas ou plusieurs article poitent vers exactement le même lieu.
    Chez moi du coup je ne vois qu’un seul marker, les autres sont cachés en dessous.
    As-tu une idée de comment les décalaer ?

    Reply
    1. copier coller Post author

      Bonjour et merci pour le commentaire Malheureusement je n’ai pas fais de recherche dans ce sens, désolé ! je ne peux donc répondre dans l’immédiat.On peut certainement trouver des réponses sur les forums d’ACF ou stack overflow…Il faudrait pouvoir indiquer des nuances dans les coordonnées, mêmes minimes, pour qu’au zoom, on puisse différencier les marqueurs..

      Reply

Leave a Reply

Your email address will not be published. Required fields are marked *