ACF : ajouter des champs personnalisés

Introduction

Ce tutoriel explique la mise en œuvre des custom fields (champs personnalisés) sous WordPress afin d’ajouter de nouveaux champs à nos contenus avec l’aide du plugin ACF.

Il fait suite à notre précédent tutoriel qui s’intéressait aux custom post types pourquoi et comment ? (types de post personnalisé).

Nous étudierons la création d’un groupe de champs personnalisés (lieu, surface, prix) avec l’aide du plugin Advanced Custom Fields, ou plus simplement ACF, et son application dans l’interface admin.

Puis, nous aborderons son traitement afin d’en afficher les informations côté site web par l’intermédiaire des templates de notre thème et de la feuille de style. Nous étudierons en particulier comment mettre en place une google map.

Tout le processus se déroulera avec un exemple concret.

Pourquoi personnaliser des champs dans WordPress ?

WordPress possède nativement des champs standards comme le titre, le contenu, une image à la Une, les catégories, les mots-clés… Ces champs dressent un cadre général dans lequel nous pouvons saisir les informations que nous souhaitons publier. Mais, il existe de nombreux cas où nous devons en avoir d’autres comme un code couleur, une date, un prix… Que sais-je encore ?

WordPress nous laisse la possibilité d’étendre les champs standards en ajoutant des méta données (metadata). Quand nous sommes dans un article (post), nous parlons alors plus précisément de post metadata. De même pour les utilisateurs, nous parlerons de user metadata et ainsi de suite…

Nous retrouvons ces métadonnées en base de données dans les tables suivantes :

  • wp_postmeta,
  • wp_usermeta,
  • wp_commentmeta,
  • wp_termmeta (depuis la version 4.4 de WP).

Comment utiliser les méta données sous WordPress ?

Pour ajouter des méta données à un article, nous utilisons la méta box « champs personnalisés ». En renseignant le couple nom/valeur puis en cliquant sur le bouton Ajouter, nous créons une méta donnée. C’est aussi simple que cela 🙂 !

Au niveau des templates de votre thème, vous pouvez récupérer ces méta données avec l’aide de deux fonctions (template tags) :

La fonction the_meta permet d’afficher toutes les métadonnées d’un article sous la forme d’une liste.

La fonction get_post_meta permet de récupérer (puis de l’afficher avec un echo) la valeur d’une métadonnée en lui passant comme argument son nom.

De manière générale, nous parlons aussi bien de champs personnalisés que de méta données mais vous pouvez lire cet article en anglais wordpress custom fields versus wordpress post meta pour savoir en quoi ils se distinguent ou pas.

champs personnalises wp-admin

get post meta template wordpress

Ces métadonnées ont malgré tout une limite. En effet, elles ne prennent que la valeur d’une chaîne de caractères. Or, nous aimerions que son type puisse être aussi varié qu’un code couleur, une date ou un prix par exemple.

L’emploi d’un plugin nous permet d’étendre encore la possibilité des champs personnalisés en leur attribuant, entre autres, un type.

Le plugin qui fait référence dans ce domaine est Advanced Custom Fields (ACF). Ce plugin offre toute une panoplie pour la personnalisation des champs et la mise en place de règle pour déterminer quand ces champs sont utilisés.

 

Comment utiliser ACF ?

Pour utiliser les ACF, nous vous conseillons de lire la document technique et en particulier la liste des fonctions utilisables dans les templates.

Dans notre étude de cas, nous utiliserons trois fonctions the_field, get_field, get_field_object.

Enfin, nous abordons la question de comment afficher une google map. Cette implémentation demande 4 « bouts de code » :

  • le chargement de l’API de Google pour les maps,
  • un jQuery qui permet d’instancier l’API Google,
  • du CSS pour mettre en forme la google Map,
  • du code dans le template pour afficher la google map.

Pour en savoir plus

Je citerai deux références web sur les ACF :

  • Grégoire Noyelle décrit dans plusieurs articles l’utilisation des ACF
  • et Willy Bahuaud l’implémentation d’une recherche de géolocalisation à partir de champs personnalisés.

Les sources

ACF - Personnaliser des champs

PHP

functions.php
/**
 * Enqueue scripts and styles.
 * @since babel web tutos 1.0
 *
 * Mise en place du jQuery pour ACF Google Map
 * Uniquement pour les articles seuls de type immo
 */
add_action( 'wp_enqueue_scripts', 'babelweb_scripts' );
function babelweb_scripts() {
	if ("immo" == get_post_type() && is_single())
		wp_enqueue_script( 'acf-map', get_stylesheet_directory_uri() . '/js/acf-map.js', array( 'jquery' ), '20160121', false );
}

 

functions.php
/* 
 * Formatte le prix en séparant les milliers
 * ou utilisez la fonction de WordPress number_format_i18n 
 * https://codex.wordpress.org/Function_Reference/number_format_i18n
 * echo number_format_i18n(get_field("prix"));
 */
function get_format_prix($prix, $sep = ".") {
	if (strlen($prix) > 3) {
		$limit = ceil(strlen($prix) / 3);
		$prix_format = "";
		$prix = strrev ($prix);
		for ($i=0;$i<$limit;$i++)
			if ($i+1 == $limit)
				$prix_format .= substr($prix, $i*3, 3);
			else
				$prix_format .= substr($prix, $i*3, 3).$sep;
		$prix = strrev($prix_format);
	}
	return $prix;
}

/* 
 * Affiche le prix formatté sur les milliers
 */
function format_prix ($prix, $sep = ".") {
	echo get_format_prix($prix, $sep);
}

/* 
 * Affiche le tooltip avec les instructions du champs
 */
function tooltip ($field_name) {
	$field = get_field_object($field_name);
	echo "<span class='tooltip'><div class='tooltip-description'>".$field["instructions"]."</div></span>";
}

 

header.php
<?php
/**
 * Chargement de l API Google MAP dans le head
 */

?><!DOCTYPE html>
<html <?php language_attributes(); ?> class="no-js">
<head>
        /* code */
	<?php 	if ("immo" == get_post_type() && is_single()) : ?>
		<script src="https://maps.googleapis.com/maps/api/js?v=3.exp&sensor=false"></script>
	<?php endif; ?>
	<?php wp_head(); ?>
</head>

 

content-single-immo.php
<?php
/**
 * The template part for displaying single custom posts immo
 *
 * @package WordPress
 * @subpackage Babel_Web_Tutoriels
 * @since Babel Web Tutoriels 1.0
 */
?>

<article id="post-<?php the_ID(); ?>" <?php post_class(); ?>>
	<header class="entry-header">
		<?php the_title( '<h1 class="entry-title">', '</h1>' ); ?>
	</header><!-- .entry-header -->

	<?php twentysixteen_post_thumbnail(); ?>

	<div class="entry-content">
		<div class="entry-acf">
			<?php if( get_field('prix') ): ?>
				<div class="acf-prix"><label>Prix : </label><?php number_format_i18n(get_field("prix"))); ?> € <?php tooltip("prix"); ?></div><!-- acf-prix -->
			<?php endif; ?>
			<?php if( get_field('surface') ): ?>
				<div class="acf-surf"><label>Surface : </label><?php the_field("surface"); ?> m<sup>2</sup> <?php tooltip("surface"); ?></div><!-- acf-surf -->
			<?php endif; ?>
			<?php 
				$map = get_field('lieu');
				if( !empty($map) ):
			?>
			<div class="acf-map">
				<div class="marker" data-lat="<?php echo $map['lat']; ?>" data-lng="<?php echo $map['lng']; ?>">
					<div class="marker-info">
						<h4><?php the_title(); ?></h4>
					</div>
				</div>
			</div>
			<?php endif; ?>
		</div><!-- .entry-acf-->
		<?php
			the_content();
		?>
	</div><!-- .entry-content -->
</article><!-- #post-## -->

jQuery

acf-map.js
jQuery(document).ready(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( 13 );
		}
		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;
	$('.acf-map').each(function(){
		map = new_map( $(this) );
	});
});

CSS

acf.css
.acf-map {
	width: 100%;
	height: 400px;
	border: #ccc solid 1px;
	margin: 20px 0;
}

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

.marker-info h4 {
    color:#333;
}

.single-immo label {
	color: #6B50CE;
}

.tooltip:before {
	content : "?";
	color: #6B50CE;
	font-size:8px;
	left:4px;
	position:absolute;
	top:1px;
}

.tooltip {
	border: 2px solid #6B50CE;
	border-radius: 50%;
	display: inline-block;
	height: 1em;
	position: relative;
	width: 1em;
}

.tooltip:hover .tooltip-description{
	display : block;
}

.tooltip .tooltip-description {
	display:none;
    background-color: rgba(0, 0, 0, 0.1);
    border-radius: 5px;
    box-shadow: 1px 2px 1px rgba(0, 0, 0, 0.5);
    left: 20px;
    padding: 0 10px;
    position: absolute;
    top: -10px;
    width: 300px;
	z-index:1000;
}