nu publica postarea de tip custom post type dacă un câmp de meta date nu este valid
Am un custom post type (CPT) numit event
. Am o meta box pentru acest tip cu mai multe câmpuri. Aș dori să validez unele câmpuri înainte de a publica un eveniment. De exemplu, dacă data unui eveniment nu este specificată, aș dori să afișez un mesaj de eroare informativ, să salvez evenimentul pentru editare viitoare, dar să împiedic publicarea acelui eveniment. Este statusul 'pending' pentru un CPT fără toate informațiile necesare modalitatea corectă de a-l trata?
Care este cea mai bună practică pentru a valida câmpurile unui CPT și a împiedica publicarea unei postări, dar totuși să o salvezi pentru editare ulterioară.
Mulțumesc mult, Dasha

Puteți opri salvarea postării complet cu mici hack-uri JQuery și puteți valida câmpurile înainte de salvare pe partea de client sau server cu ajutorul ajax:
mai întâi adăugăm JavaScript-ul nostru pentru a captura evenimentul de submit/publish și îl folosim pentru a trimite propria noastră funcție ajax înainte de trimiterea efectivă:
add_action('wp_print_scripts','my_publish_admin_hook');
function my_publish_admin_hook(){
if (is_admin()){
?>
<script language="javascript" type="text/javascript">
jQuery(document).ready(function() {
jQuery('#post').submit(function() {
var form_data = jQuery('#post').serializeArray();
form_data = jQuery.param(form_data);
var data = {
action: 'my_pre_submit_validation',
security: '<?php echo wp_create_nonce( 'pre_publish_validation' ); ?>',
form_data: form_data
};
jQuery.post(ajaxurl, data, function(response) {
if (response.indexOf('True') > -1 || response.indexOf('true') > -1 || response === true || response) {
jQuery('#ajax-loading').hide();
jQuery('#publish').removeClass('button-primary-disabled');
return true;
}else{
alert("Vă rugăm să corectați următoarele erori: " + response);
jQuery('#ajax-loading').hide();
jQuery('#publish').removeClass('button-primary-disabled');
return false;
}
});
return false;
});
});
</script>
<?php
}
}
apoi creăm funcția pentru a face validarea efectivă:
add_action('wp_ajax_my_pre_submit_validation', 'pre_submit_validation');
function pre_submit_validation(){
//simplă verificare de securitate
check_ajax_referer( 'pre_publish_validation', 'security' );
//faceți validarea aici
//toate câmpurile din formular sunt în array-ul $_POST['form_data']
//și returnați true pentru a trimite: echo 'true'; die();
//sau mesajul de eroare: echo 'bal bla bla'; die();
}
puteți oricând să o modificați puțin pentru a face validarea doar pentru tipul dumneavoastră de postare prin adăugarea unei verificări condiționale în funcția my_publish_admin_hook
pentru tipul dumneavoastră de postare și pentru a valida pe partea de client, dar eu prefer pe partea de server.

Poate înțeleg greșit ceva. Se pare că folosești PHP doar pentru a randă JavaScript care face validarea. Aceasta nu este validare pe partea de server. Nu înțeleg cu adevărat cum se potrivește pre_submit_validation
în acest context.

Primul bloc my_publish_admin_hook
interceptează trimiterea postării pe partea de client - dar apoi face un apel AJAX către server (înainte de trimiterea oficială în pre_submit_validation
) care efectuează validarea pe server.

Aceasta este în continuare validare pe partea de client, chiar dacă folosește AJAX pentru a efectua validarea. Clientul trebuie să ruleze JavaScript-ul în primul rând pentru ca orice validare să aibă loc.
Totuși... am găsit acest răspuns util pentru validarea pre-trimitere. Mulțumesc!

Există doi pași în această metodă: mai întâi, o funcție pentru a salva datele câmpului personalizat din metabox (legată la save_post), și al doilea, o funcție pentru a citi acea post_meta nouă (pe care tocmai ai salvat-o), a o valida și a modifica rezultatul salvării după cum este necesar (de asemenea legată la save_post, dar după prima). Funcția de validare, dacă validarea eșuează, schimbă de fapt post_status înapoi la "pending", prevenind efectiv publicarea postării.
Deoarece funcția save_post este apelată frecvent, fiecare funcție are verificări pentru a se executa doar când utilizatorul intenționează să publice și doar pentru tipul tău personalizat de postare (mycustomtype).
De asemenea, de obicei adaug câteva mesaje personalizate pentru a ajuta utilizatorul să înțeleagă de ce postarea lui nu a fost publicată, dar acelea au devenit prea complicate pentru a fi incluse aici...
Nu am testat acest cod exact, dar este o versiune simplificată a ceea ce am făcut în configurații complexe de tipuri personalizate de postări.
add_action('save_post', 'save_my_fields', 10, 2);
add_action('save_post', 'completion_validator', 20, 2);
function save_my_fields($pid, $post) {
// nu executa la autosave sau când postările noi sunt create prima dată
if ( ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) || $post->post_status == 'auto-draft' ) return $pid;
// întrerupe dacă nu este tipul meu personalizat
if ( $post->post_type != 'mycustomtype' ) return $pid;
// salvează post_meta cu conținutul câmpului personalizat
update_post_meta($pid, 'mymetafield', $_POST['mymetafield']);
}
function completion_validator($pid, $post) {
// nu executa la autosave sau când postările noi sunt create prima dată
if ( ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) || $post->post_status == 'auto-draft' ) return $pid;
// întrerupe dacă nu este tipul meu personalizat
if ( $post->post_type != 'mycustomtype' ) return $pid;
// inițializează marcatorul de completare (adaugă mai multe după nevoie)
$meta_missing = false;
// preia meta pentru validare
$mymeta = get_post_meta( $pid, 'mymetafield', true );
// doar verifică dacă nu este gol - poți face și alte teste...
if ( empty( $mymeta ) ) {
$meta_missing = true;
}
// la încercarea de publicare - verifică completarea și intervine dacă este necesar
if ( ( isset( $_POST['publish'] ) || isset( $_POST['save'] ) ) && $_POST['post_status'] == 'publish' ) {
// nu permite publicarea dacă oricare dintre acestea este incomplet
if ( $meta_missing ) {
global $wpdb;
$wpdb->update( $wpdb->posts, array( 'post_status' => 'pending' ), array( 'ID' => $pid ) );
// filtrează URL-ul de redirect pentru a schimba mesajul de publicare
add_filter( 'redirect_post_location', create_function( '$location','return add_query_arg("message", "4", $location);' ) );
}
}
}
Pentru mai multe câmpuri de metabox, adaugă pur și simplu mai mulți marcatori de completare și preia mai multă post_meta și efectuează mai multe teste...

trebuie să verifici/validezi valoarea câmpului meta prin ajax, adică atunci când utilizatorul apasă butonul "Publică/Actualizează". Aici validez un produs WooCommerce care are câmpul meta "product_number" pentru valoare goală.
add_action('admin_head-post.php','ep_publish_admin_hook');
add_action('admin_head-post-new.php','ep_publish_admin_hook');
function ep_publish_admin_hook(){
global $post;
if ( is_admin() && $post->post_type == 'product' ){
?>
<script language="javascript" type="text/javascript">
(function($){
jQuery(document).ready(function() {
jQuery('#publish').click(function() {
if(jQuery(this).data("valid")) {
return true;
}
//ascunde iconița de încărcare, readuce butonul Publică la normal
jQuery('#publishing-action .spinner').addClass('is-active');
jQuery('#publish').addClass('button-primary-disabled');
jQuery('#save-post').addClass('button-disabled');
var data = {
action: 'ep_pre_product_submit',
security: '<?php echo wp_create_nonce( "pre_publish_validation" ); ?>',
'product_number': jQuery('#acf-field-product_number').val()
};
jQuery.post(ajaxurl, data, function(response) {
jQuery('#publishing-action .spinner').removeClass('is-active');
if ( response.success ){
jQuery("#post").data("valid", true).submit();
} else {
alert("Eroare: " + response.data.message );
jQuery("#post").data( "valid", false );
}
//ascunde iconița de încărcare, readuce butonul Publică la normal
jQuery('#publish').removeClass('button-primary-disabled');
jQuery('#save-post').removeClass('button-disabled');
});
return false;
});
});
})(jQuery);
</script>
<?php
}
}
După aceea, adaugă funcția de gestionare ajax,
add_action('wp_ajax_ep_pre_product_submit', 'ep_pre_product_submit_func');
function ep_pre_product_submit_func() {
//simplă verificare de securitate
check_ajax_referer( 'pre_publish_validation', 'security' );
if ( empty( $_POST['product_number'] ) || empty( $_POST['file_attachment'] ) ) {
$data = array(
'message' => __('Te rog să introduci numărul părții și documentul de specificație.'),
);
wp_send_json_error( $data );
}
wp_send_json_success();
}

Doar voiam să adaug că pentru a citi variabilele postate, folosind soluția lui Bainternet, va trebui să analizați șirul din $_POST['form_data']
utilizând funcția PHP parse_str
(doar pentru a vă economisi timpul de cercetare).
$vars = parse_str( $_POST['form_data'] );
Apoi puteți accesa fiecare variabilă folosind direct $varname
. De exemplu, dacă aveți un câmp meta numit "my_meta", l-ați accesa astfel:
$vars = parse_str ( $_POST['form_data'] )
if ( $my_meta == "something" ) { // faci ceva }
