8768 sujets

Développement web côté serveur, CMS

Bonjour,
j'ai fait un petit formulaire de recherche par ingrédient pour un site de recettes. La recherche sera effectuée dans le titre et dans la liste d'ingrédients des articles.
Pour parer à beaucoup de petits problèmes, j'ai nettoyé un peu le terme recherché : tout en minuscule, suppression des " à ", " le ", " d/'", "coeur" devient "cœur"... vous voyez ce que je veux dire !
Et pour parachever le tout, ma requête utilise le comparateur PHP 'RLIKE' pour autoriser les éventuels féminin/pluriel.
Et c'est là que je rencontre un problème : si on cherche "œuf", on obtient les articles qui contiennent de l’œuf, mais aussi du bœuf !
Comment parer à ce problème ?
Est ce que je dois utiliser if/else (si $ingredient = oeuf { sois strict dans ta recherche ! }, sinon { sois plus cool }
Ou y a-t-il un autre moyen ?
Et comment dire 'sois strict dans ta recherche' ? avec '=' ?
Merci de votre coup de main,
Claire
pst: je travaille sur Wordpress, je n'utilise pas de plugin pour ça, et voici le script déjà développé :

<?php 
// si il y a une valeur au champ de recherche :
if(isset($_POST['ingredient'])){ 
	// nettoyage et formatage de la valeur envoyée
	$ingredient = $_POST['ingredient'];
	$ingredient = filter_var($ingredient, FILTER_SANITIZE_STRING, FILTER_FLAG_NO_ENCODE_QUOTES);
	$ingredient = strtolower($ingredient);
	$ingredient = str_replace(" d\'", "|", $ingredient);
	$ingredient = str_replace(" de ", "|", $ingredient);
	$ingredient = str_replace(" en ", "|", $ingredient);
	$ingredient = str_replace(" au ", "|", $ingredient);
	$ingredient = str_replace(" à ", "|", $ingredient);
	$ingredient = str_replace(" le ", "|", $ingredient);
	$ingredient = str_replace(" la ", "|", $ingredient);
	$ingredient = str_replace(" ", "|", $ingredient);
	$ingredient = str_replace("oeuf", "œuf", $ingredient);
	$ingredient = str_replace("coeur", "cœur", $ingredient);
	$ingredient = str_replace("boeuf", "bœuf", $ingredient);
	
// Rédaction du tableau des arguments de la nouvelle query QuerySearch
	$paged = ( get_query_var('page') ) ? get_query_var('page') : 1;
	
	$args = array( 
		'post_type' => 'recette', //recherche dans les articles custom post type "Recette"
		'posts_per_page' => 100, //limitation de résultat par page
		'paged' => $paged, //rendre possible la navigation page 1 page 2 ect dans les résultats de recherche
		'key' => array( 'Ingredient', 'title' ),//recherche dans le titre de l'article et dans le custom field "Ingredient"
		'meta_value' => $ingredient, //le terme à rechercher 
		'meta_compare' => 'RLIKE', //le terme doit apparaitre mais pas forcément exactement (pluriel, féminin... ex: pain/pains, piquant/piquante ect... )
	);
	
	// QuerySearch
	$QuerySearch = new WP_Query( $args );
	
?>
Pour supprimer les pluriels tu peux chercher les mots qui terminent par un s ou un x et supprimer la dernière lettre du mot

// $1 = [a-zàâæçéèêëîïôœùûüÿ]+ = série de lettres minuscules (on a déjà utilisé strtolower donc pas de majuscules)
// [sx] = le caractère s ou x
// $2 = $|[^a-zàâæçéèêëîïôœùûüÿ] = fin de la chaîne $ ou un caractère autre qu’une lettre
$ingredient = preg_replace('/([a-zàâæçéèêëîïôœùûüÿ]+)[sx]($|[^a-zàâæçéèêëîïôœùûüÿ])/g', '$1$2', $ingredient);
Voici un code pour trouver tes recettes contenant le maximum d’ingrédients à partir d’une liste d’ingrédients donnée :
  <?php
// En entrée une liste de mots et une liste de textes. On cherche les textes qui contiennent le plus de mots parmis la liste de mots fournie.

/**
 * Remplace un mot entier dans un texte. Exemple remplacer_mot_entier('œuf', 'youpi', 'œuf bœuf œuf') => 'youpi bœuf youpi'
 *
 * @param $ancien_mot chaîne à remplacer
 * @param $nouveau_mot mot de remplacement
 * @param $texte chaîne en minuscule dans laquelle se fera la recherche du mot à remplacer
 * @return chaîne
 */
function remplacer_mot_entier($ancien_mot, $nouveau_mot, $texte)
{
    return preg_replace('/(^|[^a-zàâæçéèêëîïôœùûüÿ])' . $ancien_mot . '($|[^a-zàâæçéèêëîïôœùûüÿ])/', '$1' . $nouveau_mot . '$2', $texte);
}

/**
 * Fonction qui met en minuscule, remplace les ligatures æ, œ par ae, oe, remplace des pluriels irréguliers ou des synonymes ou des expressions, tout mettre au singulier
 *
 * @param texte chaîne
 * @retour chaîne
 */
function simplifier($texte)
{
    // met en minuscule
    $texte = strtolower($texte);
    // remplace les ligatures æ, œ par ae, oe
    $texte = str_replace('æ', 'ae', $texte);
    $texte = str_replace('œ', 'oe', $texte);
    // remplace des pluriels irréguliers ou des synonymes ou des expressions
    $tab_synonymes = array(
        'litchi' => array('litchies', 'letchi', 'lychee'),
        'noixdebeurre' => array('noix de beurre'), // Pour que quand on recherche des recettes avec des noix on ne tombe sur toutes les recettes où il faut beurrer un moule
        'pommedeterre' => array('pomme de terre', 'pommes de terre')
    );
    foreach ($tab_synonymes as $terme_générique => $tab_à_remplacer) {
        foreach ($tab_à_remplacer as $à_remplacer) {
            $texte = remplacer_mot_entier($à_remplacer, $terme_générique, $texte);
        }
    }
    // tout mettre au singulier
    return preg_replace('/([a-zàâæçéèêëîïôœùûüÿ]+)[sx]($|[^a-zàâæçéèêëîïôœùûüÿ])/', '$1$2', $texte);
}

$ingrédients = simplifier('œuf'); // ingrédients que l’utilisateur à rentré dans le champ recherche séparés par des espaces
$tab_recettes = array(
    'poire',
    'pommes',
    'banane et pomme noix',
    'bœuf courge noix de beurre',
    'carotte oeufs',
    'boeuf carotte',
    'oeufs banane',
    'chocolat'
); // liste des recettes

// On va créer un tableau qui liste tous les ingrédients de la chaîne $ingrédients
$tab_ingrédients = explode(' ', $ingrédients);
$recettes = array();
$score_max = 1;
foreach ($tab_recettes as $recette_origine) {
    $score = 0;
    $recette = simplifier($recette_origine);
    foreach ($tab_ingrédients as $ingrédient) {
        if (preg_match('/(^|[^a-zàâæçéèêëîïôœùûüÿ])' . $ingrédient . '($|[^a-zàâæçéèêëîïôœùûüÿ])/', $recette) === 1) {
            $score += 1;
        }
    }
    if ($score_max < $score) {
        $recettes = array(); // On ne va afficher que les recettes qui ont eu le meilleur score
	$score_max = $score;
    }
    if ($score_max === $score) {
        array_push($recettes, $recette_origine);
    }
}
print_r($recettes);
?> 

Modifié par adrien881 (04 Jul 2017 - 19:41)
Hello,
merci à tous pour vos réponses... Smiley ravi
Je reviens super tard ici, mais je me suis heurté à un problème ardu qui provient de Wordpress himself.
En fait, si on fait une recherche dans les custom fields, on ne peut pas chercher en même temps dans le titre de la recette. Et en plus, le paramètre key n'accepte qu'une string, pas d'array. C'est balot, mais c'est comme ça.
Et à force d'à force, j'ai fini par supprimer la ligne " 'key' => array( 'Ingredient', 'title' ), " de mon array $args tout en rajoutant un custom fied qui reprend exactement le titre de la recette.

C'est nul, c'est lourd pour rien, mais on fait ce qu'on peut ^^

revenons à nos moutons.
voici ma bidouille :

<?php 
// si il y a une valeur au champ de recherche :
if(isset($_POST['ingredient'])){ 
	// nettoyage et formatage de la valeur envoyée
	$ingredient = $_POST['ingredient'];
	$ingredient = filter_var($ingredient, FILTER_SANITIZE_STRING, FILTER_FLAG_NO_ENCODE_QUOTES);
	$ingredient = strtolower($ingredient);
	$ingredient = str_replace(" d\'", "|", $ingredient);
	$ingredient = str_replace(" de ", "|", $ingredient);
	$ingredient = str_replace(" en ", "|", $ingredient);
	$ingredient = str_replace(" au ", "|", $ingredient);
	$ingredient = str_replace(" à ", "|", $ingredient);
	$ingredient = str_replace(" le ", "|", $ingredient);
	$ingredient = str_replace(" la ", "|", $ingredient);
	$ingredient = str_replace(" ", "|", $ingredient);
	$ingredient = str_replace("oeuf", "œuf", $ingredient);
	$ingredient = str_replace("coeur", "cœur", $ingredient);
	$ingredient = str_replace("boeuf", "bœuf", $ingredient);

	//l'œuf et le bœuf 
	//si $ingredient = œuf, on ne veut pas avoir aussi les résultats pour bœuf. 
	//donc dans ce cas précis, on indique à la REGEXP qu'on veut un terme qui commence par 'œuf' 
	if($ingredient == 'œuf') { $ingredient = "[[:<:]]".$ingredient; }	
	else { //do nothing }
	
// Rédaction du tableau des arguments de la nouvelle query QuerySearch
	$paged = ( get_query_var('page') ) ? get_query_var('page') : 1;
	
	$args = array( 
		'post_type' => 'recette', //recherche dans les articles custom post type "Recette"
		'posts_per_page' => 100, //limitation de résultat par page
		'paged' => $paged, //rendre possible la navigation page 1 page 2 ect dans les résultats de recherche
		'meta_value' => $ingredient, //le terme à rechercher 
		'meta_compare' => 'RLIKE', //le terme doit apparaitre mais pas forcément exactement (pluriel, féminin... ex: pain/pains, piquant/piquante ect... )
	);
	
	// QuerySearch
	$QuerySearch = new WP_Query( $args );
	
?>


Je voulais aussi signaler à adrien881 que simplement supprimer le s ou le x à la fin d'un mot pour éviter le pluriel transforme un ananas en anana et le gravlax en gravla... Smiley hum

Par contre, ta 2e fonction est impressionnante ! Difficile pour moi à implémenter avec le système un peu contraignant de Wordpress, mais je la garde sous le coude pour la prochaine fois où je joue avec les expressions régulières, merci !

Bref, c'est [RESOLU] !
Merci à tous Smiley ravi