Пользовательские admin_notices Сообщения, игнорируемые во время перенаправления

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

Итак, я предполагаю, что это то, что происходит

  1. Пользователь изменяет тип персонализированного сообщения и показывает публикацию
  2. Вызывается мой post_updated callback, который проверяет и сохраняет пользовательские поля
  3. Обратный вызов добавляет сообщение об ошибке
  4. WordPress выполняет перенаправление на какую-либо страницу, чтобы выполнить некоторую обработку
  5. Вызывается обратный вызов admin_notices, который печатает и очищает сообщения
  6. WordPress перенаправляет обратно на почту
  7. Обратный вызов admin_notices вызывается снова, но нет сообщений для печати, поскольку они были напечатаны на шаге № 5

При нормальных обстоятельствах шаги 4 и 5 не происходят, поэтому все работает нормально, но я думаю, что когда WordPress сохраняет сообщения, он вводит дополнительную перенаправление. Я могу что-то сделать, чтобы это всегда срабатывало? Я думал, что смогу проверить что-то внутри printMessages () и немедленно вернуться, если это на шаге 4, но я не уверен, что.

Эти два вопроса могут пролить свет на проблему, но не дают полного решения: добавьте проверку и обработку ошибок при сохранении настраиваемых полей? , Как отобразить уведомление об ошибке администратора, если настройки сохранены успешно? ,

Вот код:

/** * Constructor * @author Ian Dunn <redacted@mpangodev.com> */ public function __construct() { // Initialize variables $defaultOptions = array( 'updates' => array(), 'errors' => array() ); $this->options = array_merge( get_option( self::PREFIX . 'options', array() ), $defaultOptions ); $this->updatedOptions = false; $this->userMessageCount = array( 'updates' => 0, 'errors' => 0 ); // more add_action( 'admin_notices', array($this, 'printMessages') ); add_action( 'post_updated', array($this, 'saveCustomFields') ); // does other stuff } /** * Saves values of the the custom post type's extra fields * @author Ian Dunn <redacted@mpangodev.com> */ public function saveCustomFields() { // does stuff if( true ) // if there was an error $this->enqueueMessage( 'foo', 'error' ); } /** * Displays updates and errors * @author Ian Dunn <redacted@mpangodev.com> */ public function printMessages() { foreach( array('updates', 'errors') as $type ) { if( $this->options[$type] && ( self::DEBUG_MODE || $this->userMessageCount[$type] ) ) { echo '<div id="message" class="'. ( $type == 'updates' ? 'updated' : 'error' ) .'">'; foreach($this->options[$type] as $message) if( $message['mode'] == 'user' || self::DEBUG_MODE ) echo '<p>'. $message['message'] .'</p>'; echo '</div>'; $this->options[$type] = array(); $this->updatedOptions = true; $this->userMessageCount[$type] = 0; } } } /** * Queues up a message to be displayed to the user * @author Ian Dunn <redacted@mpangodev.com> * @param string $message The text to show the user * @param string $type 'update' for a success or notification message, or 'error' for an error message * @param string $mode 'user' if it's intended for the user, or 'debug' if it's intended for the developer */ protected function enqueueMessage($message, $type = 'update', $mode = 'user') { array_push($this->options[$type .'s'], array( 'message' => $message, 'type' => $type, 'mode' => $mode ) ); if($mode == 'user') $this->userMessageCount[$type . 's']++; $this->updatedOptions = true; } /** * Destructor * Writes options to the database * @author Ian Dunn <redacted@mpangodev.com> */ public function __destruct() { if($this->updatedOptions) update_option(self::PREFIX . 'options', $this->options); } 

Обновление: обновленный код с принятым ответом был передан core.php в соединительной линии плагина, если кто-то хочет увидеть полную рабочую копию. Следующий стабильный релиз, который будет иметь это 1,2.

Обновление 2: я отвлек эту функциональность на автономную библиотеку, которую вы можете включить в свой плагин. Core обсуждает, включая аналогичную функциональность в # 11515 .

Solutions Collecting From Web of "Пользовательские admin_notices Сообщения, игнорируемые во время перенаправления"

Есть несколько вещей, которые я указал в приведенном ниже коде:

  1. Вы перезаписывали параметры, прочитанные из get_option используя array_merge
  2. У вас были жесткие коды сообщений.
  3. сохранение параметров в __destruct просто не работает. (У меня пока нет подсказок, возможно, эксперты прольют на него некоторый свет.

Я отметил все разделы, где я внес изменения с помощью HKFIX , с небольшим описанием:

 /** * Constructor * @author Ian Dunn <redacted@mpangodev.com> */ public function __construct() { // Initialize variables $defaultOptions = array( 'updates' => array(), 'errors' => array() ); /* HKFIX: array_merge was overwriting the values read from get_option, * moved $defaultOptions as first argument to array_merge */ $this->options = array_merge( $defaultOptions, get_option( self::PREFIX . 'options', array() ) ); $this->updatedOptions = false; /* HKFIX: the count for update and error messages was hardcoded, * which was ignoring the messages already in the options table read above * later in print the MessageCounts is used in loop * So I updated to set the count based on the options read from get_option */ $this->userMessageCount = array(); foreach ( $this->options as $msg_type => $msgs ) { $this->userMessageCount[$msg_type] = count( $msgs ); } // more add_action( 'admin_notices', array($this, 'printMessages') ); add_action( 'post_updated', array($this, 'saveCustomFields') ); // does other stuff } /** * Saves values of the the custom post type's extra fields * @author Ian Dunn <redacted@mpangodev.com> */ public function saveCustomFields() { // does stuff /* HKFIX: this was false, so changed it to true, may be not a fix but thought I should mention ;) */ if( true ) $this->enqueueMessage( 'foo', 'error' ); } /** * Displays updates and errors * @author Ian Dunn <redacted@mpangodev.com> */ public function printMessages() { foreach( array('updates', 'errors') as $type ) { if( $this->options[$type] && ( self::DEBUG_MODE || $this->userMessageCount[$type] ) ) { echo '<div id="message" class="'. ( $type == 'updates' ? 'updated' : 'error' ) .'">'; foreach($this->options[$type] as $message) if( $message['mode'] == 'user' || self::DEBUG_MODE ) echo '<p>'. $message['message'] .'</p>'; echo '</div>'; $this->options[$type] = array(); $this->updatedOptions = true; $this->userMessageCount[$type] = 0; } } /* HKFIX: Save the messages, can't wait for destruct */ if ( $this->updatedOptions ) { $this->saveMessages(); } } /** * Queues up a message to be displayed to the user * @author Ian Dunn <redacted@mpangodev.com> * @param string $message The text to show the user * @param string $type 'update' for a success or notification message, or 'error' for an error message * @param string $mode 'user' if it's intended for the user, or 'debug' if it's intended for the developer */ protected function enqueueMessage($message, $type = 'update', $mode = 'user') { array_push($this->options[$type .'s'], array( 'message' => $message, 'type' => $type, 'mode' => $mode ) ); if($mode == 'user') $this->userMessageCount[$type . 's']++; /* HKFIX: save the messages, can't wait for destruct */ $this->saveMessages(); } /* HKFIX: Dedicated funciton to save messages * Can also be called from destruct if that is really required */ public function saveMessages() { update_option(self::PREFIX . 'options', $this->options); } /** * Destructor * Writes options to the database * @author Ian Dunn <redacted@mpangodev.com> */ public function __destruct() { /* HKFIX: Can't rely on saving options in destruct, this just does not work */ // its very late to call update_options in destruct //update_option(self::PREFIX . 'options', $this->options); } 

В настоящее время я не знаю, что происходит с вашим плагином, поэтому я указываю вам на две вещи:

wp_parse_args() – отличный способ объединить значения по умолчанию с другими аргументами.

 private $defaults; function wpse20130_parse_us( $args ); { $new_args = wp_parse_args( $this->defaults, $args ); return $new_args; } 

И этот плагин немного ближе к тому, как ядро ​​обрабатывает ошибки (прямо из моей головы – может содержать ошибки):

EDIT: тестовый плагин

 <?php /** Plugin Name: WPSE Show Error on post Plugin URI: https://github.com/franz-josef-kaiser/ Description: Example for the useage of the WP Error class in a plugin Author: Franz Josef Kaiser Author URI: https://github.com/franz-josef-kaiser Version: 0.1 License: GPL v2 - http://www.gnu.org/licenses/old-licenses/gpl-2.0.html */ // Secure: doesn't allow to load this file directly if( ! class_exists('WP') ) { header( 'Status: 403 Forbidden' ); header( 'HTTP/1.1 403 Forbidden' ); exit; } if ( ! class_exists('wpse20130Error') ) { class wpse20130Error { private $args = array(); private $error_msg; const TEXTDOMAIN = 'textdomain'; function __construct() { $this->wpse20130_input( $this->args ); add_action( 'admin_notices', array($this, 'wpse20130_trigger_error') ); } function wpse20130_input( $args ) { if ( ! isset( $args['some_important_value'] ) ) $this->error_msg = sprintf( __( 'You have to specify the some_important_value inside the %2$s function.'.'<br />'. 'Error triggered inside: file name %1$s (line number %3$s)' ,self::TEXTDOMAIN ) ,__FILE__ ,__FUNCTION__ ,__LINE__ ); } function wpse20130_trigger_error() { // Trigger Errors if we got some if ( isset( $this->error_msg ) ) { $error = new WP_Error( 'input_data', $this->error_msg ); if ( is_wp_error( $error ) ) { $output = '<div id="error-'.$error->get_error_code().'" class="error error-notice">'. $error->get_error_message(). '</div>'; // die & print error message echo $output; } } } } // END Class wpse20130Error new wpse20130Error(); } // endif; ?> 

Попробуйте. 🙂