Mensajes personalizados de admin_notices ignorados durante las redirecciones

4

Tengo una configuración de mecanismo de manejo de errores en uno de mis complementos para agregar avisos y Errores en el área de administración, al igual que el núcleo hace. Funciona bien en la mayoría de los casos, pero hay algunas situaciones (como guardar un tipo de publicación personalizada) donde no lo hace. Supongo que se está produciendo una redirección tras bambalinas, y los mensajes se imprimen antes de que ocurra la redirección, de modo que parezcan nunca aparecer.

Entonces, supongo que esto es lo que está pasando

  1. El usuario edita un tipo de publicación personalizada y pulsa Publicar
  2. Se llama a mi devolución de llamada post_updated, que valida y guarda los campos personalizados
  3. La devolución de llamada agrega un mensaje de error
  4. Wordpress redirecciona a alguna página para procesar algo
  5. Se llama a la devolución de llamada de admin_notices, que imprime y borra los mensajes
  6. Wordpress redirige de nuevo a la publicación
  7. La devolución de llamada de admin_notices se vuelve a llamar, pero no hay mensajes para imprimir porque se imprimieron en el paso # 5

En circunstancias normales, los pasos 4 y 5 no ocurren, por lo que todo funciona bien, pero creo que cuando Wordpress guarda las publicaciones, introduce una redirección adicional. ¿Hay algo que pueda hacer para asegurarme de que esto siempre funcione? Estaba pensando que podría revisar algo dentro de PrintMessages () y regresar inmediatamente si está en el paso 4, pero no estoy seguro de qué.

Estas dos preguntas pueden arrojar algo de luz sobre el problema, pero no ofrecen una solución completa: ¿Agregar validación y manejo de errores al guardar campos personalizados? , ¿Cómo mostrar un aviso de error de administrador si la configuración se guardó con éxito? .

Aquí está el código:

/**
 * Constructor
 * @author Ian Dunn <[email protected]>
 */
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 <[email protected]>
 */
public function saveCustomFields()
{
    // does stuff

    if( true ) // if there was an error
        $this->enqueueMessage( 'foo', 'error' );
}

/**
 * Displays updates and errors
 * @author Ian Dunn <[email protected]>
 */
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 <[email protected]>
 * @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 <[email protected]>
 */
public function __destruct()
{
    if($this->updatedOptions)
        update_option(self::PREFIX . 'options', $this->options);
}   

Actualización: El código actualizado con la respuesta aceptada se ha asignado a core.php en el complemento trunk en caso de que alguien quiera ver una copia de trabajo completa. La siguiente versión estable que tendrá es 1.2.

Actualización 2: he resumido esta funcionalidad en una biblioteca independiente que puedes incluir en tu plugin. Core está discutiendo la inclusión de una funcionalidad similar en # 11515 .

    
pregunta Ian Dunn 16.06.2011 - 03:01

2 respuestas

2

Hay algunas cosas que he señalado en el código a continuación también:

  1. Estaba sobrescribiendo las opciones leídas de get_option usando array_merge
  2. Tuviste un código duro para el recuento de mensajes.
  3. las opciones de guardado en __destruct simplemente no funcionan. (No tengo ninguna pista todavía, puede ser que los expertos arrojen algo de luz sobre esto.

He marcado todas las secciones donde he realizado los cambios con HKFIX , con un poco de descripción:

/**
 * Constructor
 * @author Ian Dunn <[email protected]>
 */
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 <[email protected]>
 */
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 <[email protected]>
 */
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 <[email protected]>
 * @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 <[email protected]>
 */
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);

}
    
respondido por el Hameedullah Khan 28.06.2011 - 08:26
0

Actualmente no tengo ni idea de lo que está pasando con tu complemento, por lo que te señalo dos cosas:

wp_parse_args() es una buena forma de combinar los valores predeterminados con otros argumentos.

private $defaults;

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

Y este complemento está un poco más cerca de cómo el núcleo maneja los errores (directamente de mi cabeza - puede contener errores en sí mismo):

EDITAR: Probar complemento

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

Inténtalo. :)

    
respondido por el kaiser 16.06.2011 - 04:55

Lea otras preguntas en las etiquetas