Une rédactrice en chef nous a expliqué son problème avec une précision presque comique : « Je cherche tous les articles publiés entre le 15 mars et le 2 avril, mais WordPress ne me propose que des mois entiers dans son menu déroulant. » Elle avait raison : le filtre natif par date, dans l’écran des articles, ne descend pas en dessous du mois. Pour une recherche par plage précise, il fallait construire quelque chose sur mesure.
La solution tient en deux morceaux : un formulaire HTML simple, injecté au-dessus du tableau des articles via restrict_manage_posts, et une correction de la requête SQL sous-jacente via pre_get_posts. Voici comment les assembler pas à pas.
Étape 1 : afficher les deux champs de date
Le hook restrict_manage_posts s’exécute juste avant le bouton « Filtrer », dans la barre d’outils au-dessus de la liste. Il reçoit le type de contenu courant, ce qui permet de limiter l’affichage aux seuls articles :
function rd_afficher_filtre_dates( $post_type ) {
if ( 'post' !== $post_type ) {
return;
}
$date_debut = isset( $_GET['rd_date_debut'] ) ? sanitize_text_field( $_GET['rd_date_debut'] ) : '';
$date_fin = isset( $_GET['rd_date_fin'] ) ? sanitize_text_field( $_GET['rd_date_fin'] ) : '';
?>
<input type="date" name="rd_date_debut" value="<?php echo esc_attr( $date_debut ); ?>" style="margin-right:4px;" />
<input type="date" name="rd_date_fin" value="<?php echo esc_attr( $date_fin ); ?>" />
<?php
}
add_action( 'restrict_manage_posts', 'rd_afficher_filtre_dates' );
Étape 2 : corriger la requête principale

Le hook pre_get_posts intercepte la requête avant son exécution. Il faut impérativement vérifier qu’on se trouve bien sur l’écran d’administration concerné, sur la requête principale, et pour le bon type de contenu, sous peine de casser d’autres requêtes du site :
function rd_appliquer_filtre_dates( $query ) {
if ( ! is_admin() || ! $query->is_main_query() ) {
return;
}
global $pagenow;
if ( 'edit.php' !== $pagenow || 'post' !== $query->get( 'post_type' ) ) {
return;
}
$date_debut = isset( $_GET['rd_date_debut'] ) ? sanitize_text_field( $_GET['rd_date_debut'] ) : '';
$date_fin = isset( $_GET['rd_date_fin'] ) ? sanitize_text_field( $_GET['rd_date_fin'] ) : '';
if ( empty( $date_debut ) && empty( $date_fin ) ) {
return;
}
$query->set( 'date_query', array(
array(
'after' => $date_debut ? $date_debut : '1970-01-01',
'before' => $date_fin ? $date_fin . ' 23:59:59' : current_time( 'mysql' ),
'inclusive' => true,
),
) );
}
add_action( 'pre_get_posts', 'rd_appliquer_filtre_dates' );
L’argument date_query repose sur la classe interne WP_Date_Query, la même qui alimente les filtres natifs par mois. Utiliser cette classe plutôt qu’une clause SQL manuelle garantit une compatibilité totale avec les fuseaux horaires configurés sur le site.
Ne pas casser le bouton « Filtrer » natif
Une erreur fréquente consiste à oublier que le formulaire de filtre, une fois soumis, conserve tous les paramètres $_GET existants, y compris ceux du filtre par catégorie ou par auteur déjà présents sur l’écran. Comme restrict_manage_posts s’exécute à l’intérieur du même formulaire que les filtres natifs, il n’y a rien de spécial à faire : les champs ajoutés sont automatiquement transmis avec le reste.
Adapter à un type de contenu personnalisé
Pour appliquer ce filtre à un CPT nommé evenement plutôt qu’aux articles, il suffit d’ajuster les deux conditions de type de contenu dans les fonctions ci-dessus. Le reste de la logique, formulaire et requête, reste identique. Ce filtre par plage ne remplace pas un filtre par taxonomie personnalisée, déjà couvert par ailleurs sur ce même écran ; les deux peuvent d’ailleurs cohabiter sans conflit, puisqu’ils agissent sur des paramètres $_GET distincts.
Limiter l’impact sur les performances
- Le filtre par date s’appuie sur l’index de la colonne
post_date, déjà présent nativement, donc aucune requête coûteuse supplémentaire. - Éviter de combiner ce filtre avec un tri par méta-donnée non indexée : la combinaison des deux ralentit sensiblement les grandes tables d’articles.
- Sur un site avec plusieurs dizaines de milliers d’articles, envisager de limiter la plage maximale acceptée pour éviter des requêtes portant sur des années entières.
En résumé
Un formulaire minimal et une correction de requête via pre_get_posts suffisent à combler un manque réel de l’écran d’administration natif. Cette approche reste légère, ne dépend d’aucune extension tierce, et s’adapte à n’importe quel type de contenu en quelques minutes.