Jouer avec Widget : Comment ajouter un champ image dans le vôtre ?

Si vous développez un peu sur wordpress, vous avez sûrement déjà trouvé des tutos sur la création de widget persos directement dans le thème, sans passer par un plugin. Seulement peut-être que comme moi vous avez eu besoin à un moment donné d’ajouter un champ image dans votre widget, et là vous avez été un peu démunis ? Voici une synthèse de ce que j’ai pu glaner ci et là, et qui fonctionne très bien !

Comment ça marche un widget ?

Avant de regarder à droite et à gauche, je rappelerai juste que WordPress met à disposition un codex très bien fourni, offrant plein d’explication notamment sur les widgets : http://codex.wordpress.org/Widgets_API.

 

 

Sur cette page, vous avez déjà pas mal d’explications. On ne va pas réinventer la roue, il y a même un « template » de class qui fait le café :

class My_Widget extends WP_Widget {
	/**
	 * Sets up the widgets name etc
	 */
	public function __construct() {
		// widget actual processes
	}
	/**
	 * Outputs the content of the widget
	 *
	 * @param array $args
	 * @param array $instance
	 */
	public function widget( $args, $instance ) {
		// outputs the content of the widget
	}
	/**
	 * Outputs the options form on admin
	 *
	 * @param array $instance The widget options
	 */
	public function form( $instance ) {
		// outputs the options form on admin
	}
	/**
	 * Processing widget options on save
	 *
	 * @param array $new_instance The new options
	 * @param array $old_instance The previous options
	 */
	public function update( $new_instance, $old_instance ) {
		// processes widget options to be saved
	}
}

On voit bien qu’il y a un constructeur pour initialiser le widget, une fonction qui décrit quoi afficher coté site web, une fonction qui définit les champs à afficher dans l’interface d’administration, puis une fonction qui sera appelée à l’enregistrement du widget.

Créer la classe ne suffit pas, il faut aussi l’instancier. Pour cela il faut rajouter une action :

add_action('widgets_init', create_function('', 'return register_widget("Kicoe_Profile");'));

J’ai personnellement fait le choix de faire ce widget dans un fichier à part, appelé dans mon functions.php. J’aime bien compartimenter, mais c’est tout à fait personnel.

 

Ce qui change pour un widget avec un média

C’est bête, mais j’y ai perdu pas mal de temps à ne pas comprendre pourquoi rien ne marchait… Il faut dans le constructeur appeler une fonction wordpress : http://codex.wordpress.org/Function_Reference/wp_enqueue_media

Cette fonction va initialiser tout ce qui est nécessaire en termes de style, scripts et paramètres pour pouvoir avoir un champ « média ». Pour faire un widget média, ça pourra toujours être utile 😉

 

Coté backoffice

Vous l’aurez compris avec le template de classe fourni par wordpress, tout va se passer dans la fonction « form ». Il va falloir y configurer un bouton qui permet d’ouvrir la fenêtre de sélection de média, et qui va sauvegarder l’image que l’on souhaite insérer. Ca parait bête comme ça, mais ça ne l’est pas autant qu’il y parait. En effet, pour ouvrir une fenêtre en mode « overlay » (ou popin, ou lightbox en fonction de votre dialecte informethnique) il faut du javascript. Là, j’ai vu de tout sur internet… La solution la plus répendue, c’est l’utilisation d’un js externe qui est ajouté à la file de script à la condition où on se trouve dans bla bla bla…

Bon, on est en train de parler d’une trentaine de ligne là… Franchement, cela a-t-il une réelle valeur ajouter d’ajouter du temps de traitement, des conditions, des appels… J’ai choisi de m’élever et de dire non ! Je met donc mon bout de js dans un <script> et ça ira très bien  :

jQuery(document).ready( function(){
	function media_upload(mediaclass) {
		var _custom_media = true,
		_orig_send_attachment = wp.media.editor.send.attachment;
		jQuery('body').on('click',mediaclass, function(e) {
			var button_id ='#'+jQuery(this).attr('id');
			/* console.log(button_id); */
			var self = jQuery(button_id);
			var send_attachment_bkp = wp.media.editor.send.attachment;
			var button = jQuery(button_id);
			var id = button.attr('id').replace('_button', '');
			_custom_media = true;
			wp.media.editor.send.attachment = function(props, attachment){
				if ( _custom_media  ) {
				   jQuery('.custom_media_id').val(attachment.id);
				   jQuery('.custom_media_url').val(attachment.url);
				   jQuery('.custom_media_image').attr('src',attachment.url).css('display','block');
				} else {
					return _orig_send_attachment.apply( button_id, [props, attachment] );
				}
			}
			wp.media.editor.open(button);
			return false;
		});
	}
	media_upload('.custom_media_upload');
});

Ensuite la question que je me suis posée, c’est « qu’est-ce que je récupère, et dans quoi? ». Au départ, j’avais un simple champ texte, qui récupérait l’adresse de l’image. Seulement voilà, en front j’affichait l’image en grand. Mais on se prive de l’avantage de ce mode de fonctionnement qui est de générer des miniatures à la demande. Et puis je me suis dit aussi, à quoi ça sert? Finalement, je veux juste m’assurer que je récupère bien la bonne image non ?

J’ai donc choisit d’avoir trois éléments  :

  1. Un champ hidden pour récupérer l’url de l’image (on verra plus tard pourquoi)
  2. Un champ hidden pour récupérer l’id de l’image (spoiler alert : wp_get_attachment_image)
  3. Une image
<img class="custom_media_image" src="<?php if(!empty($instance['custom_media_uri'])){echo $instance['custom_media_uri'];} ?>" style="margin:0px 10px 0px 0px; border-radius: 2px; padding:5px;max-width:80px; border: 1px solid #ccc; float:left;display:inline-block" />
<input type="hidden" class="custom_media_url" name="<?php echo $this->get_field_name('custom_media_uri'); ?>" id="<?php echo $this->get_field_id('custom_media_uri'); ?>" value="<?php echo $instance['custom_media_uri']; ?>">
<input type="hidden" class="custom_media_id" name="<?php echo $this->get_field_name('custom_media_id'); ?>" id="<?php echo $this->get_field_id('custom_media_id'); ?>" value="<?php echo $instance['custom_media_id']; ?>">

Jusque là tout va bien. En rajoutant un champ texte pour mettre quelque chose d’hyper important au dessus de l’image, la fonction finale ressemble à ça :

public function form( $instance ) {
	// outputs the options form on admin
	?>
	<p>
		<label for="<?php echo $this->get_field_id('text'); ?>"><?php _e('Text', THEMENAME); ?></label><br />
		<input type="text" name="<?php echo $this->get_field_name('text'); ?>" id="<?php echo $this->get_field_id('text'); ?>" value="<?php echo $instance['text']; ?>" class="" />
	</p>
	<p>
		<label for="<?php echo $this->get_field_id('image_uri'); ?>">Image</label>
		<br />
		<img class="custom_media_image" src="<?php if(!empty($instance['image_uri'])){echo $instance['image_uri'];} ?>" style="margin:0px 10px 0px 0px; border-radius: 2px; padding:5px;max-width:90px; border: 1px solid #ccc; float:left;display:inline-block" />
		<input type="hidden" class="custom_media_url" name="<?php echo $this->get_field_name('image_uri'); ?>" id="<?php echo $this->get_field_id('image_uri'); ?>" value="<?php echo $instance['image_uri']; ?>">
		<input type="hidden" class="custom_media_id" name="<?php echo $this->get_field_name('image_id'); ?>" id="<?php echo $this->get_field_id('image_id'); ?>" value="<?php echo $instance['image_id']; ?>">
		<input type="button" value="<?php _e( 'Upload Image', 'theme name' ); ?>" class="button custom_media_upload" id="custom_image_uploader"/>
	</p>
	<br /><br /><br />
	<script>
		jQuery(document).ready( function(){
			function media_upload(mediaclass) {
				var _custom_media = true,
				_orig_send_attachment = wp.media.editor.send.attachment;
				jQuery('body').on('click',mediaclass, function(e) {
					var button_id ='#'+jQuery(this).attr('id');
					/* console.log(button_id); */
					var self = jQuery(button_id);
					var send_attachment_bkp = wp.media.editor.send.attachment;
					var button = jQuery(button_id);
					var id = button.attr('id').replace('_button', '');
					_custom_media = true;
					wp.media.editor.send.attachment = function(props, attachment){
						if ( _custom_media  ) {
						   jQuery('.custom_media_id').val(attachment.id);
						   jQuery('.custom_media_url').val(attachment.url);
						   jQuery('.custom_media_image').attr('src',attachment.url).css('display','block');
						} else {
							return _orig_send_attachment.apply( button_id, [props, attachment] );
						}
					}
					wp.media.editor.open(button);
					return false;
				});
			}
			media_upload('.custom_media_upload');
		});
	</script>
	<?php
}

Enregistrer les informations

Pour enregistrer ce que j’ai définit, ça se passe en trois temps :

  1. J’initialise  une nouvelle variable à partir de mon ancienne instance de widget
  2. Je mets à jour tous les champs : ainsi, ceux non modifiés vont juste écraser leurs propres valeurs
  3. Je renvoie la nouvelle variable

En pratique ça donne ça :

public function update( $new_instance, $old_instance ) {
	// processes widget options to be saved
	$instance = $old_instance;
    $instance['text'] = strip_tags( $new_instance['text'] );
    $instance['image_uri'] = strip_tags( $new_instance['image_uri'] );
    $instance['image_id'] = strip_tags( $new_instance['image_id'] );
    return $instance;
}

 

Afficher tout cela

Pour tout afficher, ça sera simple : la fonction widget. Vous vous souvenez, tout à l’heure on a voulu sauvegarder l’id de l’image? C’est parce que à partir de cet id, je peux retrouver n’improte quelle taille de mon image.

J’ai par exemple créé une taille dans mon functions.php :

add_image_size( 'profilethumb', 200, 200, true);

Ainsi, ma fonction widget donne ceci :

public function widget( $args, $instance ) {
	// outputs the content of the widget
    extract( $args );
	echo wp_get_attachment_image($instance['image_id'], 'profilethumb', false);
}

 

Résultat

Dans mon cas, j’ai appelé mon widget « Kicoe Profile », voici ce que cela donne :

capture

Et voici le code complet :

 

<?php
/**
 * Custom widgets
 *
 * @package kicoe
 */
 class Kicoe_Profile extends WP_Widget {
	/**
	 * Sets up the widgets name etc
	 */
	public function __construct() {
		// widget actual processes
		parent::WP_Widget(false, $name = __('Kicoe Profile', 'wp_widget_plugin') );
		wp_enqueue_media();
	}
	/**
	 * Outputs the content of the widget
	 *
	 * @param array $args
	 * @param array $instance
	 */
	public function widget( $args, $instance ) {
		// outputs the content of the widget
        extract( $args );
		echo wp_get_attachment_image($instance['image_id'], 'profilethumb', false);
	}
	/**
	 * Outputs the options form on admin
	 *
	 * @param array $instance The widget options
	 */
	public function form( $instance ) {
		// outputs the options form on admin
		?>
		<p>
			<label for="<?php echo $this->get_field_id('text'); ?>"><?php _e('Text', THEMENAME); ?></label><br />
			<input type="text" name="<?php echo $this->get_field_name('text'); ?>" id="<?php echo $this->get_field_id('text'); ?>" value="<?php echo $instance['text']; ?>" class="" />
		</p>
		<p>
			<label for="<?php echo $this->get_field_id('image_uri'); ?>">Image</label>
			<br />
			<img class="custom_media_image" src="<?php if(!empty($instance['image_uri'])){echo $instance['image_uri'];} ?>" style="margin:0px 10px 0px 0px; border-radius: 2px; padding:5px;max-width:90px; border: 1px solid #ccc; float:left;display:inline-block" />
			<input type="hidden" class="custom_media_url" name="<?php echo $this->get_field_name('image_uri'); ?>" id="<?php echo $this->get_field_id('image_uri'); ?>" value="<?php echo $instance['image_uri']; ?>">
			<input type="hidden" class="custom_media_id" name="<?php echo $this->get_field_name('image_id'); ?>" id="<?php echo $this->get_field_id('image_id'); ?>" value="<?php echo $instance['image_id']; ?>">
			<input type="button" value="<?php _e( 'Upload Image', 'theme name' ); ?>" class="button custom_media_upload" id="custom_image_uploader"/>
		</p>
		<br /><br /><br />
		<script>
			jQuery(document).ready( function(){
				function media_upload(mediaclass) {
					var _custom_media = true,
					_orig_send_attachment = wp.media.editor.send.attachment;
					jQuery('body').on('click',mediaclass, function(e) {
						var button_id ='#'+jQuery(this).attr('id');
						/* console.log(button_id); */
						var self = jQuery(button_id);
						var send_attachment_bkp = wp.media.editor.send.attachment;
						var button = jQuery(button_id);
						var id = button.attr('id').replace('_button', '');
						_custom_media = true;
						wp.media.editor.send.attachment = function(props, attachment){
							if ( _custom_media  ) {
							   jQuery('.custom_media_id').val(attachment.id);
							   jQuery('.custom_media_url').val(attachment.url);
							   jQuery('.custom_media_image').attr('src',attachment.url).css('display','block');
							} else {
								return _orig_send_attachment.apply( button_id, [props, attachment] );
							}
						}
						wp.media.editor.open(button);
						return false;
					});
				}
				media_upload('.custom_media_upload');
			});
		</script>
		<?php
	}
	/**
	 * Processing widget options on save
	 *
	 * @param array $new_instance The new options
	 * @param array $old_instance The previous options
	 */
	public function update( $new_instance, $old_instance ) {
		// processes widget options to be saved
		$instance = $old_instance;
        $instance['text'] = strip_tags( $new_instance['text'] );
        $instance['image_uri'] = strip_tags( $new_instance['image_uri'] );
        $instance['image_id'] = strip_tags( $new_instance['image_id'] );
        return $instance;
	}
}
add_action('widgets_init', create_function('', 'return register_widget("Kicoe_Profile");'));
 ?>

1 commentaire

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *