nie publikuj wpisu typu niestandardowego, jeśli pole metadanych jest nieprawidłowe


12

Mam niestandardowy typ posta (CPT) o nazwie event. Mam meta box dla typu z kilkoma polami. Chciałbym zweryfikować niektóre pola przed opublikowaniem wydarzenia. Na przykład, jeśli data wydarzenia nie jest określona, ​​chciałbym wyświetlić informacyjny komunikat o błędzie, zapisz to zdarzenie do przyszłej edycji, ale zapobiegaj jego opublikowaniu. Czy status „w toku” dla posta CPT bez wszystkich niezbędnych informacji jest właściwym sposobem na jego potraktowanie?

Jaka jest najlepsza praktyka do sprawdzania poprawności pól CPT i zapobiegania publikowaniu postów, ale zachowaj je do późniejszej edycji.

Wielkie dzięki, Dasha


Delikatne poruszenie przypominające o tym pytaniu wciąż wymaga zaakceptowanej odpowiedzi;;) Jeśli żadna z odpowiedzi nie dotyczyła twojego pytania, rozważ zaktualizowanie pytania o dodatkowe komentarze opisujące to, czego nie uwzględniono (lub gdzie możesz potrzebować pomocy, jeśli dotyczy).
t31os

Odpowiedzi:


14

Możesz zatrzymać zapisywanie posta razem z drobnymi hackami JQuery i zweryfikować pola przed zapisaniem po stronie klienta lub serwera za pomocą ajax:

najpierw dodajemy JavaScript, aby przechwycić zdarzenie wysyłania / publikowania i używamy go do przesłania własnej funkcji ajax przed faktycznym przesłaniem:

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

następnie tworzymy funkcję do faktycznej weryfikacji:

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

zawsze możesz to trochę zmienić, aby wykonać walidację tylko dla swojego typu postu, dodając warunkową kontrolę my_publish_admin_hookdziałania dla twojego typu postu i sprawdzania poprawności po stronie klienta, ale ja wolę po stronie serwera.


Czy nie ma na to sposobu po stronie serwera?
Jeff

1
Jest to sposób na wykonanie tego po stronie serwera.
Bainternet,

1
Może coś nie rozumiem. Wygląda na to, że używasz PHP do renderowania JavaScript, który sprawdza poprawność. To nie jest weryfikacja po stronie serwera. Naprawdę nie rozumiem, jak to pre_submit_validationpasuje.
Jeff

Pierwszy my_publish_admin_hookblok przechwytuje przesyłanie po stronie po stronie klienta - ale następnie wykonuje wywołanie AJAX do serwera (przed oficjalnym przesłaniem pre_submit_validation), który wykonuje weryfikację po stronie serwera.
emc

1
Jest to nadal weryfikacja po stronie klienta, nawet jeśli używa ona AJAX do weryfikacji. Klient musi uruchomić JavaScript w pierwszej kolejności, aby można było przeprowadzić walidację. Jednak ... nadal uważam, że ta odpowiedź jest przydatna do weryfikacji przed przesłaniem. Dzięki!
cr0ybot,

7

Metoda składa się z dwóch etapów: po pierwsze, funkcja zapisywania niestandardowych danych pola metaboksu (podpięta do save_post), a po drugie, funkcja odczytywania nowego post_meta (właśnie zapisanego), sprawdzania go i modyfikowania wyniku zapisywanie w razie potrzeby (również podpięte do save_post, ale po pierwszym). Funkcja sprawdzania poprawności, jeśli sprawdzanie poprawności się nie powiedzie, faktycznie zmienia stan post_status z powrotem na „oczekujący”, skutecznie zapobiegając opublikowaniu posta.

Ponieważ funkcja save_post jest często wywoływana, każda funkcja musi sprawdzać, czy jest wykonywana tylko wtedy, gdy użytkownik chce opublikować, i tylko w przypadku niestandardowego typu postu (typ niestandardowy).

Zazwyczaj dodaję też niestandardowe komunikaty z powiadomieniami, aby pomóc użytkownikowi dowiedzieć się, dlaczego jego post nie został opublikowany, ale dodanie ich tutaj jest nieco skomplikowane ...

Nie testowałem dokładnie tego kodu, ale jest to uproszczona wersja tego, co zrobiłem w niestandardowych konfiguracjach typu post na dużą skalę.

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

W przypadku wielu pól metaboksu wystarczy dodać więcej znaczników ukończenia i pobrać więcej post_meta i wykonać więcej testów.


1

musisz sprawdzić / zweryfikować wartość pola meta na stronie ajax, tj. kiedy użytkownik naciśnie przycisk „Publikuj / Aktualizuj”. Tutaj sprawdzam poprawność produktu woocommerce o polu meta „numer_produktu” pod kątem pustej wartości.

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

Po tym dodaj funkcję obsługi 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

Chciałem tylko dodać, że aby odczytać zmienne wpisu, korzystając z rozwiązania Bainternet, będziesz musiał przeanalizować ciąg znaków przy $_POST['form_data']użyciu parse_strfunkcji PHP (aby zaoszczędzić trochę czasu na badania).

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

Następnie możesz uzyskać dostęp do każdej zmiennej za pomocą $varname. Na przykład, jeśli masz pole meta o nazwie „my_meta”, uzyskasz do niego dostęp w następujący sposób:

$vars = parse_str ( $_POST['form_data'] ) 
if ( $my_meta == "something" ) { // do something }
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.