Cum să preluați date POST dintr-un apel AJAX
Am următorul script JS
:
jQuery('#form-recherche').submit(ajaxSubmit);
function ajaxSubmit(){
var newFormRecherche = jQuery(this).serialize();
jQuery.ajax({
type:"post",
data: {
action: "mon_action",
newFormRecherche: newFormRecherche,
},
url: ajaxurl,
success: function(response){
console.log(response);
}
});
return false;
}
Pe partea de PHP
:
add_action( 'wp_ajax_mon_action', 'mon_action' );
add_action( 'wp_ajax_nopriv_mon_action', 'mon_action' );
function mon_action() {
if (isset($_POST["newFormRecherche"])) {
$field1= $_POST["field1"];
$field2= $_POST["field2"];
}
}
După cum ați ghicit, pot accesa $_POST["newFormRecherche"]
dar nu pot prelua $_POST["field1"]
și nici $_POST["field2"]
.
jQuery serialize()
funcționează corect: am testat variabila newFormRecherche
cu un alert și este afișată în forma corectă: $field1=whatever&$field2=anything
.
În mod normal, nu ar trebui să analizez rezultatele pentru a accesa variabilele $_POST[], conform cu ce am citit aici, dar evident nu funcționează. De unde vine această problemă? Ar trebui să folosesc altceva decât data
pentru a transmite argumentele mele?
EDIT: $_POST["newFormRecherche"]
există pe partea PHP și conține șirul așteptat $field1=whatever&$field2=anything
.
EDIT #2: Iată o actualizare, conform observației interesante de la @czerspalace și postării foarte detaliate de la @bosco. Încerc aici să rezum ce au spus ei și să ofer câteva soluții.
Problema aici era o serializare dublă, una făcută "manual", alta făcută de jQuery în timpul apelului AJAX. Faptul că variabilele $_POST[]
nu pot fi preluate corect pe partea de server vine de la data
, care trebuie să se potrivească cu formalismul WordPress, adică: o action
(care este o funcție PHP) și datele trimise (de obicei, dintr-un formular).
Soluția propusă de @Bosco - Folosiți metoda jQuery
serializeArray()
. În acest caz, datele trimise sunt compuse din 2 obiecte. Pentru a prelua corect câmpurile pe partea de server, trebuie să gestionez un array asociativ astfel:$_POST['newFormRecherche'][0]['name']
și$_POST['newFormRecherche'][0]['value']
. Același lucru pentru celelalte câmpuri (înlocuind [0] cu alte numere). Pentru a rezolva acest lucru, @Bosco propune mai jos funcțiaformFieldsToObject
care este apelată pe date, când se efectuează apelul AJAX.Soluția propusă de @czerspalace - Folosiți metoda jQuery
serialize()
și faceți o deserializare manuală pe partea de server, folosindparse_str( $_POST[ 'newFormRecherche' ], $newFormRecherche );
pentru a putea prelua câmpurile dorite: $newFormRecherche['field1'],... și așa mai departe.
În ambele cazuri, datele pe partea de server trebuie să fie corect sanitizate, așa cum trebuie întotdeauna datele trimise de un utilizator prin formulare. Aceasta implică: verificarea tipurilor de câmpuri, verificarea (și chiar trunchierea) lungimii câmpurilor..., cu alte cuvinte: nu aveți niciodată încredere în utilizator.
EDIT #3: În cazul în care folosiți FormData
, asigurați-vă că adăugați această linie în apelul AJAX: processData: false,
. Cu toate acestea, nu am implementat o soluție completă cu această tehnică.
Problemă
"Serializarea" este actul de a transforma un obiect de date într-o reprezentare sub formă de șir de caractere. jQuery serializează automat proprietatea data
înainte de a trimite o cerere AJAX. Serverul apoi deserializează șirul de interogare GET
din URL și corpul cererii pentru cererile POST
înainte de a popula variabilele de cerere PHP.
Codul dvs. a funcționat conform așteptărilor atunci când data
consta doar din datele serializate ale formularului (adică data: newFormRecherche,
), deoarece datele erau deja într-un format de șir și, prin urmare, nu puteau fi serializate în continuare. Pasul de deserializare al serverului a analizat corect datele formularului în variabilele de cerere.
Cu toate acestea, când argumentul data
este un obiect, jQuery trebuie să îl serializeze pentru a-l trimite către server. Ca proprietate a acelui obiect, datele dvs. pre-serializate ale formularului sunt tratate ca orice alt șir - mai precis, sunt escaponate într-un mod care să împiedice "confundarea" lor cu un obiect serializat. Deci, când serverul deserializează data
, newFormRecherche
este deserializat în valoarea pe care jQuery a primit-o inițial - adică un șir - și, prin urmare, necesită al doilea pas de deserializare la care @czerspalace a făcut referire în comentarii pentru a produce un tablou asociativ de date ale formularului.
Soluții
- jQuery
Pentru a preveni dubla serializare a datelor formularului, obțineți-le ca un tablou de perechi cheie/valoare în loc de un șir serializat, invocând metoda jQuery .serializeArray()
pe elementul formular în loc de .serialize()
.
Deși jQuery este capabil să serializeze corect acest format de tablou cheie/valoare al data
, se pare că întâmpină probleme atunci când un astfel de tablou este imbricat ca proprietate a unui obiect data
(trimitând în schimb șirul '[object Object]'
în locul fiecărei perechi cheie/valoare), precum și atunci când încearcă să imbriche un astfel de tablou cheie/valoare în altul. Prin urmare, cred că cel mai bun mod de a trimite datele formularului ca parte a unor date multidimensionale este să convertiți tabloul cheie/valoare într-un obiect.
Toate acestea pot fi făcute după cum urmează:
function ajaxSubmit() {
var newFormRecherche = jQuery( this ).serializeArray();
jQuery.ajax({
type:"POST",
data: {
action: "mon_action",
newFormRecherche: formFieldsToObject( newFormRecherche )
},
url: ajaxurl,
success: function( response ){
console.log( response );
}
});
return false;
}
function formFieldsToObject( fields ) {
var product = {};
for( var i = 0; i < fields.length; i++ ) {
var field = fields[ i ];
if( ! product.hasOwnProperty( field.name ) ) {
product[ field.name ] = field.value;
}
else {
if( ! product[ field.name ] instanceof Array )
product[ field.name ] = [ product[ field.name ] ];
product[ field.name ].push( field.value );
}
}
return product;
}
- HTML5 FormData
Alternativ, dacă trebuie să suportați doar browsere moderne sau nu vă deranjează să încărcați un polifil pentru a suporta cele mai vechi, puteți folosi obiectul FormData
pentru a trimite datele formularului ca un obiect de date propriu-zis:
function ajaxSubmit() {
var newFormRecherche = new FormData( this );
jQuery.ajax({
type:"POST",
data: {
action: "mon_action",
newFormRecherche: newFormRecherche
},
url: ajaxurl,
success: function( response ){
console.log( response );
}
});
return false;
}
- Deserializare Dublă pe Server
Așa cum sugerează @czerspalace în comentarii, contabilizarea dublei serializări prin simpla deserializare manuală a datelor formularului pe server este, de asemenea, o soluție complet validă:
add_action( 'wp_ajax_mon_action', 'mon_action' );
add_action( 'wp_ajax_nopriv_mon_action', 'mon_action' );
function mon_action() {
if( isset( $_POST[ 'newFormRecherche' ] ) ) {
parse_str( $_POST[ 'newFormRecherche' ], $newFormRecherche );
die( json_encode( $newFormRecherche ) );
}
}
Sunt înclinat să cred că celelalte abordări sunt mai "profesionale" prin faptul că toate datele trimise către server sunt ambalate într-un format consistent și așteptat - nu este necesară nicio "decodare" suplimentară din partea serverului, îmbunătățind modularitatea codului.
Dar modularitatea codului și "profesionalismul" subiectiv nu sunt întotdeauna cei mai importanți factori - uneori soluția cea mai simplă este cea mai potrivită.
Nu uitați să validați și să curățați datele cererii pe server înainte de a le folosi pentru a reduce vulnerabilitățile de securitate.

mulțumesc mult pentru această explicație clară și simplă, acum înțeleg unde era problema! Totuși, ai scris că "jQuery va serializa corect aceste perechi cheie/valoare în variabile de cerere", dar încă nu le pot accesa și nu le mai pot parsa deoarece nu mai sunt șiruri de caractere. Care este cea mai elegantă soluție pentru a obține valorile lor?

@Fafanellu se pare că am dat jQuery mai mult credit decât merită - nu-i place când folosești acea matrice cheie/valoare în structuri de date imbricate și de fapt nu reușește să le serializeze corect în astfel de situații. Am adăugat o mică funcție helper care ar trebui să rezolve problema - datele ar trebui accesibile în PHP printr-un array $_POST
structurat corect, adică $_POST["newFormRecherche"]["field1"]
. Poți folosi echo json_encode( $_POST );
în handler-ul tău AJAX, sau var_dump( $_POST );
pentru a vedea structura exactă a datelor formularului.

mulțumesc pentru acest subiect foarte interesant! Am actualizat postarea inițială pentru a ține cont de comentariile constructive făcute aici

Apropo, care este scopul lui die( json_encode( $newFormRecherche ) ) ?

Acesta este doar un placeholder temporar pentru orice ar fi codul tău =). die()
încheie imediat execuția unui script PHP, opțional afișând (echo()
) un argument, dacă este furnizat - așa că va încheia imediat cererea AJAX, răspunzând cu datele formularului pe care serverul le-a primit ca un obiect JSON (deși probabil cu header-ul Content-Type
greșit, dar jQuery nu ar trebui să aibă probleme). În combinație cu callback-ul success
pe care l-ai specificat în JavaScript-ul tău și care afișează (console.log()
) răspunsul serverului, ar trebui să obții o ieșire clară și ușor de navigat a datelor formularului în consola JavaScript a browserului tău.

ok, mulțumesc! de fapt, nu am scris întregul cod PHP, dar era un die() gol la final. Dacă am înțeles corect, scopul este de a încheia cererea AJAX cât mai repede posibil pentru a trimite datele înapoi.

Practic! Această pagină Codex o menționează pe scurt. Ideea generală este că după ce ai gestionat cererea AJAX și ai trimis un răspuns cu echo()
, nu prea mai ai motive să lași WordPress să continue execuția. Dacă WordPress este lăsat să ruleze în mod normal, există riscul ca codul executat după handler-ul tău AJAX să mai adauge ceva în răspuns cu echo()
, ceea ce ar putea strica funcționarea JavaScript-ului când callback-ul tău success
încearcă să proceseze răspunsul.

wp_die()
este considerată o alternativă mai bună decât die()
. Este rar să folosești oricare dintre ele în afara handler-elor AJAX, cu excepția depanărilor temporare - există aproape întotdeauna o metodă mai bună de a gestiona o problemă sau de a raporta o eroare decât să oprești pur și simplu execuția scriptului!
