Sommaire
Introduction
Ce tutoriel fait suite aux deux précédents qui traitaient des custom post types (types d’article personnalisés) et des custom fields (champs personnalisés). Cette fois-ci, nous traitons des widgets et nous verrons pratiquement comment créer un widget qui affiche notre custom post type – immo, pour les biens immobiliers – et un champ personnalisé associé – le prix.
Certes, il existe déjà des plugins qui font ce travail (exemples ci dessous) mais l’exercice du jour est de se familiariser avec la programmation d’un widget et de comprendre comment, à partir des sources de WordPress, nous pouvons élaborer nos propres widgets. Il ne s’agit donc pas de réinventer la roue mais de comprendre la bonne pratique de programmation pour WordPress. Et quoi de mieux que de reprendre le code originel de WordPress ! 🙂
Dans le tutoriel, j’ai évoqué très rapidement la différence entre un plugin et un widget et je n’y reviendrai pas. J’ai aussi introduit très succinctement les notions de classe, d’objet et de sous-classe. En fin de tutoriel, j’aborde la question de la localisation (traduction de l’anglais vers le français). Je vous laisse découvrir ces sujets dans la vidéo car je me concentrerai dans cet article sur le code pour la gestion d’un widget.
Avant de commencer toute programmation, il est toujours bon de lire la doc (le codex) et vous pouvez la consulter dans l’API Widget de WordPress !
Ici, nous partirons de la classe WP_Widget de WordPress et de sa sous classe WP_Widget_Recent_Posts qui est le widget par défaut de WordPress pour afficher les articles récents (les N dernières parutions d’article).
En effet, dans un premier temps, notre objectif sera d’afficher les dernières parutions de nos biens immobiliers avec le CPT – immo. Cette fonctionnalité est très proche de celle du widget qui, justement, affiche les articles récents. Une seule modification fonctionnelle est à changer en remplaçant la date de parution par le prix du bien immobilier (sans compter évidemment le changement de type d’article de post en immo).
Dans un second temps, nous généraliserons le widget afin de pouvoir sélectionner le Custom Post Type de notre choix.
La classe WP_Widget de WordPress
Vous pourrez retrouver le source de cette classe dans le dossier wp-includes de WordPress et dans le fichier class-wp-widget.php.
Voici le squelette de cette classe.
Ce qu’il faut retenir de cette description est liée aux commentaires des lignes 88 et 140. Ces commentaires indiquent quelles sont les fonctions (les méthodes de la classe) que le nouveau widget devra surcharger (autrement dit remplacer) et celles dont on aura besoin.
Les fonctions à surcharger sont au nombre de trois et nous allons les décrire. Il est toujours bon de lire les commentaires au dessus de la fonction qui renseignent sur la fonctionnalité, les arguments et valeur de retour de la fonction.
widget
La première fonction widget est appelée lors de l’affichage du widget sur le site internet (front end) dans la barre latérale où il a été instancié. Elle prend deux arguments $args et $instance. Le premier argument est un tableau qui comprend, entre autres, les paramètres before_widget et after_widget, before_title et after_title.
D’où proviennent ces paramètres ? Un widget s’intègre dans une barre latérale (sidebar). Lors de la déclaration de cette sidebar, on indique comment encadrer les widgets en son sein en définissant les balises HTML qui s’afficheront avant et après le widget (en règle générale une section), avant et après le titre du widget (en générale une balise h2).
Dans notre étude de cas, nous avons développé un thème enfant prénommée babelweb, fils du thème twentysixteen (2016). C’est dans le fichier function.php que nous retrouvons la déclaration des sidebars et de ses paramètres.
Le deuxième argument, $instance, est un tableau qui nous donne les paramètres du widget lors de la validation du formulaire depuis l’interface admin. Nous y reviendrons dans les fonctions suivantes.
form
La fonction form est appelée lors de l’affichage du widget et de son paramétrage dans l’interface admin (back end) . Elle prend un seul argument $instance. Cet argument est un tableau avec les valeurs qui ont été précédemment sauvegardées en base de données. Il permet précisément d’afficher ces valeurs dans le formulaire.
Cette fonction se résume à l’affichage des champs (et des libellés) correspondants aux paramètres du widget. Elle ne décrit pas le formulaire HTML dans son entier, c’est WordPress qui s’en charge. Le développeur se concentre donc sur l’essentiel ! 🙂
update
Enfin, la fonction update est appelée lors de la validation des paramètres du widget dans l’interface admin (back end) . Elle prend deux arguments $new_instance et $old_instance. $new_instance est un tableau qui comprend les nouvelles valeurs tandis que $old_instance est le tableau des valeurs précédemment sauvegardées.
De la même façon que la fonction form, cette fonction ne prend pas en charge la sauvegarde en base de données. Il suffit juste de retourner le tableau des valeurs à sauvegarder. Autrement dit, WordPress nous prémache le boulot et c’est fun ! 😉
Les fonctions dont nous aurons besoin
Dernier point à aborder, quelles sont les autres fonctions qui nous serons utiles ?
La première de toute est __construct (notez bien les deux underscores avant le nom). Cette fonction est toujours appelée lors de la création d’un objet d’une classe. C’est aussi le moment que l’on indique comme instanciation. Elle sert notamment à initialiser tous les paramètres de l’objet. Lorsque nous déclarerons notre fonction __construct dans notre classe widget, nous ferons appel à cette même fonction de la classe mère mais nous y reviendrons plus tard.
Enfin, nous utiliserons deux autres méthodes get_field_id et get_field_name. Ces deux fonctions nous permettront de créer respectivement les identifiant et nom des attributs des différents champs correspondant aux paramètres de notre formulaire.
Procédure de création d’un widget
Maintenant que nous avons vu comment était constitué un widget, la question de savoir comment l’on crée un nouveau widget se pose ?
La structure est donc déjà existante et il faut l’utiliser. En programmation orientée objet (POO), on peut étendre une classe en une sous-classe. Cette sous-classe conserve la structure initiale de sa classe mère. Cette opération est très simple en PHP, elle prend la forme suivante :
Il nous reste à créer les fonctions widget, update, form et __construct.
Comme le widget Articles récents est très proche de ce que l’on veut réaliser, nous partirons de ce code que l’on adaptera à nos propres besoin.
Vous trouverez le source dans le dossier wp-includes/widgets de WordPress et dans le fichier class-wp-widget-recent-posts.php. Vous constaterez que les quatre fonctions que nous voulions sont bien là ! :).
Il suffit de copier/coller ce fichier dans l’arborescence des plugins de WordPress wp-content/plugins/nom-de-votre-plugin (sans oublier de renommer le nom de la classe).
Pour que votre widget soit reconnu, il faut mettre à jour les informations le concernant dans le premier bloc de commentaire. Attention le deux points ‘:’ doivent être collés au texte.
Vous trouverez dans ce qui suit, le code mis à jour des différentes fonctions. Les lignes surlignées en jaune indiquent que nous y avons porté une modification ou est un ajout de notre part.
Le point important ici est la ligne 7. Cette ligne de code fait appel à la fonction __construct de la classe WP_Widget en lui passant des arguments.
Je reprends ici la documentation de PHP sur les fonctions d’objet.
PHP permet aux développeurs de déclarer des constructeurs pour les classes. Les classes qui possèdent une méthode constructeur appellent cette méthode à chaque création d’une nouvelle instance de l’objet, ce qui est intéressant pour toutes les initialisations dont l’objet a besoin avant d’être utilisé.
Note: Les constructeurs parents ne sont pas appelés implicitement si la classe enfant définit un constructeur. Si vous voulez utiliser un constructeur parent, il sera nécessaire de faire appel à parent::__construct() depuis le constructeur enfant. Si l’enfant ne définit pas un constructeur alors il peut être hérité de la classe parent, exactement de la même façon qu’une méthode le serait (si elle n’a pas été déclarée comme privée).
Vous pouvez ensuite procéder par étapes pour chacune des fonctions suivantes :
- formulaire (form),
- validation (update),
- affichage (widget).
Je crois que l’on peut dire que, si l’on maitrise un tant soit peu le PHP, ces modifications sont relativement simples à mettre en place. Qu’en pensez-vous ?
Encore un petit effort
Oui, mais je ne vois toujours pas mon widget s’afficher dans l’interface admin. 🙁
En effet, si l’on en restait là, WordPress n’est pas encore en mesure d’intégrer complétement notre nouveau widget. Il faut donc une étape supplémentaire qui consiste à raccrocher notre code (en l’occurrence notre classe widget) au cœur de WordPress.
WordPress a encore une fois tout prévu et met à notre disposition des hook (crochets) qui permettent d’intégrer nos développements à WP. On distingue deux types de hook : le hook d’action, le hook de filtre. Pour notre cas, il nous faut utiliser un hook d’action widgets_init et l’on procède comme suit.
Dans son processus de lancement, WordPress déclenche un certain nombre d’évènements ou d’actions. Lorsqu’il déclenche le hook d’action widgets_init, il va procéder à toutes les initialisations des widgets présents dans les différents plugins ou thèmes. Dans notre cas, il appellera la fonction register_bwp_cpt_widget qui elle-même se chargera d’initialiser notre widget avec la fonction register_widget.
Une fois cette étape réalisée, WordPress reconnait notre widget et nous pouvons le visualiser aussi bien côté front end que back end !!! 🙂
Généraliser le widget à tous nos custom post types
Le dernier point que nous aborderons dans cet article est la généralisation à tous les custom post types créés dans notre thème ou les plugins installés.
Autrement dit, la création d’un menu déroulant avec tous les CPT dans le formulaire de paramétrage de notre widget.
Il suffit d’ajouter ces lignes dans la fonction form.
Ici, nous faisons appel à la fonction get_post_types qui nous ramène tous les CPT puis nous construisons le menu déroulant.
Si vous voulez en savoir plus, je vous invite à visualiser la vidéo.
Téléchargement des sources
Vous pouvez télécharger les sources sur GitHub.
Bonjour, merci pour ce tuto !!
J’ai tout suivi et mis en application pour les 3 types de widgets archives, post et comments. De plus ça m’a aidé à créé des widgets qui vont se filtrer automatiquement en récupérant le post type courant get_post_type()
Par contre je bloque sur la traduction… Je suis en mode thème enfant et j’essaye de tout lancer depuis une classe unique qui initialise tout (ça marche parfait pour tous les widgets créé suivant ta méthode) mais rien n’y fait pour la langue que j’ai créé avec POEdit 🙁
add_action(‘after_setup_theme’, ‘cpt_widgets_textdomain’);
function cpt_widgets_textdomain() {
if (function_exists(‘load_plugin_textdomain’)) {
load_child_theme_textdomain(‘ctp-widgets’, false, dirname( plugin_basename( __FILE__ ) ) . ‘/lang’ );
}
}
J’ai essayé after_setup_theme et plugins_loaded; load_child_theme_textdomain et load_plugin_textdomain…
Je fais choux blanc, si vous aviez une idée ?
Bonjour et merci pour ce retour positif pour mon tuto.
Ca fait toujours plaisir 🙂
Pour la traduction, il faudrait préciser dans quel dossier où tu as mis la traduction.
En effet, je crois qu’il y a une confusion entre le thème et le plugin…
load_child_theme_textdomain se charge de la traduction du thème alors que
load_plugin_textdomain se charge de la traduction du plugin.
La path passé à votre load_child_theme_textdomain se construit à partir de plugin_basename donc dans l’arbo wp-content/plugins/nom-du-plugin
alors qu’il devrait se construire à partir de get_stylesheet_directory() qui ramenerait l’arbo wp-content/themes/theme-enfant
Enfin, les hooks sont after_setup_theme et plugins_loaded respectivement pour les thèmes et les plugins.
J’espère que cela vous donne une piste…
Bonne continuation.
Olivier.
Nickel !
J’ai même compris … Mais je n’irai pas à mettre en pratique 😉
Très bonne présentation. Bravo.