Trois cent mille annonces immobilières indexées dans WordPress, et la recherche native affichait des temps de réponse supérieurs à la seconde dès qu’un utilisateur tapait plus de deux mots. La requête générée par WP_Query pour une recherche texte repose sur des clauses LIKE %mot% sur la colonne post_content, sans index dédié possible côté MySQL : au-delà de quelques dizaines de milliers de lignes, le temps de réponse se dégrade de façon presque linéaire.
La solution la plus répandue consiste à externaliser la recherche vers un service SaaS spécialisé, facturé à la requête ou au volume de documents. Pour un site à fort trafic et à budget contraint, Typesense propose une alternative auto-hébergée : un moteur de recherche open source, écrit en C++, installable sur son propre serveur, sans dépendance à un tiers facturé mensuellement.
Le problème posé
Indexer trois cent mille documents dans un moteur externe soulève trois questions concrètes : comment synchroniser l’index à chaque publication ou modification, comment adapter la requête de recherche du thème sans tout réécrire, et comment gérer la tolérance aux fautes de frappe que MySQL ne propose pas nativement.
Le snippet commenté : indexation à la publication

Typesense expose une API HTTP classique, appelable depuis PHP via wp_remote_post(), sans bibliothèque cliente obligatoire. À chaque sauvegarde d’annonce, un document est envoyé vers la collection Typesense correspondante :
add_action( 'save_post_annonce', function( $post_id ) {
if ( wp_is_post_revision( $post_id ) ) {
return;
}
$document = array(
'id' => (string) $post_id,
'titre' => get_the_title( $post_id ),
'ville' => get_post_meta( $post_id, 'ville', true ),
'prix' => (int) get_post_meta( $post_id, 'prix', true ),
'texte' => wp_strip_all_tags( get_post_field( 'post_content', $post_id ) ),
);
wp_remote_post( 'https://recherche.interne.test/collections/annonces/documents?action=upsert', array(
'headers' => array(
'X-TYPESENSE-API-KEY' => TYPESENSE_CLE_ECRITURE,
'Content-Type' => 'application/json',
),
'body' => wp_json_encode( $document ),
'timeout' => 5,
) );
}, 20 );
Le paramètre action=upsert évite de distinguer une création d’une mise à jour : Typesense remplace le document existant si l’identifiant correspond déjà à une entrée de la collection.
Le snippet commenté : brancher la recherche du thème
Le point d’intégration le plus propre consiste à intercepter la requête avant que WordPress ne construise sa clause SQL, via le filtre posts_pre_query, qui permet de renvoyer directement un tableau de résultats déjà connus :
add_filter( 'posts_pre_query', function( $posts, $query ) {
if ( ! $query->is_search() || ! $query->is_main_query() ) {
return $posts;
}
$reponse = wp_remote_get( add_query_arg( array(
'q' => $query->get( 's' ),
'query_by' => 'titre,texte,ville',
'per_page' => 20,
), 'https://recherche.interne.test/collections/annonces/documents/search' ), array(
'headers' => array( 'X-TYPESENSE-API-KEY' => TYPESENSE_CLE_LECTURE ),
) );
if ( is_wp_error( $reponse ) ) {
return $posts;
}
$resultats = json_decode( wp_remote_retrieve_body( $reponse ), true );
$ids = wp_list_pluck( $resultats['hits'] ?? array(), 'document' );
$ids = wp_list_pluck( $ids, 'id' );
$query->found_posts = $resultats['found'] ?? 0;
$query->max_num_pages = ceil( $query->found_posts / 20 );
return array_map( 'get_post', $ids );
}, 10, 2 );
En cas d’échec de Typesense (is_wp_error()), la fonction renvoie le tableau $posts d’origine sans le modifier, ce qui laisse WordPress retomber sur son comportement de recherche natif plutôt que d’afficher une page vide.
Variantes
Tolérance aux fautes de frappe réglable
Le paramètre num_typos de l’API de recherche Typesense accepte une valeur de 0 à 2 par champ interrogé, ce qui permet de retrouver « appartment » pour une recherche « appartement » mal orthographiée, sans configuration supplémentaire côté MySQL, qui ne propose rien d’équivalent nativement.
Réindexation complète via WP-CLI
Pour reconstruire l’index après une modification de schéma de collection, une commande personnalisée enregistrée via WP_CLI::add_command() boucle sur l’ensemble des annonces par lots de mille, en s’appuyant sur l’API d’import /documents/import de Typesense, bien plus rapide que trois cent mille appels HTTP individuels.
Facettes de filtrage
En déclarant les champs ville et prix comme facettes lors de la création de la collection, Typesense calcule des comptages de résultats par valeur, utilisables pour afficher des filtres latéraux sans requête SQL supplémentaire.
Notre verdict
Sur un corpus de trois cent mille documents, Typesense a ramené les temps de recherche sous les 50 millisecondes, contre plus d’une seconde avec la recherche native. L’auto-hébergement impose de maintenir un service supplémentaire, mais élimine toute facturation liée au volume de requêtes ou de documents, un critère décisif pour un site à fort trafic organique.