Filtre de taxonomie d'un Custom Post Type WordPress, écran d'administration

Ajouter automatiquement un filtre de taxonomie pour chaque Custom Post Type WordPress

Les pages d’administration des posts de WordPress proposent un certain nombre de listes déroulantes, permettant de filtrer le tableau en fonction de critères comme le titre, la date ou l’auteur, mais la gestion d’un Custom Post Type et ses taxonomies peut nécessiter un peu plus de travail. Si certains plugins simplifient la création de Custom Post Types et taxonomies, ils ne permettent pas toujours de créer automatiquement un filtre de taxonomie personnalisée pour chaque type de contenu du site internet.

Lors d’une récente refonte de site internet, j’ai du réorganiser l’ensemble des contenus du site et fournir pour de nouveaux Custom Post Types des outils d’administration liées à leurs taxonomies. Le client souhait avoir la garantie que tous les Custom Post Types et taxonomies à venir seraient pris en compte par le système de filtre de l’écran d’administration de WordPress. En bon webmaster freelance, j’ai recherché une solution 😉

Nous allons voir comment créer, dans les sections de navigations hautes et basses de nos tableaux de posts, des filtres de taxonomies personnalisées, pour chaque taxonomie personnalisée présente sur le site, rattachée aux types de posts non natifs de WordPress.

Affichage d’un champ select pour chaque taxonomie de chaque Custom Post Type

L’action « restrict_manage_posts » permet d’ajouter un contenu supplémentaire aux sections de navigation d’un tableau de posts. Pour les curieux, elle est présente dans la class WP_Posts_List_Table au sein de la méthode extra_tablenav() qui surcharge celle de la classe mère WP_List_Table.

Nous nous servons de ce hook pour créer une liste déroulante de type <select> (voire plusieurs) servant de filtre à la liste des articles de l’écran d’administration (edit.php).

La fonction WordPress wp_dropdown_categories() nous permet de récupérer une liste déroulante de catégories ou de termes de taxonomies.

Les principaux arguments attendus par cette fonction sont :

  • l’identifiant de la taxonomie souhaitée : « taxonomy » (pour en afficher les termes) ;
  • l’attribut « name » du champ de formulaire <select> ;
  • la colonne de la table SQL sur laquelle le tri doit être effectué (« orderby ») ;
  • l’ordre de trie souhaité : « order » (ASC ou DESC) ;
  • la valeur de l’option sélectionnée : « selected ».

Les autres options parlent d’elles-mêmes.

La plupart des articles portant sur le sujet couplent le callback, la fonction wp_dropdown_categories() et les CPT et les taxonomies attendues. On lit donc souvent du code comme celui-ci pour proposer de façon conditionnelle des listes déroulantes :


function restrict_by_business(){
	global $typnenow ;
	if ($typenow=='listing') {
		$taxonomy = 'business';
		$business_taxonomy = get_taxonomy($taxonomy);
		// la suite du code…
}
add_action( ‘restrict_manage_posts’, ‘restrict_bu_business’ ) ;

Ici le type de post est testé grâce à la variable globale $typenow, et la taxonomie est injectée manuellement dans le code, ce qui rend la fonction dépendante de cette dernière.

Recherchons plutôt les taxonomies liées au Custom Post Type courant.

Récupérer chaque Custom Post Type du site

Nous allons lister les types de contenus disponibles avec get_post_types() qui retourne par défaut un tableau présentant une clé et une valeur équivalentes pour chaque entrée. Nous allons donc récupérer les valeurs uniquement (via array_values() ou array_keys()), tout en supprimant du résultat les types de posts natifs (_builtin’ => false ) :


/**
 * Récupération des types de contenus non natifs enregistrés
 */
if( !function_exists( 'jst_get_all_non_builtin_custom_post_types' ) )
{
	function jst_get_all_non_builtin_custom_post_types()
	{
		return array_values( get_post_types( array( '_builtin' => false ) ) );
	}
}

Générer automatiquement les listes déroulante

Le type de post courant est accessible depuis l’argument du callback du hook « restrict_manage_posts »… Pas vraiment besoin, donc, de passer par la variable global $typenow…

La fonction assigne les ID (term_id) des termes de la taxonomie aux valeurs des options du champ <select> généré. Nous allons donc assigner l’identifiant de la taxonomie (utilisé lors de son enregistrement avec register_taxonomy()) à l’attribut name de ce champ de formulaire. Nous pourrons donc récupérer, en paramètre GET, l’ID du terme sélectionné avec $_GET[ $tax_id ].

Itérons maintenant sur notre tableau de Custom Post Types afin d’ajouter une liste déroulante pour chaque taxonomie liée :


/**
 * Ajouter d'un filtre de taxonomie à chaque Custom Post Type sur l'écran edit.php
 */
function jst_restrict_manage_posts( $post_type )
{
	// Si ce n’est pas un Custom Post Type je ne fais rien
	$all_cpts = jst_get_all_non_builtin_custom_post_types();
	if( ! in_array( $post_type, $all_cpts ) )
	{
		return;
	}
	// Récupération des taxonomies liées au Custom Post Type
	$taxos = get_object_taxonomies( $post_type );
	// Itération
	foreach( $taxos as $tax_id )
	{
		$tax = get_taxonomy( $tax_id );
		// Récupération du l’ID du terme sélectionné au lors de la soumission
		$selected = isset( $_GET[ $tax_id ] ) ? $_GET[ $tax_id ] : 0;
		wp_dropdown_categories(array(
			'show_option_all'	=> sprintf( __( 'All %s', 'jst' ), $tax->label ),
			'taxonomy'		=> $tax_id,
			'name'			=> $tax_id,
			'orderby'		=> 'name',// colonne name de la table terms
			'order'			=> 'ASC',
			'hierarchical'		=> true,
			'show_count'		=> true,
			'selected'		=> $selected,
			‘hide_if_empty’		=> true,
		));

	}
}
add_action( 'restrict_manage_posts', 'jst_restrict_manage_posts' );

Les filtres sont affichés, mais il va nous falloir intercepter la requête pour transformer les paramètres de taxonomies et fournir à WP_Query le slug du terme sélectionné pour la taxonomie (au lieu de term_id).

Filtrer le tableau des posts : Intercepter la requête WordPress avec le hook « parse_query »

Comme nous l’avons vu, nous avons nommé chaque champ <select> avec l’identifiant de la taxonomie correspondante, et nous l’avons transmis en variable GET avec la valeur term_id du terme sélectionné pour filtrer le tableau.

Le hook « parse_query » va nous permettre d’agir directement sur les variables de la requête via la propriété query_vars de l’objet $wp_query. Nous allons échanger l‘ID du terme avec son slug pour reconstruire notre requête SQL.

Le processus de notre callback est le suivant :

  • récupération des variables de requête de WP_Query ;
  • validation de la présence de $_GET[ ‘post_type’ ] ou $wp_query->query_vars[ ‘post_type’ ] ;
  • validation du type de post (Custom Post Type ;
  • validation de l’écran d’édition avec global $pagenow ;
  • récupération des taxonomies pour l’identification des variables de termes wp_term.term_id ;
  • validation du type numérique de la valeur des variables de taxonomies ;
  • récupération de l’objet WP_Term avec get_term_by( ‘id’ ) ;
  • injection du slug du terme en lieu et place de son term_id dans wp_query->query_vars ;

/**
 * On Parse WP_Query uniquement sur l’écran edit.php et lorsqu’un CPT est filtré
 */
function themework_parse_query_to_manage_restrict( $wp_query )
{
	// Récupération d’une référence de $query_vars
	$qv =& $wp_query->query_vars;
	// Récupération de l’écran pour valider que l’on est sur la page d’administration
	global $pagenow;
	// Si ce n’est pas la page d’administration d’un Custom Type on retourne simplement les 
	// éléments de requête en l'état
	$all_post_types = jst_get_all_non_builtin_custom_post_types();
	if( 'edit.php' != $pagenow || !isset( $_GET[ 'post_type' ] ) || 
		! in_array( $_GET[ 'post_type' ], $all_post_types ) )
	{
		return $wp_query;
	}
	$requested_post_type = $_GET[ 'post_type' ];// Ou $qvs[ ‘post_type’ ]
	
	// Récupération des taxonomies liées au Custom Post Type
	$post_type_taxonomies = get_object_taxonomies( $requested_post_type );
	// Pour chaque taxonomie, modification de la variable de requête 
	// si elle est présente dans wp_query->query_vars
	foreach( $post_type_taxonomies as $tax_id )
	{
		if( isset( $qv[ $tax_id ] ) && is_numeric( $qv[ $tax_id ] ) )// Ou $_GET[ $tax_id ]
		{
			// Récupération de l’objet WP_Term via son ID
			$term = get_term_by( 'id', $qv[ $tax_id ], $tax_id );
			// Si le terme est trouvéon remplace l’ID par le slug du terme
			$qv[ $tax_id ]	= $term ? $term->slug : '';
		}
	}
	return $wp_query;
}
add_action( 'parse_query', 'themework_parse_query_to_manage_restrict' );

La requête est désormais « parsée » à chaque soumission du formulaire de filtre WordPress ajoutant un paramètre de taxonomie. Notez au passage qu’il est tout à fait possible de filtrer les posts selon les termes de plusieurs taxonomies :

Page d'un Custom Post Type WordPress filtrée avec les termes d'une taxonomie

Nous avons maintenant pour filtrer nos Custom Post Types, un champ <select> pour chaque taxonomie, sans nous soucier de leur identifiant ni des taxonomies associées. Nous avons donc découplé notre processus de filtre de toute taxonomie attendue. Notre système est devenu générique !

Filtrer les Custom Post Types par leur taxonomie, c’est pas mal. Mais avoir la possibilité de trier les résultats par ces mêmes colonnes de taxonomies, c’est encore mieux ! Je vous propose de voir ça dans l’article Une colonne triable de taxonomie dans la page d’administration des Custom Posts Type WordPress 😉

Laisser un commentaire

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