Développer une page d’options pour sa propre extension WordPress peut s’avérer un vrai parcours du combattant, surtout si on essaie de réinventer la roue en utilisant uniquement l’API WordPress d’options.
Heureusement pour nous, de nombreuses librairies & plugins permettent de faciliter la création de ces pages : Redux Framework, ACF, Pods, CMB2… la liste est longue.
Attardons nous aujourd’hui sur Carbon Fields et apprenons à développer une page d’options modulaire pour notre plugin WordPress, pleine de hooks !
L’intégralité du code détaillé ici est paqueté dans un plugin WordPress disponible sur GitHub. Téléchargez-le, faites un composer install
dedans et servez-vous en comme base !
Une page d’options flexible pour plugin WordPress
Démonstration
Principe général
L’excellente librairie Carbon Fields est une vraie pépite d’or pour simplifier notre vie de développeur — comme ACF et d’autres ressources précieuses de l’écosystème WordPress.
Cette librairie open-source permet entre autre de :
- créer des groupes de champs remplis de champs complexes
- définir des conditions d’affichage de ces metaboxes
- les assigner à différentes entités WordPress pour sauvegarder des métadonnées de posts, de taxonomies, de commentaires, d’utilisateurs, de menus de navigation
- créer des blocs Gutenberg uniquement avec du PHP
Une autre précieuse fonctionnalité de Carbon Fields est de pouvoir créer des pages d’options en quelques lignes de code et profiter des multiples types de champs : WYSIWYG, upload d’image, champ relationnel, carte Google Maps, etc.
Plongeons dans le code !
L’intégralité du code détaillé ici est paqueté dans un plugin WordPress disponible sur GitHub. Il est décortiqué ci-dessous, étape par étape.
1. Inclure Carbon Fields, dépendance Composer
<?php
function load_carbonfields() {
require_once plugin_dir_path( __FILE__ ) . '/vendor/autoload.php';
\Carbon_Fields\Carbon_Fields::boot();
}
add_action( 'after_setup_theme', __NAMESPACE__ . '\\load_carbonfields' );
Après avoir exécuté la commande composer install
à la racine de l’extension, la librairie Carbon Fields sera installée comme dépendance de notre projet.
Ce code permet :
- d’inclure l’autoloader Composer pour charger cette dépendance,
- d’initialiser Carbon Fields pour profiter de ses super-pouvoirs
Notez que Carbon Fields peut être chargé via une extension — comme ACF — comme l’explique la documentation officielle. Dans notre cas, on souhaite livrer et profiter de Carbon Fields dans notre propre extension, d’où son usage en tant que dépendance Composer.
2. Enregistrer une page d’options d’admin WordPress
<?php
function options_initialize_admin_page() {
$tabs = apply_filters( 'msk_plugin_options_tabs', [] );
if ( empty( $tabs ) ) {
return;
}
$theme_options = Container::make( 'theme_options', __( 'Options du plugin', 'msk-plugin' ) );
$theme_options->set_page_file( 'plugin-mosaika' );
$theme_options->set_page_menu_title( __( 'Plugin Mosaika.fr', 'msk-plugin' ) );
$theme_options->set_page_menu_position( 31 );
$theme_options->set_icon( 'dashicons-palmtree' );
foreach ( $tabs as $tab_slug => $tab_title ) {
$theme_options->add_tab(
esc_html( $tab_title ),
apply_filters( "msk_plugin_options_fields_tab_{$tab_slug}", [] )
);
}
}
add_action( 'carbon_fields_register_fields', __NAMESPACE__ . '\\options_initialize_admin_page' );
Tout d’abord, il nous faut créer le « conteneur » de nos metaboxes et champs, à savoir notre page d’options. On l’enregistre grâce à Container::make( 'theme_options')
.
On en profite pour utiliser de nombreuses méthodes de cette classe Container
pour :
- définir le slug de notre page
- changer son titre dans le menu d’admin
- modifier sa position dans le menu d’admin
- changer son icône Dashicons
Enfin, on boucle sur une variable $tabs
afin d’enregistrer les onglets composant cette page d’options. Comme vous l’aurez remarqué en haut de fonction, cette variable n’est qu’un simple tableau vide pour l’instant, mais elle est rendue disponible globalement via un filtre.
On pourra ainsi la construire « ailleurs » dans les fonctions suivantes, simplifiant ainsi cette première fonction dont la seule responsabilité est d’enregistrer notre conteneur.
Cette même flexibilité — via un filtre — est utilisée dans notre boucle enregistrant les onglets de la page d’options : le filtre dynamique msk_plugin_options_fields_tab_{$tab_slug}
va nous permettre d’enregistrer les champs de chaque onglet via d’autres fonctions.
Un mot sur les hooks et la modularité qu’ils offrent
En plus de séparer les responsabilités dans des fonctions distinctes (pour lister les onglets et pour lister les champs de chaque onglet), l’usage de filtres permet une modularité précieuse et appréciée des développeurs WordPress.
Car qui dit hook dit possibilité de modifier une logique et la personnaliser selon ses besoins grâce à du code additionnel ! En optant pour ces filtres, on offre la possibilité aux utilisateurs/dévs de notre plugin :
- de modifier/supprimer des réglages de notre extension. C’est sans doute peu désiré mais peut parfois s’avérer utile (changer une tournure ou cacher un réglage pour certains utilisateurs novices par exemple)
- d’ajouter des onglets et des champs via un code tiers. Très utile pour permettre à quiconque de développer des « add-ons » de votre plugin WordPress par exemple et ainsi charger son propre onglet avec ses propres champs dans NOTRE page d’options.
C’est ainsi que fonction en grande partie WooCommerce : une logique initiale « de base » est développée mais des actions et des filtres dûment placés dans le code source permettent de modifier ce comportement par défaut pour l’étendre via d’autres extensions ou du code sur-mesure.
Prenez l’habitude de parsemer votre code de thème/plugin WordPress public avec des hooks (actions ou filtres). En faisant cela, vous le rendrez flexible et modulaire pour ceux qui souhaiteraient altérer son comportement d’origine.
3. Enregistrer les onglets de la page d’options
<?php
function options_set_tabs( $tabs ) {
return [
'general' => __( 'Général', 'msk-plugin' ),
'social' => __( 'Réseaux sociaux', 'msk-plugin' ),
'advanced' => __( 'Avancé', 'msk-plugin' ),
];
}
add_filter( 'msk_plugin_options_tabs', __NAMESPACE__ . '\\options_set_tabs' );
Maintenant que notre page d’options est prête et que notre « code maître » initialise le tableau blanc, on va profiter des filtres à disposition pour peindre ce tableau.
La première chose à faire et de définir les onglets composant notre page d’options. On se hooke sur msk_plugin_options_tabs
pour injecter un tableau d’onglets.
Chaque élément de ce tableau associatif indique :
- le « slug » (ou identifiant) de l’onglet, défini via la clé de l’élément
- le titre de l’onglet, défini via la valeur de l’élément
Notez bien l’importance de ce slug : il est utilisé dans notre filtre dynamique msk_plugin_options_fields_tab_{$tab_slug}
et nous servira dans l’étape suivante pour définir les champs de chaque onglet.
4. Charger les champs de chaque onglet
<?php
function options_general_tab_theme_fields() {
$fields = [];
$fields[] = Field::make( 'rich_text', 'champ_riche', __( 'Champs WYSIWYG', 'msk-plugin' ) );
$fields[] = Field::make( 'select', 'champ_select', __( 'Champs menu déroulant', 'msk-plugin' ) )
->set_options( [
'option1' => __( 'Option n°1', 'msk-plugin' ),
'option2' => __( 'Option n°2', 'msk-plugin' ),
'option3' => __( 'Option n°3', 'msk-plugin' ),
'option4' => __( 'Option n°4', 'msk-plugin' ),
] );
return $fields;
}
add_filter( 'msk_plugin_options_fields_tab_general', __NAMESPACE__ . '\\options_general_tab_theme_fields', 10 );
Comme expliqué à l’instant, on injecte maintenant une logique sur notre filtre dynamique. Pourquoi dynamique ? Car la définition des champs d’un onglet de slug ABC se fera via le filtre msk_plugin_options_fields_tab_ABC
!
On utilise cette fois Field::make
pour ajouter des champs CarbonFields dans un onglet. La documentation officielle vous permettra de découvrir la variété de champs à disposition dans cette librairie. Son usage de base se fait comme suit :
- en premier paramètre, on indique le type de champ que l’on souhaite crééer
- en second paramètre, on définit l’identifiant de ce champ qui nous permettra de récupérer sa valeur plus tard
- en troisième paramètre, on indique le nom/titre affiché avant le champ
Dans notre exemple ci-dessus, on enregistre un champ WYSIWYG (rich_text
) et un menu déroulant (select
) pour peupler notre premier onglet « Général ».
Jetez un œil au plugin final sur GitHub pour voir tous les champs d’examples présentés dans chaque onglet et quelques options disponibles.
On peut notamment :
- indiquer qu’un champ est requis avec
set_required(true)
- changer sa taille avec
set_width(...)
- indiquer un texte explicatif du champ avec
set_help_text()
Gardez le sens des priorités
Notez la priorité à 10 lors de notre fonction options_general_tab_theme_fields
. En indiquant une telle priorité, on offre à d’autres développeurs la possibilité d’injecter d’autres champs via le hook msk_plugin_options_fields_tab_general
à l’endroit où ils le souhaitent :
- avant nos champs enregistrés ci-dessus s’ils injectent leur propre fonction avec une priorité inférieure à 10
- après nos champs enregistrés s’ils injectent leur propre fonction avec une priorité supérieure à 10
5. Inclure du contenu promotionnel dans la barre latérale
Et voila ! Nous venons de créer une belle page d’options pour notre extension WordPress, et ce sans s’être embêté avec la Settings API native de WordPress.
Pour couronner le tout, voyons comment ajouter un contenu additionnel dans la sidebar de cette page pour, par exemple, faire la promotion de la version premium du plugin ou proposer des liens vers la documentation.
<?php
function display_content_after_sidebar() {
?>
<h3>Coucou, je suis un contenu extra !</h3>
<?php
}
add_action( 'carbon_fields_container_options_du_plugin_after_sidebar', __NAMESPACE__ . '\\display_content_after_sidebar' );
Sur cette page d’admin présentant nos réglages, Carbon Fields offre plusieurs hooks intéressants :
carbon_fields_container_{$id}_before_fields
pour afficher du contenu avant l’affichage des champs de CFcarbon_fields_container_{$id}_after_fields
pour afficher du contenu après l’affichage des champs de CFcarbon_fields_container_{$id}_before_sidebar
pour afficher du contenu dans la sidebar avant la boîte d’enregistrement de CFcarbon_fields_container_{$id}_after_sidebar
pour afficher du contenu dans la sidebar après la boîte d’enregistrement de CF
C’est cette dernière action que nous utilisons ici afin d’inclure du contenu additionnel en bas de sidebar. Avec un peu de HTML et de CSS, on peut par exemple afficher une boîte pour promouvoir la version premium de notre plugin WordPress et ce directement via la page de réglages de ce dernier.
Nomenclature de ces filtres
Vous avez remarqué le nom dynamique de ces filtres : l’$id
de notre conteneur est présent dans le nom du filtre.
Dans notre cas, notre filtre se nomme carbon_fields_container_options_du_plugin_after_sidebar
car notre page d’options a été enregistrée (via Container::make
) en indiquant le titre « Options du plugin ».
6. Récupérer et utiliser la valeur d’un réglage
<?php
$value = carbon_get_theme_option( 'champ_riche' );
echo wp_kses_post( $value );
Enfin, quel intérêt d’offrir une page d’options si on ne peut pas se servir des réglages définis par l’utilisateur ailleurs dans notre plugin ?
Manipuler ces valeurs se fait via l’utilisation de la fonction carbon_get_theme_option()
en passant en paramètre l’identifiant du champ concerné. Simple comme bonjour !
Conclusion
J’espère que cet article vous aura fait apprécier l’usage de Carbon Fields comme librairie pour facilement développer une page d’options dans votre extension WordPress.
Un conseil
N’oubliez pas que Carbon Fields ne limite pas sa logique de groupes de champs et champs uniquement aux pages d’options. Vous pouvez très facilement créer des champs meta pour vos posts ou utilisateurs en quelques lignes de code, et bien plus encore !
Cet article aura également tenté de présenter une logique de développement WordPress évolutive et modulable grâce à un fin usage de hooks. Essayez de garder cette flexibilité à l’esprit lorsque vous codez : vous et vos utilisateurs vous remercieront à l’avenir !
13 commentaires
Salut Pierre,
Merci beaucoup pour cet article. Est-ce que le stockage de Carbon fields est mieux fait que ACF dans la table d’options OU Carbon fields utilise-t’il ses propre table?
Hello Grégoire,
Merci pour ton commentaire 🙂
Plusieurs avantages (selon moi) de CF par rapport à ACF :
1. Pas de duplication de ligne dans la BDD comme sait le faire salement ACF (pour stocker l’identifiant du champ), on a juste les valeurs et rien d’autre. C’est le gros inconvénient d’ACF selon moi pour des gros sites, on remplit vite la BDD avec des trucs qu’on pourrait éviter de stocker.
2. On peut crééer son propre « data store » pour indiquer à CF comment sauvegarder en BDD (sérialisé VS non-serialisé serait l’exemple tout con mais on peut imaginer plus complexe). Regarde https://carbonfields.net/docs/guides-serialized-datastore/
3. Le champ CF dit Complexe (https://docs.carbonfields.net/#/fields/complex — qui équivaut au Répéteur ACF) stocke ses données à peu près de la même manière qu’ACF : http://media.mosaika.fr/8808893d4051
J’espère avoir répondu à ta question !
Par auteur
Merci beaucoup Pierre. C’est parfait. Je regarde les liens et je me pose de vraies questions ce matin 🙂
Autre point très négatif d’ACF: aucune donnée n’est sérialisée. Je viens de publier un article ce matin qui en parle: https://www.gregoirenoyelle.com/creer-blocs-editeur-moderne-wordpress-gutenberg-acf-5-8/
Est-ce le cas pour Carbon Fields dans les fonctions natives d’affichage?
Grégoire, pas compris ta question 🙂
Vu que tu peux plugger ton propre datastore dans CF, tu peux faire en sorte d’enregistrer des meta (ou options) dans une seule clé avec toutes les valeurs sérialisées.
Par auteur
Pierre. Excuse moi, j’ai répondu trop vite. Je voulais dire qu’aucune data n’est nettoyée (Output Sanitization).
Merci Pierre pour cet article qui m’a donné envie de tester Carbon Fields pour gérer les options de mes extensions.
Petite question, sais tu comment gérer l’option champs requis ? Par gérer j’entends interdire l’enregistrement des options et afficher un message d’erreur.
Hello Nicolas,
Oui tu peux utiliser la méthode
->set_required( true )
sur un champ pour le définir comme étant obligatoire.Cf https://docs.carbonfields.net/#/fields/usage
Par auteur
Oui j’avais bien utilisé set_required( true ) mais apparemment lorsque tu arrives sur la page rien n’interdit l’enregistrement. Il faut un event sur l’un des champs requis pour que le bouton d’enregistrement soit désactivé. Je ne sais pas si tu constates le même problème.
Ha oui tout à fait, c’est un bug que j’avais relevé et apparemment la résolution est en cours : https://github.com/htmlburger/carbon-fields/issues/627
Par auteur
Bonjour, j’aime la façon de déclarer les champs de Carbon Fields, c’est beaucoup plus simple que la méthode par défaut de WordPress! J’utilise votre plugin à partir de GitHub et tout fonctionne pour les champs, par contre lorsque j’essaie d’utiliser carbon_get_theme_option pour obtenir la valeur d’un champ, j’obtiens constamment le message suivant « Fatal error: Uncaught Error: Call to undefined function carbon_get_theme_option() ». Je n’arrive pas à trouver quelque chose à propos de cela dans l’article, serait-il possible de m’éclairer?
Merci.
Bonjour,
Est-ce que CF est bien chargé ? cf https://docs.carbonfields.net/#/quickstart — la partie « autoload » en bas de code.
Par auteur
Oui CF gagne à être connu. Mais même problème de mon coté, j’explique:
– Carbon Fields installé en plugin séparé et activé (plusieurs autres custom plugins en dépendent)
– Création des settings d’un custom plugin via » Container::make( ‘theme_options’, ‘MONJOLICONTAINER’ ) » dans monplugin.php
– La fonction carbon_get_theme_option() est également dans monplugin.php
et ça ne fonctionne pas :-((
En creusant un peu dans le plugin CF on trouve add_action( ‘after_setup_theme’, ‘carbon_fields_boot_plugin’ );
Je suis encore novice en WP mais j’ai comme l’impression que les instructions php des plugins interviennent avant le chargement de CF, contrairement à celles des templates..
Impression comfirmée. En effet, avec le script ci-dessous dans monplugin.php plus de problème. Ouf! :-))
add_action( ‘after_setup_theme’, ‘recup_des_settings’ );
function recup_des_settings(){
$mavar = carbon_get_theme_option( ‘monsetting’ );
}
Mais je n’ai peut-être pas tout compris. Je laisse donc les experts commenter.
[…] Theme and Plugin Development Course on UdemyIntégrer une page d’options dans un plugin WordPressThe Writing Plugins Pocket Guide Source Code12 Tips for Creating a Successful WordPress Premium […]