Transmiterea mesajelor de eroare/avertisment de la o meta box la "admin_notices"
Am o meta box simplă care actualizează câmpurile personalizate ale postării (folosind update_post_meta()
).
Cum pot trimite un mesaj de eroare sau avertisment către pagina următoare după ce utilizatorul publică/actualizează postarea și nu completează unul dintre câmpurile meta box (sau le completează cu date invalide)?

poți folosi hook-ul admin_notices
mai întâi definește funcția pentru notificare:
function my_admin_notice(){
//afișează mesajul
echo '<div id="message">
<p>metabox ca erori la salvarea mesajului aici!!!</p>
</div>';
//asigură-te că elimini notificarea după afișare, astfel încât să fie afișată doar când este necesar.
remove_action('admin_notices', 'my_admin_notice');
}
Apoi în funcția de salvare a metabox-ului, în funcție de nevoie, adaugă:
...
...
if($errors){
add_action('admin_notices', 'my_admin_notice');
}
...
...
Actualizare
După cum am promis, iată un exemplu despre cum adaug un mesaj de eroare pentru metabox-ul meu
<?php
/*
Plugin Name: one-trick-pony-notice
Plugin URI: http://en.bainternet.info
Description: Doar pentru a demonstra un punct folosind notificarea admin din metabox
Version: 1.0
Author: Bainternet
Author URI: http://en.bainternet.info
*/
/* notificare admin */
function my_admin_notice(){
//afișează mesajul
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>';
//asigură-te că elimini notificarea după afișare, astfel încât să fie afișată doar când este necesar.
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);
//adaugă metabox
function OT_mt_add() {
add_meta_box('OT_mt_sectionid', __( 'Notificare Metabox One Trick', 'textdomain' ),'OT_mt_display','post');
}
//afișează metabox
function OT_mt_display() {
// Folosește nonce pentru verificare
wp_nonce_field( plugin_basename(__FILE__), 'myplugin_noncename' );
// Câmpurile efective pentru introducerea datelor
echo '<label for="myplugin_new_field">';
_e("lasă gol pentru a primi o notificare la publicare sau actualizare", 'textdomain' );
echo '</label> ';
echo '<input type="text" id="ot_field" name="ot_field" value="" size="25" />';
}
//salvează metabox - aici verific câmpurile și dacă sunt goale afișez un mesaj
function OT_mt_save( $post_id ) {
// verifică dacă aceasta provine din ecranul nostru și cu autorizația corespunzătoare,
// deoarece save_post poate fi declanșat în alte momente
if (!isset($_POST['myplugin_noncename'])) return $post_id;
if ( !wp_verify_nonce( $_POST['myplugin_noncename'], plugin_basename(__FILE__) ) )
return $post_id;
// verifică dacă aceasta este o rutină de salvare automată.
// Dacă este, formularul nostru nu a fost trimis, așa că nu vrem să facem nimic
if ( defined('DOING_AUTOSAVE') && DOING_AUTOSAVE )
return $post_id;
if(!isset($_POST['ot_field']) || empty($_POST['ot_field'])){
//câmp lăsat gol, așa că adăugăm o notificare
$notice = get_option('otp_notice');
$notice[$post_id] = "Ai lăsat câmpul gol";
update_option('otp_notice',$notice);
}
}
Acum, când am căutat acest cod, am găsit vechiul meu mod de a face acest lucru folosind hook-ul de filtru post_updated_messages
în aproximativ același mod, așa că voi adăuga și asta:
<?php
/*
Plugin Name: one-trick-pony-notice2
Plugin URI: http://en.bainternet.info
Description: la fel ca cel de mai sus, dar de data aceasta folosind hook-ul post_updated_messages
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');
//adaugă metabox
function OT_mt_add() {
add_meta_box('OT_mt_sectionid', __( 'Notificare Metabox One Trick', 'textdomain' ),'OT_mt_display','post');
}
//afișează metabox
function OT_mt_display() {
// Folosește nonce pentru verificare
wp_nonce_field( plugin_basename(__FILE__), 'myplugin_noncename' );
// Câmpurile efective pentru introducerea datelor
echo '<label for="myplugin_new_field">';
_e("lasă gol pentru a primi o notificare la publicare sau actualizare", 'textdomain' );
echo '</label> ';
echo '<input type="text" id="ot_field" name="ot_field" value="" size="25" />';
}
//salvează metabox - aici verific câmpurile și dacă sunt goale afișez un mesaj
function OT_mt_save( $post_id ) {
// verifică dacă aceasta provine din ecranul nostru și cu autorizația corespunzătoare,
// deoarece save_post poate fi declanșat în alte momente
if (!isset($_POST['myplugin_noncename'])) return $post_id;
if ( !wp_verify_nonce( $_POST['myplugin_noncename'], plugin_basename(__FILE__) ) )
return $post_id;
// verifică dacă aceasta este o rutină de salvare automată.
// Dacă este, formularul nostru nu a fost trimis, așa că nu vrem să facem nimic
if ( defined('DOING_AUTOSAVE') && DOING_AUTOSAVE )
return $post_id;
if(!isset($_POST['ot_field']) || empty($_POST['ot_field'])){
//câmp lăsat gol, așa că adăugăm o notificare
$notice = get_option('otp_notice');
$notice[$post_id] = "Ai lăsat câmpul gol";
update_option('otp_notice',$notice);
}
}
//filtru de mesaje
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;
}

nu funcționează cu adevărat pentru că după ce salvezi postarea, ești redirecționat astfel încât acea acțiune nu se execută niciodată...

Redirecționat unde? Și codul de mai sus este ceea ce folosesc eu, așa că știu că funcționează.

funcția ta de salvare a metabox-ului este conectată la save_post
?

pentru că nu funcționează :) După ce apeși butonul de publicare, postarea este salvată și apoi ești redirecționat înapoi la pagina de editare.

M-ai făcut să mă îngrijorez pentru un minut, notificarea este afișată pe ecranul de editare și funcționează perfect.

poți posta codul pe care îl folosești, metabox-ul și toate cele? Pentru că am încercat codul tău de mai sus și nu văd nicio notificare venind din meta box-ul meu...

mers, dar acesta face același lucru precum a indicat Rarst: mesajul de eroare este salvat în baza de date, apoi preluat și șters pe pagina următoare.

@One Trick Pony: da, salvează în baza de date, dar este o opțiune frumoasă (doar un rând în baza de date) și este șters automat când folosești codul de mai sus, așa că nu trebuie să-ți faci griji că baza de date se va umple cu tranziții.

-1 pentru utilizarea unei baze de date. Nu poți garanta că utilizatorul corect va vedea eroarea. De asemenea, nu merită overhead-ul inutil. Pentru lipsa unei metode clare de gestionare a erorilor metabox, aceasta este o soluție temporară bună, dar încă ineficientă. Am adăugat un exemplu despre cum abordez eu acest lucru într-un răspuns nou pentru a ajuta pe alții.

Acest răspuns [oglindă] de la Otto în WP Tavern, rezolvă de fapt problema tranzientelor făcând ceea ce face WordPress însuși pentru a depăși problema redirecționării. A funcționat perfect pentru mine.
Problema este că tranzientele sunt disponibile pentru toată lumea. Dacă ai mai mult de un utilizator care efectuează acțiuni în același timp, mesajul de eroare poate ajunge la persoana greșită. Este o condiție de concurență.
WordPress rezolvă acest lucru prin transmiterea unui parametru de mesaj în URL. Numărul mesajului indică care mesaj să fie afișat.
Poți face același lucru prin conectarea la filtrul
redirect_post_location
și apoi folosindadd_query_arg
pentru a adăuga propriul parametru la cerere. Ca în exemplul de mai jos:add_filter('redirect_post_location','mesajul_meu'); function mesajul_meu($loc) { return add_query_arg( 'mesajul_meu', 123, $loc ); }
Aceasta adaugă
mesajul_meu=123
la interogare. Apoi, după redirecționare, poți detecta setarea mesajul_meu în$_GET
și afișa mesajul corespunzător.

Puteți face asta manual, dar WordPress face asta în mod nativ pentru erorile de setări:
add_settings_error()
pentru a crea mesajul.- Apoi
set_transient('settings_errors', get_settings_errors(), 30);
settings_errors()
în hook-uladmin_notices
pentru afișare (va trebui să folosiți hook-ul pentru ecranele care nu sunt de setări).

face ce vreau eu, dar nu ar umple asta baza de date cu o grămadă de transient-uri?

@One Trick Pony în procesul nativ transient-ul este șters explicit (vezi codul sursă get_settings_errors()
). Poate fi necesar să faci asta manual dacă adaptezi logica pentru o pagină non-settings.

totuși nu-mi place ideea de a stoca mesaje de eroare temporare în baza de date. voi folosi ajax pentru a avertiza utilizatorul la schimbarea input-ului

Știu că această întrebare este veche, dar consider că răspunsurile de aici nu rezolvă problema.
Extinzând răspunsul de la Ana Ban, folosind metoda lui Otto, am constatat că aceasta este cea mai bună metodă pentru gestionarea erorilor. Aceasta nu necesită stocarea erorilor în baza de date.
Am inclus o versiune simplificată a unui obiect Metabox pe care îl folosesc. Acest lucru îmi permite să adaug cu ușurință noi mesaje de eroare și să mă asigur că utilizatorul corect vede mesajul de eroare (folosind baza de date, acest lucru nu este garantat).
<?php
/**
* Class MetaboxExample
*/
class MetaboxExample {
/**
* Definește lista de ecrane permise (post_types)
*/
private $_allowedScreens = array( 'SCREENS_TO_ALLOW_METABOX' );
/**
* Parametru GET pentru codul de eroare al cutiei de eroare
*/
const GET_METABOX_ERROR_PARAM = 'meta-error';
/**
* Definește hook-urile pentru admin
*/
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')); // NOTĂ: admin_notices nu poziționează acest lucru corect pe paginile de tip custom post type, nu am testat acest lucru pe POST sau PAGE dar nu văd aceasta ca pe o problemă
}
/**
* Adaugă metabox-ul la tipurile de postări specificate
*/
public function addMetabox() {
foreach ( $this->_allowedScreens as $screen ) {
add_meta_box(
'PLUGIN_METABOX',
__( 'TITLU', 'text_domain' ),
array($this, 'metaBox'),
$screen,
'side',
'high'
);
}
}
/**
* Afișează conținutul metabox-ului
* @param $post
*/
public function metaBox($post) {
// Adaugă un câmp nonce pentru a putea verifica mai târziu
wp_nonce_field( 'metaboxnonce', 'metaboxnonce' );
// Încarcă meta datele pentru acest metabox
$someValue = get_post_meta( $post->ID, 'META_KEY_IDENTIFIER', true );
?>
<p>
<label for="some-value" style="width: 120px; display: inline-block;">
<?php _e( 'Un câmp:', 'text_domain' ); ?>
</label>
<input type="text" id="some-value" name="some_value" value="<?php esc_attr_e( $someValue ); ?>" size="25" />
</p>
<?php
}
/**
* Metodă de salvare pentru metabox
* @param $post_id
*/
public function saveMetabox($post_id) {
global $wpdb;
// Verifică dacă nonce-ul nostru este setat
if ( ! isset( $_POST['metaboxnonce'] ) ) {
return $post_id;
}
// Verifică dacă nonce-ul este valid
if ( ! wp_verify_nonce( $_POST['metaboxnonce'], 'metaboxnonce' ) ) {
return $post_id;
}
// Dacă acesta este un autosave, formularul nostru nu a fost trimis, așa că nu vrem să facem nimic
if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) {
return $post_id;
}
// Verifică permisiunile utilizatorului
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;
}
}
// Asigură-te că este setat
if ( !isset( $_POST['some_value'] ) ) {
return $post_id;
}
// Sanitizează input-ul utilizatorului
$someValue = sanitize_text_field( $_POST['some_value'] );
// Verifică să existe o valoare
if (empty($someValue)) {
// Adaugă codul nostru de eroare
add_filter('redirect_post_location', function($loc) {
return add_query_arg( self::GET_METABOX_ERROR_PARAM, 1, $loc );
});
return $post_id; // asigură-te că returnezi pentru a nu permite procesare suplimentară
}
// Actualizează câmpul meta în baza de date
update_post_meta( $post_id, 'META_KEY_IDENTIFIER', $someValue );
}
/**
* Notificări admin pentru metabox
*/
public function adminNotices() {
if (isset($_GET[self::GET_METABOX_ERROR_PARAM])) {
$screen = get_current_screen();
// Asigură-te că suntem în tipul de postare corect
if (in_array($screen->post_type, $this->_allowedScreens)) {
$errorCode = (int) $_GET[self::GET_METABOX_ERROR_PARAM];
switch($errorCode) {
case 1:
$this->_showAdminNotice( __('A apărut o eroare', 'text_domain') );
break;
// Mai multe coduri de eroare pot fi adăugate aici pentru afișarea erorilor
}
}
}
}
/**
* Afișează notificarea admin pentru 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
}
}

Singura problemă pe care o am cu acest răspuns este că nu funcționează cu PHP 5.2. Nu spun că ar trebui să suportăm toți PHP 5.2, dar până când WordPress va avea PHP 5.2 ca cerință minimă, trebuie să-l suportăm dacă distribuim pluginul :(

Dacă elimini funcția anonimă și o faci o metodă publică, ar trebui să funcționeze bine. Înțeleg problema ta, dar personal nu voi dezvolta pentru o versiune EOL a PHP (http://php.net/eol.php) 5.2 EOL a fost pe 6 ianuarie 2011. WordPress ar trebui să depună mai mult efort pentru a nu suporta versiunile EOL, dar asta e altă poveste, la care se adaugă multe companii de hosting proaste care încă oferă versiuni EOL...
