Adăugarea validării și gestionarea erorilor la salvarea câmpurilor personalizate?

9 dec. 2010, 23:57:18
Vizualizări: 37.2K
Voturi: 31

Am o funcție care definește un câmp personalizat pentru un tip de postare. Să zicem că acest câmp este "subhead".

Când postarea este salvată, vreau să fac validarea valorii introduse și să afișez un mesaj de eroare pe ecranul de editare a postării dacă este necesar. Ceva de genul:

// Gestionează actualizarea postării
function wpse_update_post_custom_values($post_id, $post) {

    // Facem verificări...
    if($_POST['subhead'] != 'valoarea asteptata') {

        // Adăugăm o eroare aici
        $errors->add('oops', 'A apărut o eroare.');

    }

    return $errors;

} 
add_action('save_post','wpse_update_post_custom_values',1,2);

Încerc să folosesc action-ul save_post, dar nu reușesc să găsesc o modalitate de a gestiona erorile. Nu pare să existe un obiect de eroare transmis în funcție, iar dacă îmi creez propriul obiect WP_Error și îl returnez, acesta nu este recunoscut de mecanismul care afișează erorile pe pagina de editare a postării.

În prezent am un mesaj de eroare în meta box-ul personalizat, dar aceasta nu este soluția ideală - aș prefera să am o eroare mare, roșie, afișată în partea de sus, așa cum afișează WordPress în mod normal.

Aveți idei?

ACTUALIZARE:

Pe baza răspunsului lui @Denis, am încercat câteva abordări diferite. Stocarea erorilor ca variabilă globală nu a funcționat, deoarece WordPress face o redirecționare în timpul procesului save_post, care elimină variabila globală înainte de a putea fi afișată.

Am ajuns să le stochez într-un câmp meta. Problema cu această abordare este că trebuie să le ștergi, altfel nu vor dispărea când navighezi pe altă pagină, așa că a trebuit să adaug o altă funcție atașată la admin_footer care doar șterge erorile.

Nu m-aș fi așteptat ca gestionarea erorilor pentru ceva atât de comun (actualizarea postărilor) să fie atât de greoaie. Îmi scapă ceva evident sau aceasta este cea mai bună abordare?

// Gestionează actualizarea postării
function wpse_5102_update_post_custom_values($post_id, $post) {

    // Pentru a păstra erorile
    $errors = false;

    // Facem validarea...
    if($_POST['subhead'] != 'valoarea asteptata') {

        // Adăugăm o eroare aici
        $errors .= 'Ups... a apărut o eroare.';

    }

    update_option('my_admin_errors', $errors);

    return;

} 
add_action('save_post','wpse_5102_update_post_custom_values',1,2);


// Afișează orice eroare
function wpse_5102_admin_notice_handler() {

    $errors = get_option('my_admin_errors');

    if($errors) {

        echo '<div class="error"><p>' . $errors . '</p></div>';

    }   

}
add_action( 'admin_notices', 'wpse_5102_admin_notice_handler' );


// Șterge orice eroare
function wpse_5102__clear_errors() {

    update_option('my_admin_errors', false);

}
add_action( 'admin_footer', 'wpse_5102_clear_errors' );
6
Comentarii

Bună întrebare. Cred că ai putea să scapi de hook-ul admin_footer dacă cureți erorile la sfârșitul funcției de gestionare a notificărilor. Simplifică lucrurile puțin.

Geert Geert
3 mai 2011 09:54:21

Cum te ocupi de repopularea câmpurilor formularului (cu posibilele date invalide)?

Geert Geert
3 mai 2011 09:58:27

Am o întrebare de bază. În ce fișier PHP WordPress se află acest cod?

User User
27 mai 2011 02:25:20

@Karen Aceasta ar fi într-un fișier de plugin personalizat sau în functions.php.

MathSmath MathSmath
27 mai 2011 07:38:37

S-ar putea să-mi scape ceva evident, dar nu ar fi puțin mai eficient să rulezi update_option('my_admin_errors', false); imediat după instrucțiunea if de la sfârșitul funcției wpse_5102_admin_notice_handler()?

Andrew Odri Andrew Odri
1 dec. 2012 00:55:24

@AndrewOdri Da, presupun că și așa ar funcționa. Atâta timp cât nu ai nevoie de informațiile despre eroare mai târziu (pentru a evidenția elemente în formular sau altele). Bună observație!

MathSmath MathSmath
5 dec. 2012 18:19:40
Arată celelalte 1 comentarii
Toate răspunsurile la întrebare 7
2

Stochează erorile în clasa ta sau ca o variabilă globală, eventual într-un transient sau meta, și afișează-le în notificările din admin la cererile POST. WordPress nu are un sistem încorporat de gestionare a mesajelor flash.

10 dec. 2010 00:02:19
Comentarii

Mulțumesc că m-ai îndrumat în această direcție! Am ajuns să folosesc un meta pentru a stoca erorile, pentru că am avut probleme când am încercat să le fac ca variabilă globală sau proprietate. Actualizez acum răspunsul meu pentru a explica cum fac asta... te rog să-mi spui dacă acesta este genul de lucru la care te refereai sau dacă există o metodă mai bună pe care nu o înțeleg.

MathSmath MathSmath
10 dec. 2010 02:15:03

Da, ceva de genul ăsta. Poate ar fi mai bine să le stochezi într-o variabilă de sesiune, la a doua gândire, totuși. Asta pentru a permite mai multor autori să editeze articole în același timp. :-) De asemenea, cred că nu este posibil să stochezi false într-o opțiune. Mai bine stochezi un șir gol.

Denis de Bernardy Denis de Bernardy
10 dec. 2010 11:35:09
4

Sugerez utilizarea sesiunilor, deoarece acest lucru nu va crea efecte ciudate atunci când doi utilizatori editează simultan. Iată ce fac eu:

WordPress nu inițializează sesiuni. Deci trebuie să începeți o sesiune în plugin-ul dvs., functions.php sau chiar wp-config.php:

if (!session_id())
  session_start();

Când salvați postarea, adăugați erori și notificări în sesiune:

function my_save_post($post_id, $post) {
   if($something_went_wrong) {
     //Adăugați notificare de eroare dacă ceva nu a funcționat
     $_SESSION['my_admin_notices'] .= '<div class="error"><p>Acest lucru sau acela nu a funcționat</p></div>';
     return false; //poate opri procesarea aici
   }
   if($somthing_to_notice) {  //de exemplu, salvarea reușită
     //Adăugați notificare dacă ceva nu a funcționat
     $_SESSION['my_admin_notices'] .= '<div class="updated"><p>Postarea a fost actualizată</p></div>';
   }

   return true;
} 
add_action('save_post','my_save_post');

Afișați notificările și erorile, apoi curățați mesajele din sesiune:

function my_admin_notices(){
  if(!empty($_SESSION['my_admin_notices'])) print  $_SESSION['my_admin_notices'];
  unset ($_SESSION['my_admin_notices']);
}
add_action( 'admin_notices', 'my_admin_notices' );
14 iun. 2011 13:36:04
Comentarii

reparare pentru versiunea de sesiune: la prima utilizare a variabilei de sesiune nu folosi .= ci doar =. Dacă activezi depanarea, poți verifica de ce...

User User
13 iul. 2012 16:12:01

Am făcut și eu asta, dar dacă lansezi un plugin pentru o audiență largă în felul acesta, oamenii vor ajunge să te urască pentru asta. WordPress nu inițializează sesiuni deoarece este conceput să fie fără stare și să nu aibă nevoie de ele, iar unele configurații ciudate de server le pot strica. Folosește API-ul pentru transiente - http://codex.wordpress.org/Transients_API în loc de sesiuni și vei menține compatibilitatea. Am considerat că merită să menționez un motiv pentru a nu face asta aici.

pospi pospi
12 sept. 2012 04:37:55

@pospi aceasta pare să aibă probleme similare cu utilizarea inițială a funcțiilor get_option și update_option. Deci, presupun că soluția ar fi să adaugi ID-ul utilizatorului curent la cheie?

Gazillion Gazillion
24 oct. 2013 19:55:28

Da, asta ar funcționa perfect! Atâta timp cât adaugi ceva pentru a identifica utilizatorul în mod unic, vei evita amestecarea mesajelor între utilizatorii autentificați (:

pospi pospi
28 oct. 2013 02:23:34
2

Bazat pe sugestia lui pospi de a folosi transients, am venit cu următoarea soluție. Singura problemă este că nu există un hook pentru a plasa mesajul sub h2 unde merg celelalte mesaje, așa că a trebuit să folosesc un hack cu jQuery pentru a-l plasa acolo.

Mai întâi, salvează mesajul de eroare în timpul handler-ului tău save_post (sau similar). I-am dat o durată scurtă de viață de 60 de secunde, astfel încât să fie acolo doar suficient timp pentru a se întâmpla redirect-ul.

if($has_error)
{
  set_transient( "acme_plugin_error_msg_$post_id", $error_msg, 60 );
}

Apoi, doar preia acel mesaj de eroare la următoarea încărcare de pagină și afișează-l. De asemenea, îl șterg pentru a nu fi afișat de două ori.

add_action('admin_notices', 'acme_plugin_show_messages');

function acme_plugin_show_messages()
{
  global $post;
  if ( false !== ( $msg = get_transient( "acme_plugin_error_msg_{$post->ID}" ) ) && $msg) {
    delete_transient( "acme_plugin_error_msg_{$post->ID}" );
    echo "<div id=\"acme-plugin-message\" class=\"error below-h2\"><p>$msg</p></div>";
  }
}

Deoarece admin_notices se declanșează înainte ca conținutul principal al paginii să fie generat, notificarea nu apare acolo unde merg celelalte mesaje de editare a postării, așa că a trebuit să folosesc acest jQuery pentru a o muta acolo:

jQuery('h2').after(jQuery('#acme-plugin-message'));

Deoarece ID-ul postării face parte din numele transient, acest lucru ar trebui să funcționeze în majoritatea mediilor cu mai mulți utilizatori, cu excepția cazului în care mai mulți utilizatori editează simultan aceeași postare.

16 sept. 2012 00:55:49
Comentarii

Poți să elaborezi despre "Deoarece ID-ul postării face parte din numele transient"? Am creat o clasă pentru a gestiona mesajele de eroare folosind această tehnică, dar am nevoie ca constructorul meu să transmită un user_ID. API-ul transient utilizează user_id-ul la hashing-ul cheii? (întreb pentru că codex-ul nu pare să menționeze acest lucru)

Gazillion Gazillion
24 oct. 2013 20:37:01

Nu, dar îl poți adăuga manual. În codul pe care l-am postat mai sus, numele transient-ului este acme_plugin_error_msg_POSTID. Ai putea pur și simplu să adaugi ID-ul utilizatorului acolo, precum acme_plugin_error_msg_POSTID_USERID.

Josh Coady Josh Coady
30 ian. 2015 06:34:21
1

Când acțiunea save_post rulează, postarea a fost deja salvată în baza de date.

Analizând codul WordPress, mai exact funcția update_post() din fișierul wp-includes/post.php, nu există nicio modalitate integrată de a intercepta o cerere înainte ca aceasta să fie salvată în baza de date.

Totuși, putem folosi hook-ul pre_post_update și funcțiile header() și get_post_edit_link() pentru a preveni salvarea postării.

<?php

/**
*   Efectuează validarea înainte de salvarea/inserarea unui tip de postare personalizat
*/
function custom_post_site_save($post_id, $post_data) {
    // Dacă aceasta este doar o revizie, nu face nimic.
    if (wp_is_post_revision($post_id))
        return;

    if ($post_data['post_type'] == 'my_custom_post_type') {
        // Respinge titlurile de postare cu mai puțin de 5 caractere
        if (strlen($post_data['post_title'] < 5)) {
            header('Location: '.get_edit_post_link($post_id, 'redirect'));
            exit;
        }
    }
}
add_action( 'pre_post_update', 'custom_post_site_save', 10, 2);

Dacă doriți să notificați utilizatorul despre ce a mers greșit, consultați acest gist: https://gist.github.com/Luc45/09f2f9d0c0e574c0285051b288a0f935

30 iul. 2018 00:54:58
Comentarii

Mulțumesc pentru asta, gestionează validarea perfect, indiferent dacă publici pentru prima dată sau actualizezi postarea. Tocmai mi-ai economisit mult timp și efort.

Zade Zade
15 dec. 2018 10:31:52
2

De ce nu validezi câmpul cu ajutorul unui Javascript? Cred că aceasta ar fi cea mai bună abordare pentru această situație.

10 dec. 2010 10:10:10
Comentarii

Mulțumesc pentru sugestie! Ce am omis din întrebare (pentru simplitate) este că încerc să gestionez erorile la încărcarea fișierelor, deci trebuie să fie pe partea de server. Totuși, mulțumesc pentru sugestie!

MathSmath MathSmath
10 dec. 2010 18:33:45

validarea în javascript nu preîntâmpină unele atacuri, validarea pe partea de server este singura sigură. În plus, wordpress oferă unele instrumente bune pentru validarea datelor utilizatorilor. Dar ai dreptate dacă doar verifică niște valori înainte de a trimite datele pe server, poți economisi timp pe un server slab ^^

nderambure nderambure
15 mar. 2011 01:50:40
2

Încercând să folosesc scriptul de mai sus, am întâmpinat o problemă ciudată. Două mesaje sunt afișate pe ecranul de editare, după actualizarea articolului. Unul arată starea conținutului de la salvarea anterioară, iar celălalt de la cea curentă. De exemplu, dacă salvez corect articolul și apoi fac o eroare, primul mesaj este "eroare" și al doilea este "ok" - deși sunt generate în același timp. Dacă modific scriptul și adaug doar un mesaj (de ex. "eroare"), inițiez o actualizare cu "eroare" și apoi alta cu "ok", mesajul "eroare" rămâne (este afișat pentru a doua oară). Trebuie să salvez din nou cu "ok" pentru a scăpa de el. Nu înțeleg ce este greșit, am testat pe trei servere locale diferite și problema apare la fel pe fiecare. Dacă cineva are vreo idee sau sugestie, vă rog să mă ajutați!

8 sept. 2011 19:57:15
Comentarii

Am făcut mai multe teste cu versiunea mai simplă, a doua a scriptului pe care am menționat-o mai sus și se pare că dacă mesajul de "eroare" este într-adevăr adăugat la array-ul de sesiune, acesta este afișat pe ecranul de editare. Dacă nu există niciun mesaj (totul este "ok") și mesajul anterior a fost o eroare, acesta apare pe ecran. Ceea ce este ciudat este că este generat în momentul salvării (nu este cache-uit) - am verificat acest lucru folosind date() în corpul mesajului de eroare. Sunt total confuz acum.

jlub jlub
8 sept. 2011 20:55:32

Ok, în cazul în care altcineva își smulge părul din cap - s-a dovedit că sistemul de revizii Wordpress era problema (probabil un fel de bug?). L-am dezactivat și acum totul funcționează perfect.

User User
12 sept. 2011 12:41:27
1

Am scris un plugin care adaugă gestionarea erorilor în timp real pe ecranele de editare a articolelor și previne publicarea postărilor până când câmpurile obligatorii sunt completate:

https://github.com/interconnectit/required-fields

Acesta vă permite să setați orice câmpuri ale articolului ca obligatorii, dar puteți folosi API-ul oferit pentru a face și câmpuri personalizate obligatorii, cu mesaje de eroare personalizabile și funcție de validare. Implicit, verifică dacă câmpul este gol sau nu.

19 nov. 2012 12:00:22
Comentarii

Nu ezitați să adăugați orice probleme pe github dacă întâlniți astfel de situații. Trebuie să documentez și API-ul mai bine, deoarece există câteva filtre suplimentare pe care le puteți utiliza.

sanchothefat sanchothefat
7 dec. 2012 16:13:53