Cum să validezi câmpuri personalizate în tipuri de postare personalizate în WordPress
Am scris un plugin care creează un tip de postare personalizat cu câmpuri personalizate. Pentru a preveni utilizatorii să introducă informații incorecte, cum pot valida datele?
Am presupus că funcția hook save_post ar procesa validarea câmpurilor, dar nu găsesc o metodă directă care să afișeze erorile utilizatorului.
Există o funcție/trăsătură încorporată în WordPress pentru asta? Care este tehnica generală pentru validarea câmpurilor personalizate?

Ești pe drumul cel bun. Testez câmpurile în callback-ul save_post
, apoi folosesc notificări admin pentru a afișa erorile utilizatorului când un câmp nu trece de validare. Acestea apar într-o casetă evidențiată în partea de sus a paginii, exact ca orice erori/mesaje generate de WordPress însuși.
Iată un exemplu simplu de creare a unei notificări admin:
function my_admin_notice()
{
?>
<div class="updated">
<p>Aenean eros ante, porta commodo lacinia.</p>
</div>
<?php
}
add_action( 'admin_notices', 'my_admin_notice' );
Totuși, acest lucru nu este foarte practic. Într-o astfel de situație, ai nevoie de o funcție căreia să-i poți transmite un mesaj. Ceva de genul:
if( $pizza != 'warm' )
$notices->enqueue( 'Pizza nu este caldă', 'error' );
Așadar, poți scrie singur funcția enqueue()
(împreună cu o funcție pentru afișarea notificărilor), sau poți include o bibliotecă precum IDAdminNotices.
Iată un exemplu din un plugin pe care l-am scris. Acesta folosește funcții de adăugare/afișare a notificărilor care sunt integrate în clasa în sine, în loc să includă o bibliotecă externă.
public function saveCustomFields( $postID )
{
// ...
if( filter_var( $_POST[ self::PREFIX . 'zIndex'], FILTER_VALIDATE_INT ) === FALSE )
{
update_post_meta( $post->ID, self::PREFIX . 'zIndex', 0 );
$this->enqueueMessage( 'Ordinea de suprapunere trebuie să fie un număr întreg.', 'error' );
}
else
update_post_meta( $post->ID, self::PREFIX . 'zIndex', $_POST[ self::PREFIX . 'zIndex'] );
// ...
}
add_action( 'save_post', array( $this, 'saveCustomFields' );

Nu sunt foarte sigur în privința asta...codul exemplu necesită cod de la terți sau va funcționa în WordPress așa cum este?

Aceasta pare să funcționeze doar când pagina este încărcată pentru prima dată. Dacă se apasă butonul "Actualizează/Publică", nu sunt afișate notificări.

Ambele abordări funcționează pentru mine. Poți să postezi un link către codul complet?

Exemplu de cod: http://pastebin.com/vTxv9cw1

Cred că problema este că folosești o variabilă globală în loc să salvezi notificările în baza de date. Datele din variabile nu persistă între cereri. Deci, notificarea este adăugată în $bh_errorMessages la momentul salvării, apoi WordPress redirecționează înapoi la ecranul Editare Postare (care este o nouă cerere), iar toate variabilele sunt resetate. Vezi http://en.wikipedia.org/wiki/Post/Redirect/Get. Analizează mai atent IDAdminNotices și asigură-te că faci tot ce face acesta.

Nu sunt foarte sigur ce folosești pentru a permite variabilelor să persiste între cereri. Este vorba despre includerea variabilei $instance
? Sau este una dintre declarațiile add_action
? Sau ambele? Altceva?

ok, cred că am înțeles. Magia se întâmplă cu funcțiile WordPress add_option
și get_option
pentru a stoca și prelua variabila, iar hook-ul shutdown
este util pentru a apela funcția add_option
doar o dată per sesiune după ce totul s-a finalizat.

Am scris un mic plugin care nu doar validează câmpurile de intrare pe tipurile personalizate de postări, dar și elimină notificarea implicită din administrare, fără a folosi Javascript.
Iată o parte din cod
/ Filtre de validare
$title = $album->post_title;
if ( ! $title ) {
$errors['title'] = "Titlul este obligatoriu";
}
// dacă avem erori, să configurăm niște mesaje
if (! empty($errors)) {
// trebuie să eliminăm această acțiune altfel va intra într-o buclă infinită
remove_action('save_post', 'album_save_post');
// salvăm erorile ca opțiune
update_option('album_errors', $errors);
// Schimbăm starea postării din publicat în ciornă
$album->post_status = 'draft';
// actualizăm postarea
wp_update_post( $album );
// trebuie să readăugăm această acțiune
add_action('save_post', 'album_save_post');
// admin_notice este creat de un $_GET['message'] cu un număr pe care WordPress îl folosește pentru a
// afișa mesajul de administrare, așa că vom adăuga un filtru pentru a înlocui mesajul implicit cu o redirecționare
add_filter( 'redirect_post_location', 'album_post_redirect_filter' );
}
Puteți vedea tutorialul complet aici

Când acțiunea save_post
rulează, postarea a fost deja salvată în baza de date.
Dacă utilizați ACF, acesta are validare încorporată.
Cu toate acestea, dacă trebuie să validați elemente în afara ACF, cum ar fi post_title, lucrurile devin puțin mai complicate.
Analizând codul WordPress, mai exact funcția update_post()
din wp-includes/post.php
, nu există nicio metodă încorporată de a intercepta o cerere înainte de a fi salvată în baza de date.
Totuși, putem utiliza hook-ul pre_post_update
și funcțiile header()
și get_post_edit_link()
pentru a preveni salvarea postării.
<?php
/**
* Efectuează validare personalizată pentru tipul de postare personalizat "Site"
*/
function custom_post_site_save($post_id, $post_data) {
# Dacă aceasta este doar o revizie, nu face nimic.
if (wp_is_post_revision($post_id))
return;
if ($post_data['post_type'] == 'site') {
# În acest exemplu, vom genera o eroare pentru titluri de postare cu mai puțin de 5 caractere
if (strlen($post_data['post_title']) < 5) {
# Adaugă o notificare
update_option('my_notifications', json_encode(array('error', 'Titlul postării nu poate avea mai puțin de 5 caractere.')));
# Și redirecționează
header('Location: '.get_edit_post_link($post_id, 'redirect'));
exit;
}
}
}
add_action( 'pre_post_update', 'custom_post_site_save', 10, 2);
/**
* Afișează notificări personalizate în panoul de administrare WordPress
*/
function my_notification() {
$notifications = get_option('my_notifications');
if (!empty($notifications)) {
$notifications = json_decode($notifications);
#notifications[0] = (string) Tipul notificării: error, updated sau update-nag
#notifications[1] = (string) Mesajul
#notifications[2] = (boolean) este dismissable?
switch ($notifications[0]) {
case 'error': # roșu
case 'updated': # verde
case 'update-nag': # ?
$class = $notifications[0];
break;
default:
# Implicit la error pentru orice eventualitate
$class = 'error';
break;
}
$is_dismissable = '';
if (isset($notifications[2]) && $notifications[2] == true)
$is_dismissable = 'is_dismissable';
echo '<div class="'.$class.' notice '.$is_dismissable.'">';
echo '<p>'.$notifications[1].'</p>';
echo '</div>';
# Resetează notificarea
update_option('my_notifications', false);
}
}
add_action( 'admin_notices', 'my_notification' );

Vreau să adaug la excelentul răspuns al lui @Lucas Bustamante că valoarea câmpurilor personalizate poate fi accesată prin variabila globală $_POST
.
Astfel, răspunsul lui @Lucas Bustamante este valabil și dacă validarea se referă la un câmp personalizat. De exemplu:
<?php
/**
* Efectuează validare personalizată pentru tipul de postare "Site"
*/
function custom_post_site_save($post_id, $post_data) {
# Dacă aceasta este doar o revizie, nu face nimic.
if (wp_is_post_revision($post_id))
return;
if ($post_data['post_type'] == 'site') {
# În acest exemplu, vom genera o eroare pentru titlurile de postare cu mai puțin de 5 caractere
if (strlen($_POST['zip_code']) < 5) {
# Adaugă o notificare
update_option('my_notifications', json_encode(array('error', 'Codul poștal nu poate avea mai puțin de 5 caractere.')));
# Și redirecționează
header('Location: '.get_edit_post_link($post_id, 'redirect'));
exit;
}
}
}
add_action( 'pre_post_update', 'custom_post_site_save', 10, 2);
/**
* Afișează notificări personalizate în panoul de administrare WordPress
*/
function my_notification() {
$notifications = get_option('my_notifications');
if (!empty($notifications)) {
$notifications = json_decode($notifications);
#notifications[0] = (string) Tipul notificării: error, updated sau update-nag
#notifications[1] = (string) Mesajul
#notifications[2] = (boolean) is_dismissible?
switch ($notifications[0]) {
case 'error': # roșu
case 'updated': # verde
case 'update-nag': # ?
$class = $notifications[0];
break;
default:
# Implicit, consideră eroare pentru orice eventualitate
$class = 'error';
break;
}
$is_dismissable = '';
if (isset($notifications[2]) && $notifications[2] == true)
$is_dismissable = 'is_dismissable';
echo '<div class="'.$class.' notice '.$is_dismissable.'">';
echo '<p>'.$notifications[1].'</p>';
echo '</div>';
# Resetează notificarea
update_option('my_notifications', false);
}
}
add_action( 'admin_notices', 'my_notification' );
``

poți folosi filtrul "wp_insert_post_data" pentru a modifica sau verifica datele înainte să fie introduse în baza de date
add_filter( 'wp_insert_post_data', 'validate_posttypes' );
function wpb_custom_excerpt($data) {
str_starts_with($data['post_title'],'wp')?$data['post_title']='wp'.$data['post_title']:null;
return $data;
}
