web-dev-qa-db-fra.com

Custom admin_notices Messages ignorés pendant les redirections

J'ai un mécanisme de gestion des erreurs configuré dans l'un de mes plugins pour ajouter des notifications et des erreurs à la zone d'administration, comme le fait le noyau. Cela fonctionne bien dans la plupart des cas, mais il existe certaines situations (comme la sauvegarde d'un type d'article personnalisé) dans lesquelles cela ne fonctionne pas. J'imagine qu'une redirection se produit en coulisse et que les messages sont imprimés avant la redirection, de sorte qu'ils ne semblent jamais s'afficher.

Donc, je suppose que c'est ce qui se passe

  1. L'utilisateur édite un type d'article personnalisé et clique sur Publier
  2. Mon rappel post_updated est appelé, ce qui valide et enregistre les champs personnalisés.
  3. Le rappel ajoute un message d'erreur
  4. Wordpress fait une redirection vers une page pour effectuer un traitement
  5. Mon rappel admin_notices est appelé pour imprimer et effacer les messages.
  6. Wordpress redirige vers le poste
  7. Mon rappel admin_notices est rappelé, mais aucun message ne doit être imprimé car il a été imprimé à l'étape 5.

Dans des circonstances normales, les étapes 4 et 5 ne se produisent pas, donc tout fonctionne bien, mais je pense que lorsque Wordpress enregistre les publications, il introduit la redirection supplémentaire. Est-ce que je peux faire quelque chose pour m'assurer que cela fonctionne toujours? Je pensais que je pourrais peut-être vérifier quelque chose dans printMessages () et revenir immédiatement si c'est à l'étape 4, mais je ne sais pas quoi.

Ces deux questions peuvent éclaircir le problème, mais ne donnent pas une solution complète: Ajoute une validation et une gestion des erreurs lors de la sauvegarde des champs personnalisés? , Comment afficher la notification d'erreur d'administrateur si les paramètres ont été enregistrés avec succès? .

Voici le code:

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

Update:Le code mis à jour avec la réponse acceptée a été validé dans core.php dans le fichier trunk du plugin, au cas où quelqu'un voudrait voir une copie de travail complète. La prochaine version stable qui l’aura est la 1.2.

Update 2:J'ai résumé cette fonctionnalité dans une bibliothèque autonome que vous pouvez inclure dans votre plugin. Core discute de l’inclusion de fonctionnalités similaires dans # 11515 .

4
Ian Dunn

Il y a peu de choses que j'ai mentionnées dans le code ci-dessous aussi:

  1. Vous avez écrasé les options lues à partir de get_option en utilisant array_merge
  2. Vous avez codé en dur les messages compte.
  3. les options d'enregistrement dans __destruct ne fonctionnent tout simplement pas. (Je n'ai pas encore la moindre idée, peut-être que des experts vont nous éclairer.

J'ai marqué toutes les sections où j'ai apporté les modifications avecHKFIX, avec un peu de description:

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

}
2
Hameedullah Khan

Je n'ai actuellement aucune idée de ce qui se passe avec votre plugin. Je vous signale donc deux choses:

wp_parse_args() est un bon moyen de fusionner les valeurs par défaut avec d'autres arguments.

private $defaults;

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

Et ce plugin est un peu plus proche de la façon dont le noyau traite les erreurs (directement de ma tête - peut contenir des erreurs lui-même):

EDIT: Test Plugin

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

Essaie. :)

0
kaiser