Contenu principal

Afficher les articles d’une catégorie, sans les sous-catégories

Dans WordPress, lorsque vous affichez une page « catégorie », vous obtenez bien sûr les articles dans cette catégorie, mais également ceux dans ses sous-catégories.
Voici une petite astuce rapide pour afficher seulement les articles de la catégorie en question.

Programme minceur

L’astuce est en soi très simple, mais faut-il encore savoir quelle ficelle tirer pour avoir le résultat escompté.
Il faut aller voir du côté du hook pre_get_posts, qui permet de modifier la requête principale de la page avant d’aller chercher les articles à afficher.
Le truc à savoir et qu’on ne peut pas deviner c’est que lorsqu’on lance une requête sur une catégorie, il y a un paramètre appelé include_children qui se balade dans la classe WP_Tax_Query et dont la valeur par défaut est true. L’astuce ne va pas consister à mettre ce paramètre à false directement, mais nous allons passer par un intermédiaire.

Allez, je vous jette ça et on en discute après. Ceci est à insérer dans le fichier functions.php de votre thème.

123456789

add_action('pre_get_posts', 'no_sub_cat');
function no_sub_cat($query) {
    if ( $query->is_category() && $query->is_main_query() ) {
        $cat_ID = $query->get_queried_object_id();
        $query->set( 'category_name', null );
        $query->set( 'cat', null );
        $query->set( 'category__in', array($cat_ID) );
    }
}

Tout d’abord avec $query->is_category() && $query->is_main_query() on vérifie que nous sommes bien sur une page « catégorie » et qu’il s’agit bien de la requête principale. Si ce n’est pas le cas on ne fait rien.
Ensuite on va aller chercher l’ID de la catégorie désirée grâce à $query->get_queried_object_id().
L’étape suivante consiste à rendre null le paramètre original qui devait retrouver les articles de la catégorie, là il y a deux possibilités : si la réécriture d’url est active c’est category_name qui contient le slug de la catégorie, sinon c’est cat qui contient son ID. On les met donc tous les deux à la valeur null.
La dernière étape sera de ranger l’ID de la catégorie dans category__in.
Pourquoi ?
Tout simplement parce qu’en utilisant category__in , include_children passe automatiquement à false :)
Ainsi, ne seront retournés que les articles de cette catégorie.

Bonus : sur la page « catégorie », afficher des liens vers les sous-catégories

Selon votre thème et l’endroit où vous voulez afficher ce menu, ce qui suit sera à mettre dans sidebar.php ou category.php par exemple.

0102030405060708091011

if ( is_category() ) {
	$params = array(
		'parent' => get_queried_object_id()
	);
	
	if ( count( get_categories( $params ) ) ) {
		echo '<ul>';
		wp_list_categories( $params );
		echo '</ul>';
	}
}

Avec is_category() on vérifie d’abord que sommes bien sur une page « catégorie ».
La fonction wp_list_categories() permet d’afficher une liste de catégories et dispose de pas mal de paramètres. L’idée est donc d’afficher les catégories qui sont des filles de celle affichée sur notre page.
Ici nous aurons le choix entre 2 paramètres possibles :

  • parent permet d’afficher les catégories dont le parent DIRECT est notre catégorie. Autrement dit, un seul niveau, pas de « arrière-petite-fille » ou autre, seulement une relation directe.
  • child_of permet d’afficher toutes les catégories dont un des parents est notre catégorie. Donc ici on pourra avoir plusieurs niveaux, les « arrières-petites-filles » seront de la partie.

Dans notre cas, je pense que parent est le plus approprié.

Un petit détail, si la fonction wp_list_categories() ne trouve pas de catégorie fille, elle affichera un élément « Aucune catégorie ». A vous de voir, mais là je préfère m’en passer et ne rien afficher du tout dans ce cas, d’où l’utilité du if ( count( get_categories( $params ) ) ) : s’il n’y a pas de catégories, rien ne sera affiché.
Au passage vous remarquerez qu’on utilise 2 fois $params, donc les mêmes paramètres pour les 2 fonctions (c’est pratique qu’elles aient certains paramètres en commun). On fait du recyclage :)

Oui, c’est tout.

See ya!