Pasar mensajes de error / advertencia de un cuadro de meta a "admin_notices"

20

Tengo un cuadro meta simple que actualiza los campos personalizados de publicación (usando update_post_meta() ).

¿Cómo puedo enviar un mensaje de error o advertencia a la página siguiente después de que el usuario publique / actualice la publicación y no complete uno de los campos del cuadro meta (o los complete con datos no válidos)?

Pony de un solo truco
fuente

Respuestas:

9

Puede hacerlo a mano, pero WP lo hace de forma nativa para errores de configuración:

  1. add_settings_error() para crear un mensaje
  2. Luego set_transient('settings_errors', get_settings_errors(), 30);
  3. settings_errors()en el admin_noticesteléfono para que aparezca (de conexión en la configuración para los no-pantallas).
Rarst
fuente
hace lo que quiero, pero ¿no llenaría esto la base de datos con toneladas de transitorios?
onetrickpony
@ One Trick Pony en el proceso nativo transitorio se elimina explícitamente (ver get_settings_errors()fuente). Es posible que deba hacerlo usted mismo si está adaptando la lógica para la página sin configuración.
Rarst
2
Todavía no me gusta la idea de almacenar mensajes de error temporales en la base de datos.
Usaré
Con el almacenamiento en caché de objetos, el desorden de la base de datos no sería un problema.
lkraav
15

puedes usar admin_noticesgancho

Primero defina la función de aviso:

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 función de guardado de metabox en función de si es necesario agrega:

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

Actualizar

Como prometí aquí, hay un ejemplo de cómo agrego un mensaje de error desde mi 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);
  }

}

Ahora, al buscar este código, encontré mi antigua forma de hacerlo usando el post_updated_messagesgancho de filtro de la misma manera, así que también lo agregaré:

<?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
fuente
no funciona muy bien porque después de guardar el mensaje, es redireccionado por lo que la acción nunca se queda ...
onetrickpony
1
Redirigido a dónde? Y el código anterior es lo que uso, así que sé que funciona.
Bainternet
¿está conectada su función de guardar metabox save_post?
onetrickpony
1
gracias, pero esto hace lo mismo que Rarst señaló: el mensaje de error se guarda en la base de datos y luego se recupera y elimina en la página siguiente.
onetrickpony
1
-1 por usar un DB. No puede garantizar que el usuario correcto verá el error. Además, no vale la pena la sobrecarga innecesaria. Para no tener una forma clara de manejar los errores de metabox, esta es una buena solución, pero aún no es eficiente. Agregué un ejemplo de la forma en que hago esto en una nueva respuesta para ayudar a otros.
Jeremy
11

Esta respuesta [ espejo ] de Otto en WP Tavern, en realidad resuelve el problema transitorio haciendo lo que hace WordPress para superar el problema de redireccionamiento. Totalmente trabajado para mi.

El problema es que los transitorios están ahí para todos. Si tiene más de un usuario haciendo cosas al mismo tiempo, el mensaje de error puede ir a la persona equivocada. Es una condición de carrera.

WordPress realmente hace esto al pasar un parámetro de mensaje en la URL. El número de mensaje indica qué mensaje mostrar.

Puede hacer lo mismo conectando el redirect_post_locationfiltro y luego usando add_query_argpara agregar su propio parámetro a la solicitud. Al igual que:

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

Esto se suma my_message=123a la consulta. Luego, después de la redirección, puede detectar la configuración de my_message en el $_GETy mostrar el mensaje adecuado en consecuencia.

Ana Ban
fuente
3

Sé que esta pregunta es antigua, pero encuentro las respuestas aquí para no resolver el problema.

Extendiendo la respuesta de Ana Ban, usando el método de Otto , encontré que este es el mejor método para manejar errores. Esto no requiere almacenar los errores en la base de datos.

Incluí una versión simplificada de un objeto Metabox que uso. Esto me permite agregar fácilmente nuevos mensajes de error y garantizar que el usuario correcto vea el mensaje de error (usando el db, esto no es una garantía).

<?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
fuente
El único problema que tengo con esta respuesta es que no funciona con PHP 5.2. No digo que todos debamos admitir HPP 5.2, pero hasta que WordPress tenga PHP 5.2 como requisito mínimo, debemos admitirlo si estamos distribuyendo el complemento :(
Sudar
1
Si eliminó la función anónima y la convierte en un método público, debería funcionar bien. Entiendo su problema, pero personalmente no desarrollaré para una versión EOL de PHP ( php.net/eol.php ) 5.2 EOL fue el 6 de enero de 2011. WordPress debería hacer un mayor esfuerzo para no admitir versiones EOL, pero esa es otra historia además de muchas malas empresas de alojamiento que todavía proporcionan versiones EOL ...
Jeremy