vendredi 25 septembre 2026

À propos

Contact

Extensions

WP_List_Table : construire un tableau d’administration complet

4 000 demandes de devis à afficher, trier et filtrer dans l'admin, sans réinventer la pagination ni le tri des colonnes : WP_List_Table fait exactement ce travail, à condition d'accepter ses limites.

Par Clément Hadrot • 24 novembre 2020 • 5 min de lecture • Aucun commentaire
WP_List_Table : construire un tableau d'administration complet

Un site de menuiserie sur mesure recevait plusieurs milliers de demandes de devis par an, stockées dans un Custom Post Type devis. L’équipe commerciale avait besoin d’un écran d’administration dédié, distinct de la liste des articles, avec tri par montant, filtre par statut, et actions groupées pour marquer plusieurs devis comme traités d’un coup. C’est exactement le terrain de jeu de WP_List_Table.

Cette classe équipe déjà tous les tableaux natifs de l’admin — la liste des articles, des utilisateurs, des extensions — mais elle n’est officiellement pas documentée comme API publique stable. Il faut donc l’utiliser en connaissance de cause.

Étendre la classe et définir les colonnes

WP_List_Table n’est pas chargée par défaut : il faut explicitement inclure wp-admin/includes/class-wp-list-table.php avant de l’étendre, généralement depuis le callback de la page d’administration.

if ( ! class_exists( 'WP_List_Table' ) ) {
    require_once ABSPATH . 'wp-admin/includes/class-wp-list-table.php';
}

class Menuiserie_Devis_List_Table extends WP_List_Table {

    public function get_columns() {
        return array(
            'cb'        => '<input type="checkbox" />',
            'client'    => 'Client',
            'montant'   => 'Montant',
            'statut'    => 'Statut',
            'date'      => 'Date',
        );
    }

    public function get_sortable_columns() {
        return array(
            'montant' => array( 'montant', false ),
            'date'    => array( 'date', true ),
        );
    }
}

La colonne cb, pour checkbox, est une convention du cœur : lui associer ce nom active automatiquement les cases à cocher nécessaires aux actions groupées, sans code supplémentaire.

Préparer les données avec prepare_items

La méthode prepare_items() concentre toute la logique métier : récupération des données, tri, pagination et affectation des colonnes visibles. C’est le cœur du fonctionnement de la classe.

L'essentiel à retenir : WP_List_Table est une classe privée du cœur, non garantie stable entre versions ; prepare_items gère colonnes, tri, pagination et actions groupées en un seul endroit ; Les recherches et filtres restent à coder manuellement dans la requête
public function prepare_items() {
    $par_page = 20;
    $page_courante = $this->get_pagenum();

    $orderby = ! empty( $_GET['orderby'] ) ? sanitize_key( $_GET['orderby'] ) : 'date';
    $order   = ! empty( $_GET['order'] ) && 'asc' === $_GET['order'] ? 'ASC' : 'DESC';

    $requete = new WP_Query( array(
        'post_type'      => 'devis',
        'posts_per_page' => $par_page,
        'paged'          => $page_courante,
        'orderby'        => 'montant' === $orderby ? 'meta_value_num' : 'date',
        'meta_key'       => 'montant' === $orderby ? '_menuiserie_montant' : '',
        'order'          => $order,
    ) );

    $this->items = array_map( 'menuiserie_formater_ligne_devis', $requete->posts );

    $this->set_pagination_args( array(
        'total_items' => $requete->found_posts,
        'per_page'    => $par_page,
    ) );

    $this->_column_headers = array( $this->get_columns(), array(), $this->get_sortable_columns() );
}

Oublier set_pagination_args() est une erreur discrète : le tableau continue de s’afficher, mais sans les liens de pagination en bas de page, ce qui devient rapidement un problème sur un catalogue de plusieurs milliers de lignes.

Actions groupées et rendu des colonnes

Les actions groupées demandent deux morceaux : la liste des actions disponibles, et leur traitement effectif, généralement réalisé au tout début de prepare_items() avant la requête principale.

protected function get_bulk_actions() {
    return array(
        'marquer_traite' => 'Marquer comme traité',
    );
}

public function column_default( $item, $column_name ) {
    return isset( $item[ $column_name ] ) ? esc_html( $item[ $column_name ] ) : '';
}

public function column_montant( $item ) {
    return esc_html( number_format_i18n( $item['montant'], 2 ) ) . ' €';
}

Chaque colonne peut recevoir une méthode dédiée nommée column_{nom_de_colonne}, ce qui permet un rendu spécifique (mise en forme monétaire, badge coloré selon le statut) sans alourdir column_default.

Ce que WP_List_Table ne fait pas pour vous

La recherche et les filtres personnalisés (par statut, par plage de dates) ne sont pas gérés automatiquement : il faut les câbler à la main, généralement via des champs de formulaire au-dessus du tableau et une lecture de $_GET dans prepare_items(). La classe fournit seulement extra_tablenav() comme point d’accroche pour afficher ces contrôles au bon endroit visuellement.

  • La recherche par mot-clé demande d’implémenter $_REQUEST['s'] soi-même dans la requête
  • Les filtres par statut se placent typiquement dans extra_tablenav( $which )
  • Aucune protection CSRF n’est fournie automatiquement pour les actions groupées : le nonce doit être vérifié manuellement dans le traitement

Traitez toujours WP_List_Table comme un squelette, pas comme une solution clé en main : elle structure l’affichage, mais chaque comportement métier reste entièrement à votre charge.

Une classe privée, à utiliser en connaissance de cause

Le point le plus important à retenir, souvent absent des tutoriels : WP_List_Table est explicitement documentée par l’équipe cœur comme non destinée à un usage par des extensions tierces, sans garantie de stabilité de son API entre deux versions majeures de WordPress. Dans les faits, elle change rarement de façon incompatible, mais ce risque doit être assumé consciemment, en particulier pour une extension distribuée largement plutôt que développée sur mesure pour un seul client.

En résumé

Pour un écran d’administration interne, comme celui des devis de ce projet de menuiserie, WP_List_Table reste le choix le plus rapide et le plus cohérent avec le reste de l’interface WordPress. Elle impose son propre vocabulaire de méthodes à respecter, mais évite de réinventer pagination, tri et actions groupées à la main.

Partager :

À propos de l'auteur

Clément Hadrot

Développeur WordPress, passionné par Elementor, le FSE et l’automatisation par IA.

Voir tous ses articles

Dans la même veine

À lire aussi