Passaggio di messaggi di errore/avviso da una meta box a "admin_notices"

21 apr 2011, 22:48:59
Visualizzazioni: 14.2K
Voti: 22

Ho una semplice meta box che aggiorna i campi personalizzati del post (usando update_post_meta()).

Come posso inviare un messaggio di errore o avviso alla pagina successiva quando l'utente pubblica/aggiorna il post senza compilare uno dei campi della meta box (o li compila con dati non validi)?

0
Tutte le risposte alla domanda 4
13
16

puoi usare l'hook admin_notices

prima definisci la funzione per il notice:

function my_admin_notice(){
    //stampa il messaggio
    echo '<div id="message">
       <p>messaggio di errore del metabox durante il salvataggio qui!!!</p>
    </div>';
    //assicurati di rimuovere il notice dopo che è stato visualizzato, così viene mostrato solo quando necessario
    remove_action('admin_notices', 'my_admin_notice');
}

Poi nella tua funzione di salvataggio del metabox, in base alla necessità aggiungi:

...
...
if($errors){
    add_action('admin_notices', 'my_admin_notice');
}
...
...

Aggiornamento

Come promesso, ecco un esempio di come aggiungere un messaggio di errore dal mio metabox

<?php
/*
Plugin Name: one-trick-pony-notice
Plugin URI: http://en.bainternet.info
Description: Solo per dimostrare un punto usando admin notice da un metabox
Version: 1.0
Author: Bainternet
Author URI: http://en.bainternet.info
*/

/*  admin notice */
function my_admin_notice(){
    //stampa il messaggio
    global $post;
    $notice = get_option('otp_notice');
    if (empty($notice)) return '';
    foreach($notice as $pid => $m){
        if ($post->ID == $pid ){
            echo '<div id="message" class="error"><p>'.$m.'</p></div>';
            //assicurati di rimuovere il notice dopo che è stato visualizzato, così viene mostrato solo quando necessario
            unset($notice[$pid]);
            update_option('otp_notice',$notice);
            break;
        }
    }
}

//hooks

add_action('add_meta_boxes', 'OT_mt_add');
add_action('save_post', 'OT_mt_save');
add_action('admin_notices', 'my_admin_notice',0);

//aggiungi metabox
function OT_mt_add() {
    add_meta_box('OT_mt_sectionid', __( 'Meta Box notice One Trick', 'textdomain' ),'OT_mt_display','post');
}

//visualizza metabox
function OT_mt_display() {

  // Usa nonce per la verifica
  wp_nonce_field( plugin_basename(__FILE__), 'myplugin_noncename' );

  // I campi effettivi per l'inserimento dei dati
  echo '<label for="myplugin_new_field">';
       _e("lascia vuoto per ottenere un notice durante la pubblicazione o l'aggiornamento", 'textdomain' );
  echo '</label> ';
  echo '<input type="text" id="ot_field" name="ot_field" value="" size="25" />';

}


//salva metabox qui è dove controllo i campi e se vuoti mostro un messaggio
function OT_mt_save( $post_id ) {

  // verifica che provenga dalla nostra schermata e con la giusta autorizzazione,
  // perché save_post può essere attivato in altri momenti
    if (!isset($_POST['myplugin_noncename'])) return $post_id;
  if ( !wp_verify_nonce( $_POST['myplugin_noncename'], plugin_basename(__FILE__) ) )
      return $post_id;

  // verifica se si tratta di un salvataggio automatico
  // Se lo è, il nostro form non è stato inviato, quindi non vogliamo fare nulla
  if ( defined('DOING_AUTOSAVE') && DOING_AUTOSAVE ) 
      return $post_id;


  if(!isset($_POST['ot_field']) || empty($_POST['ot_field'])){
    //campo lasciato vuoto quindi aggiungiamo un notice
    $notice = get_option('otp_notice');
    $notice[$post_id] = "Hai lasciato il campo vuoto";
    update_option('otp_notice',$notice);
  }

}

Ora cercando questo codice ho trovato il mio vecchio modo di farlo usando l'hook filter post_updated_messages più o meno nello stesso modo, quindi lo aggiungo anche:

<?php
/*
Plugin Name: one-trick-pony-notice2
Plugin URI: http://en.bainternet.info
Description: come quello sopra ma questa volta usando l'hook post_updated_messages
Version: 1.0
Author: Bainternet
Author URI: http://en.bainternet.info
*/

//hooks
add_filter('post_updated_messages','my_messages',0);
add_action('add_meta_boxes', 'OT_mt_add');
add_action('save_post', 'OT_mt_save');


//aggiungi metabox
function OT_mt_add() {
    add_meta_box('OT_mt_sectionid', __( 'Meta Box notice One Trick', 'textdomain' ),'OT_mt_display','post');
}

//visualizza metabox
function OT_mt_display() {

  // Usa nonce per la verifica
  wp_nonce_field( plugin_basename(__FILE__), 'myplugin_noncename' );

  // I campi effettivi per l'inserimento dei dati
  echo '<label for="myplugin_new_field">';
       _e("lascia vuoto per ottenere un notice durante la pubblicazione o l'aggiornamento", 'textdomain' );
  echo '</label> ';
  echo '<input type="text" id="ot_field" name="ot_field" value="" size="25" />';

}


//salva metabox qui è dove controllo i campi e se vuoti mostro un messaggio
function OT_mt_save( $post_id ) {

  // verifica che provenga dalla nostra schermata e con la giusta autorizzazione,
  // perché save_post può essere attivato in altri momenti
    if (!isset($_POST['myplugin_noncename'])) return $post_id;
  if ( !wp_verify_nonce( $_POST['myplugin_noncename'], plugin_basename(__FILE__) ) )
      return $post_id;

  // verifica se si tratta di un salvataggio automatico
  // Se lo è, il nostro form non è stato inviato, quindi non vogliamo fare nulla
  if ( defined('DOING_AUTOSAVE') && DOING_AUTOSAVE ) 
      return $post_id;


  if(!isset($_POST['ot_field']) || empty($_POST['ot_field'])){
    //campo lasciato vuoto quindi aggiungiamo un notice
    $notice = get_option('otp_notice');
    $notice[$post_id] = "Hai lasciato il campo vuoto";
    update_option('otp_notice',$notice);
  }

}

//filtro messaggi
function my_messages($m){
    global $post;
    $notice = get_option('otp_notice');
    if (empty($notice)) return $m;
    foreach($notice as $pid => $mm){
        if ($post->ID == $pid ){
            foreach ($m['post'] as $i => $message){
                $m['post'][$i] = $message.'<p>'.$mm.'</p>';

            }
            unset($notice[$pid]);
            update_option('otp_notice',$notice);
            break;
        }
    }
    return $m;
}
21 apr 2011 23:02:08
Commenti

non funziona davvero perché dopo aver salvato il post, vieni reindirizzato e quindi quell'azione non viene mai eseguita...

onetrickpony onetrickpony
23 apr 2011 00:16:17

Reindirizzato dove? E il codice sopra è quello che uso io, quindi so che funziona.

Bainternet Bainternet
23 apr 2011 00:23:13

la tua funzione di salvataggio del metabox è agganciata a save_post?

onetrickpony onetrickpony
23 apr 2011 00:31:00

Perché save_post o wp_insert_post_data?

Bainternet Bainternet
23 apr 2011 00:34:54

perché non funziona :) Dopo aver premuto il pulsante di pubblicazione, il post viene salvato e poi si viene reindirizzati nuovamente alla pagina di modifica.

onetrickpony onetrickpony
23 apr 2011 00:43:10

Mi hai fatto preoccupare per un momento, l'avviso viene mostrato nella schermata di modifica e funziona perfettamente.

Bainternet Bainternet
23 apr 2011 15:47:08

puoi postare il codice che stai utilizzando, la metabox e tutto il resto? Perché ho provato il tuo codice sopra ma non vedo alcun avviso proveniente dalla mia meta box...

onetrickpony onetrickpony
23 apr 2011 17:16:12

Certo, appena arrivo a casa incollerò il mio codice.

Bainternet Bainternet
23 apr 2011 17:43:15

@One Trick Pony: dai un'occhiata ai plugin che ti ho postato.

Bainternet Bainternet
24 apr 2011 04:39:56

grazie, ma questo fa la stessa cosa che Rarst ha evidenziato: il messaggio di errore viene salvato nel db, e poi recuperato e cancellato nella pagina successiva.

onetrickpony onetrickpony
25 apr 2011 14:56:41

@One Trick Pony: sì, salva nel db ma è solo una bella opzione (una riga nel db) e viene cancellata automaticamente quando si usa il codice sopra, quindi non c'è bisogno di preoccuparsi che il db si riempia di transizioni.

Bainternet Bainternet
26 apr 2011 14:24:18

-1 per l'uso di un DB. Non puoi garantire che l'utente corretto veda l'errore. Inoltre, non vale la pena il sovraccarico non necessario. Per non avere un modo chiaro per gestire gli errori dei metabox questo è un buon workaround ma comunque non efficiente. Ho aggiunto un esempio del modo in cui lo faccio in una nuova risposta per aiutare gli altri.

Jeremy Jeremy
12 feb 2015 17:32:13

Aggiungerei if (empty($post)) return ''; sopra if (empty($notice)) return ''; altrimenti mostrerà errori in tutto il sito specialmente se non contengono le informazioni $post.

soniccool soniccool
12 feb 2020 22:34:27
Mostra i restanti 8 commenti
0
11

Questa risposta [mirror] di Otto su WP Tavern risolve effettivamente il problema dei transient facendo ciò che WordPress stesso fa per superare il problema di reindirizzamento. Ha funzionato perfettamente nel mio caso.

Il problema è che i transient sono disponibili per tutti. Se hai più di un utente che esegue operazioni contemporaneamente, il messaggio di errore può essere visualizzato dalla persona sbagliata. È una condizione di competizione.

WordPress gestisce questo passando un parametro message nell'URL. Il numero del messaggio indica quale messaggio visualizzare.

Puoi fare lo stesso agganciando il filtro redirect_post_location e poi usando add_query_arg per aggiungere il tuo parametro alla richiesta. In questo modo:

add_filter('redirect_post_location','my_message');
function my_message($loc) {
 return add_query_arg( 'my_message', 123, $loc );
}

Questo aggiunge my_message=123 alla query. Poi, dopo il reindirizzamento, puoi rilevare l'impostazione my_message in $_GET e visualizzare il messaggio appropriato di conseguenza.

14 mag 2012 11:27:11
4
10

Puoi farlo manualmente, ma WordPress lo fa nativamente in questo modo per gli errori delle impostazioni:

  1. add_settings_error() per creare il messaggio.
  2. Poi set_transient('settings_errors', get_settings_errors(), 30);
  3. settings_errors() nell'hook admin_notices per visualizzare (dovrai usare l'hook anche per schermate non relative alle impostazioni).
21 apr 2011 23:04:16
Commenti

fa quello che voglio, ma questo non riempirebbe il database con tantissimi transient?

onetrickpony onetrickpony
23 apr 2011 00:14:58

@One Trick Pony nel processo nativo il transient viene eliminato esplicitamente (vedi sorgente di get_settings_errors()). Potresti doverlo fare manualmente se adatti la logica per una pagina che non è di impostazioni.

Rarst Rarst
23 apr 2011 00:20:48

comunque non mi piace l'idea di memorizzare messaggi di errore temporanei nel database. Userò ajax per avvisare l'utente durante la modifica dell'input

onetrickpony onetrickpony
23 apr 2011 00:23:02

Con la cache degli oggetti, il disordine del database non sarebbe un problema.

lkraav lkraav
3 ott 2017 15:16:37
2

So che questa domanda è vecchia ma trovo che le risposte qui non risolvano il problema.

Estendendo la risposta di Ana Ban, utilizzando il metodo di Otto, ho trovato che questo è il miglior metodo per gestire gli errori. Non richiede di memorizzare gli errori nel database.

Ho incluso una versione semplificata di un oggetto Metabox che utilizzo. Questo mi permette di aggiungere facilmente nuovi messaggi di errore e assicurarmi che l'utente corretto veda il messaggio di errore (usando il database, questa non è una garanzia).

<?php
/**
 * Class MetaboxExample
 */
class MetaboxExample {

    /**
     * Definisce la whitelist per gli schermi consentiti (post_types)
     */
    private $_allowedScreens = array( 'SCREENS_TO_ALLOW_METABOX' );

    /**
     * Parametro GET per il codice di errore del box errori
     */
    const GET_METABOX_ERROR_PARAM = 'meta-error';

    /**
     * Definisce gli hook per l'admin
     */
    public function __construct() {
        add_action('add_meta_boxes', array($this, 'addMetabox'), 50);
        add_action('save_post', array($this, 'saveMetabox'), 50);
        add_action('edit_form_top', array($this, 'adminNotices')); // NOTA: admin_notices non posiziona correttamente questo sulle pagine dei custom post type, non ho testato questo su POST o PAGE ma non vedo questo come un problema
    }

    /**
     * Aggiunge il metabox ai tipi di post specificati
     */
    public function addMetabox() {
        foreach ( $this->_allowedScreens as $screen ) {
            add_meta_box(
                'PLUGIN_METABOX',
                __( 'TITOLO', 'text_domain' ),
                array($this, 'metaBox'),
                $screen,
                'side',
                'high'
            );
        }
    }

    /**
     * Output del contenuto del metabox
     * @param $post
     */
    public function metaBox($post) {
        // Aggiunge un campo nonce per poterlo verificare dopo
        wp_nonce_field( 'metaboxnonce', 'metaboxnonce' );
        // Carica i meta dati per questo metabox
        $someValue = get_post_meta( $post->ID, 'META_KEY_IDENTIFIER', true );
        ?>
        <p>
            <label for="some-value" style="width: 120px; display: inline-block;">
                <?php _e( 'Un campo:', 'text_domain' ); ?>
            </label>
            &nbsp;
            <input type="text" id="some-value" name="some_value" value="<?php esc_attr_e( $someValue ); ?>" size="25" />
        </p>
    <?php
    }

    /**
     * Metodo di salvataggio per il metabox
     * @param $post_id
     */
    public function saveMetabox($post_id) {
        global $wpdb;

        // Controlla se il nostro nonce è impostato
        if ( ! isset( $_POST['metaboxnonce'] ) ) {
            return $post_id;
        }
        // Verifica che il nonce sia valido
        if ( ! wp_verify_nonce( $_POST['metaboxnonce'], 'metaboxnonce' ) ) {
            return $post_id;
        }
        // Se questo è un autosalvataggio, il nostro form non è stato inviato, quindi non vogliamo fare nulla
        if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) {
            return $post_id;
        }
        // Controlla i permessi dell'utente
        if ( isset( $_POST['post_type'] ) && 'page' == $_POST['post_type'] ) {
            if ( ! current_user_can( 'edit_page', $post_id ) ) {
                return $post_id;
            }
        } else {
            if ( ! current_user_can( 'edit_post', $post_id ) ) {
                return $post_id;
            }
        }
        // Assicurati che sia impostato
        if ( !isset( $_POST['some_value'] ) ) {
            return $post_id;
        }
        // Sanifica l'input dell'utente
        $someValue = sanitize_text_field( $_POST['some_value'] );
        // Controlla per assicurarsi che ci sia un valore
        if (empty($someValue)) {
            // Aggiungi il nostro codice di errore
            add_filter('redirect_post_location', function($loc) {
                return add_query_arg( self::GET_METABOX_ERROR_PARAM, 1, $loc );
            });
            return $post_id; // assicurati di restituire per non permettere ulteriori elaborazioni
        }
        // Aggiorna il campo meta nel database
        update_post_meta( $post_id, 'META_KEY_IDENTIFIER', $someValue );
    }

    /**
     * Notifiche admin del metabox
     */
    public function adminNotices() {
        if (isset($_GET[self::GET_METABOX_ERROR_PARAM])) {
            $screen = get_current_screen();
            // Assicurati che siamo nel tipo di post corretto
            if (in_array($screen->post_type, $this->_allowedScreens)) {
                $errorCode = (int) $_GET[self::GET_METABOX_ERROR_PARAM];
                switch($errorCode) {
                    case 1:
                        $this->_showAdminNotice( __('È successo un errore', 'text_domain') );
                        break;
                    // Altri codici di errore vanno qui per mostrare errori
                }
            }
        }
    }

    /**
     * Mostra la notifica admin per il metabox
     * @param $message
     * @param string $type
     */
    private function _showAdminNotice($message, $type='error') {
        ?>
        <div class="<?php esc_attr_e($type); ?> below-h2">
            <p><?php echo $message; ?></p>
        </div>
    <?php
    }

}
12 feb 2015 17:11:54
Commenti

L'unico problema che ho con questa risposta è che non funziona con PHP 5.2. Non sto dicendo che dovremmo tutti supportare PHP 5.2, ma finché WordPress non avrà PHP 5.2 come requisito minimo, dobbiamo supportarlo se distribuiamo il plugin :(

Sudar Sudar
23 giu 2015 06:47:20

Se rimuovi la funzione anonima e la trasformi in un metodo pubblico, dovrebbe funzionare perfettamente. Capisco il tuo problema ma personalmente non svilupperò per una versione EOL di PHP (http://php.net/eol.php) 5.2 EOL era il 6 gennaio 2011. WordPress dovrebbe fare più sforzi per non supportare versioni EOL ma questa è un'altra storia, per non parlare dei tanti hosting provider scadenti che continuano a offrire versioni EOL...

Jeremy Jeremy
23 giu 2015 16:39:15