Le WordPress d'aujourd'hui, décodé pour les développeurs

Extensions

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.

Par WordPress Développement • 26 mars 2023 • 4 min de lecture • Aucun commentaire
Brancher Typesense sur une extension à fort volume, sans service SaaS payant

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.

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *

Partager :

À propos de l'auteur

WordPress Développement

Développeur WordPress, passionné par Elementor, le FSE et l’automatisation par IA.

Voir tous ses articles

Dans la même veine

À lire aussi