Cómo agregar una notificación de administrador al guardar/actualizar una entrada
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.

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

¡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(..
)

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

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.

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'

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>';
}

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

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'.

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