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
_wpnonceall'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
_wpnonceal 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-Nonceagli 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-scriptnell'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 —
myScriptVarsnell'esempio sopra — sarebbeundefinedil 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.
Matthew Brown aka Lord Matt
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.
Matthew Brown aka Lord Matt