# 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.

- Auteur : Clément Hadrot
- Publié le : 2020-11-24
- Mis à jour le : 2020-11-24
- Catégorie : Extensions
- URL : https://wpmoderne.dev.wordpress-developpement.fr/extensions/wp-list-table-tableau-administration-complet/

## L’essentiel

- 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

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.
