La navigation avec Ajax : LE guide

02. décembre 2013 Front-end, Guides 19
La navigation avec Ajax : LE guide

L’Ajax (Asynchronous Javascript and XML) est une méthode qui combine plusieurs technologies afin de charger du contenu dans une page web sans la recharger.

C’est en utilisant du JavaScript qu’une requête va être soumise au serveur (de façon asynchrone) puis retournée vers celui-ci afin qu’il opère des modifications sur cette page, telles qu’insérer ou modifier certaines sections.

C’est une méthode très utilisée pour plusieurs raisons :

La première est que les sites d’aujourd’hui ont une structure commune à l’ensemble de leur page. L’Ajax permet d’économiser du temps de calcul et de téléchargement en modifiant uniquement le contenu qui change à travers le site.

La seconde est que l’Ajax permet de concevoir des sites à la navigation dynamique et attractive. Le phénomène du rechargement de page n’a pas réellement la côte ; il est souvent perçu (à mon avis) comme un élément qui vient perturber l’utilisateur alors que l’on souhaite lui proposer une navigation limpide.

L’objet de cet article va être de vous montrer deux méthodes pour faire de l’ajax sous WordPress.

Admin ajax pour des brêves requêtes

Faire de l’Ajax, c’est envoyer des requêtes en JavaScript vers des fichiers PHP afin de déclencher des actions ou récolter des données.

WordPress c’est un noyau, une interface d’administration, mais aussi des plugins et des thèmes. Le système Ajax y est très intensivement utilisé. Si chaque page, module, ou composant faisait ses propres requêtes vers n’importe quel fichier d’une installation, cela deviendrait très rapidement le bazar …

Il y aurait des bootstraps partout !

Les développeurs de WordPress ont donc conçu un fichier qui se nomme admin-ajax.php dont le rôle est de réceptionner l’ensemble de ces requêtes, puis de les diriger vers les bonnes fonctions. Ce fichier est situé à la racine de l’administration et s’utilise, sans surprise, via un système de hook.

Pour l’utiliser il faut faire un appel Ajax à ce fichier /wp-admin/admin-ajax.php – ou la variable JavaScript adminurl si l’on se trouve dans l’administration – en lui précisant un paramètre « action » auquel on doit attribuer une valeur unique.

Ensuite, il suffit simplement utiliser les hooks wp_ajax_{$action} et/ou wp_ajax_nopriv_{$action} pour câbler les fonctions à utiliser. Le premier désigne la fonction qui sera exécutée si l’utilisateur est connecté à l’administration, l’autre désigne la fonction exécutée le cas échéant.

Après, à l’intérieur de ces fonctions, on peut faire ce que l’on veut. Tout ce que l’on y imprime sera renvoyé vers la page ayant déclenchée l’action.

Il ne faudra pas oublier d’utiliser la fonction wp_send_json() ou die() avant la fermeture de ces fonctions.

C’est donc une méthode simple et assez bien pensée pour la plupart des utilisations.

Et si on veut faire une navigation en full ajax, quelles sont les possibilités ?

Le problème de cette méthode apparait lorsque l’on veut concevoir un site « full Ajax ». Un site ayant une structure et des contraintes habituelles en terme d’URL, mais où jamais aucune page n’est chargée de façon classique. Par exemple sur le site Wabeo.

Si on utilisait admin-ajax.php :

Il faudrait alors mettre un événement JavaScript sur chaque clic de lien (ce qui n’est pas un problème) et déclencher une requête vers admin-ajax.php en y poussant un paramètre pour désigner le contenu que l’internaute souhaite afficher.

Ce paramètre pourrait être un ID et un type de contenu, mais cela sous-entendrait un travail colossal pour prévoir les informations pour chaque lien du site, que ce soit lors du la réalisation du thème ou lors de la saisie des contenus. On oublie donc …

Ce paramètre pourrait sinon être directement l’URL. Tout à fait sauf que… en fait il est assez difficile dans WordPress de déterminer quel type de contenu va être chargé pour une URL du site. Il existe des fonctions pour retrouver l’ID d’un article selon une URL, mais c’est tout.

Nous devrions donc concevoir un long chemin critique (un peu comme lorsque l’on réalise un fil d’ariane, mais en pire) pour deviner quel contenu l’internaute souhaite afficher. J’ai utilisé cette technique pour le précédent thème de Wabeo, et je vous garanti que c’était hardcore.

On oublie aussi alors…

Si on faisait une requête directement sur la page :

Dans ce cas on pourrait se dire « au diable admin-ajax » et mettre un événement JavaScript sur chaque clic de lien pour faire une requête Ajax vers son attribut href.

Cette méthode permet de récupérer l’intégralité du DOM de la page, même ce dont nous n’avons pas besoin. Et c’est là qu’est le soucis : on perd un des gros avantage de l’Ajax qui est l’optimisation du temps de chargement puisqu’on a le choix du retour, ici, on ne l’a pas.

On perd beaucoup de l’intérêt de l’Ajax en procédant ainsi. Passons notre chemin une fois de plus …

Si on faisait une requête directement sur la page, mais en annonçant l’Ajax via un paramètre :

Voilà l’idée intéressante, et elle m’a été soufflée par Julio.

Il suffit d’écouter chaque clic de lien pour déclencher un appel Ajax vers l’attribut href du lien, mais en poussant également un paramètre qui annoncerait la nature de la requête : « Attention, je suis Ajax ! Affiche-moi uniquement ce dont j’ai besoin ».

Ce paramètre pourrait être n’importe quoi : une variable post, get, server, head 

Puis, dans les templates de nos pages, il faudrait tester la présence de ce paramètre pour afficher ou non certains éléments.

La méthode parfaite pour un site full ajax

Cette dernière technique tire les meilleurs parties en terme de simplicité et de performance. Plus simple que d’utiliser admin-ajax.php, et mois brutal que de charger toute la page.

En type de paramètre, le plus discret est de pousser un argument directement dans les entêtes, à la place de l’attribut X-Requested-With qui n’est quasiment jamais utilisé.

Voici une fonction javascript d’exemple :

// j'écoute les clic de tous les liens, sauf de l'admin bar
$( document ).on( 'click', 'a[href^="http://www.example.com"]:not(.ab-item)', do_ajax_request );

// lors d'un clic, j'exécute une fonction qui prend le lien en paramètre
function do_ajax_request( e ) {
    e.preventDefault();
    var url = $( this ).attr( 'href' );
    perform_ajax_request( url );
}

// je fais une requête ajax vers le lien, en poussant BAWXMLHttpRequest dans les headers
function perform_ajax_request( url ) {
    $.ajax({
        url    : url,
        type   : 'POST',
        headers: {
            'X-Requested-With':'BAWXMLHttpRequest'
        }
    }).done( function( data ) {
        // Do stuff
    }).error( function() {
        // Error
    });
}

Sur les templates du site, il faut alors faire des conditions, pour tester la valeur de X-Requested-With et renvoyer les informations qu’il faut, en HTML ou JSON.

Ou bien nous pourrions même faire une condition plus tôt dans le chargement de WordPress, et choisir un template pour renvoyer les objets Ajax !

Utiliser un template différent pour servir le contenu ajax

Faire des conditions partout dans ses thèmes est en fait assez ennuyeux. Il y a encore plus simple : utiliser un template spécial qui va se substituer au fichier normalement utilisé pour afficher la page. Cette idée m’a également été soumise par Julio.

Il faut donc, au moment du choix du template, vérifier les headers de la requête et si ces headers contiennent notre paramètre, switcher le template.

Voici le code qui fait ce job (à coller dans le functions.php du thème) :

add_filter( 'template_include', 'baw_template_include' );
function baw_template_include( $template ) {
	if( isset( $_SERVER['HTTP_X_REQUESTED_WITH'] ) && $_SERVER['HTTP_X_REQUESTED_WITH']== 'BAWXMLHttpRequest' ):
		$pre = dirname( $template );
		$suf = basename( $template );
		$_template = $pre . '/ajax-' . $suf;
		if( !file_exists( $_template ) )
			$_template = $template;
		$template = $_template;
	endif;
	return $template;
}

Rien n’oblige de mettre du HTML dans ce template. Nous pouvons, si l’on le souhaite, utiliser du JSON pour faciliter la manipulation des éléments qui seront insérés en JavaScript.

Pour faire la bascule de vos contenus facilement, je vous conseille de renvoyer dans l’objet JSON, un élément pour identifier le template.

Switchez vos contenus

À ce stade, vous êtes en moyen de faire des appels Ajax pour récupérer uniquement le contenu à mettre à jour dans vos pages. Il ne reste plus qu’à faire la bascule de vos contenus.

Votre utilisateur a souhaité changer d’URL, certains contenus ne sont donc plus utiles, et il faut les supprimer.

La méthode que j’utilise pour déterminer les contenus à sortir est de constamment tenir à jour une variable qui m’indique le template actuellement utilisé. Cette variable a été initialement posté par le biais d’un wp_localize_script() au chargement de la page. Elle permet, lorsque la requête Ajax réussie, d’identifier quelles éléments du document doivent être supprimés.

Ensuite, il faut alors insérer les nouveaux contenus, via la fonction append() de jQuery, par exemple.

On fini en mettant à jour la variable indiquant le template courant, puis en mettant à jour le titre de la page, dans l’onglet du navigateur.

Il ne faudra pas non plus oublier d’exécuter les fonctions habituellement appliquées au chargement d’une page (Google analytics, boutons sociaux, scripts des plugins…).

Par exemple :

// je fais une requête ajax vers le lien, en poussant BAWXMLHttpRequest dans les headers
function perform_ajax_request( url ) {
    $.ajax({
        url    : url,
        type   : 'POST',
        headers: {
            'X-Requested-With':'BAWXMLHttpRequest'
        }
    }).done( function( data ) {
        var data = $.parseJSON( data );
        switch_content( template_actuel, data );
    }).error( function() {
        // Error
        alert( 'Impossible de mettre à jour le contenu' );
    });
}

//la fonction pour la bascule des contenus
switch_content( template_actuel, data ) {
    switch( template_actuel ) {
        case 'detail':
            $( '.detail' ).remove();
            break;
        case 'liste':
            $( '.intro, .liste' ).remove();
            break;
        default :
    }

    switch( data.template ) {
        case 'detail':
            $('body').append($(data.detail));
            break;
        case 'liste':
            $('body').append($(data.intro + data.liste ));
            break;
        default :
    }

    // mise à jour du template
    template_actuel = data.template;

    // changement du nom de l'onglet
    window.document.title = data.title;
}

Ajax et compatibilité

L’ajax n’est pas une technologie, mais une utilisation conjointe de plusieurs technologies qui sont toutes supportées depuis Internet Explorer 5. Le code jQuery présenté sur cet article fonctionnera donc partout.

Cependant, dans le cadre d’un site entièrement dynamique, il ne vaut mieux utiliser l’ajax que si le navigateur supporte l’objet History d’HTML5. Cet objet donne accès à des méthodes et des propriétés qui permettent de manipuler l’historique du navigateur, de changer le contenu de la barre d’URL et d’écouter l’utilisation des boutons précédent et suivant.

Imaginez un site où l’on navigue sans savoir où l’on est… ça serait l’horreur : impossible de bookmarker une page ou de partager une URL.

L’Objet History est heureusement supporté par tous les navigateurs récents.

Il faut tout de même tester sa prise en charge, en utilisant la librairie Modernizr, par exemple, et n’appliquer notre système de navigation qu’à cette condition.

Ce qui est bien avec cette méthode, c’est que même avec l’Ajax ou le JavaScript désactivé, le site restera totalement utilisable !

Petit Bémol

Les plugins de cache vont renvoyer la page complète et non la partie templatée car l’url est la même. Si vous utilisez un plugin de cache, ajoutez alors simplement un paramètre comme « ?ajax=true », celui évitera le cache et seul votre template ajax sera chargé.

Si vous utilisez ou pensez utiliser ce système, merci de nous dire ce que vous en pensez !

Lire la suite

Vous aimez ? Partagez !

Abonnement gratuit à 0€


19 thoughts on “La navigation avec Ajax : LE guide”

  • 1
    Julien Maury on 2 décembre 2013 Répondre
    Super synthèse. Merci. Je ne suis pas convaincu de l’absolue nécessité d’une nav Ajax même si elle est bien réalisée. En revanche si on peut éviter le refresh autant le faire. Bien d’accord. Merci pour les pistes. A explorer… :)
  • 2
    Gaël Poupard on 2 décembre 2013 Répondre
    J’en reviens pas, c’est d’une ingéniosité déconcertante @_@

    Je ne suis pas persuadé non plus de l’utilité concrète de cette mécanique pour des sites «standards» : quels sont les avantages réels ? Performance, création des templates, maintenabilité, gestion de contenus… Sur Wabeo je le vois bien, pour du design émotionnel (comme tu l’as dit lors de ta précédente refonte) ça amène un véritable plus, et ça reste très agréable et surprenant même pour des professionnels du web. Mais ça reste une mécanique complète à mettre en place, alors est-ce que ça vaut le coup ? Dans quelle mesure est-ce quelque chose que l’on peut proposer à un client ?

    En tout cas Willy, cette fin d’année est extraordinaire ! Merci pour tous ces articles ;)

  • 3
    Willy Bahuaud on 3 décembre 2013 Répondre
    Oui tout à fait, il faut explorer ces pistes.

    @Gaël Merci, j’ai aussi trouvé ça déconcertant de facilité :-P

    En ce qui concerne les avantages, les inconvénients et bénéfices d’une navigation ajax, j’ai pris un peu de temps pour réfléchir avant de vous répondre.

    Cette méthode, celle que j’ai expérimenté sur mon nouveau site, à été très simple à mettre en place, du fait que j’ai relativement peu de templates (4). Et j’ai passé une journée de travail à mettre en place la navigation ajax (conception du script de navigation, du loader, des transition css, des templates et de leur câblage). C’est finalement assez peu, ou du moins c’est beaucoup plus rapide qu’avant.

    Au niveau maintenabilité, il faut juste faire attention à correctement factoriser son code javascript. Par exemple, dans le code de cet article, vous remarquerez que la fonction qui exécute la requête ajax est séparée… comme cela je peux l’appeler par le biais d’autre événements, et lui pousser une URL que j’aurais déterminé de différente manière (changement d’history, clic sur lien, soumission de formulaire de recherche…).
    Je pense qu’un code clair et factorisé sera relativement facile à maintenir :-)

    Enfin, pour les bénéfices…

    Effectivement, cela relève en grande partie du design émotionnel… mais pas que.
    L’internaute qui surf sur un site full ajax perçoit le site différemment. Il bénéficie d’une navigation davantage scénarisée (entrée et sortie des éléments) qui peut, si elle est bien faite, améliorer son expérience du site.

    Et puis, si le temps de chargement des données reste correct, alors on n’a même plus envie de parler de « temps de chargement », mais de « durée de transition ». Car il se passe quelque chose… nous ne sommes plus en train d’attendre le téléchargement d’informations, simplement la fin d’une transition graphique qui, à mon avis, est plus agréablement perçue par l’utilisateur.

    En tout cas, une navigation ajax, au même titre que le responsive web design, doit être pensé dès les fondation du site. Je vois mal le truc venir se greffer après…

    • 4
      Gaël Poupard on 3 décembre 2013
      En effet, c’est un outil redoutable mais à double-tranchant (ça peut devenir très perturbant si c’est mal géré, je pense).

      Merci pour la réponse ! Concernant ta remarque sur le temps de chargement, j’aimerais préciser aussi que sur une navigation «classique» les états actifs des liens et boutons sont déjà censés nous indiquer qu’il se passe quelque chose. Je le précise parce que c’est rarement le cas (et je ne le fais pas toujours moi-même, honte sur moi). Les transitions simples sur des éléments survolés, focusés ou actifs peuvent aussi être d’un grand secours pour du design émotionnel !

    • 5
      Willy Bahuaud on 3 décembre 2013
      Oui, son idée est excellente :-) Merci l’ami !
  • 6
    Daniel@Infogérance on 3 décembre 2013 Répondre
    Encore un article à garder impérativement en favori pour faire de l’Ajax proprement et simplement.

    Et l’idée de julio est tout simplement géniale pour simplifier les requêtes en Ajax sur WordPress. Bravo encore à tous les deux ;)

    • 7
      Willy test on 25 juillet 2014
      Test
    • 8
      Willy Bahuaud on 25 juillet 2014
      test
  • 9
    Marienoob on 27 avril 2014 Répondre
    Bonjour,

    Je trouve l’article très intéressant et c’est exactement ce que je souhaiterais faire pour mon nouveau site/blog wordpress.
    Cependant, je suis une grande débutante en code, que ce soit en javascript, jQuery, wordpress, php ou AJAX. J’arrive à me débrouiller mais je n’ai pas encore tout compris ^^’.

    Je souhaiterais donc « switcher » les articles à afficher, à partir d’une , au lieu de changer de page.
    Qu’est-ce que je dois changer à votre code pour que ça fonctionne ? Dois-je écrire le nom de mon template à la place de template_actuel ou $template, ou c’est des fonctions déjà gérées par wordpress ? Quand est-ce que je créée le nouveau template ? sa création et son changement se font automatiquement avec le code que vous avez écrit ?
    à la place des $(.detail) j’ai mis $(#id_de_ma_div), mais jusqu’à présent, quelles que soient les modifications que j’ai apporté au code, rien ne se passe… enfin si, je change toujours de page dès que je clique sur les liens Suivant , mais le code pour « switcher » ne s’exécute pas.
    Que dois-je modifier ?

    Merci pour votre aide !

  • 10
    Séverine on 9 mai 2014 Répondre
    Bonjour,

    Merci pour cet excellent tuto, je l’ai mis en place sur mon site. C’est vraiment fluide et agréable.
    Par contre je sèche totalement pour forcer le chargement de plugins qui ne se chargent pas initialement ( à moins des charger manuellement dans functions.php ?)
    Si quelqu’un pouvait me donner l’astuce ça serait génial!
    Merci d’avance.

    Merci.

    • 11
      Edmonk on 13 août 2015
      J’ai lu ta réponse après avoir posté mon message… Si tu as la méthode ça m’intéresse.

      Merci à toi

  • 12
    gino on 21 juin 2014 Répondre
    Je sais pas si vous avez remarqué, mais cela fait des années que Facebook a une navigation ajax et leur site est probablement le site le plus rapide que je connaisse.
  • 13
    Echo on 23 juillet 2014 Répondre
    Salut,

    Merci pour le tuto :)

    J’ai à peu près tout compris, mais il y a une chose qui me chiffonne… Comment fais tu pour récupérer ton contenu dans une variable JSON. Le script me renvoie seulement le html généré dans mon template. Le parseJSON me renvoyait une erreur. J’ai du oublié une étape quelque part.. Certainement là où tu parles de la fonction wp_localize_script.
    Si je mets du JSON dans mon template, la ça fonctionne mais je n’arrive pas à insérer mon contenu dedans, cela me renvoie systématiquement une erreur dûe à la syntaxe de php.

    J’ai du manquer quelque chose..

  • 15
    E. Geremy on 27 août 2014 Répondre
    Bonjour

    Merci pour ce tuto qui est plein de ressource et d’ingéniosité. Bien que je n’ai pas saisi la dernière partie concernant l’histoire des templates (qui semble être le coeur même de l’ingéniosité du script).

    J’ai d’assez bonne connaissance en jQuery/JS et Php, et je pense maitriser WordPress correctement. Cependant, l’Ajax (qui m’attire énormément) est loin d’être quelques choses que je maitrise.

    Ce que je voudrais que tu m’expliques (si tu as le temps bien sûr), c’est la manière dont tu fais pour déclarer tes templates et les récupérer dans ton script Ajax ? (j’ai regarder l’exemple que tu donnes avec le JSON, j’ai l’impression de toucher quelque chose mais ca fonctionne pas ^^)

    • 16
      E. Geremy on 27 août 2014
      Petite précision : dans mon cas, je n’ai que la partie central (ce qui est contenu dans une div.container-content) qui aurait besoin de se charger sur les pages, le reste ne doit pas se charger (enfin c’est ce que j’aimerai)

      PS : désolé pour le double post

  • 17
    Yoann on 22 septembre 2014 Répondre
    Super tuto, ta méthode est vraiment efficace.

    Je rencontre un soucis avec l’affichage du système de commentaires. Je n’arrive pas à utiliser wp_list_comments() lors du load Ajax et je ne trouve pas d’alternatives. Penses tu qu’il faille recoder toute la fonction ?

  • 18
    Edmonk on 13 août 2015 Répondre
    Salut,
    C’est une solution idéale en effet! Par contre je bloque sur un point (depuis un certain temps): si l’un des templates comporte un slider, lorsqu’on change les contenus, plus rien ne fonctionne. La fonction d’initialisation du slider n’est pas reconnue tant qu’elle n’est pas dans le template lui même. Quelle est la bonne méthode pour lier proprement un script à un template chargé en ajax?
  • 19
    onigetoc on 15 décembre 2015 Répondre
    J’ai fait un plugin WordPress pour la navigation ajax pour mes propres besoin car je n’aimait pas les autres et ne faisaient pas tout ce que je voulais, alors j’ai fait le mien qui s’appelle Zajax.
    https://wordpress.org/plugins/zajax-ajax-navigation/

Laisser un commentaire

Avant de parler, merci de lire la charte des commentaires.

Utiliser le tag [php][/php] pour ajouter du code ou utilisez un service comme pastebin.com.
Cibler un commentateur avec un "@", merci à Mention Comments Authors !