Mes lecteurs assidus savent à quel point je porte dans mon coeur les aspects techniques du web. Certes, les livres que j'ai publiés traitent tous du webmarketing jusqu'à présent mais je reste attaché au code et à son intérêt pour les sites que nous créons à longueur de temps.
Mi-2013, j'avais créé un moteur de recherche PHP en programmation orientée objet (POO pour les intimes) que je fais évoluer régulièrement pour lui apporter sans cesse plus de possibilités. Désormais, ce moteur déjà puissant à l'origine s'est dotée de propriétés intéressantes telles que l'ajout d'une pagination personnalisable, une fonction d'autocomplétion (avec création automatique d'un index de mots ou non), la possibilité de faire des recherches d'expressions exactes comme sur Google (ex : "une super expression") ou encore le surlignage des mots recherchés en gras...
Tous les explications de base propres au moteur sont accessibles à cette adresse : moteur de recherche PHP Objet (POO) complet (pagination, surlignage, fulltext…).
Moteur de recherche PHP Ajax avec nouvelle pagination...
Je vais vous présenter deux scripts jQuery-Ajax que j'ai codés afin d'apporter des alternatives à la pagination de mon moteur de recherche PHP. Je précise que ces deux scripts peuvent être utilisés dans un autre contexte que mon moteur de recherche mais je l'ai fait essentiellement pour lui apporter un plus. Voici les deux alternatives adaptables au moteur :
- Scroll infini (souvent appelé "infinite scroll") pour développer les résultats au fur et à mesure que l'on descend dans la fenêtre ;
- Développement par cran ("trigger") en cliquant sur un lien du type "Afficher plus..." à la manière de Facebook.
Ces deux possibilités permettent d'obtenir de bons résultats visuels mais surtout d'éviter de cliquer sur les classiques liens "suivants" et "précédents". L'autre avantage de ces scripts est de générer des appels Ajax pour le moteur de recherche PHP.
Sans plus attendre, vous pouvez les télécharger individuellement ou récupérer le pack contenant plusieurs versions d'exemple du moteur avec tous les fichiers utiles (scripts JS, CSS, images de chargement, class du moteur de recherche PHP...).
Télécharger “AjaxTrigger”ajaxTrigger.zip – Téléchargé 2184 fois – 1,64 Ko
Télécharger “AjaxInfiniteScroll”ajaxInfiniteScroll.zip – Téléchargé 2203 fois – 1,85 Ko
N.B. : le pack comprend désormais uniquement les versions compatibles PHP 5.5 du moteur de recherche et de chaque démo en langage PHP 5.5 !
Edit (03/10/2014)
La version 2.2 du moteur de recherche PHP Ajax a vu quelques modifications, je précise cela à ceux qui téléchargerait cette nouvelle mouture après l'avoir déjà utilisée auparavant. Désormais, deux paramètres sont à changer dans les fichiers du moteur au niveau du troisième paramètre de la méthode "moteurAffichage()".
Comparez avant et après au sein du fichier principal du moteur :
- Avant la version 2.2 : $moteur->moteurAffichage('display', '', array(true, 1, $limit));
- Depuis la version 2.2 : $moteur->moteurAffichage('display', '', array(true, 0, $limit, false));
Dans le tableau du 3e paramètre, il faut désormais mettre la limite de départ à 0 plutôt que 1 et ajouter une 4e valeur (un booléen true/false, false étant la valeur pour les paginations infinies ou par trigger, true pour la pagination classique).
Ensuite, l'autre modification à apporter est dans le fichier "queryAjax" (selon la version utilisée le nom diffère) au niveau de la variable $page, voici les lignes à modifier de la sorte :
if(isset($_GET['nb'])) { $page = htmlspecialchars($_GET['nb']); } else { $page = 0; }
N.B. : les exemples présentés dans cet article sont adaptés à cette nouvelle version !
Etapes de fonctionnement du moteur de recherche PHP-Ajax
Voici la liste des étapes à respecter pour que les scripts jQuery fonctionnent parfaitement :
- Installation des scripts dans le <head>...</head> en HTML (dans la page qui réceptionne les résultats tout du moins).
- Ajout d'un formulaire de recherche.
- Chargement d'une première page de résultats en PHP classique. Cette page reçoit la première "vague" de résultats avant que le script ne se mette en route pour dérouler le reste des résultats...
- Lancement du script Ajax vers un fichier PHP externe (connecté à la BDD indépendamment) qui ajoute les résultats suivants dans la liste.
N.B. : ces scripts étant codés en jQuery, il faut bien entendu charger la bibliothèque avant de les charger !
Exemple de première page du moteur de recherche PHP
Les codes suivants sont à placer dans le <body>...</body> de la page qui réceptionne les résultats. Seul le formulaire peut être placé ailleurs avec une "action" différenciée, mais pour l'exemple, tout se passe dans la même page...
Formulaire du moteur de recherche :
<form id="searchForm" name="moteurSubmit" method="GET" action=""> <label for="q">Rechercher :</label> <input type="text" value="<?php if(isset($_GET['q'])) { echo htmlspecialchars($_GET['q']); } ?>" name="q" id="moteur" /> <input type="submit" value="Envoyer" /> </form>
Usage de la class PHP 5 du moteur de recherche PHP objet :
Il faut impérativement ajouter une class HTML à chaque ligne de résultats (ici, c'est la class "results") ainsi qu'un compteur de résultats qui ajoutent dynamiquement des ID (ici, c'est $nb, mais vous n'êtes pas obligés d'ajouter le nombre comme dans l'exemple en revanche, c'est juste utile dans id="<?php echo $nb; ?>").
<?php include_once("class.inc/BDD.class-inc.php"); include_once("class.inc/stopwords.php"); include_once("class.inc/moteur-php5.class-inc.php"); if(isset($_GET) && !empty($_GET['q'])) { $moteur = new moteurRecherche(stripslashes($_GET['q']), 'search', 'regexp', $stopwords); $colonnesWhere = array('title', 'description'); $moteur->moteurRequetes($colonnesWhere); } if(isset($moteur)) { // Affichage de la requête avec $moteur->requete echo '<h3>Résultats de la recherche : <em>'.$moteur->requete.'</em></h3>'; // Fonction d'affichage des résultats (callback appelé ensuite) function display($requete, $nbResults, $mots) { if($nbResults == 0) { // Si aucun résultat n'est retourné echo "<p>Aucun résultat, veuillez effectuer une autre recherche !</p>"; } else { // Sinon on affiche les résultats en boucle // Affichage du nombre de résultats (optionnel) // N.B. : important pour l'affichage de résultats suivants (class "numR") !!! $affichageResultats = new affichageResultats(); echo $affichageResultats->nbResultats(true); // Instanciation des ID (et du numéro de résultat si besoin) $nb = 0; while(($key = mysql_fetch_assoc($requete))) { $nb++; // Incrémentation de l'ID // On encode chaque clé/valeur de résultats en UTF-8 foreach($key as $k => $v) { $key[$k] = utf8_encode($v); } // Résultats de recherche à afficher (à personnaliser) $texte = "<div class='results' id='".$nb."'>\n"; $texte .= "\t<h3>".$nb." - ".$key['title']."</h3>\n"; $texte .= "\t<p>".$key['description']."</p>\n"; $texte .= "</div>\n"; // Affichage du contenu après surlignage des mots recherchés // N.B. : optionnel --> possibilité de remplacer par echo $texte; $surlignage = new surlignageMot($mots, $texte); echo $surlignage->contenu; } // Fin de la boucle while } } // Fin de la fonction display (callback) // Nombre de résultats par "tranche d'affichage" $limit = 10; // Lancement de la fonction d'affichage avec paramètres $moteur->moteurAffichage('display', '', array(true, 0, $limit, false)); // Affichage de la zone de chargement echo '<div id="loadMore">Afficher plus de résultats...</div>'; } ?>
Exemple de fichier de réception du script Ajax
Ce fichier reprend un peu le même principe que le code PHP situé juste au-dessus car il doit être en cohérence avec les résultats affichés précédemment. Seules quelques différences sont à noter :
- suppression de la ligne d'affichage du nombre de résultats ;
- suppression du lien "Afficher plus..." car il n'a pas besoin d'être rechargé ;
- modification du "$nb = 0;" en "$nb=$_GET['nb'];" ;
- modification du "$limit = 10;" (ou autre valeur) en "$limit = htmlspecialchars($_GET['limit']);".
<?php include_once("class.inc/BDD.class-inc.php"); include_once("class.inc/stopwords.php"); include_once("class.inc/moteur-php5.class-inc.php"); $moteur = new moteurRecherche(stripslashes($_GET['q']), 'search', 'regexp', $stopwords); $colonnesWhere = array('title', 'description'); $moteur->moteurRequetes($colonnesWhere); if(isset($moteur)) { function affichage($requete, $nbResults, $mots) { // Récupération du numéro de résultats $nb = $_GET['nb']; while(($key = mysql_fetch_assoc($requete)) && $nb < $nbResults) { $nb++; // Incrémentation de l'ID // On encode chaque clé/valeur de résultats en UTF-8 foreach($key as $k => $v) { $key[$k] = utf8_encode($v); } // Résultats de recherche à afficher (à personnaliser) $texte = "<div class='results' id='".$nb."'>\n"; $texte .= "\t<h3>".$nb." - ".$key['title']."</h3>\n"; $texte .= "\t<p>".$key['description']."</p>\n"; $texte .= "</div>\n"; // Affichage du contenu après surlignage des mots recherchés // N.B. : optionnel --> possibilité de remplacer par echo $texte; $surlignage = new surlignageMot($mots, $texte); echo $surlignage->contenu; } // Fin de la boucle while } // Fin de la fonction display (callback) // Nombre de résultats par "tranche d'affichage" $limit = htmlspecialchars($_GET['limit']); // Numéro de page récupéré dynamiquement if(isset($_GET['nb'])) { $page = htmlspecialchars($_GET['nb']); } else { $page = 0; } // Lancement de la fonction d'affichage avec paramètres $moteur->moteurAffichage('affichage', '', array(true, $page, $limit, false)); } ?>
Exemple de script - Ajax trigger avec jQuery
Voici comment faire fonctionner le trigger Ajax avec "Afficher plus de résultats" (à placer dans le head ou en fin de body dans le code HTML) :
- ajout du CSS pour gérer l'affichage du "loader" (bouton "Afficher plus...") dans une feuille à part ou directement dans votre propre CSS ;
- chargement de la bibliothèque jQuery (évitez les versions 2, optez plutôt pour des versions 1.7 ou 1.8 par exemple) ;
- chargement du script ajaxTrigger.js ;
- mise en place des paramètres utiles faire fonctionner le plugin jQuery.
N.B. : pour le moteur de recherche PHP, il convient absolument de mettre "nbResult: $('.numR').text()" pour que le nombre de résultats total soit récupéré dynamiquement. L'autre alternative en PHP 5 serait de charger les scripts en bas de page (fin de body) et d'utiliser à la place "<?php echo $moteur::$nbResultsChiffre; ?>"...
<link rel="stylesheet" href="css/click-trigger.css" /> <script type="application/javascript" src="js/jquery.js"></script> <script type="application/javascript" src="js/ajaxTrigger.js"></script> <script type="application/javascript"> $(document).ready(function () { // Tableau des arguments optionnels (ici les valeurs par défaut) var args = { target: 'queryAjax.php', // Cible contenant le contenu à charger (boucle PHP/MySQL en général) limit: 5, // Nombre de résultats à afficher par chargement nbResult: $('.numR').text(), // Nombre total de résultats (récupéré dynamiquement) duration: 300, // Durée d'affichage de l'image de chargement (en ms) --> 0 pour annuler ! classLast: '.results', // Class des résultats affichés (obligatoire pour fonctionner !) loadImg: 'img/loadingBlue.gif', // Image de chargement ('' pour ne pas afficher d'image) idImg: 'imgLoading', // ID du bloc contenant l'image de chargement attrID: 'id', // Attribut contenant le numéro du résultat affiché ('id' conseillé !) evt: 'click', // Type d'événement Javascript pour lancer la fonction }; // Options complémentaires (requête de recherche par exemple ici --> Totalement personnalisable !) var options = { q: '<?php if(isset($_GET['q'])) { echo $_GET['q']; } ?>' }; // Lancement de la fonction sur l'élément "Afficher plus" $('#loadMore').ajaxTrigger(args, options); }); </script>
Exemple de script - Scroll infini Ajax avec jQuery
Le scroll infini fonctionne globalement sur le même principe que le trigger Ajax, il convient donc de respecter la procédure expliquée précédemment avec le script suivant :
<link rel="stylesheet" href="css/infinite-scroll.css"/> <script type="application/javascript" src="js/jquery.js"></script> <script type="application/javascript" src="js/ajaxInfiniteScroll.js"></script> <script type="application/javascript"> $(document).ready(function () { // Tableau des arguments optionnels (ici les valeurs par défaut) var args = { target: 'queryAjax.php', // Cible contenant le contenu à charger (boucle PHP/MySQL en général) limit: 5, // Nombre de résultats à afficher par chargement nbResult: $('.numR').text(), // Nombre total de résultats (récupéré dynamiquement) duration: 500, // Durée d'affichage de l'image de chargement (en ms) --> 0 pour annuler ! classLast: '.results', // Class des résultats affichés (obligatoire pour fonctionner !) loadMore: '#loadMore', // Sélecteur de l'image de chargement attrID: 'id', // Attribut contenant le numéro du résultat affiché ('id' conseillé !) evt: 'scroll', // Type d'événement Javascript pour lancer la fonction }; // Options complémentaires (requête de recherche par exemple ici --> Totalement personnalisable !) var options = { q: '<?php if(isset($_GET['q'])) { echo $_GET['q']; } ?>' }; // Lancement de la fonction sur l'élément "Afficher plus" $(window).ajaxInfiniteScroll(args, options); }); </script>
Evolutions éventuelles pour les scrips du moteur de recherche PHP-Ajax
Comme tous les scripts, ces deux fichiers codés en jQuery sont imparfaits et peuvent demander quelques ajustements, c'est pourquoi je vous conseille de repasser de temps en temps sur cette page pour vérifier la version en cours d'usage. En général, dès que quelqu'un me signale un gros problème ou que j'en détecte un de mon côté, je fais une petite mise à jour de correction, c'est la règle du jeu... :D
Actuellement, je n'ai décelé aucun problème particulier avec ajaxTrigger.js mais le scroll infini peut parfois être taquin quand nous allons trop vite avec le scroll et la souris (il charge deux fois les mêmes résultats puis se relance normalement). J'ai ajouté un système de "timer" pour limiter ce phénomène en ralentissant l'animation, ce qui ne m'a plus causé aucun problème après ça, mais je reste méfiant toutefois que les scroll infinis ne sont jamais parfaits...
En réalité, vous pouvez "feinter" pour simuler une sorte de scroll infini mais en utilisant ajaxTrigger.js, voici comment procéder :
- mettre un événement "hover" plutôt que "click" dans le script de lancement du trigger Ajax ;
- modifier le "echo '<div id="loadMore">Afficher plus de résultats...</div>';" en "echo '<div id="loadMore"> </div>';".
Ainsi, quand vous arrivez en base de page et que vous "survolez" la div transparente, le script se lance et fait l'effet d'un scroll infini. C'est moins pratique mais c'est une solution alternative... :D