Cómo agregar un aviso de administrador al guardar / actualizar la publicación

16

Tengo un tipo de publicación que utiliza post_save para tomar la dirección del postmeta y recuperar las coordenadas lat / lng de la API de Google. Necesito una forma de notificar al usuario si hubo un problema con la recuperación de las coordenadas. Intenté usar admin_notices, pero no se muestra nada:

public static function update_notice() {
  echo "<div class='error'><p>Failed to retrieve coordinates. Please check key and address.<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 incorrecto. Para ser claros, en el código real, add_action está en otra función en la misma clase. Eso está funcionando bien.

Jason
fuente
Desarrollé una secuencia de comandos que le permite agregar fácilmente notificaciones de administrador descartables / estáticas github.com/askupasoftware/wp-admin-notification
Yoav Kadosh

Respuestas:

30

La razón por la que esto no funciona es porque ocurre una redirección después de la acción save_post. Una forma en que puede lograr lo que desea es mediante la implementación de una solución rápida utilizando vars de consulta.

Aquí hay una clase de muestra para demostrar:

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 ) {
   // Do you stuff here
   // ...

   // Add your query var if the coordinates are not retreive correctly.
   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( 'YOUR MESSAGE', 'text-domain' ); ?></p>
   </div>
   <?php
  }
}

Espero que esto te ayude un poco. Salud

jonathanbardo
fuente
Funciona muy bien, gracias! Pero falta un corchete de cierre en la primera línea del public function admin_notices()(un corchete de cierre adicional en la if ( ! isset(..línea)
Rhys Wynne
Agregué remove_query_arg('YOUR_QUERY_VAR');que encontré que se puede configurar desde la última actualización.
Tony O'Hagan
+1 Buena respuesta.
Mark
12

Hizo una clase de envoltura para este tipo de escenario. En realidad, la clase se puede usar en cualquier escenario que implique mostrar avisos. Utilizo los estándares PSR, por lo que la denominación es atí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(__('An error occurred, check logs.'));

El aviso se muestra una vez.

Neurona Oscura
fuente
6

Además de la respuesta de @ jonathanbardo, que es excelente y funciona bien, si desea eliminar el argumento de consulta después de cargar la nueva página, puede usar el filtro removable_query_args . Obtiene una serie de nombres de argumentos a los que puede agregar su propio argumento. Luego, WP 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á:

'...post.php?post=1'
AncientRo
fuente
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 su controlador de solicitud de publicación:

wpse152033_set_admin_notice(get_current_user_id(), 'Hello world', 'error');
wp_redirect(add_query_arg('settings-updated', 'true',  wp_get_referer()));

Donde desea utilizar el aviso de administrador, generalmente en el admin_noticesgancho.

$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>';
}
Fleuv
fuente