Cómo agregar una notificación de administrador al guardar/actualizar una entrada

27 jun 2014, 19:37:51
Vistas: 31.3K
Votos: 29

Tengo un tipo de entrada que usa post_save para tomar la dirección desde los meta-datos y obtener las coordenadas lat/lng desde la API de Google. Necesito una forma de notificar al usuario si hubo un problema al obtener las coordenadas. Intenté usar admin_notices, pero no se mostró nada:

public static function update_notice() {
  echo "<div class='error'><p>Error al obtener las coordenadas. Por favor verifique la clave y la dirección.<p></div>";
  remove_action('admin_notices', 'update_notice');
}

add_action('admin_notices', array('GeoPost', 'update_notice'));

No estoy seguro si lo estoy usando incorrectamente o en el contexto equivocado. Para aclarar, en el código real el add_action está en otra función dentro de la misma clase. Eso está funcionando bien.

1
Comentarios

He desarrollado un script que te permite añadir notificaciones administrativas descartables/estáticas fácilmente https://github.com/askupasoftware/wp-admin-notification

Yoav Kadosh Yoav Kadosh
25 jul 2016 17:51:29
Todas las respuestas a la pregunta 5
3
42

La razón por la que esto no funciona es porque hay una redirección que ocurre después de la acción save_post. Una forma de lograr lo que deseas es implementando una solución rápida utilizando variables de consulta.

Aquí tienes una clase de ejemplo para demostrarlo:

class My_Awesome_Plugin {
  public function __construct(){
   add_action( 'save_post', array( $this, 'save_post' ) );
   add_action( 'admin_notices', array( $this, 'admin_notices' ) );
  }

  public function save_post( $post_id, $post, $update ) {
   // Haz tus cosas aquí
   // ...

   // Añade tu variable de consulta si las coordenadas no se recuperan correctamente.
   add_filter( 'redirect_post_location', array( $this, 'add_notice_query_var' ), 99 );
  }

  public function add_notice_query_var( $location ) {
   remove_filter( 'redirect_post_location', array( $this, 'add_notice_query_var' ), 99 );
   return add_query_arg( array( 'YOUR_QUERY_VAR' => 'ID' ), $location );
  }

  public function admin_notices() {
   if ( ! isset( $_GET['YOUR_QUERY_VAR'] ) ) {
     return;
   }
   ?>
   <div class="updated">
      <p><?php esc_html_e( 'TU MENSAJE', 'text-domain' ); ?></p>
   </div>
   <?php
  }
}

Espero que esto te ayude un poco. Saludos

27 jun 2014 22:47:34
Comentarios

¡Funciona genial, gracias! Pero falta un corchete de cierre en la primera línea de la public function admin_notices() (un corchete de cierre extra en la línea if ( ! isset(..)

Rhys Wynne Rhys Wynne
28 ene 2015 18:04:12

He añadido remove_query_arg('YOUR_QUERY_VAR'); ya que descubrí que puede estar configurado desde la última actualización.

Tony O'Hagan Tony O'Hagan
6 jul 2018 11:12:29

+1 Buena respuesta.

Mark Mark
7 ago 2018 10:35:53
1
15

Creé una clase envoltorio para este tipo de escenario. En realidad, la clase puede usarse en cualquier situación que involucre mostrar notificaciones. Utilizo los estándares PSR, por lo que la nomenclatura no es típica del código de WordPress.

class AdminNotice
{
    const NOTICE_FIELD = 'my_admin_notice_message';

    public function displayAdminNotice()
    {
        $option      = get_option(self::NOTICE_FIELD);
        $message     = isset($option['message']) ? $option['message'] : false;
        $noticeLevel = ! empty($option['notice-level']) ? $option['notice-level'] : 'notice-error';

        if ($message) {
            echo "<div class='notice {$noticeLevel} is-dismissible'><p>{$message}</p></div>";
            delete_option(self::NOTICE_FIELD);
        }
    }

    public static function displayError($message)
    {
        self::updateOption($message, 'notice-error');
    }

    public static function displayWarning($message)
    {
        self::updateOption($message, 'notice-warning');
    }

    public static function displayInfo($message)
    {
        self::updateOption($message, 'notice-info');
    }

    public static function displaySuccess($message)
    {
        self::updateOption($message, 'notice-success');
    }

    protected static function updateOption($message, $noticeLevel) {
        update_option(self::NOTICE_FIELD, [
            'message' => $message,
            'notice-level' => $noticeLevel
        ]);
    }
}

Uso:

add_action('admin_notices', [new AdminNotice(), 'displayAdminNotice']);
AdminNotice::displayError(__('Ocurrió un error, revisa los registros.'));

La notificación se muestra una sola vez.

29 mar 2016 20:01:13
Comentarios

¡Gracias, funciona de maravilla!

JorensM JorensM
10 mar 2023 11:54:00
0

Además de la respuesta de @jonathanbardo que es excelente y funciona bien, si deseas eliminar el argumento de consulta después de que se cargue la nueva página, puedes usar el filtro removable_query_args. Obtienes un array de nombres de argumentos a los que puedes agregar el tuyo. Luego WordPress se encargará de eliminar todos los argumentos de la lista de la URL.

public function __construct() {
    ...
    add_filter('removable_query_args', array($this, 'add_removable_arg'));
}

public function add_removable_arg($args) {
    array_push($args, 'my-query-arg');
    return $args;
}

Algo como:

'...post.php?post=1&my-query-arg=10'

Se convertirá en:

'...post.php?post=1'
20 mar 2017 23:20:23
2

Simple, elegante, basado en get_settings_errors().

function wpse152033_set_admin_notice($id, $message, $status = 'success') {
    set_transient('wpse152033' . '_' . $id, [
        'message' => $message,
        'status' => $status
    ], 30);
}

function wpse152033_get_admin_notice($id) {
    $transient = get_transient( 'wpse152033' . '_' . $id );
    if ( isset( $_GET['settings-updated'] ) && $_GET['settings-updated'] && $transient ) {
        delete_transient( 'wpse152033' . '_' . $id );
    }
    return $transient;
}

Uso

En tu manejador de solicitud POST:

wpse152033_set_admin_notice(get_current_user_id(), 'Hola mundo', 'error');
wp_redirect(add_query_arg('settings-updated', 'true',  wp_get_referer()));

Donde quieras usar el aviso de administración, usualmente en el hook admin_notices.

$notice = $this->get_admin_notice(get_current_user_id());
if (!empty($notice) && is_array($notice)) {
    $status = array_key_exists('status', $notice) ? $notice['status'] : 'success';
    $message = array_key_exists('message', $notice) ? $notice['message'] : '';
    print '<div class="notice notice-'.$status.' is-dismissible">'.$message.'</div>';
}
9 ene 2019 10:37:36
Comentarios

Esta es una implementación muy buena, felicitaciones a usted, amable señor. ¿Tendría sentido eliminar la línea wp_redirect... y simplemente agregar un tercer elemento al array transitorio usando un nonce para mayor seguridad? El transitorio no devolverá nada si no está configurado, eso sería suficiente para salir de la declaración if en get_admin_notice, ¿no es así?

csaborio csaborio
23 may 2021 06:58:47

Hice este gist por si a alguien le sirve: https://gist.github.com/csaborio001/d5a8fa84fba3ff4ff22d43f64179feba Para usarlo, simplemente AdminNotice::display_admin_message( 'mensaje', 'estado'), y necesitarías enganchar el process_messages con el hook 'admin_notices'.

csaborio csaborio
23 may 2021 07:20:30
0

Puedes lograr esto haciendo una redirección y pasando argumentos de consulta con el filtro redirect_post_location. También existe redirect_term_location que funcionará para taxonomías/términos.

Primero agrega la acción admin_notices que siempre estará activa, pero solo mostrará el aviso bajo ciertas condiciones.

add_action( 'admin_notices', 'general_admin_notice' );

function general_admin_notice(){
  global $pagenow;

  if ( 'post.php' === $pagenow && isset($_GET['post']) && 'custom_post_type' === get_post_type( $_GET['post'] ) ){

    if ( isset($_GET['empty'])) {
      
      // Convertir cadena en array para poder iterar
      $terms_id = explode( ',', $_GET['empty'] );

      echo '<div class="notice notice-error is-dismissible">
                <p>';
                foreach ( $terms_id as $term_id ) {
                  $term = get_term( $term_id, 'custom_taxonomy' );
                  echo '<a href="'.get_term_link( $term ).'">'.$term->name.'</a>, ';
                }
              echo 'los nutrientes están vacíos.</p>
            </div>';
      }
    }
}

Luego necesitas redirigir la página después de guardar y pasar un argumento de consulta con add_query_arg. De la forma en que lo he hecho aquí puedes tener una entrada dinámica que se muestra en el aviso del administrador.

        if ( !empty($empty_error) ) {
            add_filter('redirect_post_location', function($loc) use ($empty_error) {
                trigger_error( $empty_error);
                return add_query_arg( 'empty', implode(',', $empty_error), $loc );
            }); 
        }

En mi caso hago un array_push en la variable $empty_error con un ID de término. El aviso del administrador mostrará entonces todos los términos que tienen un error con un enlace al término respectivo.

También puedes usar removable_query_args para eliminar los argumentos de consulta añadidos, así la URL se ve más limpia. El aviso del administrador desaparecerá si recargas la página.

add_filter('removable_query_args', 'add_removable_arg');

function add_removable_arg($args) {
    array_push($args, 'empty');
    return $args;
}
16 abr 2021 16:29:44