# Améliorer la recherche interne WordPress avec pre_get_posts

> La recherche native de WordPress reste limitée par défaut. Quelques ajustements bien ciblés avec pre_get_posts la rendent nettement plus pertinente, sans service tiers.

- Auteur : Clément Hadrot
- Publié le : 2021-07-08
- Mis à jour le : 2021-07-08
- Catégorie : Tips
- URL : https://wpmoderne.dev.wordpress-developpement.fr/tips/ameliorer-recherche-interne-wordpress-pre-get-posts/

## L’essentiel

- pre_get_posts modifie la requête principale sans plugin
- Limiter la recherche à certains types de contenu évite le bruit
- Pondérer titre et contenu améliore la pertinence

La recherche native de WordPress fonctionne, mais reste sommaire : elle interroge le titre, le contenu et l'extrait de tous les types de contenu publics, sans aucune pondération, et sans tenir compte de la pertinence réelle des résultats. Sur un site avec plusieurs types de contenu (articles, pages, produits, documentation), le champ de recherche renvoie vite un mélange peu exploitable.

Avant d'envisager une solution externe comme Algolia ou une recherche basée sur Elasticsearch, il vaut la peine d'exploiter ce que WordPress propose déjà nativement, via le hook `pre_get_posts`, qui permet de modifier la requête principale avant son exécution.

## Limiter la recherche à certains types de contenu

Le cas le plus courant : exclure certains types de contenu (pages techniques, éléments de menu, réutilisables) des résultats de recherche, pour ne garder que ce qui a du sens pour le visiteur.

```
add_action( 'pre_get_posts', function( $query ) {
    if ( ! is_admin() && $query->is_search() && $query->is_main_query() ) {
        $query->set( 'post_type', array( 'post', 'page', 'produit' ) );
    }
} );
```

La double condition `! is_admin()` et `is_main_query()` est essentielle : sans elle, la modification s'appliquerait aussi à la recherche dans l'administration, ou à des requêtes secondaires déclenchées ailleurs sur la page, avec des effets de bord difficiles à diagnostiquer.

## Exclure certains contenus explicitement

Un contenu peut avoir besoin d'exister publiquement sans jamais apparaître dans les résultats de recherche (une page de mentions légales, par exemple). Un champ personnalisé couplé à `pre_get_posts` permet cette exclusion ciblée :

```
add_action( 'pre_get_posts', function( $query ) {
    if ( ! is_admin() && $query->is_search() && $query->is_main_query() ) {
        $ids_exclus = get_posts( array(
            'post_type'      => 'any',
            'posts_per_page' => -1,
            'fields'         => 'ids',
            'meta_key'       => 'exclure_recherche',
            'meta_value'     => '1',
        ) );
        $query->set( 'post__not_in', $ids_exclus );
    }
} );
```

> L'essentiel à retenir : pre_get_posts modifie la requête principale sans plugin ; Limiter la recherche à certains types de contenu évite le bruit ; Pondérer titre et contenu améliore la pertinence

## Rechercher aussi dans les champs personnalisés

Par défaut, WordPress ne recherche que dans le titre, le contenu et l'extrait. Pour inclure un champ personnalisé (une référence produit, par exemple), il faut intervenir directement sur la clause SQL via les filtres `posts_join` et `posts_where` :

```
add_filter( 'posts_join', function( $join, $query ) {
    global $wpdb;
    if ( $query->is_search() && $query->is_main_query() ) {
        $join .= " LEFT JOIN {$wpdb->postmeta} AS pm_ref ON ({$wpdb->posts}.ID = pm_ref.post_id AND pm_ref.meta_key = 'reference')";
    }
    return $join;
}, 10, 2 );

add_filter( 'posts_where', function( $where, $query ) {
    global $wpdb;
    if ( $query->is_search() && $query->is_main_query() ) {
        $search_term = $wpdb->esc_like( $query->get( 's' ) );
        $where = preg_replace(
            "/\(\s*{$wpdb->posts}.post_title\s+LIKE\s*(\'[^\']+\')\s*\)/",
            "({$wpdb->posts}.post_title LIKE $1) OR (pm_ref.meta_value LIKE '%{$search_term}%')",
            $where
        );
    }
    return $where;
}, 10, 2 );
```

Cette manipulation directe du SQL reste délicate et doit être testée avec attention : une expression régulière mal calée peut casser la recherche native pour d'autres requêtes.

## Trier par pertinence plutôt que par date

WordPress trie les résultats de recherche par date de publication, ce qui n'a souvent aucun rapport avec la pertinence réelle. Un tri approximatif par pertinence, basé sur la présence du terme dans le titre, peut s'implémenter via `posts_orderby` :

```
add_filter( 'posts_orderby', function( $orderby, $query ) {
    global $wpdb;
    if ( $query->is_search() && $query->is_main_query() ) {
        $search_term = esc_sql( $query->get( 's' ) );
        $orderby = "(CASE WHEN {$wpdb->posts}.post_title LIKE '%{$search_term}%' THEN 0 ELSE 1 END), " . $orderby;
    }
    return $orderby;
}, 10, 2 );
```

Ce tri place en tête les résultats dont le titre contient exactement le terme recherché, avant les résultats qui ne le contiennent que dans le corps du contenu.

## Limiter la longueur minimale de recherche

Un terme d'un ou deux caractères déclenche souvent une requête très large et peu utile. Une vérification simple évite ce cas :

```
add_action( 'pre_get_posts', function( $query ) {
    if ( $query->is_search() && $query->is_main_query() ) {
        $terme = $query->get( 's' );
        if ( mb_strlen( trim( $terme ) ) < 3 ) {
            $query->set( 's', '' );
            $query->set( 'post__in', array( 0 ) );
        }
    }
} );
```

## Quand passer à une solution externe

- Le volume de contenu dépasse plusieurs dizaines de milliers d'entrées, avec un impact mesurable sur le temps de réponse
- Le besoin porte sur une vraie pertinence sémantique (fautes de frappe, synonymes, recherche à facettes)
- Les visiteurs utilisent la recherche comme point d'entrée principal du site, ce qui justifie l'investissement

> Avant de payer pour une recherche externe, mieux vaut vérifier ce que `pre_get_posts` permet déjà de résoudre : sur la majorité des sites de contenu, cela suffit largement.

## En résumé

`pre_get_posts` permet d'améliorer sensiblement la recherche native de WordPress sans dépendance externe : filtrage par type de contenu, exclusions ciblées, tri par pertinence approximative. Les manipulations SQL plus poussées (recherche dans les champs personnalisés) demandent davantage de rigueur, mais restent accessibles. Une solution comme Elasticsearch ne se justifie vraiment qu'à partir d'un volume de contenu conséquent ou d'un besoin de pertinence sémantique fine.
