Передача сообщений об ошибках / предупреждений из мета-бокса в «admin_notices»

20

У меня есть простое мета-поле, которое обновляет пользовательские поля сообщений (используя update_post_meta()).

Как я могу отправить сообщение об ошибке или предупреждение на следующую страницу после того, как пользователь публикует / обновляет сообщение и не заполняет одно из полей мета-поля (или заполняет их недействительными данными)?

onetrickpony
источник

Ответы:

9

Вы можете сделать это вручную, но WP изначально делает это так для ошибок настроек:

  1. add_settings_error() создать сообщение.
  2. потом set_transient('settings_errors', get_settings_errors(), 30);
  3. settings_errors()в admin_noticesкрючке для отображения (потребуется подключить для экранов без настроек).
Rarst
источник
он делает то, что я хочу, но разве это не заполнит базу тоннами переходных процессов?
onetrickpony
@ Один трюк Пони в переходном процессе нативного процесса явно удален (см. get_settings_errors()Источник). Возможно, вам придется сделать это самостоятельно, если вы адаптируете логику для страницы без настроек.
Первое
2
Тем не менее, мне не нравится идея хранения временных сообщений об ошибках в БД. Я буду использовать ajax, чтобы предупредить пользователя об изменении ввода
onetrickpony
При кэшировании объектов беспорядок в базе данных не будет проблемой.
1
15

Вы можете использовать admin_noticesкрючок

Сначала определим функцию уведомления:

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

Вы сохраните функцию метабокса в зависимости от необходимости добавить:

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

Обновить

Как я и обещал, вот пример того, как я могу добавить сообщение об ошибке из моего метабокса

<?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);
  }

}

Теперь, когда я искал этот код, я нашел свой старый способ сделать это, используя post_updated_messagesфильтр-фильтр примерно таким же образом, поэтому я добавлю это тоже:

<?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
источник
на самом деле не работает, потому что после сохранения сообщения вы перенаправляетесь так, что действие никогда не запускается ...
onetrickpony
1
Перенаправлен куда? И код выше, который я использую, поэтому я знаю, что это работает.
Bainternet
Ваша функция сохранения метабокса подключена save_post?
onetrickpony
1
спасибо, но это делает то же самое, что указал Rarst: сообщение об ошибке сохраняется в БД, а затем извлекается и удаляется на следующей странице.
onetrickpony
1
-1 за использование БД. Вы не можете гарантировать, что правильный пользователь увидит ошибку. Также не стоит лишних накладных расходов. Отсутствие четкого способа обработки ошибок метабокса - это хороший обходной путь, но все же неэффективный. Я добавил пример того, как я делаю это, в новом ответе, чтобы помочь другим.
Джереми
11

Этот ответ [ зеркало ] от Отто в WP Tavern фактически решает временную проблему, делая то, что делает сам WordPress, чтобы преодолеть проблему перенаправления. Полностью работал для меня.

Проблема в том, что переходные процессы существуют для всех. Если у вас одновременно работают несколько пользователей, сообщение об ошибке может быть отправлено не тому человеку. Это состояние гонки.

WordPress фактически делает это, передавая параметр сообщения в URL. Номер сообщения указывает, какое сообщение отображать.

Вы можете сделать то же самое, подключив redirect_post_locationфильтр и затем add_query_argдобавив свой собственный параметр в запрос. Вот так:

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

Это добавляет my_message=123к запросу. Затем, после перенаправления, вы можете определить настройку my_message в $_GETи отобразить соответствующее сообщение.

Ана Бан
источник
3

Я знаю, что этот вопрос старый, но я нахожу здесь ответы, чтобы не решить проблему.

Продолжая ответ Ана Бана, используя метод Отто , я обнаружил, что это лучший метод для обработки ошибок. Это не требует хранения ошибок в БД.

Я включил урезанную версию объекта Metabox, который я использую. Это позволяет мне легко добавлять новые сообщения об ошибках и гарантировать, что правильный пользователь увидит сообщение об ошибке (используя db, это не гарантия).

<?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
    }

}
Джереми
источник
Единственная проблема, с которой я столкнулся в этом ответе, заключается в том, что он не работает с PHP 5.2. Я не говорю, что мы все должны поддерживать HPP 5.2, но до тех пор, пока WordPress не установит PHP 5.2 как минимальное требование, мы должны его поддерживать, если мы распространяем плагин :(
Sudar
1
Если вы удалили анонимную функцию и сделали ее публичным методом, она должна работать нормально. Я понимаю вашу проблему, но лично я не буду разрабатывать версию EOL для PHP ( php.net/eol.php ). 5.2 EOL был 6 января 2011 года. WordPress должен приложить больше усилий, чтобы не поддерживать версии EOL, но это уже другая история. плюс много плохих хостинговых компаний, которые до сих пор предоставляют версии EOL ...
Джереми