non pubblicare post di tipo post personalizzato se un campo di metadati non è valido


12

Ho un tipo di post personalizzato (CPT) chiamato event. Ho una meta box per il tipo con diversi campi. Vorrei convalidare alcuni campi prima di pubblicare un evento. Ad esempio, se non viene specificata la data di un evento, vorrei visualizzare un messaggio di errore informativo, salvare l'evento per future modifiche, ma impedire che tale evento venga pubblicato. Lo stato "in sospeso" di un post CPT senza tutte le informazioni necessarie è il modo giusto di trattarlo?

Qual è la migliore pratica per eseguire la convalida dei campi CPT e impedire la pubblicazione di un post, ma salvarlo per future modifiche.

Mille grazie, Dasha


Gentile incoraggiamento a ricordarti che questa domanda ha ancora bisogno di una risposta accettata ..;) Se nessuna delle due risposte ha risposto alla tua domanda, considera di aggiornare la tua domanda con commenti aggiuntivi che dettagliano ciò che non è stato affrontato (o dove potresti aver bisogno di aiuto, se applicabile).
t31os,

Risposte:


14

Puoi impedire al post di salvare tutti insieme a piccoli hack di JQuery e convalidare i campi prima di salvare sul lato client o sul lato server con ajax:

per prima cosa aggiungiamo il nostro JavaScript per acquisire l'evento di invio / pubblicazione e utilizzarlo per inviare la nostra funzione ajax prima dell'invio effettivo:

 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("please correct the following errors: " + response);
                            jQuery('#ajax-loading').hide();
                            jQuery('#publish').removeClass('button-primary-disabled');
                            return false;
                        }
                    });
                    return false;
                });
            });
        </script>
        <?php
    }
}

quindi creiamo la funzione per eseguire la validazione effettiva:

add_action('wp_ajax_my_pre_submit_validation', 'pre_submit_validation');
function pre_submit_validation(){
    //simple Security check
    check_ajax_referer( 'pre_publish_validation', 'security' );

    //do your validation here
    //all of the form fields are in $_POST['form_data'] array
    //and return true to submit: echo 'true'; die();
    //or your error message: echo 'bal bla bla'; die();
}

puoi sempre cambiarlo un po 'per fare la convalida solo per il tuo tipo di post aggiungendo un controllo condizionale per my_publish_admin_hookfunzionare per il tuo tipo di post e per convalidare sul lato client, ma preferisco sul lato server.


Non esiste un modo lato server per farlo?
Jeff,

1
Questo è un modo lato server per farlo.
Bainternet,

1
Forse sto fraintendendo qualcosa. Sembra che tu stia semplicemente utilizzando PHP per eseguire il rendering di JavaScript che esegue la convalida. Questa non è una convalida lato server. Non capisco davvero come si pre_submit_validationadatta.
Jeff

Il primo my_publish_admin_hookblocco intercetta il lato client di invio post-invio, ma quindi effettua una chiamata AJAX al server (invio pre-ufficiale pre_submit_validation) che esegue la convalida lato server.
emc

1
Questa è ancora la convalida lato client, anche se sta usando AJAX per fare la convalida. Il client deve innanzitutto eseguire JavaScript per consentire qualsiasi convalida. Tuttavia ... ho ancora trovato questa risposta utile per la convalida pre-presentazione. Grazie!
cr0ybot,

7

Il metodo prevede due passaggi: primo, una funzione per salvare i dati del campo metabox personalizzato (collegato a save_post) e, in secondo luogo, una funzione per leggere quel nuovo post_meta (che hai appena salvato), convalidarlo e modificare il risultato di salvataggio se necessario (anche agganciato a save_post, ma dopo il primo). La funzione validator, se la validazione fallisce, in realtà cambia il post_status a "pending", impedendo efficacemente la pubblicazione del post.

Poiché la funzione save_post viene chiamata molto, ogni funzione ha dei controlli da eseguire solo quando l'utente intende pubblicare e solo per il tuo tipo di post personalizzato (mycustomtype).

In genere aggiungo anche alcuni messaggi di avviso personalizzati per aiutare l'utente a sapere perché il loro post non è stato pubblicato, ma quelli sono diventati un po 'complicati da includere qui ...

Non ho testato questo codice esatto, ma è una versione semplificata di ciò che ho fatto in configurazioni di tipo di posta personalizzate su larga scala.

add_action('save_post', 'save_my_fields', 10, 2);
add_action('save_post', 'completion_validator', 20, 2);

function save_my_fields($pid, $post) {
    // don't do on autosave or when new posts are first created
    if ( ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) || $post->post_status == 'auto-draft' ) return $pid;
    // abort if not my custom type
    if ( $post->post_type != 'mycustomtype' ) return $pid;

    // save post_meta with contents of custom field
    update_post_meta($pid, 'mymetafield', $_POST['mymetafield']);
}


function completion_validator($pid, $post) {
    // don't do on autosave or when new posts are first created
    if ( ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) || $post->post_status == 'auto-draft' ) return $pid;
    // abort if not my custom type
    if ( $post->post_type != 'mycustomtype' ) return $pid;

    // init completion marker (add more as needed)
    $meta_missing = false;

    // retrieve meta to be validated
    $mymeta = get_post_meta( $pid, 'mymetafield', true );
    // just checking it's not empty - you could do other tests...
    if ( empty( $mymeta ) ) {
        $meta_missing = true;
    }

    // on attempting to publish - check for completion and intervene if necessary
    if ( ( isset( $_POST['publish'] ) || isset( $_POST['save'] ) ) && $_POST['post_status'] == 'publish' ) {
        //  don't allow publishing while any of these are incomplete
        if ( $meta_missing ) {
            global $wpdb;
            $wpdb->update( $wpdb->posts, array( 'post_status' => 'pending' ), array( 'ID' => $pid ) );
            // filter the query URL to change the published message
            add_filter( 'redirect_post_location', create_function( '$location','return add_query_arg("message", "4", $location);' ) );
        }
    }
}

Per più campi metabox, basta aggiungere più marcatori di completamento e recuperare più post_meta ed eseguire più test.


1

devi controllare / convalidare il valore del tuo metacampo su ajax, ad esempio quando l'utente preme il pulsante "Pubblica / Aggiorna". Qui sto convalidando il prodotto woocommerce con meta field "product_number" per valore vuoto.

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;
                        }

                        //hide loading icon, return Publish button to 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("Error: " + response.data.message );
                                jQuery("#post").data( "valid", false );

                            }
                            //hide loading icon, return Publish button to normal
                            jQuery('#publish').removeClass('button-primary-disabled');
                            jQuery('#save-post').removeClass('button-disabled');
                        });
                        return false;
                    });
                });
            })(jQuery);
        </script>
        <?php
    }
}

Dopodiché aggiungi la funzione del gestore ajax,

add_action('wp_ajax_ep_pre_product_submit', 'ep_pre_product_submit_func');
function ep_pre_product_submit_func() {
    //simple Security check
    check_ajax_referer( 'pre_publish_validation', 'security' );

    if ( empty( $_POST['product_number'] ) || empty( $_POST['file_attachment'] ) ) {
         $data = array(
            'message' => __('Please enter part number and specification document.'),
        );
        wp_send_json_error( $data );
    }
    wp_send_json_success();
}

0

Volevo solo aggiungere che per leggere le variabili post, usando la soluzione di Bainternet, dovrai analizzare la stringa $_POST['form_data']usando la parse_strfunzione PHP (solo per risparmiare tempo di ricerca).

$vars = parse_str( $_POST['form_data'] );

Quindi puoi accedere ad ogni variabile semplicemente usando $varname. Ad esempio, se hai un meta campo chiamato "my_meta", accederai in questo modo:

$vars = parse_str ( $_POST['form_data'] ) 
if ( $my_meta == "something" ) { // do something }
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.