Aggiungere la convalida e la gestione degli errori durante il salvataggio dei campi personalizzati?


27

Ho una funzione che definisce un campo personalizzato su un tipo di post. Supponiamo che il campo sia "sottotitolo".

Quando il post viene salvato, voglio fare un po 'di validazione sull'input e, se necessario, visualizzare un messaggio di errore nella schermata di modifica del post. Qualcosa di simile a:

// Handle post updating
function wpse_update_post_custom_values($post_id, $post) {

    // Do some checking...
    if($_POST['subhead'] != 'value i expect') {

        // Add an error here
        $errors->add('oops', 'There was an error.');

    }

    return $errors;

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

Sto cercando di agganciarlo all'azione save_post, ma non riesco a capire come gestire gli errori. Non sembra esserci un oggetto errore passato nella funzione, e se creo il mio oggetto WP_Error e lo restituisco, non viene rispettato da qualunque meccanismo spenga errori nella pagina di modifica post.

Al momento ho un messaggio di errore on-page all'interno della mia meta box personalizzata, ma questo è meno che ideale - Preferirei avere un grosso errore rosso al top come normalmente visualizza WP.

Qualche idea?

AGGIORNARE:

Sulla base della risposta di @Denis, ho provato alcune cose diverse. La memorizzazione degli errori come globale non ha funzionato, perché Wordpress esegue un reindirizzamento durante il processo save_post, che uccide il globale prima di poterlo visualizzare.

Ho finito per memorizzarli in un meta campo. Il problema è che devi eliminarli, altrimenti non andranno via quando navighi in un'altra pagina, quindi ho dovuto aggiungere un'altra funzione allegata a admin_footer che cancella gli errori.

Non mi sarei aspettato che la gestione degli errori per qualcosa di così comune (aggiornamento dei post) sarebbe stata così goffa. Mi sto perdendo qualcosa di ovvio o è questo l'approccio migliore?

// Handle post updating
function wpse_5102_update_post_custom_values($post_id, $post) {

    // To keep the errors in
    $errors = false;

    // Do some validation...
    if($_POST['subhead'] != 'value i expect') {

        // Add an error here
        $errors .= 'whoops...there was an error.';

    }

    update_option('my_admin_errors', $errors);

    return;

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


// Display any errors
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' );


// Clear any errors
function wpse_5102__clear_errors() {

    update_option('my_admin_errors', false);

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

Buona domanda. Penso che potresti sbarazzarti del admin_footergancio se cancelli gli errori alla fine della tua funzione di gestione degli avvisi. Semplifica un po 'le cose.
Geert,

Come gestite il ripopolamento dei campi del modulo (con i possibili dati non validi)?
Geert,

Ho una domanda di base. In quale file php di Wordpress si trova questo?

@Karen Questo sarebbe in un file plugin personalizzato, o nel tuo Functions.php.
MathSmath,

Potrei mancare qualcosa di ovvio, ma sarebbe leggermente più efficiente eseguire update_option('my_admin_errors', false);immediatamente dopo l'istruzione if alla fine di wpse_5102_admin_notice_handler()?
Andrew Odri,

Risposte:


6

Archivia gli errori nella tua classe o come globali, possibilmente in un transitorio o meta, e visualizzali negli avvisi di amministrazione sulle richieste POST. WP non presenta alcun gestore di messaggi flash.


Grazie per avermi indicato in questa direzione! Ho finito per usare un meta per archiviare errori, perché avevo problemi nel tentativo di farlo come globale o come proprietà. Sto aggiornando la mia risposta proprio ora per spiegare come lo sto facendo ... per favore fatemi sapere se questo è il tipo di cosa che stavate suggerendo, o se c'è un modo migliore che non sto ottenendo.
MathSmath il

Questo genere di cose, sì. Forse è possibile memorizzarlo in una variabile di sessione, ripensandoci, però. Questo, al fine di consentire a più autori di modificare i post contemporaneamente. :-) Inoltre, credo che non sia possibile archiviare false in un'opzione. Conservare invece una stringa vuota.
Denis de Bernardy,

6

Suggerisco di utilizzare le sessioni in quanto ciò non creerà strani effetti quando due utenti modificano contemporaneamente. Quindi questo è quello che faccio:

Le sessioni non vengono avviate da wordpress. Quindi devi avviare una sessione nel tuo plugin, Functions.php o anche wp-config.php:

if (!session_id())
  session_start();

Quando si salva il post, aggiungere errori e avvisi alla sessione:

function my_save_post($post_id, $post) {
   if($something_went_wrong) {
     //Append error notice if something went wrong
     $_SESSION['my_admin_notices'] .= '<div class="error"><p>This or that went wrong</p></div>';
     return false; //might stop processing here
   }
   if($somthing_to_notice) {  //i.e. successful saving
     //Append notice if something went wrong
     $_SESSION['my_admin_notices'] .= '<div class="updated"><p>Post updated</p></div>';
   }

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

Stampa avvisi ed errori e quindi pulisci i messaggi nella sessione:

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' );

correzione per la versione della sessione: al primo utilizzo della variabile di sessione non utilizzare. = only = se si attiva il debug, è possibile verificare perché ...

3
Lo sto facendo anche io, ma se rilasci un plugin per un vasto pubblico come quello, la gente finirà per odiarti per questo. Wordpress non crea istanze delle sessioni perché è progettato per essere apolide e non necessario, e alcune strane configurazioni del server lo interromperanno. Usa l'API dei transitori - codex.wordpress.org/Transients_API invece delle sessioni e manterrai la compatibilità. Ho solo pensato che valesse la pena segnalare un motivo per non farlo qui.
pospi,

@pospi sembra che abbia problemi simili all'uso originale delle funzioni get_option e update_option. Quindi immagino che la soluzione sarebbe quella di aggiungere l'ID dell'utente corrente alla chiave?
Gazillion,

Sì, funzionerebbe totalmente! Finché aggiungi qualcosa per identificare in modo univoco l'utente, eviterai che i messaggi vengano confusi tra gli utenti che hanno effettuato l'accesso (:
pospi,

5

Sulla base del suggerimento di pospi di usare i transienti , ho pensato a quanto segue. L'unico problema è che non esiste un hook per mettere il messaggio sotto il punto in cui vanno gli altri messaggi, quindi ho dovuto fare un hack jQuery per farlo lì.h2

Innanzitutto, salva il messaggio di errore durante il save_postgestore (o simile). Gli dò una breve durata di 60 secondi, quindi è lì abbastanza a lungo da consentire il reindirizzamento.

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

Quindi, recupera quel messaggio di errore nella pagina successiva e visualizzalo. Inoltre lo elimino in modo che non venga visualizzato due volte.

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>";
  }
}

Poiché viene admin_noticesgenerato prima che venga generato il contenuto della pagina principale, l'avviso non è dove vanno gli altri messaggi di modifica post, quindi ho dovuto usare questo jQuery per spostarlo lì:

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

Poiché l'ID post fa parte del nome temporaneo, dovrebbe funzionare nella maggior parte degli ambienti multiutente, tranne quando più utenti modificano contemporaneamente lo stesso post.


Potresti approfondire "Dato che l'ID post fa parte del nome transitorio"? Ho creato una classe per gestire i messaggi di errore usando questa tecnica, ma ho bisogno che il mio costruttore passi un ID_utente. L'API transitoria utilizza user_id quando esegue l'hashing della chiave? (Chiedo perché il codice non sembra menzionarlo)
Gazillion

No, ma è possibile aggiungerlo manualmente. Nel codice che ho pubblicato sopra, il nome del transitorio è acme_plugin_error_msg_POSTID. Potresti semplicemente aggiungere l'ID utente a quel tipo acme_plugin_error_msg_POSTID_USERID.
Joshua Coady,

2

Quando save_postviene eseguito, ha già salvato il post nel database.

Guardando nel codice di base di WordPress, più precisamente al wp-includes/post.php's update_post()funzioni, non v'è alcun built-in modo di intercettare una richiesta prima che venga salvato nel database.

Tuttavia, possiamo agganciare pre_post_updatee utilizzare header()e get_post_edit_link()per impedire il salvataggio del post.

<?php

/**
*   Performs validation before saving/inserting custom post type
*/
function custom_post_site_save($post_id, $post_data) {
    // If this is just a revision, don't do anything.
    if (wp_is_post_revision($post_id))
        return;

    if ($post_data['post_type'] == 'my_custom_post_type') {
        // Deny post titles with less than 5 characters
        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);

Se si avvisa l'utente di cosa è andato storto, controllare questa sintesi: https://gist.github.com/Luc45/09f2f9d0c0e574c0285051b288a0f935


Grazie per questo, gestisce perfettamente la convalida, sia per la prima volta che per la pubblicazione o l'aggiornamento del post. Mi hai appena risparmiato un sacco di tempo e fatica.
Zade,

1

Perché non convalidi il tuo campo con l'aiuto di Javascript? Penso che questo sarebbe l'approccio migliore per questo.


Grazie per il suggerimento! Ciò che ho lasciato fuori questione (per semplicità) è che sto cercando di gestire gli errori di caricamento dei file, quindi deve essere lato server. Grazie per il suggerimento però!
MathSmath,

la convalida JavaScript non impedisce alcuni attacchi, la convalida lato server è l'unica sicura. Inoltre, wordpress offre alcuni buoni strumenti per convalidare i dati dell'utente. Ma hai ragione se controlla solo alcuni valori prima di inviare i dati al server, puoi risparmiare un po 'di tempo nel server basso ^^
nderambure

1

Cercando di usare la sceneggiatura sopra, ho riscontrato uno strano problema. Due messaggi vengono visualizzati nella schermata di modifica, dopo l'aggiornamento post. Uno mostra lo stato del contenuto del salvataggio precedente e un altro dalla corrente. Ad esempio, se salvo il messaggio correttamente e poi faccio un errore, il primo è "errore" e il secondo è "ok", anche se vengono generati contemporaneamente. Se cambio lo script e aggiungo solo un messaggio (ad es. "Errore"), avvia un aggiornamento con "errore" e successivamente un altro con "ok", il messaggio "errore" rimane (viene visualizzato per la seconda volta). Devo salvare con "ok" ancora una volta per liberarmene. Davvero non so cosa c'è che non va, l'ho testato su tre diversi server locali e c'è lo stesso problema su ciascuno di essi.


Ho fatto altri test della seconda versione più semplice dello script che ho menzionato sopra e sembra che se il messaggio di "errore" viene realmente aggiunto all'array di sessioni, viene mostrato nella schermata di modifica. Se non c'è nessun messaggio (tutto è "ok") e il messaggio precedente era un errore, appare sullo schermo. Ciò che è strano, viene generato al momento del salvataggio (non memorizzato nella cache) - L'ho verificato usando date () nel corpo del messaggio di errore. Sono totalmente confuso ora.
jlub,

Ok, nel caso in cui qualcun altro si stia togliendo i capelli dalla testa - si è scoperto che il sistema di revisioni di Wordpress era il problema (probabilmente una specie di bug?). L'ho disabilitato e ora va tutto bene.

0

Ho scritto un plug-in che aggiunge una gestione degli errori flash per le schermate di modifica dei post e impedisce la pubblicazione dei post fino alla compilazione dei campi obbligatori:

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

Ti consente di rendere obbligatori tutti i campi di posta ma puoi utilizzare l'API che fornisce per rendere necessari anche eventuali campi personalizzati con un messaggio di errore personalizzabile e una funzione di convalida. L'impostazione predefinita è verificare se il campo è vuoto o meno.


Non esitare ad aggiungere problemi su github se li incontri. Devo documentare un po 'meglio anche l'API in quanto ci sono alcuni filtri aggiuntivi che puoi usare.
sanchothefat,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.