¿Cómo configurar correctamente un nonce AJAX para la API REST de WordPress?
Siguiendo un comentario con enlace aquí que me llevó a esta documentación, intenté configurar un nonce para autenticación de usuarios.
Agregué:
wp_localize_script( 'wp-api', 'wpApiSettings', array(
'root' => esc_url_raw( rest_url() ),
'nonce' => wp_create_nonce( 'wp_rest' )
) );
al condicional que verifica si el usuario está logueado y puede realizar las acciones solicitadas en la llamada REST.
También agregué:
beforeSend: function ( xhr ) {
xhr.setRequestHeader( 'X-WP-Nonce', wpApiSettings.nonce );
},
a mi clase jQuery que realiza la llamada API.
Recibí un error indicando que wpApiSettings no existe. ¿Qué hice mal?

Primero que nada...
(Esta información es para otros lectores que aún no lo saben.) Hay dos formas de autenticar tu solicitud REST API:
Usando la autenticación estándar por cookies
Usando un plugin como Application Passwords
Puedes leer más en el manual oficial de REST API aquí, y esta respuesta es para la autenticación estándar por cookies, donde el nonce debe ser enviado ya sea a través de un parámetro de consulta GET/POST
llamado _wpnonce
o un encabezado (HTTP personalizado) llamado X-WP-Nonce
.
Opciones para enviar el nonce de la cookie
Opción fácil: Agregar
_wpnonce
a la URL del endpoint REST API. Esto funciona con solicitudesGET
,POST
, etc. incluyendo cargas JSON.jQuery.ajax({ method: 'POST', // _wpnonce como un parámetro de consulta GET/$_GET url: '/path/to/endpoint?_wpnonce=<nonce>', data: { foo: 'bar', baz: 1 }, dataType: 'json', success: function ( data ) { console.log( data ); }, });
O añadir
_wpnonce
al cuerpo de la solicitud.jQuery.ajax({ method: 'POST', url: '/path/to/endpoint', // _wpnonce como un parámetro POST/$_POST // pero puede ser GET; mira el `method` arriba que por defecto es GET cuando no se especifica data: { foo: 'bar', baz: 1, _wpnonce: '<nonce>' }, dataType: 'json', success: function ( data ) { console.log( data ); }, });
O particularmente al enviar carga JSON (como el código de ejemplo en esta pregunta): Añadir
X-WP-Nonce
a los encabezados de la solicitud. Esta opción también funciona bien con solicitudesGET
,POST
, etc.jQuery.ajax({ method: 'POST', url: '/path/to/endpoint', data: JSON.stringify( { foo: 'bar', baz: 1 } ), // enviando una cadena codificada en JSON contentType: 'application/json; charset=utf-8', // y un encabezado Content-Type JSON // Enviar el nonce como parte de los encabezados. beforeSend: function ( xhr ) { xhr.setRequestHeader( 'X-WP-Nonce', '<nonce>' ); }, dataType: 'json', success: function ( data ) { console.log( data ); }, });
Ahora un ejemplo:
Parte PHP: (en el archivo de funciones de tu tema o tu plugin)
// Registrar un endpoint REST API de prueba...
add_action( 'rest_api_init', 'my_register_rest_routes' );
function my_register_rest_routes() {
register_rest_route( 'my-plugin/v1', '/foo', [
'methods' => 'POST',
'callback' => function ( $request ) {
return [
$request->get_params(),
'¿Usuario autenticado?: ' . ( is_user_logged_in() ? 'Sí' : 'NO' ),
'¿Usuario puede publicar posts?: ' . ( current_user_can( 'publish_posts' ) ? 'Sí' : 'NO' )
];
},
] );
}
add_action( 'wp_enqueue_scripts', 'my_enqueue_scripts' );
function my_enqueue_scripts() {
// Encolar el script que hace la llamada AJAX a /wp-json/my-plugin/v1/foo.
wp_enqueue_script( 'my-script', '/path/to/my-script.js', [ 'jquery' ] );
// Registrar variables personalizadas para el script AJAX.
wp_localize_script( 'my-script', 'myScriptVars', [
'root' => esc_url_raw( rest_url() ),
'nonce' => wp_create_nonce( 'wp_rest' ),
] );
}
Notas:
Recuerda que el primer parámetro para
wp_enqueue_script()
—my-script
en el ejemplo anterior — es exactamente el mismo que el primer parámetro parawp_localize_script()
. Y ese parámetro es el handle del script que es un slug único como identificador para el script que estás encolando o localizando.Si esos parámetros no coinciden, entonces el script no se localizará, y el objeto JS —
myScriptVars
en el ejemplo anterior — sería unundefined
lo que podría resultar en un error como el mencionado en la pregunta ("wpApiSettings no existe"). :)
Parte JS: (en my-script.js
o cualquiera que sea el nombre del archivo...)
Aquí, añadimos _wpnonce
al cuerpo de la solicitud.
jQuery.ajax({
method: 'POST',
url: myScriptVars.root + 'my-plugin/v1/foo',
data: { foo: 'bar', baz: 1, _wpnonce: myScriptVars.nonce },
dataType: 'json',
success: function ( data ) {
console.log( data );
},
});
Notas:
El código JS anterior y los otros en esta respuesta usan ajax()
de jQuery.

¡Ah, por supuesto! Me siento tan tonto, claro que la localización debe hacerse antes de los encabezados. Doh. Gran respuesta.

Nota para los más lentos entre nosotros (como yo): el primer parámetro de wp_localize_script
es el handle con el que registraste tu script para encolarlo.
