Développez un widget WordPress avec upload d’image

Les widgets existants de WordPress ne répondent pas à votre besoin ? Vous souhaitez disposer d’un widget personnalisé avec par exemple la possibilité d’uploader une image ?

Les widgets sont indispensables pour la personnalisation votre site. Vous avez certainement remarqué qu’en utilisant certains themes ou plugins du marché, de nouveaux widgets sont apparus dans votre section d’administration.

Dans cet article, nous allons apprendre à coder notre propre widget en PHP. Nous allons pour cela, créer un plugin qui implémentera ce nouveau widget.

Widget sur-mesure

Nous allons développer un widget promotionnel pour mettre en avant un produit sur notre site.

Dans un premier temps, le widget permettra la saisie de contenu. Puis dans un second temps, l’upload d’image.

Création du plugin

Vous pouvez ajouter tout le code de cet article dans le fichier functions.php de votre thème, cependant un widget doit être initialisé à partir d’un plugin.

Tout d’abord, créez un nouveau dossier dans votre répertoire wp-content/plugins. Nous l’appellerons widget-promo

Ensuite, créez le fichier plugin principal dans le dossier. il doit avoir le même nom que le dossier, avec une extension PHP: widget-promo.php.

Ouvrez le nouveau fichier et collez le code PHP ci-dessous. Celui-ci est analysé par WordPress et les informations sont utilisées pour lister votre plugin dans la section plugins.

/*
Plugin Name: Widget Promo
Version: 1.0
Plugin URI: https://www.partikuls.com
Description: Widget de promotion d'un produit amazon
Author: @khelil
Author URI: https://www.partikuls.com
*/

A ce stade, vous avez un plugin entièrement fonctionnel ! Il ne fait rien, mais est quand même listé dans la section plugins. Nous allons donc l’activer !

Anatomie du widget

L’implémentation de notre widget WordPress, va se dérouler en quatre étapes distinctes :

  1. initialisation du widget,
  2. affichage du formulaire dans le backend,
  3. traitement des données du formulaire,
  4. comportement du widget sur le frontend.

Ces étapes se traduisent toutes par des fonctions spécifiques de la classe WP_Widget. Voyons ce que ça donne en posant  la structure de notre code.

add_action( 'widgets_init', 'pk_widget_promo_init' );

function pk_widget_promo_init() {
  register_widget( 'pk_widget_promo' );
}

class pk_widget_promo extends WP_Widget {

  public function __construct() {
   // Constructeur, intialisation du widget
  }
  
  public function form( $instance ) { 
   // affichage du formulaire en backend 
  } 

  public function update( $new_instance, $old_instance ) { 
   // traitement des données du formulaires 
  }
  public function widget( $args, $instance ) {
   // comportement du widget en frontend
  }

}

Vous notez que parce que la classe pk_widget_promo étend la classe WP_Widget, elle hérites donc de ses propriétés et fonctions.

Pour que notre widget soit visible dans l’administration du site nous devons l’enregistrer auprès de WordPress. Pour cela nous allons appeler la fonctionregister_widget('pk_widget_promo') en lui passant le nom de notre classe

Cette fonction doit être appelé au bon moment, dans le chargement de tous les composants de WordPress. Pour cela, WordPress met à disposition un hook d’initialisation des widgets add_action( 'widgets_init', 'pk_widget_promo_init' );

A noter que la partie pk_ du schéma de nommage fait référence à Partikuls. Cette convention s’appelle le pré-fixage de fonction et sert à bien différencier les fonctions pour éviter les conflits de noms avec d’autres plugins.

Le constructeur de widget

La méthode __construct() implémente les informations de base du widget. Le constructeur de la classe de base WP_Widget va faire le gros du travail, nous allons simplement l’appeler en lui transmettant quelques valeurs. En ajoutant le code ci-dessous dans le constructeur, notre widget apparaîtra dans la section des widgets de WordPress.

$widget_details = array(
  'classname'   => 'pk_widget_promo',
  'description' => 'Cree un produit avec titre, image, description and lien.'
);

parent::__construct( 'pk_widget_promo', 'Widget Promo', $widget_details );

Le formulaire d’administration (backend)

Lorsque l’utilisateur fait glisser son widget dans la barre latérale, un formulaire s’affiche. Les informations renseignées seront utilisées pour l’affichage en frontend. Le formulaire va proposer les champs suivants :  titre, description, le lien et l’URL du lien. Nous ajoutons l’image plus tard.

La version finale de la méthode form() est ci-dessous :

public function form( $instance )
{

    $title = '';
    if( !empty( $instance['title'] ) ) {
        $title = $instance['title'];
    }

    $description = '';
    if( !empty( $instance['description'] ) ) {
        $description = $instance['description'];
    }

    $link_url = '';
    if( !empty( $instance['link_url'] ) ) {
        $link_url = $instance['link_url'];
    }

    $link_title = '';
    if( !empty( $instance['link_title'] ) ) {
        $link_title = $instance['link_title'];
    }

    ?>
    <p>
        <label for="<?php echo $this->get_field_name( 'title' ); ?>"><?php _e( 'Title:' ); ?></label>
        <input class="widefat" id="<?php echo $this->get_field_id( 'title' ); ?>" name="<?php echo $this->get_field_name( 'title' ); ?>" type="text" value="<?php echo esc_attr( $title ); ?>" />
    </p>

    <p>
        <label for="<?php echo $this->get_field_name( 'description' ); ?>"><?php _e( 'Description:' ); ?></label>
        <textarea class="widefat" id="<?php echo $this->get_field_id( 'description' ); ?>" name="<?php echo $this->get_field_name( 'description' ); ?>" type="text" ><?php echo esc_attr( $description ); ?></textarea>
    </p>

    <p>
        <label for="<?php echo $this->get_field_name( 'link_url' ); ?>"><?php _e( 'Link URL:' ); ?></label>
        <input class="widefat" id="<?php echo $this->get_field_id( 'link_url' ); ?>" name="<?php echo $this->get_field_name( 'link_url' ); ?>" type="text" value="<?php echo esc_attr( $link_url ); ?>" />
    </p>

    <p>
        <label for="<?php echo $this->get_field_name( 'link_title' ); ?>"><?php _e( 'Link Title:' ); ?></label>
        <input class="widefat" id="<?php echo $this->get_field_id( 'link_title' ); ?>" name="<?php echo $this->get_field_name( 'link_title' ); ?>" type="text" value="<?php echo esc_attr( $link_title ); ?>" />
    </p>

<?php
}

La fonction form() affiche le formulaire de saisie du widget. Vous remarquez que la fonction prend en argument $instance. Cette variable contient les valeurs de nos champs quand le formulaire est validé par l’utilisateur. Pour chaque variable de notre formulaire, nous créons un label et un champ de saisie, en utilisant les fonctions get_field_name() et get_field_id(), de WordPress et en leur passant le nom de la variable.

La raison pour laquelle nous avons besoin de ces fonctions au lieu de simplement taper les noms et les identifiants nous-mêmes est qu’il peut y avoir plusieurs instances du même widget. Heureusement pour nous, c’est WordPress qui gère tout cela. Le nom final de notre élément d’entrée sera de la forme widget-pk_widget_promo[2][link_url] au lieu de simplement[link_url] . C’est ainsi que WordPress gère plusieurs barres latérales et plusieurs widgets.

Le résultat de ce code est un formulaire dans la section widgets.

Formulaire de widget
Le formulaire de notre widget dans la section des widgets.

Traitement des données du formulaire

Grâce à la fonction update(), nous pouvons traiter les données du formulaire avant de les sauvegarder en base. Cette fonction est pratique si vous voulez transformer les données, vous pouvez par exemple nettoyer des URL, des numéros ou autres données numériques.

Dans notre cas, nous n’avons besoin de rien de spécial, donc notre fonction finale ressemblera à ceci:

public function update( $new_instance, $old_instance ) {        
    return $new_instance;
}

Affichage du widget

Enfin, la fonction widget($args, $instance) affiche notre widget. Vous pouvez ajouter n’importe quel HTML ici, il s’affichera dans la barre latérale.

La fonction prend deux arguments : le premier$args contient des données de la zone du widget elle-même, et la seconde $instance contient les variables de l’instance de notre widget.

Lorsque les zones de widget sont configurées, un certain nombre de paramètres sont définis. Le contenu à ajouter avant / après le widget et avant / après le titre du widget est le plus visible. Pour vous assurer que vos widgets fonctionnent bien avec d’autres plugins et WordPress, il est conseillé d’utiliser la structure suivante lors de la création de widgets :

echo $args['before_widget'];
if ( ! empty( $instance['title'] ) ) {
  echo $args['before_title'] . apply_filters( 'widget_title', $instance['title'] ). $args['after_title'];
}

// Rest of the widget content
echo $args['after_widget'];

Nous ajoutons les valeurs des champs description et lien, que nous construisons à partir des variables link_url et link_title, ce qui donne :

echo $args['before_widget']; 
if ( ! empty( $instance['title'] ) ) {
  echo $args['before_title'] . apply_filters( 'widget_title', $instance['title'] ). $args['after_title']; 
}

  <div class='mfc-description'>
    <?php echo wpautop( esc_html( $instance['description'] ) ) ?>
  </div>

  <div class='mfc-link'>
    <a href='<?php echo esc_url( $instance['link_url'] ) ?>'><?php echo esc_html( $instance['link_title'] ) ?></a>
  </div>

// Rest of the widget content 
echo $args['after_widget'];

N’oubliez pas d’utiliser des fonctions d’échappement de chaîne, qui servent à protéger les données avant qu’elles ne soient servies à l’utilisateur. Le résultat de notre code devrait être le suivant:

Contenu en vedette
Le widget jusqu’à présent.

Ajouter une image au Widget

Vous pouvez utiliser plusieurs méthodes pour gérer l’ajout d’une image. Dans tous les cas, vous devrez inclure du JavaScript et des css. Ce qui signifie que nous devrons apprendre à les ajouter aux widgets. Nous utiliserons la fonction native de WordPress pour la gestion de la bibliothèque de médias – pas besoin de réinventer la roue. Si vous créez une solution personnalisée, les méthodes d’inclusion du JavaScript et de feuilles de style sont presque identiques.

Nous devons mettre en file d’attente les scripts, comme nous le ferions sur le front-end ou l’admin WordPress. Les actions pour ce faire doivent être définies dans la fonction constructeur. Ajoutons ce qui suit:

add_action( 'admin_enqueue_scripts', array( $this, 'pk_widget_assets' ) );

Si vous n’êtes pas familier avec le OOP (PHP orienté objet), la notation peut vous perturber. Le deuxième paramètre de la fonction add_action() est généralement une chaîne qui indique la fonction appelée. La même chose se passe ici mais nous indiquons que nous voulons que la fonction pk_widget_assets() de notre classe et pas celle dans la portée globale.

L’étape suivante consiste à créer la fonction pk_widget_assets() dans notre classe et à mettre en file d’attente les scripts et les styles nécessaires.

public function pk_widget_assets()
{
    wp_enqueue_script('media-upload');
    wp_enqueue_script('thickbox');
    wp_enqueue_script('pk-widget-media-upload', plugin_dir_url(__FILE__) . 'pk-widget-media-upload.js', array( 'jquery' )) ;
    wp_enqueue_style('thickbox');
}

Ci-dessus, nous avons mis en file d’attente les scripts media-upload et thickbox . Ceux-ci sont inclus dans WordPress et sont les composants de base de la gestion des médias. Nous incluons également notre propre fichier pk-widget-media-upload.js, qui est un fichier JavaScript très simple qui régit notre processus de téléchargement (plus de détails dans un instant). Dernier point, mais non le moindre, le style requis pour la fonctionnalité thickbox est également mis en file d’attente.

L’étape suivante consiste à modifier le formulaire backend pour ajouter le champ image. Nous avons besoin d’identifier la variable et d’afficher le champ d’upload, comme nous l’avons fait auparavant :

$image = '';
if(isset($instance['image']))
{
    $image = $instance['image'];
}

<p>
    <label for="<?php echo $this->get_field_name( 'image' ); ?>"><?php _e( 'Image:' ); ?></label>
    <input name="<?php echo $this->get_field_name( 'image' ); ?>" id="<?php echo $this->get_field_id( 'image' ); ?>" class="widefat" type="text" size="36"  value="<?php echo esc_url( $image ); ?>" />
    <input class="upload_image_button" type="button" value="Upload Image" />
</p>

Notez que ceci est très similaire à ce que nous avons fait précédemment. Le seul ajout est une entrée de bouton avec la classe upload_image_button. Notre Javascript détectera quand ce bouton est utilisé, pour uploader l’image.

Créez un nouveau fichier dans le répertoire de votre plugin, nommez-le pk-widget-media-upload.js. Le code que vous devrez coller à l’intérieur est le suivant :

jQuery(document).ready(function($) {
    $(document).on("click", ".upload_image_button", function() {

        jQuery.data(document.body, 'prevElement', $(this).prev());

        window.send_to_editor = function(html) {
            var imgurl = jQuery('img',html).attr('src');
            var inputText = jQuery.data(document.body, 'prevElement');

            if(inputText != undefined &amp;&amp; inputText != '')
            {
                inputText.val(imgurl);
            }

            tb_remove();
        };

        tb_show('', 'media-upload.php?type=image&amp;TB_iframe=true');
        return false;
    });
});

Ce script va ouvrir l’écran de gestion des médias lorsque l’utilisateur cliquera sur le bouton. Une fois l’image chargée, l’URL sera transmise au champ du formulaire pour être sauvegardée.

Enfin, nous devons utiliser la nouvelle valeur de l’image pour l’afficher sur le frontend. C’est fait en ajoutant le code suivant à la fonction widget() :

<p>
<img src='<?php echo $instance['image'] ?>'>
</p>

Le résultat final devrait ressembler à l’image ci-dessous:

Widget de contenu en vedette avec l'image
Notre widget produit

Comme vous pouvez le voir, la création d’un widget demande un peu de travail, mais une fois que vous l’aurez compris, cela ne devrait prendre que 15 à 20 minutes pour produire un widget simple comme celui-ci. Il peut ajouter beaucoup de puissance et de contrôle pour un utilisateur sur un site Web, sans parler du stress qu’il peut enlever aux épaules d’un développeur – le client peut gérer la barre latérale.