Note for English speakers: Source code, UI strings, and comments are written in English. Translations ship as gettext PO/MO files under
languages/. The rest of this README stays in French because the project targets French-language WordPress sites and documents French-specific Elasticsearch analyzer behavior.
Addon open-source pour ElasticPress qui corrige et optimise l'analyzer Elasticsearch pour le contenu en langue française.
Inspiré de la documentation officielle des language analyzers
(chaîne french : élision, stop, keyword_marker, stemmer light_french) et de l’article
Construire un bon analyzer français pour Elasticsearch
(JoliCode). On part de cette base officielle, puis on ajoute volontairement
l’asciifolding — absent de l’analyzer french natif — après les stopwords et
avant le stemming, pour gérer accents et ligatures (haïti/haiti, bœuf/boeuf)
sans casser la liste _french_.
Prérequis : WordPress 6.5+, PHP 8.0+, et le plugin ElasticPress.
Le mapping ElasticPress par défaut (EP ≥ 4, mappings 5-2 / 7-0+) n'est pas optimisé
pour le français :
ep_asciifolding(type: asciifolding,preserve_original: true) est déjà présent surdefault/default_search, mais aprèsewp_snowball→ le stemming travaille sur des formes accentuées, et chaque token accentué émet aussi sa forme ASCII (double token) ;- le stemmer par défaut est un
snowballFrench, réputé agressif (troncature fréquente à 4-5 lettres), qui crée des collisions entre mots sans rapport ; - aucune gestion de l'élision française.
Symptôme typique observé en production : une recherche sans accent (?s=haiti) remonte des
résultats hors sujet ("haine", "haute", "fait"), alors que la même recherche avec accent
(?s=haïti) fonctionne correctement. Ce n'est pas dû à l'absence d'asciifolding, mais à
l'ordre Snowball-avant-folding et à l'agressivité du stemmer. Diagnostic complet
reproductible via l'API _analyze d'Elasticsearch.
Prérequis : ElasticPress installé et actif. Après activation de cet addon, une réindexation complète est obligatoire.
Le package beapi/elasticpress-french-addon est de type wordpress-plugin. Avec
composer/installers dans votre projet,
il est installé sous wp-content/plugins/.
Ajoutez le dépôt GitHub dans le composer.json de votre projet (tant que le
package n’est pas publié sur Packagist) :
{
"repositories": [
{
"type": "vcs",
"url": "https://github.com/BeAPI/elasticpress-french-addon.git"
}
]
}Puis :
composer require beapi/elasticpress-french-addon
wp plugin activate elasticpress-french-addon
wp elasticpress index --setup --network-wideExemple d’installer-paths côté projet (à adapter à votre arborescence) :
{
"extra": {
"installer-paths": {
"wp-content/plugins/{$name}/": ["type:wordpress-plugin"]
}
}
}À chaque tag Git, le workflow de release produit un ZIP propre
(elasticpress-french-addon.zip, hors artefacts de développement via .distignore)
et le joint à la release GitHub.
- Téléchargez le fichier
elasticpress-french-addon.zipde la dernière release. - Dans l’admin WordPress : Extensions > Ajouter > Téléverser une extension,
ou décompressez le ZIP dans
wp-content/plugins/. - Activez le plugin, puis réindexez :
wp plugin activate elasticpress-french-addon
wp elasticpress index --setup --network-widecd wp-content/plugins
git clone https://github.com/BeAPI/elasticpress-french-addon.git
wp plugin activate elasticpress-french-addon
wp elasticpress index --setup --network-widePrérequis : DDEV et Docker.
ddev start
ddev composer install
ddev composer setupCela installe WordPress dans wordpress/, télécharge ElasticPress via Composer,
symlinke cet addon, configure EP_HOST vers le service Elasticsearch DDEV, puis
lance une sync initiale.
Le setup active aussi Query Monitor et ElasticPress Debugging Add-On par
défaut, pour inspecter les requêtes ElasticPress directement dans la barre
d'admin WordPress.
- Site : https://elasticpress-french-addon.ddev.site
- Admin :
admin/admin - Elasticsearch (depuis le conteneur web) :
http://elasticsearch:9200 - Elasticsearch (depuis l’hôte) :
https://elasticpress-french-addon.ddev.site:9201
Scripts Composer utiles :
| Commande | Description |
|---|---|
ddev composer setup |
Boot complet (WP + plugins de debug + sync EP) |
ddev composer setup:wp |
Télécharge / installe WordPress si besoin |
ddev composer setup:plugins |
Symlink + activation des plugins, Query Monitor et EP Debugging |
ddev composer setup:ep |
Configure le host ES et relance la sync |
ddev composer cs |
Vérifie les WordPress Coding Standards (PHPCS) |
ddev composer test |
Lance les tests unitaires PHPUnit (build_analyzer / build_filters / injection query .stemmed / fuzziness) |
ddev composer cbf |
Corrige automatiquement ce que PHPCBF peut fixer |
ddev composer fetch:bulk |
Télécharge ~980 extraits Wikipédia FR (CC BY-SA) |
ddev composer seed:corpus |
Crée ~1000 posts de test (pièges + bulk) |
ddev composer verify:options |
Vérifie fonctionnellement chaque réglage de l’admin (mapping, analyse, requêtes) |
ddev composer verify:corpus |
Exécute les requêtes pièges (profil addon) |
ddev composer compare:corpus |
Compare baseline (addon off) vs addon (2× sync) |
Les hooks Git de qualité (GrumPHP) s’installent avec Composer. Sur une PR, le workflow
.github/workflows/quality.yml lance composer validate, composer cs et composer test.
Un tag Git déclenche une release GitHub avec le ZIP (.github/workflows/release-version.yml) ;
le fichier .distignore exclut les artefacts de développement du package.
Après un changement de réglages du mapping, réindexer :
ddev wp elasticpress sync --setup --yes --path=wordpressCorpus hybride pour valider la recherche française :
- ~20 posts pièges (
tests/fixtures/french-search-traps.json) : accents, collisions de stemmer, élision, fuzziness — seuls à être assertés ; - ~980 extraits Wikipédia FR (
tests/fixtures/french-search-bulk.json.gz, CC BY-SA) : bruit de ranking réaliste.
Voir aussi tests/fixtures/ATTRIBUTION.md.
ddev composer fetch:bulk # une fois (~980 extraits), ou pour régénérer
ddev composer seed:corpus # ~1000 posts, sans sync EP inline
ddev wp elasticpress sync --setup --yes --path=wordpress
ddev composer verify:options
ddev composer verify:corpus
ddev composer compare:corpus # purge + reseed + 2× sync --setup : prévoir plusieurs minutesLes assertions verify / compare sont scopées aux posts pièges (présence / absence de match via ElasticPress), pas au top 20 du corpus bulk — sinon les articles Wikipédia évinceraient les pièges sur des termes fréquents (amour, cheval, etc.).
Options utiles :
# Reprendre un fetch interrompu
php bin/fetch-bulk-corpus.php --count=980 --resume
# Resemer en partant de zéro (évite les doublons si le bulk a été régénéré)
ddev wp eval-file bin/seed-search-corpus.php epfr-purge --path=wordpress
# Vérifier le profil baseline (addon désactivé + réindex)
ddev wp eval-file bin/toggle-addon.php epfr-enabled-0 --path=wordpress
ddev wp elasticpress sync --setup --yes --path=wordpress
ddev wp eval-file bin/verify-search-corpus.php epfr-profile-baseline --path=wordpressDétail de la chaîne d’analyse (ordre des filtres, mode dual, fuzziness) :
docs/french-search-algorithm.md.
Le plugin s'accroche aux filtres natifs d'ElasticPress, sans surcharger ni dupliquer son coeur :
| Filtre ElasticPress | Usage dans ce plugin |
|---|---|
ep_config_mapping |
Injecte asciifolding (après stop), elision, stemmer, stopwords additionnels, stem_exclusion ; en mode dual sur l’index posts, default/default_search restent light et epfr_heavy sert aux multi-fields ; les autres indexables gardent une chaîne full |
ep_post_mapping |
En mode dual, ajoute les multi-fields .stemmed sur post_title, post_content, post_excerpt |
ep_formatted_args (prio 25) |
En mode dual, injecte les champs .stemmed (boost réduit, filtrable via epfr_stemmed_boost_factor) dans les multi_match après le weighting ElasticPress (prio 20), qui sinon les supprimerait |
ep_analyzer_language |
Force la liste de stopwords _french_ (filter_ep_stop) tant que l'addon est activé |
ep_post_fuzziness_arg |
Permet de fixer la fuzziness des requêtes (auto / 0 / 1 / 2) |
Un filtre epfr_mapping reste disponible pour les ajustements avancés (ex. stemmer_override).
Pour une simple exclusion de stemming, préférez le réglage stem_exclusion de l’admin.
add_filter( 'epfr_mapping', function ( array $mapping, array $settings ) {
// Example: custom stemmer overrides (advanced).
$mapping['settings']['analysis']['filter']['epfr_stemmer_override'] = [
'type' => 'stemmer_override',
'rules' => [ 'croissant=>croisan' ],
];
return $mapping;
}, 10, 2 );Le code source et les chaînes UI sont en anglais (text domain elasticpress-french-addon).
Les traductions se trouvent dans languages/ :
elasticpress-french-addon.pot— catalogue des chaîneselasticpress-french-addon-fr_FR.po/.mo— traduction française
Sur un site WordPress en fr_FR, l’interface d’administration s’affiche automatiquement en français.
Réglable dans ElasticPress > French Addon (menu site, ou Network Admin lorsque
ElasticPress est en mode EP_IS_NETWORK), ou directement en base via epfr_settings
(option de blog, ou site_option en mode réseau) :
asciifolding(bool) : ignore les accents à l'indexation et à la recherche (filtre natifasciifolding, sanspreserve_original— remplaceep_asciifolding).elision(bool) : gère l'élision française (l', d', qu'...).stemmer(none|minimal_french|light_french|french) : niveau de racinisation.fuzziness(auto|0|1|2) : tolérance aux fautes de frappe.extra_stopwords(string, séparé par virgules) : mots additionnels à ignorer.stem_exclusion(string, séparé par virgules) : mots exclus du stemming (keyword_marker), ex.croixpour éviter la collision « La Croix » / « croissant ».dual_analyzers(bool, défautfalse) : analyzer light sur les champs posts principaux (pertinence) + heavy stémmé sur.stemmed(rappel). Opt-in, index posts uniquement ; réindex--setupobligatoire.
- Toute modification de réglage nécessite une réindexation complète
(
wp elasticpress index --setup --network-wide) : un mapping Elasticsearch ne se met jamais à jour à chaud sur un index existant. - Ce plugin ne gère pas les synonymes : utilisez la fonctionnalité Synonyms native d'ElasticPress, prévue à cet effet.
- Testez toujours vos changements de stemmer sur un jeu de requêtes de référence avant mise en production : un stemmer plus doux change le classement de toutes les recherches du site, pas seulement le cas qui a motivé le changement.
curl -s 'http://YOUR_CLUSTER:9200/YOUR_INDEX/_analyze' \
-H 'Content-Type: application/json' \
-d '{"analyzer":"default","text":"Haïti haïti haiti haine haute fait"}'Les trois premières formes doivent produire le même token ; "haine", "haute" et "fait" ne doivent plus être ramenés à une racine proche de "haiti".
Avec stem_exclusion=croix, comparer :
curl -s 'http://YOUR_CLUSTER:9200/YOUR_INDEX/_analyze' \
-H 'Content-Type: application/json' \
-d '{"analyzer":"default","text":"La Croix croissant"}'En mode dual, comparer l’analyzer light (default) et le champ stémmé :
curl -s 'http://YOUR_CLUSTER:9200/YOUR_INDEX/_analyze' \
-H 'Content-Type: application/json' \
-d '{"field":"post_content.stemmed","text":"tomates"}'Liste classée par utilité pour comprendre et étendre cet addon :
- Language analyzers (Elastic) — source de vérité : définition reproductible de l’analyzer
frenchnatif. À privilégier sur tout blog tiers en cas de doute. - Construire un bon analyzer français (JoliCode) — référence francophone : limites du french natif, dual light/heavy, pertinence vs rappel.
- Leviers Elasticsearch pour les spécificités linguistiques (blog Elastic FR) — cas concret
stem_exclusion(« La Croix » / « croissant ») et_analyze. - Analyzer reference — vue d’ensemble des analyzers (french, standard, keyword…).
- ASCII Folding et
_analyze(Aymeric Lagier) — diagnostic via l’API_analyze. - Elasticsearch: The Definitive Guide — Languages (O'Reilly) — pédagogique mais historique (ES 1.x/2.x) : l’affirmation selon laquelle le french retire les diacritiques ne correspond plus à l’implémentation actuelle (pas d’asciifolding dans le french stock).
- Discuss — Language analyzer en français / Google Groups elasticsearch-fr — compléments communautaires (pièges de config, démarche
_analyze).
Historique des versions : CHANGELOG.md.
GPL v2 or later. Voir LICENSE.
Développé et maintenu par Be API. Issues et pull requests bienvenues.