Come configurare correttamente un nonce AJAX per l'API REST di WordPress?
Seguendo un commento con link qui che mi ha portato a questa documentazione, ho provato a configurare un nonce per l'autenticazione degli utenti.
Ho aggiunto:
wp_localize_script( 'wp-api', 'wpApiSettings', array(
'root' => esc_url_raw( rest_url() ),
'nonce' => wp_create_nonce( 'wp_rest' )
) );
all'istruzione if che verifica se l'utente è loggato e può eseguire le operazioni richieste dalla chiamata REST.
Ho anche aggiunto:
beforeSend: function ( xhr ) {
xhr.setRequestHeader( 'X-WP-Nonce', wpApiSettings.nonce );
},
alla mia classe jQuery che effettua la chiamata API.
Ho ricevuto un errore che mi diceva che wpApiSettings non esiste. Cosa ho sbagliato?

Prima di tutto..
(Questa informazione è per altri lettori che non lo sanno ancora.) Ci sono due modi per autenticare la tua richiesta REST API:
Utilizzando l'autenticazione standard via cookie
Utilizzando un plugin come Application Passwords
Puoi leggere di più sul manuale ufficiale della REST API qui, e questa risposta riguarda l'autenticazione standard via cookie, dove il nonce dovrebbe essere inviato tramite un parametro di query GET/POST
chiamato _wpnonce
o un header (HTTP personalizzato) chiamato X-WP-Nonce
.
Opzioni per inviare il nonce del cookie
Opzione semplice: Aggiungi
_wpnonce
all'URL dell'endpoint REST API. Funziona con richiesteGET
,POST
, ecc. inclusi payload JSON.jQuery.ajax({ method: 'POST', // _wpnonce come parametro di query GET/$_GET url: '/path/to/endpoint?_wpnonce=<nonce>', data: { foo: 'bar', baz: 1 }, dataType: 'json', success: function ( data ) { console.log( data ); }, });
Oppure aggiungi
_wpnonce
al corpo della richiesta.jQuery.ajax({ method: 'POST', url: '/path/to/endpoint', // _wpnonce come parametro di query POST/$_POST // ma può essere GET; vedi il `method` sopra che di default è GET quando non specificato data: { foo: 'bar', baz: 1, _wpnonce: '<nonce>' }, dataType: 'json', success: function ( data ) { console.log( data ); }, });
O in particolare quando invii un payload JSON (proprio come il codice di esempio in questa domanda): Aggiungi
X-WP-Nonce
agli header della richiesta. Questa opzione funziona bene anche con richiesteGET
,POST
, ecc.jQuery.ajax({ method: 'POST', url: '/path/to/endpoint', data: JSON.stringify( { foo: 'bar', baz: 1 } ), // inviando una stringa codificata JSON contentType: 'application/json; charset=utf-8', // e un header Content-Type JSON // Invia il nonce come parte degli header. beforeSend: function ( xhr ) { xhr.setRequestHeader( 'X-WP-Nonce', '<nonce>' ); }, dataType: 'json', success: function ( data ) { console.log( data ); }, });
Ora un esempio:
Parte PHP: (nel file functions del tuo tema o nel file del tuo plugin)
// Registra un endpoint REST API fittizio..
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(),
'L\'utente è loggato: ' . ( is_user_logged_in() ? 'Sì' : 'NO' ),
'L\'utente può pubblicare post: ' . ( current_user_can( 'publish_posts' ) ? 'Sì' : 'NO' )
];
},
] );
}
add_action( 'wp_enqueue_scripts', 'my_enqueue_scripts' );
function my_enqueue_scripts() {
// Includi lo script che effettua la chiamata AJAX a /wp-json/my-plugin/v1/foo.
wp_enqueue_script( 'my-script', '/path/to/my-script.js', [ 'jquery' ] );
// Registra variabili personalizzate per lo script AJAX.
wp_localize_script( 'my-script', 'myScriptVars', [
'root' => esc_url_raw( rest_url() ),
'nonce' => wp_create_nonce( 'wp_rest' ),
] );
}
Note:
Ricorda che il primo parametro per
wp_enqueue_script()
—my-script
nell'esempio sopra — è esattamente lo stesso del primo parametro perwp_localize_script()
. E quel parametro è l'handle dello script, che è uno slug univoco come identificatore per lo script che stai includendo o localizzando.Se quei parametri non corrispondono, allora lo script non verrebbe localizzato, e l'oggetto JS —
myScriptVars
nell'esempio sopra — sarebbeundefined
il che potrebbe risultare in un errore come quello menzionato nella domanda ("wpApiSettings non esiste"). :)
Parte JS: (in my-script.js
o qualsiasi sia il nome del file...)
Qui, aggiungiamo _wpnonce
al corpo della richiesta.
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 );
},
});
Note:
Il codice JS sopra e gli altri in questa risposta utilizzano ajax()
di jQuery.

Ah, certo! Mi sento così stupido, ovviamente la localizzazione deve essere fatta prima degli header. Doh. Ottima risposta.

Nota per i più lenti tra noi (come me) il primo parametro di wp_localize_script
è l'handle con cui hai registrato il tuo script per metterlo in coda.
