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.

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()etwp_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.