it-swarm.com.de

Benutzerdefinierte admin_notices-Nachrichten, die bei Umleitungen ignoriert werden

Ich habe einen Fehlerbehandlungsmechanismus in einem meiner Plugins eingerichtet, um dem Admin-Bereich Hinweise und Fehler hinzuzufügen, genau wie der Core. In den meisten Fällen funktioniert es einwandfrei, aber in einigen Situationen (z. B. beim Speichern eines benutzerdefinierten Beitragstyps) ist dies nicht der Fall. Ich vermute, dass eine Umleitung hinter den Kulissen stattfindet und die Nachrichten gedruckt werden, bevor die Umleitung stattfindet, sodass sie anscheinend nie angezeigt werden.

Ich schätze, das ist es, was passiert

  1. Der Benutzer bearbeitet einen benutzerdefinierten Beitragstyp und klickt auf Veröffentlichen
  2. Mein post_updated Callback wird aufgerufen, wodurch die benutzerdefinierten Felder überprüft und gespeichert werden
  3. Der Rückruf fügt eine Fehlermeldung hinzu
  4. Wordpress führt eine Weiterleitung zu einer bestimmten Seite durch, um eine bestimmte Verarbeitung durchzuführen
  5. Mein admin_notices-Rückruf wird aufgerufen, der die Nachrichten druckt und löscht
  6. Wordpress leitet zurück zum Beitrag
  7. Mein admin_notices-Rückruf wird erneut aufgerufen, es sind jedoch keine zu druckenden Nachrichten vorhanden, da sie in Schritt 5 gedruckt wurden

Unter normalen Umständen finden die Schritte 4 und 5 nicht statt, daher funktioniert alles einwandfrei, aber ich denke, wenn Wordpress Beiträge speichert, wird die zusätzliche Umleitung eingeführt. Kann ich etwas tun, um sicherzustellen, dass dies immer funktioniert? Ich dachte, ich könnte etwas in printMessages () überprüfen und sofort zurückkehren, wenn es bei Schritt 4 ist, aber ich bin nicht sicher, was.

Diese beiden Fragen geben möglicherweise Aufschluss über das Problem, geben jedoch keine vollständige Lösung: Validierung und Fehlerbehandlung beim Speichern benutzerdefinierter Felder hinzufügen? , Wie zeige ich einen Administratorfehler an, wenn die Einstellungen erfolgreich gespeichert wurden? .

Hier ist der 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: Der aktualisierte Code mit der akzeptierten Antwort wurde in die Datei core.php im trunk des Plugins geschrieben, falls jemand eine vollständige Arbeitskopie sehen möchte. Die nächste stabile Version die es haben wird ist 1.2.

Update 2: Ich habe diese Funktionalität in eine eigenständige Bibliothek abstrahiert, die Sie in Ihr Plugin aufnehmen können. Core diskutiert die Aufnahme ähnlicher Funktionen in # 11515 .

4
Ian Dunn

Es gibt einige Dinge, auf die ich auch im folgenden Code hingewiesen habe:

  1. Sie haben die aus get_option gelesenen Optionen mit array_merge überschrieben.
  2. Sie haben die Anzahl der Nachrichten fest programmiert.
  3. das Speichern von Optionen in __destruct funktioniert einfach nicht. (Ich habe noch keine Ahnung, vielleicht werden Experten etwas Licht ins Dunkel bringen.

Ich habe alle Abschnitte, in denen ich die Änderungen vorgenommen habe, mitHKFIXmarkiert, mit ein bisschen Beschreibung:

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

Ich habe momentan keine Ahnung, was mit deinem Plugin los ist, also weise ich dich auf zwei Dinge hin:

wp_parse_args() ist eine gute Möglichkeit, Standardwerte mit anderen Argumenten zusammenzuführen.

private $defaults;

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

Und dieses Plugin ist ein bisschen näher dran, wie der Kern mit Fehlern umgeht (direkt aus meinem Kopf - kann selbst Fehler enthalten):

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

Versuche es. :)

0
kaiser