page de réglages d’une extension WordPress : formats de champs différents

Notre extension a été démarrée dans les premiers articles de cette série (). A ce stade, elle affiche uniquement des champs de type « texte » et n’affiche pas le contenu des arguments supplémentaires que l’on peut ajouter au champs.

Vous pouvez récupérer l’extension à ce stade dans ce fichier zip : clea-add-button V0.1 (zip)

Nous allons donc voir maintenant comment afficher des champs de type textarea, select, checkbox, radio button, wysiwig.

Modifier la fonction de restitution des champs

Dans le fichier « /admin/clea-add-button-settings-page.php « , il faut modifier la fonction clea_add_button_settings_field_callback( $arguments  )  pour qu’elle s’adapte à différents types de champs.

Nous utilisons la commande « switch » qui choisira l’action à réaliser selon le ‘type’ de champs à restituer :

switch( $arguments['type'] ){
	
	case 'text' : 
		echo "<input type='text' name='my-plugin-settings[$field]' value='$value' />";	
		break ;
	default : 
		printf( esc_html__( 'This field is type <em>%s</em> and could not be rendered.', 'clea-add-button' ), $arguments['type']  );
}

Ca fonctionne : le champs 1-1 est restitué comme un texte mais pas les autres puisque nous n’avons pas défini leur type pour l’instant.

Il va donc falloir que je modifie l’array qui définit les champs, dans la fonction clea_add_button_settings_fields_val() . Je veux que tous les champs soient définis par un array avec la forme suivante :

array(
	'field_id' 		=> 'field-1-1', 							
	'label'			=> __( 'Field One', 'clea-add-button' ), 	
	'field_callbk'	=> 'clea_add_button_settings_field_callback', 					
	'menu_slug'		=> 'my-plugin', 							
	'section_name'	=> 'section-1',
	'type'			=> 'text',
	'helper'		=> __( 'help 1-1', 'clea-presentation' ),
	'default'		=> ''			
)

J’en profite pour créer des champs avec tous les types que je vais définir dans cet article :

  • textarea,
  • select,
  • checkbox,
  • radio,
  • wysiwig
  • color picker

Et voici maintenant le nouveau contenu de la fonction clea_add_button_settings_fields_val()  :

function clea_add_button_settings_fields_val() {

	$section_1_fields = array (
		array(
			'field_id' 		=> 'field-1-1', 							
			'label'			=> __( 'Field One', 'clea-add-button' ), 	
			'field_callbk'	=> 'clea_add_button_settings_field_callback', 					
			'menu_slug'		=> 'my-plugin', 							
			'section_name'	=> 'section-1',
			'type'			=> 'text',
			'helper'		=> __( 'help 1-1', 'clea-presentation' ),
			'default'		=> ''			
		),	
		array(
			'field_id' 		=> 'field-1-2',
			'label'			=> __( 'Field Two : textarea', 'clea-add-button' ),
			'field_callbk'	=> 'clea_add_button_settings_field_callback', 
			'menu_slug'		=> 'my-plugin', 
			'section_name'	=> 'section-1',
			'type'			=> 'textarea',
			'helper'		=> __( 'help 1-2', 'clea-presentation' ),
			'default'		=> ''			
		),
	);
	
	$section_2_fields = array (
		array(
			'field_id' 		=> 'field-2-1', 
			'label'			=> __( 'Field One : radio', 'clea-add-button' ), 
			'field_callbk'	=> 'clea_add_button_settings_field_callback', 
			'menu_slug'		=> 'my-plugin', 
			'section_name'	=> 'section-2',
			'type'			=> 'radio',
			'helper'		=> __( 'help 2-1', 'clea-presentation' ),
			'default'		=> ''						
		),
		array(
			'field_id' 		=> 'field-2-2', 
			'label'			=> __( 'Field Two : wysiwig', 'clea-add-button' ), 
			'field_callbk'	=> 'clea_add_button_settings_field_callback', 
			'menu_slug'		=> 'my-plugin', 
			'section_name'	=> 'section-2',
			'type'			=> 'wysiwig',
			'helper'		=> __( 'help 2-2', 'clea-presentation' ),
			'default'		=> ''			
		),
				array(
			'field_id' 		=> 'field-2-3', 
			'label'			=> __( 'Field three : color', 'clea-add-button' ), 
			'field_callbk'	=> 'clea_add_button_settings_field_callback', 
			'menu_slug'		=> 'my-plugin', 
			'section_name'	=> 'section-2',
			'type'			=> 'color',
			'helper'		=> __( 'help 2-3', 'clea-presentation' ),
			'default'		=> ''			
		),
	);
	

	$section_fields = array(
		'section-1'	=> $section_1_fields,
		'section-2' => $section_2_fields
	) ;	

	
	
	return $section_fields ;
}

On a défini un champs pour chaque type qu’il faudra pouvoir afficher dans notre page de réglages.

Afficher des champs « textarea »

dans la fonction clea_add_button_settings_fields_val() , à l’intérieur du « switch », j’ajoute le cas ‘textarea’.

L’affichage d’un champs de type textarea nécessite les arguments suivants :

Pour l’affichage du contenu, on utilisera quelque chose comme :

<textarea name="whatever"><?php echo esc_textarea( $description ); ?></textarea>

Noter que l’on utilise la fonction esc_textarea() pour interdire qu’un caractère présent dans la variable $description  puisse être interprété comme du HTML.

Output en sécurité avec esc_…()

Pour plus de détails, voir cette page WordPress en anglais sur la sanitation et la validation de données.

Dans notre cas, nous restituerons les valeurs de la manière suivante :

Affichage du « textarea » plus précis

Dans la référence HTML5 du W3C, la page dédiée à <textarea> indique une multitude d’arguments pour définir sa forme. Et les attributs globaux, applicables à tous les éléments HTML5 contiennent entre autre « id » et « value ». Nous allons au minimum vouloir définir « rows » et « cols », respectivement le nombre de lignes et de colonnes de la zone de texte à définir. Au final, l’expression de notre textarea sera sous la forme : 

<textarea name="whatever" id="id" rows="4" cols="80" value=""><?php echo esc_textarea( $description ); ?></textarea>

Pour tous nos champs, les attributs devront prendre une valeur liée à la définition du champs. J’utilise printf pour rendre plus simple la définition de ce qui doit être affiché.

Et voici notre fonction modifiée pour utiliser esc_attr pour le cas ‘text’ et pour afficher correctement notre zone textarea :

function clea_add_button_settings_field_callback( $arguments  ) {

	$settings = (array) get_option( 'my-plugin-settings' );
	$field = $arguments['field_id'] ;
	$value = $settings[$field] ;

	// for development only
	if ( ENABLE_DEBUG ) {
		
		echo "<hr /><pre>";
		print_r( $arguments ) ;	
		echo "</pre><hr />";
	}
	
	$name = 'my-plugin-settings['. $field . ']' ;
	
	switch( $arguments['type'] ){
		
		case 'text' : 
			printf( '<input type="text" id="%3$s" name="%2$s" value="%1$s" />', esc_attr( $value ), $name, $field );
			break ;
		case 'textarea' : 
			printf( '<textarea name="%2$s" id="%3$s" rows="4" cols="80" value="%1$s">%1$s</textarea>', esc_textarea( $value ), $name, $field );
			break ;
		
		default : 
			printf( esc_html__( 'This field is type <em>%s</em> and could not be rendered.', 'clea-add-button' ), $arguments['type']  );
	}
}

A ce stade, notre page de réglages affiche :

Affichage correct d'un champs text et d'un champs textarea
Affichage correct d’un champs text et d’un champs textarea

Correction d’une notice PHP

Query Monitor (cf l’article précédent de cette série «  » indique 3 notices PHP. Ce sont des erreurs bénignes qu’il faut corriger.

Les trois notices portent sur des index indéfinis pour field-2-1, field-2-2 et field-2-3, sous la forme « Undefined index: field-2-1 ». Ces trois champs n’ont jamais été définis puisqu’on n’a pas encore pu leur attribuer une valeur. Cependant, il n’est pas normal que notre code traite des valeurs indéfinies sans « s’en rendre compte ».

Dans cet article de code.tutsplus, je vois qu’ils font deux vérifications avant de lire la valeur de l’option. La première consiste à vérifier qu’il existe bien des options pour notre réglage (‘my-plugin-settings’ pour moi, ‘sandbox_theme_display_options’ pour eux :

if( false == get_option( 'sandbox_theme_display_options' ) ) {  
    add_option( 'sandbox_theme_display_options' );
}

Cette vérification est réalisée au moment du ‘admin_init’, dans notre cas dans la fonction clea_add_button_admin_init()  modifiée comme suit :

function clea_add_button_admin_init() {
  
	if( false == get_option( 'my-plugin-settings' ) ) {  
		add_option( 'my-plugin-settings' );
	}
	
	register_setting( 'my-settings-group', 'my-plugin-settings' ) ;
	
	$set_sections = clea_add_button_settings_sections_val() ;
 
	// add_settings_section
	foreach( $set_sections as $section ) {
		
		add_settings_section( 
			$section[ 'section_name' ], 
			$section[ 'section_title' ] ,
			$section[ 'section_callbk' ], 
			$section[ 'menu_slug' ]
		);
		
	}	

	$set_fields = clea_add_button_settings_fields_val() ;
	
	// add the fields
	foreach ( $set_fields as $section_field ) {

		foreach( $section_field as $field ){

			add_settings_field( 
				$field['field_id'], 
				$field['label'], 
				$field['field_callbk'],  
				$field['menu_slug'], 
				$field['section_name'],
				$field
			);
		}

	}	
}

La seconde vérification porte sur l’option du champs en question :

// First, we read the social options collection
$options = get_option( 'sandbox_theme_social_options' );
     
// Next, we need to make sure the element is defined in the options. If not, we'll set an empty string.
$url = '';
if( isset( $options['twitter'] ) ) {
    $url = $options['twitter'];
} // end if

Cette partie là est réalisée dans la fonction « callback » du champs ‘twitter’.

Là dessus, j’ai longtemps bloqué car je dois vérifier si $settings[ $field ] est « isset » et pour une raison que j’ignorais ce n’était jamais le cas, même lorsqu’il y avait bien une valeur… Et puis je suis tombée sur cette question dans wordpress.stackexchange et j’ai enfin compris comment faire (mais pas franchement pourquoi !).

Ma fonction clea_add_button_settings_field_callback( $arguments ) contient maintenant une vérification au début. Si $options[ « $field » ] est « set », $value  prend la valeur de $settings[ $field ] . Dans le cas contraire, elle prend la valeur par défaut du champs.

function clea_add_button_settings_field_callback( $arguments  ) {


	$settings = (array) get_option( "my-plugin-settings" );
	$field = $arguments[ 'field_id' ] ;
	
	// for development only
	if ( ENABLE_DEBUG ) {
		
		echo "<hr /><p>Arguments</p><pre>";
		print_r( $arguments ) ;	
		echo "</pre><hr />";
		echo "<hr /><p>Options</p><pre>";
		print_r( $settings ) ;	
		echo "</pre><hr />";
	}
		
	// set a $options array with the field id as it's key
	if ( !empty( $settings ) ) {
		foreach ( $settings as $key => $option ) {
			$options[$key] = $option;
		}
	}	
	
	// now check if $options[ $field ] is set
	if( isset( $options[ "$field" ] ) ) {
			$value = $settings[ $field ] ;
	} else {
			// set the value to the default value
			$value = $arguments[ 'default' ] ;
	}	

	
	$name = 'my-plugin-settings['. $field . ']' ;

	switch( $arguments['type'] ){
		
		case 'text' : 
			printf( '<input type="text" id="%3$s" name="%2$s" value="%1$s" />', esc_attr( $value ), $name, $field );
			break ;
		case 'textarea' : 
			printf( '<textarea name="%2$s" id="%3$s" rows="4" cols="80" value="%1$s">%1$s</textarea>', esc_textarea( $value ), $name, $field );
			break ;
		
		default : 
			printf( esc_html__( 'This field is type <em>%s</em> and could not be rendered.', 'clea-add-button' ), $arguments['type']  );
	}
}

Les notices PHP pour les champs qui n’ont pas encore pu être saisis ont maintenant disparu.

Afficher des champs « select »

Notre champs select sera restitué sous la forme :

<select name="lenom" id="field-id" multiple="">
  <option value="volvo">Volvo</option>
  <option value="saab">Saab</option>
  <option value="vw">VW</option>
  <option value="audi" selected>Audi</option>
</select>

Si les options ne sont pas fixes (cas où il y a plusieurs champs select), il faut pouvoir les ajouter dans l’array de définition du champs. Je crée un troisième champs dans la section 1 avec les caractéristiques suivantes :

array(
	'field_id' 		=> 'field-1-3', 
	'label'			=> __( 'Field three : select', 'clea-add-button' ), 
	'field_callbk'	=> 'clea_add_button_settings_field_callback', 
	'menu_slug'		=> 'my-plugin', 
	'section_name'	=> 'section-1',
	'type'			=> 'select',
	'helper'		=> __( 'help 1-3', 'clea-presentation' ),
	'default'		=> '',
	'options'		=> array(
						__( 'Choix 1', 'clea-add-button' ) ,
						__( 'Choix 2', 'clea-add-button' )	,
						__( 'Choix 3', 'clea-add-button' )
					),				
),

Pour le visualiser, j’ajoute le cas ‘select’ comme suit :

case 'select': // If it is a select dropdown

	if( ! empty ( $arguments['options'] ) && is_array( $arguments['options'] ) ){
	
	printf( '<select id="%2$s" name="%1$s">', $name, $field );
	foreach( $arguments['options'] as $item ) {
		$selected = ( $value	 == $item ) ? 'selected="selected"' : '';
		echo "<option value='$item' $selected>$item</option>";
	}
	echo "</select>";	
	
	} else {
		echo __( 'Indiquer les options dans la définition du champs', 'clea-add-button' ) ;
	}
	break;

Et voilà maintenant la section 1 de ma page de réglage :

Affichage d'un champs "select"
Affichage d’un champs « select »

Afficher des champs « checkbox »

Notre champs checkbox sera restitué sous la forme :

<input type="hidden" name="my-plugin-settings[field-1-4]" id="field-1-4" value="0"> 
<input id="field-1-4" name="my-plugin-settings[field-1-4]" type="checkbox">

et si le champs est coché, il prendra la forme (observer le « checked » juste après « input » :

<input checked="checked" id="field-1-4" name="my-plugin-settings[field-1-4]" type="checkbox">

J’ajoute un quatrième champs dans la section 2 avec un type checkbox :

array(
	'field_id' 		=> 'field-1-4', 
	'label'			=> __( 'Field four : checkbox', 'clea-add-button' ), 
	'field_callbk'	=> 'clea_add_button_settings_field_callback', 
	'menu_slug'		=> 'my-plugin', 
	'section_name'	=> 'section-1',
	'type'			=> 'checkbox',
	'helper'		=> __( 'help 1-4', 'clea-presentation' ),
	'default'		=> '',
)

Pour le visualiser, j’ajoute le cas ‘checkbox’ comme suit :

case 'checkbox' : 
	printf( '<input type="hidden" name="%1$s" id="%2$s" value="0" />', $name, $field ) ;			
	$checked = '' ;
        if( $value ) { $checked = ' checked="checked" ' ; }
	printf( ' <input %3$s id="%2$s" name="%1$s" type="checkbox" />', $name, $field, $checked ) ;
	break ;

Et voilà maintenant la section 1 de ma page de réglage contient un champ texte, un champ textarea, un champ select et un champ checkbox :

Affichage d'un champs "checkbox"
Affichage d’un champs « checkbox »

Afficher des champs « radio button »

Notre champs radio sera restitué sous la forme :

<span class="radio">
	<label><input type="radio" value="Choix 1" name="my-plugin-settings[field-2-1]" checked=""> Choix 1</label><br>
	<label><input type="radio" value="Choix 2" name="my-plugin-settings[field-2-1]"> Choix 2</label><br>
	<label><input type="radio" value="Choix 3" name="my-plugin-settings[field-2-1]"> Choix 3</label><br>
</span>

Si les options ne sont pas fixes, il faut pouvoir les ajouter dans l’array de définition du champs. Je modifie le premier champ de la section 2 comme pour le champs de type radio, en y ajoutant des options.

Pour le visualiser, j’ajoute le cas ‘radio’ comme suit :

case 'radio' : // radio buttons
	if( ! empty ( $arguments['options'] ) && is_array( $arguments['options'] ) ){
		
		echo "<span class='radio'>" ;
		foreach( $arguments['options'] as $key => $label ){
			
			$items[] = $label ;
		}

		foreach( $arguments['options'] as $item) {
			$checked = ( $value == $item ) ? 'checked' : '';
			printf( '<label><input type="radio" value="%2$s" name="%1$s" %3$s> %2$s</label><br />', $name, $item, $checked );
		}
		echo "</span>" ;
	}
	break ;

Et voilà maintenant la section 2 de ma page de réglage contient un premier champs radio correctement présenté :

Affichage d'un champs "radio"
Affichage d’un champs « radio »

Afficher des champs « wysiwig « 

Notre champs wisiwig correspond à un éditeur, un peu comme lorsqu’on crée un article dans WordPress. Il est restitué par la fonction wp_editor de WordPress. Ici j’ai choisi de ne pas ajouter d’arguments spécifiques.

Pour le visualiser, j’ajoute le cas ‘wysiwig’ comme suit :

case 'wysiwig' :

	// sanitize data for the wp_editor
	$content = wp_kses_post( $value ) ;
	
	$args = array(
		'textarea_name' => $name
	) ;
	
	wp_editor( $content, $field, $args );		
	break ;

Le Codex pour wp_editor() indique que l’ID de l’éditeur ne peut contenir que des minuscules et des tirets bas (underscores). J’ai donc modifié le ‘field_id’ pour qu’il devienne field_2_2.

On notera que $value est nettoyé avec la fonction wp_kses_post(), qui permet entre autres d’avoir des images dans le texte.

Et voilà maintenant la section 2 contient un éditeur de texte :

Affichage d'un champs "wp-editor"
Affichage d’un champs « wp-editor »

Et maintenant

Nous verrons dans le prochain article de cette série () comment restituer le dernier champs comme un  color picker, et aussi comment afficher les arguments supplémentaires.

L’extension à ce stade est disponible, compressée en zip : clea-add-button avec éditeur wp_editor (zip)

Poster un Commentaire

avatar
  S’abonner  
Notifier de