Passer des messages d'erreur / d'avertissement d'une méta-boîte à "admin_notices"

20

J'ai une simple meta box qui met à jour les champs post personnalisés (en utilisant update_post_meta()).

Comment puis-je envoyer un message d'erreur ou d'avertissement à la page suivante après que l'utilisateur a publié / mis à jour le message et ne remplit pas l'un des champs de la méta-boîte (ou les remplit avec des données non valides)?

onetrickpony
la source

Réponses:

9

Vous pouvez le faire à la main, mais WP le fait nativement comme ceci pour les erreurs de paramètres:

  1. add_settings_error() pour créer un message.
  2. alors set_transient('settings_errors', get_settings_errors(), 30);
  3. settings_errors()en admin_noticescrochet pour afficher (il faudra accrocher pour les écrans sans paramètres).
Rarst
la source
il fait ce que je veux, mais cela ne remplirait-il pas la base de données avec des tonnes de transitoires?
onetrickpony
@One Trick Pony en transitoire de processus natif est explicitement supprimé (voir get_settings_errors()source). Vous devrez peut-être le faire vous-même si vous adaptez la logique à une page sans paramètres.
Rarst
2
je n'aime toujours pas l'idée de stocker des messages d'erreur temporaires dans la base de données. Je vais utiliser ajax pour avertir l'utilisateur du changement d'entrée
onetrickpony
Avec la mise en cache d'objets, l'encombrement de la base de données ne serait pas un problème.
lkraav
15

vous pouvez utiliser le admin_noticescrochet

définissez d'abord la fonction d'avis:

function my_admin_notice(){
    //print the message
    echo '<div id="message">
       <p>metabox as errors on save message here!!!</p>
    </div>';
    //make sure to remove notice after its displayed so its only displayed when needed.
    remove_action('admin_notices', 'my_admin_notice');
}

La fonction de sauvegarde de vous vous metabox basée sur si nécessaire ajouter:

...
...
if($errors){
    add_action('admin_notices', 'my_admin_notice');
}
...
...

Mise à jour

Comme je l'ai promis, voici un exemple de la façon dont j'ajoute un message d'erreur depuis ma metabox

<?php
/*
Plugin Name: one-trick-pony-notice
Plugin URI: http://en.bainternet.info
Description: Just to proof a point using admin notice form metabox
Version: 1.0
Author: Bainternet
Author URI: http://en.bainternet.info
*/

/*  admin notice */
function my_admin_notice(){
    //print the message
    global $post;
    $notice = get_option('otp_notice');
    if (empty($notice)) return '';
    foreach($notice as $pid => $m){
        if ($post->ID == $pid ){
            echo '<div id="message" class="error"><p>'.$m.'</p></div>';
            //make sure to remove notice after its displayed so its only displayed when needed.
            unset($notice[$pid]);
            update_option('otp_notice',$notice);
            break;
        }
    }
}

//hooks

add_action('add_meta_boxes', 'OT_mt_add');
add_action('save_post', 'OT_mt_save');
add_action('admin_notices', 'my_admin_notice',0);

//add metabox
function OT_mt_add() {
    add_meta_box('OT_mt_sectionid', __( 'One Trick Meta Box notice', 'textdomain' ),'OT_mt_display','post');
}

//display metabox
function OT_mt_display() {

  // Use nonce for verification
  wp_nonce_field( plugin_basename(__FILE__), 'myplugin_noncename' );

  // The actual fields for data entry
  echo '<label for="myplugin_new_field">';
       _e("leave blank to get a notice on publish or update", 'textdomain' );
  echo '</label> ';
  echo '<input type="text" id="ot_field" name="ot_field" value="" size="25" />';

}


//save metabox here is were i check the fields and if empty i display a message
function OT_mt_save( $post_id ) {

  // verify this came from the our screen and with proper authorization,
  // because save_post can be triggered at other times
    if (!isset($_POST['myplugin_noncename'])) return $post_id;
  if ( !wp_verify_nonce( $_POST['myplugin_noncename'], plugin_basename(__FILE__) ) )
      return $post_id;

  // verify if this is an auto save routine. 
  // If it is our form has not been submitted, so we dont want to do anything
  if ( defined('DOING_AUTOSAVE') && DOING_AUTOSAVE ) 
      return $post_id;


  if(!isset($_POST['ot_field']) || empty($_POST['ot_field'])){
    //field left empty so we add a notice
    $notice = get_option('otp_notice');
    $notice[$post_id] = "You have left the field empty";
    update_option('otp_notice',$notice);
  }

}

Maintenant, en cherchant ce code, j'ai trouvé mon ancienne façon de le faire en utilisant le post_updated_messagescrochet de filtre à peu près de la même manière, donc j'ajouterai cela aussi:

<?php
/*
Plugin Name: one-trick-pony-notice2
Plugin URI: http://en.bainternet.info
Description: just like the one above but this time using post_updated_messages hook
Version: 1.0
Author: Bainternet
Author URI: http://en.bainternet.info
*/

//hooks
add_filter('post_updated_messages','my_messages',0);
add_action('add_meta_boxes', 'OT_mt_add');
add_action('save_post', 'OT_mt_save');


//add metabox
function OT_mt_add() {
    add_meta_box('OT_mt_sectionid', __( 'One Trick Meta Box notice', 'textdomain' ),'OT_mt_display','post');
}

//display metabox
function OT_mt_display() {

  // Use nonce for verification
  wp_nonce_field( plugin_basename(__FILE__), 'myplugin_noncename' );

  // The actual fields for data entry
  echo '<label for="myplugin_new_field">';
       _e("leave blank to get a notice on publish or update", 'textdomain' );
  echo '</label> ';
  echo '<input type="text" id="ot_field" name="ot_field" value="" size="25" />';

}


//save metabox here is were i check the fields and if empty i display a message
function OT_mt_save( $post_id ) {

  // verify this came from the our screen and with proper authorization,
  // because save_post can be triggered at other times
    if (!isset($_POST['myplugin_noncename'])) return $post_id;
  if ( !wp_verify_nonce( $_POST['myplugin_noncename'], plugin_basename(__FILE__) ) )
      return $post_id;

  // verify if this is an auto save routine. 
  // If it is our form has not been submitted, so we dont want to do anything
  if ( defined('DOING_AUTOSAVE') && DOING_AUTOSAVE ) 
      return $post_id;


  if(!isset($_POST['ot_field']) || empty($_POST['ot_field'])){
    //field left empty so we add a notice
    $notice = get_option('otp_notice');
    $notice[$post_id] = "You have left the field empty";
    update_option('otp_notice',$notice);
  }

}

//messages filter
function my_messages($m){
    global $post;
    $notice = get_option('otp_notice');
    if (empty($notice)) return $m;
    foreach($notice as $pid => $mm){
        if ($post->ID == $pid ){
            foreach ($m['post'] as $i => $message){
                $m['post'][$i] = $message.'<p>'.$mm.'</p>';

            }
            unset($notice[$pid]);
            update_option('otp_notice',$notice);
            break;
        }
    }
    return $m;
}
Bainternet
la source
ne fonctionne pas vraiment parce qu'après avoir enregistré le message, vous êtes redirigé pour que l'action ne s'exécute jamais ...
onetrickpony
1
Redirigé où? Et le code ci-dessus est ce que j'utilise donc je sais que cela fonctionne.
Bainternet
votre fonction de sauvegarde metabox est-elle accrochée save_post?
onetrickpony
1
merci, mais cela fait la même chose que Rarst a souligné: le message d'erreur est enregistré dans la base de données, puis récupéré et supprimé sur la page suivante.
onetrickpony
1
-1 pour l'utilisation d'une base de données. Vous ne pouvez pas garantir que l'utilisateur correct verra l'erreur. De plus, cela ne vaut pas les frais généraux inutiles. Pour ne pas avoir de méthode claire pour gérer les erreurs de métabox, c'est un bon travail, mais toujours pas efficace. J'ai ajouté un exemple de la façon dont je fais cela dans une nouvelle réponse pour aider les autres.
Jeremy
11

Cette réponse [ miroir ] d'Otto dans WP Tavern, résout en fait le problème transitoire en faisant ce que WordPress lui-même fait pour surmonter le problème de redirection. Totalement travaillé pour moi.

Le problème est que les transitoires sont là pour tout le monde. Si plus d'un utilisateur fait des choses en même temps, le message d'erreur peut aller à la mauvaise personne. C'est une condition de course.

WordPress fait cela en passant un paramètre de message dans l'URL. Le numéro de message indique le message à afficher.

Vous pouvez faire de même en accrochant le redirect_post_locationfiltre, puis en utilisant add_query_argpour ajouter votre propre paramètre à la demande. Ainsi:

add_filter('redirect_post_location','my_message');
function my_message($loc) {
 return add_query_arg( 'my_message', 123, $loc );
}

Cela ajoute my_message=123à la requête. Ensuite, après la redirection, vous pouvez détecter le paramètre my_message dans le $_GETet afficher le message approprié en conséquence.

Ana Ban
la source
3

Je sais que cette question est ancienne mais je trouve les réponses ici pour ne pas résoudre le problème.

En prolongeant la réponse d'Ana Ban, en utilisant la méthode d'Otto , j'ai trouvé que c'était la meilleure méthode pour gérer les erreurs. Cela ne nécessite pas de stocker les erreurs dans la base de données.

J'ai inclus une version allégée d'un objet Metabox que j'utilise. Cela me permet d'ajouter facilement de nouveaux messages d'erreur et de garantir que l'utilisateur correct voit le message d'erreur (en utilisant la base de données, ce n'est pas une garantie).

<?php
/**
 * Class MetaboxExample
 */
class MetaboxExample {

    /**
     * Defines the whitelist for allowed screens (post_types)
     */
    private $_allowedScreens = array( 'SCREENS_TO_ALLOW_METABOX' );

    /**
     * Get parameter for the error box error code
     */
    const GET_METABOX_ERROR_PARAM = 'meta-error';

    /**
     * Defines admin hooks
     */
    public function __construct() {
        add_action('add_meta_boxes', array($this, 'addMetabox'), 50);
        add_action('save_post', array($this, 'saveMetabox'), 50);
        add_action('edit_form_top', array($this, 'adminNotices')); // NOTE: admin_notices doesn't position this right on custom post type pages, haven't testes this on POST or PAGE but I don't see this an issue
    }

    /**
     * Adds the metabox to specified post types
     */
    public function addMetabox() {
        foreach ( $this->_allowedScreens as $screen ) {
            add_meta_box(
                'PLUGIN_METABOX',
                __( 'TITLE', 'text_domain' ),
                array($this, 'metaBox'),
                $screen,
                'side',
                'high'
            );
        }
    }

    /**
     * Output metabox content
     * @param $post
     */
    public function metaBox($post) {
        // Add an nonce field so we can check for it later.
        wp_nonce_field( 'metaboxnonce', 'metaboxnonce' );
        // Load meta data for this metabox
        $someValue = get_post_meta( $post->ID, 'META_KEY_IDENTIFIER', true );
        ?>
        <p>
            <label for="some-value" style="width: 120px; display: inline-block;">
                <?php _e( 'Some Field:', 'text_domain' ); ?>
            </label>
            &nbsp;
            <input type="text" id="some-value" name="some_value" value="<?php esc_attr_e( $someValue ); ?>" size="25" />
        </p>
    <?php
    }

    /**
     * Save method for the metabox
     * @param $post_id
     */
    public function saveMetabox($post_id) {
        global $wpdb;

        // Check if our nonce is set.
        if ( ! isset( $_POST['metaboxnonce'] ) ) {
            return $post_id;
        }
        // Verify that the nonce is valid.
        if ( ! wp_verify_nonce( $_POST['metaboxnonce'], 'metaboxnonce' ) ) {
            return $post_id;
        }
        // If this is an autosave, our form has not been submitted, so we don't want to do anything.
        if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) {
            return $post_id;
        }
        // Check the user's permissions.
        if ( isset( $_POST['post_type'] ) && 'page' == $_POST['post_type'] ) {
            if ( ! current_user_can( 'edit_page', $post_id ) ) {
                return $post_id;
            }
        } else {
            if ( ! current_user_can( 'edit_post', $post_id ) ) {
                return $post_id;
            }
        }
        // Make sure that it is set.
        if ( !isset( $_POST['some_value'] ) ) {
            return $post_id;
        }
        // Sanitize user input.
        $someValue = sanitize_text_field( $_POST['some_value'] );
        // Check to make sure there is a value
        if (empty($someValue)) {
            // Add our error code
            add_filter('redirect_post_location', function($loc) {
                return add_query_arg( self::GET_METABOX_ERROR_PARAM, 1, $loc );
            });
            return $post_id; // make sure to return so we don't allow further processing
        }
        // Update the meta field in the database.
        update_post_meta( $post_id, 'META_KEY_IDENTIFIER', $someValue );
    }

    /**
     * Metabox admin notices
     */
    public function adminNotices() {
        if (isset($_GET[self::GET_METABOX_ERROR_PARAM])) {
            $screen = get_current_screen();
            // Make sure we are in the proper post type
            if (in_array($screen->post_type, $this->_allowedScreens)) {
                $errorCode = (int) $_GET[self::GET_METABOX_ERROR_PARAM];
                switch($errorCode) {
                    case 1:
                        $this->_showAdminNotice( __('Some error happened', 'text_domain') );
                        break;
                    // More error codes go here for outputting errors
                }
            }
        }
    }

    /**
     * Shows the admin notice for the metabox
     * @param $message
     * @param string $type
     */
    private function _showAdminNotice($message, $type='error') {
        ?>
        <div class="<?php esc_attr_e($type); ?> below-h2">
            <p><?php echo $message; ?></p>
        </div>
    <?php
    }

}
Jeremy
la source
Le seul problème que j'ai avec cette réponse est qu'elle ne fonctionne pas avec PHP 5.2. Je ne dis pas que nous devrions tous prendre en charge HPP 5.2, mais jusqu'à ce que WordPress ait PHP 5.2 comme exigence minimale, nous devons le prendre en charge si nous distribuons le plugin :(
Sudar
1
Si vous avez supprimé la fonction anonyme et en avez fait une méthode publique, cela devrait fonctionner correctement. Je comprends votre problème, mais je ne développerai pas personnellement une version EOL de PHP ( php.net/eol.php ) 5.2 EOL était le 6 janvier 2011. WordPress devrait faire plus d'efforts pour ne pas prendre en charge les versions EOL mais c'est une autre histoire ainsi que de nombreuses mauvaises sociétés d'hébergement qui fournissaient toujours des versions EOL ...
Jeremy