Как добавить уведомление администратора при сохранении/обновлении записи
У меня есть тип записи, который использует post_save для получения адреса из post-meta и извлечения координат lat/lng из Google API. Мне нужен способ уведомить пользователя, если возникла проблема с получением координат. Я пытался использовать admin_notices, но ничего не отображалось:
public static function update_notice() {
echo "<div class='error'><p>Не удалось получить координаты. Пожалуйста, проверьте ключ и адрес.<p></div>";
remove_action('admin_notices', 'update_notice');
}
add_action('admin_notices', array('GeoPost', 'update_notice'));
Я не уверен, правильно ли я его использую или в неправильном контексте. Если быть точным, в реальном коде add_action находится в другой функции того же класса. Это работает нормально.

Причина, по которой это не работает, заключается в том, что после действия save_post происходит перенаправление. Один из способов добиться желаемого - использовать временное решение с помощью query vars.
Вот пример класса для демонстрации:
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 ) {
// Здесь выполните необходимые действия
// ...
// Добавьте ваш query var, если координаты не были получены корректно
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( 'ВАШЕ СООБЩЕНИЕ', 'text-domain' ); ?></p>
</div>
<?php
}
}
Надеюсь, это немного поможет вам. Удачи!

Работает отлично, спасибо! Но в первой строке в public function admin_notices()
отсутствует закрывающая скобка (лишняя закрывающая скобка в строке if ( ! isset(..
)

Я добавил remove_query_arg('YOUR_QUERY_VAR');
, так как обнаружил, что это может быть установлено с последнего обновления.

Создал класс-обертку для такого сценария. На самом деле, этот класс можно использовать в любом случае, связанном с отображением уведомлений. Я использую стандарты PSR, поэтому именование нетипично для кода 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
]);
}
}
Использование:
add_action('admin_notices', [new AdminNotice(), 'displayAdminNotice']);
AdminNotice::displayError(__('Произошла ошибка, проверьте логи.'));
Уведомление отображается один раз.

В дополнение к ответу @jonathanbardo, который отлично работает, если вы хотите удалить аргумент запроса после загрузки новой страницы, вы можете использовать фильтр removable_query_args. Вы получаете массив имен аргументов, к которому можете добавить свой собственный аргумент. Затем WordPress позаботится об удалении всех аргументов из списка из 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;
}
Например:
'...post.php?post=1&my-query-arg=10'
Превратится в:
'...post.php?post=1'

Простое и элегантное решение на основе 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;
}
Использование
В обработчике POST-запроса:
wpse152033_set_admin_notice(get_current_user_id(), 'Привет, мир', 'error');
wp_redirect(add_query_arg('settings-updated', 'true', wp_get_referer()));
Где вы хотите использовать уведомление администратора, обычно в хуке 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>';
}

Это очень хорошая реализация, респект вам, уважаемый. Имеет ли смысл убрать строку wp_redirect... и просто добавить третий элемент в массив транзиента, используя nonce для дополнительной безопасности? Транзиент вернет ничего, если он не установлен, этого будет достаточно, чтобы выйти из условия if в get_admin_notice, не так ли?

Я сделал этот gist на случай, если кому-то пригодится: https://gist.github.com/csaborio001/d5a8fa84fba3ff4ff22d43f64179feba Для использования просто AdminNotice::display_admin_message( 'сообщение', 'статус'), и вам нужно будет подключить process_messages к хуку 'admin_notices'.

Вы можете добиться этого, выполнив переадресацию и передав аргументы запроса с помощью фильтра redirect_post_location
. Также есть redirect_term_location
, который работает для таксономий/терминов.
Сначала добавьте действие admin_notices
, которое всегда будет активным, но будет показывать уведомление только при определенных условиях.
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'])) {
// Преобразуем строку в массив, чтобы можно было перебирать элементы
$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 'не заполнены данные по питательным веществам.</p>
</div>';
}
}
}
Затем вам нужно выполнить переадресацию страницы после сохранения и передать аргумент запроса с помощью add_query_arg
. В моем примере реализован динамический ввод, который отображается в административном уведомлении.
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 );
});
}
В моем случае я использую array_push
для переменной $empty_error
с ID термина. Административное уведомление затем покажет все термины, в которых возникла ошибка, со ссылкой на соответствующий термин.
Вы также можете использовать removable_query_args
для удаления добавленных аргументов запроса, чтобы URL выглядел чище. Административное уведомление исчезнет при перезагрузке страницы.
add_filter('removable_query_args', 'add_removable_arg');
function add_removable_arg($args) {
array_push($args, 'empty');
return $args;
}
