Le champ relationnel d’ACF est l’un des plus intéressants de l’extension. Il permet au rédacteur de choisir manuellement une liste de publications et leur ordre d’affichage, là où une WP Query est limitée par des critères.
Sommaire du cours
Présentation du champ relationnel
Le champ relationnel est un champ que j’ai mis longtemps à appréhender, et c’est bien dommage car il m’est utile sur presque tous mes projets aujourd’hui.
Dans la formation développeur de thèmes je vous ai appris à créer une requête personnalisée au travers d’une WP Query. Cela permet par exemple de lister les 4 dernières publications sur la page d’accueil d’un site.
Et grâce aux nombreux critères on peut définir exactement ce que l’on veut : quel type de publication, quel ordre (ascendant ou descendant) et comment trier (par date, par ordre alphabétique, par nombre de commentaires…).
Un jour, alors que je venais de finir un site pour un client, celui-ci m’a demandé s’il pouvait sélectionner manuellement les 4 biens immobiliers qui étaient affichés sur la page d’accueil.
J’étais bien embêté car ma WP Query récupérait les 4 les plus récents. C’est alors que j’ai découvert l’utilité du champ relationnel d’ACF !
Il permet de faire une sélection manuelle de publications à afficher dans une page. Voici comment il se présente :
À gauche se trouve la liste des publications disponibles, et lorsqu’on clique sur l’une d’entre-elle, elle vient s’ajouter à la sélection à droite. Il est possible de glisser-déposer les éléments de cette sélection pour définir leur ordre d’affichage.
Le champ relationnel possède également un moteur de recherche et 2 champs pour filtrer les résultats : le premier pour sélectionner le type de publication et le second pour la taxonomie.
Au niveau du template, on aura une boucle ACF qui nous permettra de récupérer les résultats, et les afficher comme on le souhaite.
On va voir 2 cas de figures : le premier, tout simple, permettra de faire un système d’articles similaires, et pour le second on verra une relation à double sens entre des agences de voyage et des destinations.
Cas n°1 : articles similaires
Dans ce premier exemple, on va faire un système d’articles similaires. Nos articles seront en réalité des recettes de cuisine. J’aurais pu créer un type de publication personnalisé juste pour ça, mais on va rester simple et utiliser les articles natifs.
Le but est de pouvoir sélectionner d’autres recettes à proposer à la fin d’un article. Si par exemple on propose un gâteau au chocolat, on choisira alors d’afficher d’autres recettes à base de chocolat.
Une WP Query aurait pu cependant faire le travail : en utilisant des taxonomies pour lister les ingrédients, on aurait pu faire une requête personnalisée pour récupérer 3 autres recettes avec l’étiquette « chocolat ».
Mais du coup on n’aurait pas le choix des recettes à afficher, ni leur ordre. Le champ relationnel va nous permettre de dépasser ces limites.
Configuration du groupe de champs
Pour commencer on va créer un nouveau groupe de champs dans lequel on va ajouter un champ relationnel avec pour slug related
.
En terme d’options, on va cocher « Image à la Une » pour afficher l’image mise en avant de la recette à l’intérieur du champ, comme ça ce sera plus sympa visuellement.
On verra dans le prochain cas que l’on peut filtrer sur un type de publication en particulier ainsi que sur des taxonomies. Mais pour l’instant, on va les désactiver car on n’a qu’un seul type de publications : les recettes (ou plutôt, les articles).
Il est également possible de contraindre un nombre minimum et maximum d’éléments. On va limiter à 3 recettes afin de les afficher en colonnes.
Enfin, on laisse le format de sortie en « Objet Publication » car c’est le plus simple à manipuler dans le template.
On va en profiter pour ajouter un autre champ « Temps de préparation » qui est un simple champ texte.
Mais pour cet exemple on va rester simple et on ajoute un seul champ.
Pour terminer, on va assigner ce groupe de champs au type de publication Article. C’est déjà la condition par défaut dans ACF donc on n’a normalement rien besoin de toucher.
Pour en savoir plus sur les réglages du champ relationnel, référez-vous à la documentation :
Préparer les données
Maintenant, rendez-vous dans Articles > Ajouter et écrivez quelques recettes. Je crée en dernier celle du quatre-quarts au chocolat, et j’assigne des recettes similaires : cookies, brownie… mmh !
J’en profite pour saisir un temps de préparation pour chacune d’entre-elles. Tout est prêt, on va pouvoir aller s’occuper de notre template.
Afficher les données dans le modèle
Puisqu’on est resté dans les articles, c’est la page single.php
que l’on va modifier, conformément au template hierarchy de WordPress.
Tout d’abord, on récupère les données de notre champ related
. On est sur le même principe de boucle que pour la galerie ou le répéteur.
Dans chaque itération de la boucle, on utilise la fonction WordPress setup_postdata()
qui permet d’initialiser les données. C’est grâce à elle qu’on va pouvoir utiliser the_title()
, the_content()
…
Le saviez-vous ?
Cette fonction est également utilisée par la boucle WordPress, c’est elle qui permet d’initialiser les données pour utiliser nos templates tags.
On en profite pour afficher le temps de préparation de chaque recette, via la fonction ACF the_field().
On rajoute enfin un peu de CSS avec du flex pour établir nos 3 colonnes, et le tour est joué !
Lorsque j’affiche mon quatre quart au chocolat, je devrais voir s’afficher les recettes sélectionnées à la fin de l’article !
Le champ relationnel est donc très puissant pour créer un maillage interne fort dans votre site, ce qui a une importance capitale pour le référencement naturel, en plus de proposer des suggestions sympathiques à vos internautes.
Vous pourriez l’utiliser pour des produits similaires dans une boutique, mais WooCommerce propose déjà cette fonctionnalité.
Cas n°2 : agences de voyages et destinations
On va maintenant voir un deuxième cas parce que j’ai encore une petite subtilité à vous montrer concernant ce champ relationnel.
Imaginons que vous présentiez sur votre site d’un côté des agences de voyage, et d’un autre des destinations. Chaque élément étant un type de publication à part entière, ou CPT.
Dans la page d’une agence, on va présenter les destinations disponibles en utilisant justement un champ relationnel. Jusque là tout va bien, on sait faire.
Maintenant, ce que je veux également, c’est que dans une page destination, on puisse voir la liste des agences proposant ce pays.
On va donc devoir faire appel à une requête inversée (une reverse query) pour retrouver les agences ayant cette destination dans leur champ relationnel. Et en fait, c’est moins compliqué que ce qu’on pourrait croire !
Préparer les CPT
Pour commencer on va déclarer nos types de publication à partir du fichier functions.php
:
Suite à ça, il faut bien penser à aller dans Réglages > Permaliens et cliquer sur le bouton Enregistrer, sans rien changer, pour mettre à jour la structure des URL de WordPress.
Les deux menus Agences et Destinations devraient apparaitre dans le menu de l’admin. Vous pouvez déjà commencer par ajouter quelques destinations.
Pour chacune d’entre elles, un titre et une image mise en avant trouvée sur Unsplash suffiront.
On va également créer les fichiers de templates correspondants, comme single-agency.php
et single-country.php
. En temps normal on devrait également créer les pages archive mais on n’en aura pas besoin dans cet exemple.
Configuration du groupe de champs
On va aller créer notre groupe de champ et, ici, pas de surprise, ce sera un simple champ relationnel avec pour slug « destinations ».
Au niveau des réglages je vais filtrer les types de publication disponibles, pour ne garder que les destinations. J’en profite pour retirer les sélecteurs de type de publication et de taxonomie.
Assignez ensuite ce groupe de champs au type de publication agence. Car le but est de choisir les destinations que proposent chaque agence.
Afficher les données sur le modèle
Pour l’affichage, on va utiliser le même code que précédemment en prenant soin de changer cette fois le slug du champ pour destinations
. Le code va être placé dans le fichier single-agency.php
.
Voici ce que l’on devrait obtenir avec un peu de CSS :
Chaque agence affiche donc les destinations qu’elle propose grâce à notre champ relationnel.
Relation inversée
Occupons-nous maintenant de l’inverse, c’est-à-dire que lorsqu’on est sur la page single d’une destination, on veut voir quelles agences la proposent. Et cette fois on n’a pas de champ relationnel à notre disposition puisqu’il est déjà dans les pages agences.
Ce que l’on veut donc, c’est que lorsque je consulte une destination (par exemple le Japon), je veux trouver un moyen de lister les agences qui ont ce pays dans leur champ relationnel.
Pour trouver la solution il faut déjà savoir comment sont stockées les données d’ACF dans la base :
La donnée d’un champ porte son slug, dans ce cas « destinations », et elle est stockée dans la table wp_postmeta
. Dans cet exemple on peut voir qu’on a une donnée sérialisée, c’est-à-dire qu’elle a été transformée lors du stockage.
On est face à un tableau de données PHP et ce qu’on lit, c’est sa représentation en base de données. a:4
par exemple indique que c’est un tableau avec 4 entrées et s:3
une chaine (string) de 3 caractères. WordPress désérialise automatiquement les données de la base lorsqu’il les récupère. Ce qu’il faut remarquer ici c’est qu’on a un tableau qui stocke les 4 identifiants des voyages proposés par l’agence.
Si tout ça est un peu nébuleux pour vous, je parle de WordPress et la structure des données dans un cours dédié.
Mais revenons-en à notre problème : il va falloir créer une requête pour trouver dans quelles agences cette destination est listée au travers du champ relationnel.
Une requête SQL ? Eh bien non ! En fait on va utiliser la puissance de la WP Query pour trouver nos données ! Cette fois le code est à insérer dans single-country.php
.
Voici comment interpréter notre WP Query :
- On cherche des publications dont le type est agence ;
- Qui possèdent une metadonnée « destinations » (notre champ ACF) ;
- Celle-ci doit contenir l’ID de la destination dans sa donnée sérialisée.
Petite subtilité : la valeur recherchée dans la chaine est par exemple "170"
avec les guillemets, pour éviter de trouver par erreur 170 dans un ID plus grand (par exemple 2170).
Ensuite on itère sur les résultats comme dans une WP Query classique :
Les logos des agences proposant cette destination devraient bien apparaître !
Ce besoin est tellement fréquent qu’un article lui est dédié dans la documentation ACF.
Cet exemple montre par contre ses limites si vous voulez mettre un prix pour chaque voyage. Le prix sera différent pour chaque agence. Du coup il faudrait faire autrement, par exemple avec un répéteur dans lequel on mettrait le champ Objet article et un champ prix.
Le champ relationnel trouve son utilité dans de nombreuses situations et permet plus de contrôle par rapport à une WP Query classique, vous savez maintenant en tirer pleinement parti.
Lybe
Le 15 mars 2021
Bonjour Maxime,
Dans le cas n°2 j’ai eu quelques soucis et j’aimerais savoir si ce que j’ai du faire pour les résoudre est normal ou pas
Alors mon premier est qu’au lieu d’appeler les fichiers single-agence.php et single-destination.php j’ai dû les nommer single-agencies.php et single-countries.php parce que le slug dans register_post_type sont agencies et countries
Si je ne faisait pas cela mes données n’étaient pas affichés, également dans le fichier single-countries.php dans les arguments préparant la WP_Query pour post_type j’ai dû mettre agencies comme donné et là tout fonctionne comme voulu
Maxime BJ
Le 23 mars 2021
Très bonne remarque, je te remercie. Je viens donc de corriger le cours en ce sens, afin que tout soit cohérent en terme de nommage. D’ailleurs la bonne pratique est de nommer un CPT au singulier, j’ai donc corrigé avec Agency et Country. Merci pour ton aide !
Gérald
Le 22 novembre 2023
Bonjour Maxime,
Merci pour ce cours complet et instructif !
Pour le champ relationnel ACF et les recettes au chocolat, après avoir entré la boucle dans le template single.php, WP me renvoie une erreur :
Notice: Uninitialized string offset: 0 in /Applications/MAMP/htdocs/montheme/wp-includes/class-wp-query.php on line 3738
Une idée ? Merci !
Gérald
Maxime BJ
Le 22 novembre 2023
L’erreur indique que tu essaies de lire un caractère particulier d’une chaine. De ce que je comprends, tu essaies de lire un tableau mais en fait tu as une chaine de caractères à la place. Essaie d’ajouter des var_dump() pour chaque données que tu manipules pour trouver celle qui n’est pas bonne.
Gérald
Le 22 novembre 2023
Merci Maxime,
ça marche mieux quand je remplis les champs relationnels dans les articles… pfff… 🙂
Arnaud
Le 1 décembre 2023
Bonjour, il me semble qu’il y a une petite coquille dans le code de `single-destination.php`.
Dans $args, il faut définir le `post-type` à `agency` (plutôt que `agence`) pour être consistent avec la définition du CPT dans `functions.php`.
Maxime BJ
Le 1 décembre 2023
Très bien vu ! Je viens de corriger. Je te remercie pour ta contribution !