La navigation avec Ajax : LE guide

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 !

Willy Bahuaud

Willy est intégrateur, développeur et WordPress Fanboy.

Après avoir travaillé en agence, il est désormais freelance et propose des prestations de conception de thèmes, plugins et sites WordPress.

Lire la suite

Vous aimez ? Partagez !


Réagir à cet article

120 caractères maximum