# Exporter des articles et leurs métadonnées en CSV sans extension

> Un client comptable réclamait un export Excel de son catalogue chaque trimestre. Un bouton dans l'admin et une génération en flux ont réglé la question.

- Auteur : Clément Hadrot
- Publié le : 2022-02-07
- Mis à jour le : 2022-02-07
- Catégorie : Tips
- URL : https://wpmoderne.dev.wordpress-developpement.fr/tips/exporter-articles-csv-sans-extension/

## L’essentiel

- Un point d'entrée admin_post_ traite la demande d'export
- fputcsv génère le fichier directement en flux
- Le BOM UTF-8 évite les accents cassés dans Excel

Un client gérant un catalogue de formations avait besoin, chaque trimestre, d'un export CSV de ses fiches avec leurs métadonnées (durée, tarif, référence interne) pour les transmettre à son comptable. Plutôt qu'une extension d'export généraliste, souvent surdimensionnée pour un besoin aussi précis, un bouton dédié dans l'administration et une génération du fichier directement en flux ont suffi.

Cet article couvre l'export uniquement ; l'import, qui pose des questions différentes de validation des données entrantes, mérite un traitement séparé.

## Ajouter le bouton d'export dans l'admin

Un lien simple, placé au-dessus de la liste des articles via le hook `manage_posts_extra_tablenav`, pointe vers un point d'entrée `admin-post.php` dédié à l'export.

```
function formation_bouton_export( $which ) {
    if ( 'top' !== $which ) {
        return;
    }
    $url = wp_nonce_url(
        admin_url( 'admin-post.php?action=formation_export_csv' ),
        'formation_export_csv'
    );
    echo '<a href="' . esc_url( $url ) . '" class="button">Exporter en CSV</a>';
}
add_action( 'manage_posts_extra_tablenav', 'formation_bouton_export' );
```

## Générer le fichier CSV en flux

Le point d'entrée accroché à `admin_post_{action}` récupère les contenus concernés, envoie les en-têtes HTTP appropriés, puis écrit directement le contenu avec `fputcsv()` sur un flux ouvert en sortie — sans jamais créer de fichier temporaire sur le disque.

> L'essentiel à retenir : Un point d'entrée admin_post_ traite la demande d'export ; fputcsv génère le fichier directement en flux ; Le BOM UTF-8 évite les accents cassés dans Excel

```
function formation_generer_export_csv() {
    check_admin_referer( 'formation_export_csv' );
    if ( ! current_user_can( 'export' ) ) {
        wp_die( 'Accès refusé.' );
    }

    $formations = get_posts( array(
        'post_type'      => 'formation',
        'posts_per_page' => -1,
    ) );

    header( 'Content-Type: text/csv; charset=utf-8' );
    header( 'Content-Disposition: attachment; filename=formations-' . date( 'Y-m-d' ) . '.csv' );

    $flux = fopen( 'php://output', 'w' );
    fwrite( $flux, "\xEF\xBB\xBF" ); // BOM UTF-8

    fputcsv( $flux, array( 'Titre', 'Durée (h)', 'Tarif (€)', 'Référence' ), ';' );

    foreach ( $formations as $formation ) {
        fputcsv( $flux, array(
            $formation->post_title,
            get_post_meta( $formation->ID, 'duree_heures', true ),
            get_post_meta( $formation->ID, 'tarif', true ),
            get_post_meta( $formation->ID, 'reference', true ),
        ), ';' );
    }

    fclose( $flux );
    exit;
}
add_action( 'admin_post_formation_export_csv', 'formation_generer_export_csv' );
```

Le séparateur point-virgule (`;`) plutôt que la virgule est un choix volontaire : c'est celui qu'Excel en version française interprète nativement sans demander de réglage d'import supplémentaire à l'utilisateur.

## Le piège du BOM UTF-8

Sans les trois octets du BOM (*Byte Order Mark*, `\xEF\xBB\xBF`) écrits en tout début de flux, Excel sous Windows interprète souvent le fichier en Latin-1 par défaut, ce qui casse tous les caractères accentués — un « é » devenant un symbole illisible. Ce détail, purement lié à Excel et non à la norme CSV elle-même, est la cause la plus fréquente de tickets support « l'export ne marche pas » sur ce type de fonctionnalité.

## Vérifier la capacité plutôt que le rôle

La vérification `current_user_can( 'export' )` cible une capacité précise plutôt qu'un rôle nommé : elle continue de fonctionner même si un client crée un rôle personnalisé auquel cette capacité a été attribuée séparément, contrairement à un test rigide sur `current_user_can( 'administrator' )`.

## Variantes utiles

- Filtrer l'export par plage de dates, en ajoutant des champs de date au formulaire précédant le bouton.
- Exporter uniquement les contenus publiés, avec `'post_status' => 'publish'` dans la requête.
- Ajouter une colonne pour chaque taxonomie associée, avec `wp_get_post_terms()` et `wp_list_pluck()`.

> Sur les catalogues volumineux, je préfère toujours l'écriture directe en flux plutôt que la construction d'une chaîne en mémoire : au-delà de quelques milliers de lignes, la différence de consommation mémoire devient très nette.

## En résumé

Un point d'entrée `admin_post_`, une génération en flux avec `fputcsv()` et un BOM UTF-8 en tête de fichier suffisent à produire un export CSV fiable, lisible tel quel dans Excel. Pas besoin d'extension dédiée pour ce type de besoin ponctuel et bien délimité — le code tient dans un seul fichier, facile à maintenir d'un trimestre à l'autre.
