# Brancher Typesense sur une extension à fort volume, sans service SaaS payant

> Passé un certain volume de contenu, la recherche MySQL de WordPress s'effondre. Typesense, auto-hébergé, offre une alternative sans abonnement mensuel à un service tiers.

- Auteur : WordPress Développement
- Publié le : 2023-03-26
- Mis à jour le : 2023-03-26
- Catégorie : Extensions
- URL : https://www.wpmoderne.fr/extensions/typesense-recherche-extension-fort-volume/

## L’essentiel

- LIKE %mot% sur wp_posts devient inutilisable au-delà de quelques dizaines de milliers de lignes
- Typesense s'installe sur son propre serveur, sans facturation par requête
- posts_pre_query permet de court-circuiter proprement la recherche native

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

> L'essentiel à retenir : LIKE %mot% sur wp_posts devient inutilisable au-delà de quelques dizaines de milliers de lignes ; Typesense s'installe sur son propre serveur, sans facturation par requête ; posts_pre_query permet de court-circuiter proprement la recherche native

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.
