Przekazywanie komunikatów o błędach / ostrzeżeniach z meta-boxu do „adnotacji_administracyjnych”

20

Mam prosty meta box, który aktualizuje niestandardowe pola publikowania (za pomocą update_post_meta()).

Jak mogę wysłać komunikat o błędzie lub ostrzeżenie na następną stronę po tym, jak użytkownik opublikuje / zaktualizuje post i nie wypełni jednego z pól meta-box (lub wypełni je nieprawidłowymi danymi)?

onetrickpony
źródło

Odpowiedzi:

9

Możesz to zrobić ręcznie, ale WP natywnie robi to tak w przypadku błędów ustawień:

  1. add_settings_error() stworzyć wiadomość.
  2. Następnie set_transient('settings_errors', get_settings_errors(), 30);
  3. settings_errors()w admin_noticeshaczyku, aby wyświetlić (konieczne będzie zaczepienie w przypadku ekranów bez ustawień).
Rarst
źródło
robi to, co chcę, ale czy to nie zapełni bazy danych tonami stanów przejściowych?
onetrickpony 22.04.11
@ One Trick Pony w natywnym procesie przejściowym jest jawnie usuwany (patrz get_settings_errors()źródło). Być może trzeba to zrobić samodzielnie, dostosowując logikę do strony bez ustawień.
Rarst
2
wciąż nie podoba mi się pomysł przechowywania tymczasowych komunikatów o błędach w db.
Użyję
Przy buforowaniu obiektów bałagan w bazie danych nie stanowiłby problemu.
lkraav
15

możesz użyć admin_noticeshaka

najpierw zdefiniuj funkcję powiadomienia:

function my_admin_notice(){
    //print the message
    echo '<div id="message">
       <p>metabox as errors on save message here!!!</p>
    </div>';
    //make sure to remove notice after its displayed so its only displayed when needed.
    remove_action('admin_notices', 'my_admin_notice');
}

Funkcja zapisywania metaboksu w oparciu o w razie potrzeby dodaj:

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

Aktualizacja

Tak jak obiecałem tutaj, jest to przykład dodania komunikatu o błędzie z mojego metaboxa

<?php
/*
Plugin Name: one-trick-pony-notice
Plugin URI: http://en.bainternet.info
Description: Just to proof a point using admin notice form metabox
Version: 1.0
Author: Bainternet
Author URI: http://en.bainternet.info
*/

/*  admin notice */
function my_admin_notice(){
    //print the message
    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>';
            //make sure to remove notice after its displayed so its only displayed when needed.
            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);

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

//display metabox
function OT_mt_display() {

  // Use nonce for verification
  wp_nonce_field( plugin_basename(__FILE__), 'myplugin_noncename' );

  // The actual fields for data entry
  echo '<label for="myplugin_new_field">';
       _e("leave blank to get a notice on publish or update", 'textdomain' );
  echo '</label> ';
  echo '<input type="text" id="ot_field" name="ot_field" value="" size="25" />';

}


//save metabox here is were i check the fields and if empty i display a message
function OT_mt_save( $post_id ) {

  // verify this came from the our screen and with proper authorization,
  // because save_post can be triggered at other times
    if (!isset($_POST['myplugin_noncename'])) return $post_id;
  if ( !wp_verify_nonce( $_POST['myplugin_noncename'], plugin_basename(__FILE__) ) )
      return $post_id;

  // verify if this is an auto save routine. 
  // If it is our form has not been submitted, so we dont want to do anything
  if ( defined('DOING_AUTOSAVE') && DOING_AUTOSAVE ) 
      return $post_id;


  if(!isset($_POST['ot_field']) || empty($_POST['ot_field'])){
    //field left empty so we add a notice
    $notice = get_option('otp_notice');
    $notice[$post_id] = "You have left the field empty";
    update_option('otp_notice',$notice);
  }

}

Teraz, gdy szukam tego kodu, znalazłem swój stary sposób, używając post_updated_messageshaka filtrującego w mniej więcej taki sam sposób, więc też go dodam:

<?php
/*
Plugin Name: one-trick-pony-notice2
Plugin URI: http://en.bainternet.info
Description: just like the one above but this time using post_updated_messages hook
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');


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

//display metabox
function OT_mt_display() {

  // Use nonce for verification
  wp_nonce_field( plugin_basename(__FILE__), 'myplugin_noncename' );

  // The actual fields for data entry
  echo '<label for="myplugin_new_field">';
       _e("leave blank to get a notice on publish or update", 'textdomain' );
  echo '</label> ';
  echo '<input type="text" id="ot_field" name="ot_field" value="" size="25" />';

}


//save metabox here is were i check the fields and if empty i display a message
function OT_mt_save( $post_id ) {

  // verify this came from the our screen and with proper authorization,
  // because save_post can be triggered at other times
    if (!isset($_POST['myplugin_noncename'])) return $post_id;
  if ( !wp_verify_nonce( $_POST['myplugin_noncename'], plugin_basename(__FILE__) ) )
      return $post_id;

  // verify if this is an auto save routine. 
  // If it is our form has not been submitted, so we dont want to do anything
  if ( defined('DOING_AUTOSAVE') && DOING_AUTOSAVE ) 
      return $post_id;


  if(!isset($_POST['ot_field']) || empty($_POST['ot_field'])){
    //field left empty so we add a notice
    $notice = get_option('otp_notice');
    $notice[$post_id] = "You have left the field empty";
    update_option('otp_notice',$notice);
  }

}

//messages filter
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;
}
Bainternet
źródło
tak naprawdę nie działa, ponieważ po zapisaniu postu następuje przekierowanie, dzięki czemu akcja nigdy się nie uruchamia ...
onetrickpony
1
Przekierowano gdzie? A powyższy kod jest używany, więc wiem, że działa.
Bainternet
czy funkcja zapisywania metabox jest włączona save_post?
onetrickpony 22.04.11
1
dzięki, ale robi to to samo, co wskazał Rarst: komunikat o błędzie jest zapisywany w bazie danych, a następnie pobierany i usuwany na następnej stronie.
onetrickpony,
1
-1 do korzystania z DB. Nie możesz zagwarantować, że prawidłowy użytkownik zobaczy błąd. Ponadto nie jest to warte niepotrzebnego narzutu. To, że nie ma jednoznacznego sposobu obsługi błędów metaboksu, jest dobre, ale wciąż nie jest wydajne. Dodałem przykład sposobu, w jaki to robię, w nowej odpowiedzi, aby pomóc innym.
Jeremy,
11

Ta odpowiedź [ lustro ] od Otto w WP Tavern, faktycznie rozwiązuje przejściowy problem, robiąc to, co robi sam WordPress, aby rozwiązać problem przekierowania. Totally dla mnie pracował.

Problem polega na tym, że transjenty są dostępne dla wszystkich. Jeśli w tym samym czasie działa więcej niż jeden użytkownik, komunikat o błędzie może trafić do niewłaściwej osoby. To warunek wyścigu.

WordPress faktycznie robi to, przekazując parametr wiadomości w adresie URL. Numer wiadomości wskazuje, który komunikat ma zostać wyświetlony.

Możesz zrobić to samo, zaczepiając redirect_post_locationfiltr, a następnie add_query_argdodając własny parametr do żądania. Tak jak:

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

To dodaje my_message=123do zapytania. Następnie po przekierowaniu możesz wykryć ustawienie my_message w $_GETi odpowiednio wyświetlić odpowiedni komunikat.

Ana Ban
źródło
3

Wiem, że to pytanie jest stare, ale znajduję tutaj odpowiedzi, aby nie rozwiązać problemu.

Rozszerzając odpowiedź Ana Ban, stosując metodę Otto , uznałem, że jest to najlepsza metoda radzenia sobie z błędami. Nie wymaga to przechowywania błędów w bazie danych.

Dołączyłem uproszczoną wersję używanego obiektu Metabox. To pozwala mi łatwo dodawać nowe komunikaty o błędach i upewniać się, że właściwy użytkownik widzi komunikat o błędzie (użycie db nie jest gwarancją).

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

    /**
     * Defines the whitelist for allowed screens (post_types)
     */
    private $_allowedScreens = array( 'SCREENS_TO_ALLOW_METABOX' );

    /**
     * Get parameter for the error box error code
     */
    const GET_METABOX_ERROR_PARAM = 'meta-error';

    /**
     * Defines admin hooks
     */
    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')); // NOTE: admin_notices doesn't position this right on custom post type pages, haven't testes this on POST or PAGE but I don't see this an issue
    }

    /**
     * Adds the metabox to specified post types
     */
    public function addMetabox() {
        foreach ( $this->_allowedScreens as $screen ) {
            add_meta_box(
                'PLUGIN_METABOX',
                __( 'TITLE', 'text_domain' ),
                array($this, 'metaBox'),
                $screen,
                'side',
                'high'
            );
        }
    }

    /**
     * Output metabox content
     * @param $post
     */
    public function metaBox($post) {
        // Add an nonce field so we can check for it later.
        wp_nonce_field( 'metaboxnonce', 'metaboxnonce' );
        // Load meta data for this metabox
        $someValue = get_post_meta( $post->ID, 'META_KEY_IDENTIFIER', true );
        ?>
        <p>
            <label for="some-value" style="width: 120px; display: inline-block;">
                <?php _e( 'Some Field:', 'text_domain' ); ?>
            </label>
            &nbsp;
            <input type="text" id="some-value" name="some_value" value="<?php esc_attr_e( $someValue ); ?>" size="25" />
        </p>
    <?php
    }

    /**
     * Save method for the metabox
     * @param $post_id
     */
    public function saveMetabox($post_id) {
        global $wpdb;

        // Check if our nonce is set.
        if ( ! isset( $_POST['metaboxnonce'] ) ) {
            return $post_id;
        }
        // Verify that the nonce is valid.
        if ( ! wp_verify_nonce( $_POST['metaboxnonce'], 'metaboxnonce' ) ) {
            return $post_id;
        }
        // If this is an autosave, our form has not been submitted, so we don't want to do anything.
        if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) {
            return $post_id;
        }
        // Check the user's permissions.
        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;
            }
        }
        // Make sure that it is set.
        if ( !isset( $_POST['some_value'] ) ) {
            return $post_id;
        }
        // Sanitize user input.
        $someValue = sanitize_text_field( $_POST['some_value'] );
        // Check to make sure there is a value
        if (empty($someValue)) {
            // Add our error code
            add_filter('redirect_post_location', function($loc) {
                return add_query_arg( self::GET_METABOX_ERROR_PARAM, 1, $loc );
            });
            return $post_id; // make sure to return so we don't allow further processing
        }
        // Update the meta field in the database.
        update_post_meta( $post_id, 'META_KEY_IDENTIFIER', $someValue );
    }

    /**
     * Metabox admin notices
     */
    public function adminNotices() {
        if (isset($_GET[self::GET_METABOX_ERROR_PARAM])) {
            $screen = get_current_screen();
            // Make sure we are in the proper post type
            if (in_array($screen->post_type, $this->_allowedScreens)) {
                $errorCode = (int) $_GET[self::GET_METABOX_ERROR_PARAM];
                switch($errorCode) {
                    case 1:
                        $this->_showAdminNotice( __('Some error happened', 'text_domain') );
                        break;
                    // More error codes go here for outputting errors
                }
            }
        }
    }

    /**
     * Shows the admin notice for the 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
    }

}
Jeremy
źródło
Jedyny problem, jaki mam z tą odpowiedzią, to to, że nie działa z PHP 5.2. Nie twierdzę, że wszyscy powinniśmy wspierać HPP 5.2, ale dopóki WordPress nie będzie wymagał PHP 5.2 jako minimum, musimy go wspierać, jeśli dystrybuujemy wtyczkę :(
Sudar
1
Jeśli usuniesz anonimową funkcję i uczynisz ją publiczną metodą, powinna działać dobrze. Rozumiem twój problem, ale osobiście nie zamierzam tworzyć wersji EOL PHP ( php.net/eol.php ) 5.2 EOL to 6 stycznia 2011. WordPress powinien dokładać większych starań, aby nie obsługiwać wersji EOL, ale to inna historia plus wiele złych firm hostingowych, które wciąż zapewniały wersje EOL ...
Jeremy