Custom admin_notices Mensagens ignoradas durante redirecionamentos

4

Eu tenho uma configuração de mecanismo de tratamento de erros em um dos meus plug-ins para adicionar avisos e erros para a área de administração, assim como o núcleo faz. Ele funciona bem na maioria dos casos, mas existem algumas situações (como salvar um tipo de postagem personalizado) onde isso não acontece. Eu estou supondo que um redirecionamento está acontecendo nos bastidores, e as mensagens estão sendo impressas antes que o redirecionamento aconteça, para que elas pareçam nunca aparecer.

Então, estou supondo que isso é o que está acontecendo

  1. O usuário edita um tipo de postagem personalizado e clica em Publicar
  2. Meu retorno de chamada post_updated é chamado, o que valida e salva os campos personalizados
  3. O retorno de chamada adiciona uma mensagem de erro
  4. O Wordpress redireciona para uma página para fazer algum processamento
  5. Meu callback admin_notices é chamado, que imprime e limpa as mensagens
  6. o Wordpress redireciona de volta para a postagem
  7. Meu callback admin_notices é chamado novamente, mas não há mensagens para imprimir porque foram impressas na etapa 5

Em circunstâncias normais, as etapas 4 e 5 não acontecem, então tudo funciona bem, mas acho que quando o Wordpress salva postagens, ele introduz o redirecionamento extra. É algo que posso fazer para garantir que isso sempre funcione? Eu estava pensando que eu poderia ser capaz de verificar algo dentro de printMessages () e retornar imediatamente se estiver no passo 4, mas não tenho certeza do que.

Estas duas perguntas podem lançar alguma luz sobre o problema, mas não dão uma solução completa: Adicionar validação e tratamento de erros ao salvar campos personalizados? , Como exibir o aviso de erro de administrador se as configurações forem salvas com sucesso? .

Este é o código:

/**
 * 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);
}   

Atualização: O código atualizado com a resposta aceita foi confirmado no core.php no plugin trunk caso alguém queira ver uma cópia de trabalho completa. A próxima versão estável que terá é 1.2.

Atualização 2: abstracionei essa funcionalidade em uma biblioteca autônoma que você pode incluir no seu plugin. O núcleo está discutindo incluindo funcionalidades semelhantes em # 11515 .

    
por Ian Dunn 16.06.2011 / 03:01

2 respostas

2

Também há algumas coisas que indiquei no código abaixo:

  1. Você estava sobrescrevendo as opções lidas de get_option usando array_merge
  2. Você codificou permanentemente as contagens de mensagens.
  3. salvar opções em __destruct simplesmente não funciona. (Eu não tenho nenhuma pista ainda, pode ser especialistas irão lançar alguma luz sobre isso.

Marquei todas as seções em que fiz as alterações com HKFIX , com um pouco de descrição:

/**
 * 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);

}
    
por Hameedullah Khan 28.06.2011 / 08:26
0

Atualmente, não tenho a menor idéia do que está acontecendo com o seu plug-in, por isso, indico duas coisas:

wp_parse_args() é uma boa maneira de mesclar padrões com outros argumentos.

private $defaults;

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

E este Plugin está um pouco mais perto de como o Core lida com erros (direto da minha cabeça - pode conter erros em si):

EDIT: Plugin de teste

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

Experimente. :)

    
por kaiser 16.06.2011 / 04:55