no publique una publicación de tipo de publicación personalizada si un campo de metadatos no es válido

12

Tengo un tipo de mensaje personalizado (CPT) llamado event. Tengo un cuadro de meta para el tipo con varios campos. Me gustaría validar algunos campos antes de publicar un evento. Por ejemplo, si no se especifica la fecha de un evento, me gustaría mostrar un mensaje de error informativo, guardar el evento para su posterior edición, pero evitar que se publique ese evento. ¿Es el estado 'pendiente' para una publicación de CPT sin toda la información necesaria la forma correcta de tratarla?

¿Cuál es la mejor práctica para hacer la validación de campos de CPT y evitar que se publique una publicación, pero guárdela para su futura edición?

Muchas gracias, Dasha.

dashaluna
fuente
Toque suavemente para recordarle que esta pregunta aún necesita una respuesta aceptada ...;) Si ninguna de las respuestas respondió a su pregunta, considere actualizar su pregunta con comentarios adicionales que detallen lo que no se ha respondido (o dónde puede necesitar ayuda, si corresponde).
t31os

Respuestas:

14

Puede evitar que la publicación se guarde junto con hacks menores de JQuery y validar los campos antes de guardar en el lado del cliente o del servidor con ajax:

primero agregamos nuestro JavaScript para capturar el evento de envío / publicación y lo usamos para enviar nuestra propia función ajax antes del envío real:

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

luego creamos la función para hacer la validación real:

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

siempre puede cambiarlo un poco para hacer la validación solo para su tipo de publicación agregando una verificación condicional para que my_publish_admin_hookfuncione para su tipo de publicación y validar en el lado del cliente, pero prefiero en el lado del servidor.

Bainternet
fuente
¿No hay una forma del lado del servidor para hacer esto?
Jeff
1
Esta es una forma del lado del servidor para hacerlo.
Bainternet
1
Tal vez estoy malinterpretando algo. Parece que solo estás usando PHP para representar JavaScript, que realiza la validación. Eso no es validación del lado del servidor. Realmente no entiendo cómo pre_submit_validationencaja.
Jeff
El primer my_publish_admin_hookbloque intercepta el envío desde el lado del cliente, pero luego realiza una llamada AJAX al servidor (pre-envío oficial pre_submit_validation) que realiza la validación del lado del servidor.
emc
1
Esto sigue siendo validación del lado del cliente, incluso si está usando AJAX para hacer la validación. El cliente tiene que ejecutar JavaScript en primer lugar para que se realice cualquier validación. Sin embargo ... todavía encontré esta respuesta útil para la validación previa al envío. ¡Gracias!
cr0ybot
7

Hay dos pasos para el método: primero, una función para guardar sus datos de campo de metabox personalizados (enganchado a save_post), y segundo, una función para leer ese nuevo post_meta (que acaba de guardar), validarlo y modificar el resultado de guardar según sea necesario (también enganchado a save_post, pero después del primero). La función del validador, si la validación falla, en realidad cambia el post_status de nuevo a "pendiente", evitando efectivamente la publicación de la publicación.

Como la función save_post se llama mucho, cada función tiene comprobaciones que solo se ejecutan cuando el usuario quiere publicar, y solo para su tipo de publicación personalizada (mycustomtype).

También normalmente agrego algunos mensajes de aviso personalizados para ayudar al usuario a saber por qué su publicación no se publicó, pero es un poco complicado incluirlos aquí ...

No he probado este código exacto, pero es una versión simplificada de lo que he hecho en configuraciones de tipo de publicación personalizada a gran escala.

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

Para múltiples campos de metabox, simplemente agregue más marcadores de finalización y recupere más post_meta y realice más pruebas.

somático
fuente
1

debe verificar / validar su valor de metacampo en ajax, es decir, cuando el usuario presiona el botón "Publicar / Actualizar" Aquí estoy validando el producto woocommerce que tiene un metacampo "product_number" para un valor vacío.

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

Después de eso, agregue la función de controlador 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();
}
Mohan Dere
fuente
0

Solo quería agregar eso para leer las variables de publicación, usando la solución de Bainternet, tendrá que analizar la cadena $_POST['form_data']usando la parse_strfunción PHP (solo para ahorrarle algo de tiempo de investigación).

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

Luego puede acceder a cada variable simplemente usando $varname. Por ejemplo, si tiene un metacampo llamado "my_meta", accedería de esta manera:

$vars = parse_str ( $_POST['form_data'] ) 
if ( $my_meta == "something" ) { // do something }
Agus
fuente