Logo

Documentation

/home/vhsh1501/documentation.benjamin-bruant.com/wp-content/themes/zetheme/single.phpsingle

PHP côté serveur et mise en file d’attente

Le script PHP côté serveur comporte deux parties nécessaires à la mise en œuvre de la communication AJAX. Tout d’abord, nous devons mettre en file d’attente le script jQuery sur la page web et localiser toutes les valeurs PHP dont le script jQuery a besoin. La seconde est la gestion de la requête AJAX.

Script Enqueue

Cette section couvre les deux principales bizarreries d’AJAX dans WordPress qui font trébucher les codeurs expérimentés qui découvrent WordPress. L’une d’entre elles est la nécessité de mettre en file d’attente les scripts pour que les liens <meta> apparaissent correctement dans l’en-tête de la page. L’autre est que toutes les requêtes AJAX doivent être envoyées via wp-admin/admin-ajax.php. N’envoyez jamais de requêtes directement aux pages de vos plugins.

Enqueue

Utilisez la fonction wp_enqueue_script() pour que WordPress insère un lien <meta> vers votre script dans la section de la page. Ne jamais coder en dur de tels liens dans le modèle d’en-tête. En tant que développeur de plugin, vous n’avez pas facilement accès au modèle d’en-tête, mais cette règle mérite tout de même d’être mentionnée.

La fonction enqueue accepte les cinq paramètres suivants :

  • $handle est le nom du script.
  • $src définit l’emplacement du script. Pour des raisons de portabilité, utilisez plugins_url() pour créer l’URL appropriée. Si vous demandez le script pour quelque chose d’autre qu’un plugin, utilisez une fonction connexe pour créer une URL correcte – ne la codifiez jamais en dur.
  • $deps est un tableau qui peut contenir n’importe quel script dont votre nouveau script dépend, comme jQuery. Puisque nous utilisons jQuery pour envoyer une requête AJAX, vous devrez au moins lister ‘jquery’ dans le tableau.
  • $ver vous permet de lister un numéro de version.
  • $args un tableau d’arguments qui définit l’impression du pied de page (via une clé in_footer ) et les stratégies de chargement du script (via une clé strategy ) telles que defer ou async . Ceci remplace le paramètre $in_footer à partir de la version 6.3 de WordPress.
wp_enqueue_script(
	'ajax-script',
	plugins_url( '/js/myjquery.js', __FILE__ ),
	array( 'jquery' ),
	'1.0.,0',
	array(
	   'in_footer' => true,
	)
);

Vous ne pouvez pas mettre en file d’attente des scripts directement à partir de la page de code de votre plugin lorsqu’elle est chargée. Les scripts doivent être mis en file d’attente à partir de l’un des quelques hook action – lequel dépend du type de page à laquelle le script doit être lié. Pour les pages d’administration, utilisez admin_enqueue_scripts. Pour les pages d’accueil, utilisez wp_enqueue_scripts, sauf pour la page de connexion, auquel cas utilisez login_enqueue_scripts.

Le hook admin_enqueue_scripts transmet le nom du fichier de la page courante à votre callback. Utilisez cette information pour ne mettre en file d’attente votre script que sur les pages où il est nécessaire. La version frontale ne transmet rien. Dans ce cas, utilisez des marqueurs de modèles tels que is_home(), is_single(), etc. pour vous assurer que vous ne mettez en file d’attente votre script que là où il est nécessaire. Voici le code de mise en file d’attente complet pour notre exemple :

add_action( 'admin_enqueue_scripts', 'my_enqueue' );
function my_enqueue( $hook ) {
	if ( 'myplugin_settings.php' !== $hook ) {
		return;
	}
	wp_enqueue_script(
		'ajax-script',
		plugins_url( '/js/myjquery.js', __FILE__ ),
		array( 'jquery' ),
		'1.0.0',
		array(
		   'in_footer' => true,
		)
	);
}

Pourquoi utilisons-nous ici une fonction nommée alors que nous utilisons des fonctions anonymes avec jQuery ? Parce que les fermetures ne sont supportées que depuis peu par PHP, alors que jQuery les supporte depuis un certain temps. Comme certaines personnes peuvent encore utiliser des versions plus anciennes de PHP, nous utilisons toujours des fonctions nommées pour une compatibilité maximale. Si vous disposez d’une version récente de PHP et que vous ne développez que pour votre propre installation, vous pouvez utiliser les fermetures si vous le souhaitez.

Registrer vs. Enqueue

Vous verrez des exemples dans d’autres tutoriels qui utilisent religieusement wp_register_script(). C’est très bien, mais son utilisation est facultative. Ce qui n’est pas optionnel, c’est wp_enqueue_script(). Cette fonction doit être appelée pour que votre fichier script soit correctement lié à la page web. Pourquoi enregistrer des scripts ? Il crée une balise ou un handle utile avec lesquels vous pouvez facilement référencer le script dans différentes parties de votre code, selon vos besoins. Si vous avez simplement besoin de charger votre script et que vous n’y faites pas référence ailleurs dans votre code, il n’est pas nécessaire de l’enregistrer.

Chargement différé des scripts

WordPress permet de spécifier une stratégie de chargement des scripts via les fonctions wp_register_script() et wp_enqueue_script(), au moyen de la clé strategy dans le nouveau paramètre $args array introduit dans WordPress 6.3.

Les stratégies supportées sont les suivantes :

  • defer
    • Ajouté en spécifiant une paire clé-valeur de tableau 'strategy' => 'defer' dans le paramètre $args.
    • Les scripts marqués pour une exécution différée – via l’attribut defer script – ne sont exécutés qu’une fois que l’arbre DOM est complètement chargé (mais avant les événements DOMContentLoaded et window load). Les scripts différés sont exécutés dans l’ordre dans lequel ils ont été imprimés/ajoutés dans le DOM, contrairement aux scripts asynchrones.
  • async
    • Ajouté en spécifiant une paire clé-valeur de tableau 'strategy' => 'async' au paramètre $args.
    • Les scripts marqués pour une exécution asynchrone – via l’attribut async script – sont exécutés dès qu’ils sont chargés par le navigateur. Les scripts asynchrones n’ont pas d’ordre d’exécution garanti, car le script B (bien qu’ajouté au DOM après le script A) peut s’exécuter en premier étant donné qu’il peut terminer son chargement avant le script A. De tels scripts peuvent s’exécuter soit avant que le DOM ait été entièrement construit, soit après l’événement DOMContentLoaded.

Voici un exemple de spécification d’une stratégie de chargement pour une file d’attente de scripts supplémentaire dans notre plugin :

wp_register_script(
    'ajax-script-two',
    plugins_url( '/js/myscript.js', __FILE__ ),
    array( ajax-script ),
    '1.0.,0',
    array(
          'strategy' => 'defer',
     )
);

La même approche s’applique lors de l’utilisation de wp_enqueue_script(). Dans l’exemple ci-dessus, nous indiquons que nous avons l’intention de charger le script « ajax-script-two » de manière différée.

Lors de la spécification d’une stratégie de chargement différé de script, l’arbre de dépendance du script (ses dépendances et/ou ses dépendances) est pris en compte pour décider d’une « stratégie éligible » afin de ne pas aboutir à l’application d’une stratégie valable pour un script mais préjudiciable à d’autres dans l’arbre en provoquant un désordre involontaire dans l’ordre d’exécution. Grâce à cette logique, la stratégie de chargement prévue que vous transmettez via le paramètre $args peut ne pas être la stratégie finale (choisie), mais elle ne sera jamais préjudiciable à (ou plus stricte que) la stratégie prévue.

Nonce

Vous devez créer un nonce afin que la requête AJAX de jQuery puisse être validée comme une requête légitime et non comme une requête potentiellement malveillante émanant d’un mauvais acteur inconnu. Seuls vos scripts PHP et jQuery connaîtront cette valeur. Lorsque la requête est reçue, vous pouvez vérifier qu’il s’agit de la même valeur que celle créée ici. Voici comment créer un nonce pour notre exemple :

$title_nonce = wp_create_nonce( 'title_example' );

Le paramètre title_example peut être une chaîne de caractères arbitraire. Il est suggéré que la chaîne soit en rapport avec l’utilisation du nonce, mais elle peut être n’importe quoi.

Localize

Si vous vous souvenez de la section jQuery, les données créées par PHP pour être utilisées par jQuery étaient transmises dans un objet global nommé my_ajax_obj . Dans notre exemple, ces données étaient un nonce et l’URL complète de admin-ajax.php. Le processus d’attribution des propriétés de l’objet et de création de l’objet global jQuery s’appelle la localisation. Voici le code de localisation utilisé dans notre exemple qui utilise wp_localize_script() .

wp_localize_script(
	'ajax-script',
	'my_ajax_obj',
	array(
		'ajax_url' => admin_url( 'admin-ajax.php' ),
		'nonce'    => $title_nonce,
	)
);

Notez que notre gestionnaire de script ajax-script est utilisé pour que l’objet global soit assigné au bon script. L’objet est global à notre script, pas à tous les scripts. La localisation peut également être appelée à partir du même hook que celui utilisé pour mettre les scripts en file d’attente. Il en va de même pour la création d’un nonce, bien que cette fonction particulière puisse être appelée pratiquement n’importe où. Tout cela combiné dans un seul hook callback ressemble à ceci :

add_action( 'admin_enqueue_scripts', 'my_enqueue' );

/**
 * Enqueue my scripts and assets.
 *
 * @param $hook
 */
function my_enqueue( $hook ) {
	if ( 'myplugin_settings.php' !== $hook ) {
		return;
	}
	wp_enqueue_script(
		'ajax-script',
		plugins_url( '/js/myjquery.js', __FILE__ ),
		array( 'jquery' ),
		'1.0.0',
		true
	);

	wp_localize_script(
		'ajax-script',
		'my_ajax_obj',
		array(
			'ajax_url' => admin_url( 'admin-ajax.php' ),
			'nonce'    => wp_create_nonce( 'title_example' ),
		)
	);
}

N’oubliez pas de n’ajouter cette localisation de nonce qu’aux pages nécessaires, n’affichez pas de nonce à quelqu’un qui ne devrait pas l’utiliser. Et n’oubliez pas d’utiliser current_user_can() avec une capacité ou un rôle pour compléter la sécurité.

AJAX Action

L’autre partie importante du code PHP côté serveur est le gestionnaire AJAX qui reçoit les données POST, les utilise et renvoie une réponse appropriée au navigateur. Cela prend la forme d’un hook d’action WordPress. Le hook que vous utilisez dépend du fait que l’utilisateur est connecté ou non et de la valeur que votre script jQuery a passé comme valeur action :.

$_GET , $_POST and $_COOKIE vs $_REQUEST

Vous avez probablement utilisé un ou plusieurs des super globals PHP tels que $_GET ou $_POST pour récupérer des valeurs à partir de formulaires ou de cookies (en utilisant $_COOKIE ). Peut-être préférez-vous $_REQUEST, ou du moins l’avez-vous déjà vu utilisé. C’est plutôt cool – quelle que soit la méthode de requête, POST ou GET, il y aura les valeurs du formulaire. Cela fonctionne très bien pour les pages qui utilisent les deux méthodes. De plus, il contient également les valeurs des cookies. Un seul point de vente ! C’est là que réside son défaut tragique. En cas de conflit de nom, la valeur du cookie prévaudra sur les valeurs du formulaire. Il est donc ridiculement facile pour un acteur malveillant de créer un cookie contrefait sur son navigateur, qui écrasera toute valeur de formulaire que vous pourriez attendre de la requête. $_REQUEST est un moyen facile pour les pirates d’injecter des données arbitraires dans les valeurs de votre formulaire. Pour plus de sécurité, tenez-vous en aux variables spécifiques et évitez la solution unique.

Comme notre échange AJAX concerne la page de configuration du plugin, l’utilisateur doit être connecté. Si vous vous souvenez de la section jQuery, la valeur de l’action : est « my_tag_count » . Cela signifie que notre hook action sera wp_ajax_my_tag_count . Si notre échange AJAX devait être utilisé par des utilisateurs qui ne sont pas connectés, la balise d’accroche (hook) de l’action serait wp_ajax_nopriv_my_tag_count .

Le code de base utilisé pour accrocher l’action ressemble à ceci :

add_action( 'wp_ajax_my_tag_count', 'my_ajax_handler' );

/**
 * Handles my AJAX request.
 */
function my_ajax_handler() {
	// Handle the ajax request here

	wp_die(); // All ajax handlers die when finished
}

La première chose que votre gestionnaire AJAX doit faire est de vérifier le nonce envoyé par jQuery avec check_ajax_referer() , qui doit être la même valeur que celle qui a été localisée lorsque le script a été mis en file d’attente.

check_ajax_referer( 'title_example' );

Le paramètre fourni doit être identique au paramètre fourni précédemment à wp_create_nonce() . La fonction meurt simplement si le nonce n’est pas vérifié. S’il s’agissait d’un vrai nonce, maintenant qu’il a été utilisé, la valeur n’est plus valable. Vous devriez alors en générer une nouvelle et l’envoyer au script de rappel afin qu’elle puisse être utilisée pour la prochaine requête. Mais comme les nonces de WordPress sont valables pendant vingt-quatre heures, vous n’avez rien à faire d’autre que de les vérifier.

Data

Une fois le nonce éliminé, notre gestionnaire peut traiter les données envoyées par le script jQuery contenu dans $_POST['title'] . Tout d’abord, nous assignons la valeur à une nouvelle variable, après l’avoir passée par wp_unslash() pour supprimer les guillemets inattendus.

$title = wp_unslash( $_POST['title'] );

Nous pouvons enregistrer la sélection de l’utilisateur dans les méta de l’utilisateur en utilisant update_user_meta() .

update_user_meta( get_current_user_id(), 'title_preference', sanitize_post_title( $title ) );

Ensuite, nous construisons une requête afin d’obtenir le nombre d’articles pour l’étiquette de titre sélectionnée.

$args      = array(
	'tag' => $title,
);
$the_query = new WP_Query( $args );

Enfin, nous pouvons renvoyer la réponse au script jQuery. Il existe plusieurs façons de transmettre des données. Examinons quelques-unes de ces options avant de nous pencher sur les spécificités de notre exemple.

XML

Le support de PHP pour le XML laisse à désirer. Heureusement, WordPress fournit la classe WP_Ajax_Response pour faciliter la tâche. La classe WP_Ajax_Response va générer une réponse au format XML, définir le bon type de contenu pour l’en-tête, produire la réponse xml, puis mourir – garantissant une réponse XML correcte.


JSON

Ce format est léger et facile à utiliser, et WordPress fournit la fonction wp_send_json pour encoder votre réponse en json, l’imprimer et mourir – remplaçant ainsi WP_Ajax_Response . WordPress fournit également les fonctions wp_send_json_success et wp_send_json_error, qui permettent aux callbacks done() ou fail() de se déclencher en JS.


Autres fonctions

Vous pouvez transférer des données de n’importe quelle manière, à condition que l’expéditeur et le destinataire soient coordonnés. Les formats de texte tels que les formats délimités par des virgules ou des tabulations sont l’une des nombreuses possibilités. Pour de petites quantités de données, l’envoi du flux brut peut être suffisant. C’est ce que nous ferons dans notre exemple – nous enverrons le texte HTML de remplacement, rien d’autre.

echo esc_html( $title ) . ' (' . $the_query->post_count . ') ';

Dans une application réelle, vous devez tenir compte de la possibilité que l’action échoue pour une raison quelconque – par exemple, si le serveur de la base de données est en panne. La réponse doit tenir compte de cette éventualité et le script jQuery qui reçoit la réponse doit agir en conséquence, en demandant par exemple à l’utilisateur de réessayer plus tard.
La mort

Lorsque le gestionnaire a terminé toutes ses tâches, il doit mourir. Si vous utilisez les fonctions WP_Ajax_Response ou wp_send_json*, cela est automatiquement géré pour vous. Sinon, utilisez simplement la fonction WordPress wp_die().
Résumé du gestionnaire AJAX

Le gestionnaire AJAX complet pour notre exemple ressemble à ceci :

/**
 * AJAX handler using JSON
 */
function my_ajax_handler__json() {
	check_ajax_referer( 'title_example' );
	$title = wp_unslash( $_POST['title'] );

	update_user_meta( get_current_user_id(), 'title_preference', sanitize_post_title( $title ) );

	$args      = array(
		'tag' => $title,
	);
	$the_query = new WP_Query( $args );
	wp_send_json( esc_html( $title ) . ' (' . $the_query->post_count . ') ' );
}
/**
 * AJAX handler not using JSON.
 */
function my_ajax_handler() {
	check_ajax_referer( 'title_example' );
	$title = wp_unslash( $_POST['title'] );

	update_user_meta( get_current_user_id(), 'title_preference', sanitize_post_title( $title ) );

	$args      = array(
		'tag' => $title,
	);
	$the_query = new WP_Query( $args );
	echo esc_html( $title ) . ' (' . $the_query->post_count . ') ';
	wp_die(); // All ajax handlers should die when finished
}