não publique postagem de tipo de postagem personalizada se um campo de metadados não for válido

12

Eu tenho um tipo de postagem personalizado (CPT) chamado event. Eu tenho uma caixa meta para o tipo com vários campos. Gostaria de validar alguns campos antes de publicar um evento. Por exemplo, se a data de um evento não for especificada, eu gostaria de exibir uma mensagem de erro informativa, salve o evento para edição futura, mas impeça a publicação desse evento. O status 'pendente' de uma postagem de CPT sem todas as informações necessárias é a maneira correta de tratá-la?

Qual é a melhor prática para validar campos de CPT e impedir que uma postagem seja publicada, mas salve-a para edição futura.

Muito obrigado, Dasha

dashaluna
fonte
Se você não responder a sua pergunta, considere atualizá-la com comentários adicionais detalhando o que não foi abordado (ou onde você pode precisar de ajuda, se aplicável).
T31os

Respostas:

14

Você pode impedir que a postagem salve tudo junto com pequenos hacks JQuery e valide os campos antes de salvar no lado do cliente ou no servidor com o ajax:

primeiro, adicionamos nosso JavaScript para capturar o evento de envio / publicação e o usamos para enviar nossa própria função ajax antes do envio 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
    }
}

então criamos a função para fazer a validação 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();
}

você sempre pode alterá-lo um pouco para fazer a validação apenas do seu tipo de postagem, adicionando uma verificação condicional para my_publish_admin_hookfuncionar para o seu tipo de postagem e validar no lado do cliente, mas eu prefiro no lado do servidor.

Bainternet
fonte
Não existe uma maneira do servidor de fazer isso?
Jeff
1
Esta é uma maneira do lado do servidor de fazer isso.
Bainternet
1
Talvez eu esteja entendendo mal alguma coisa. Parece que você está apenas usando PHP para renderizar JavaScript, o que faz a validação. Isso não é validação do lado do servidor. Eu não estou realmente entender como o pre_submit_validationencaixa.
Jeff
O primeiro my_publish_admin_hookbloco intercepta o envio do cliente após o envio - mas, em seguida, faz uma chamada AJAX para o servidor (envio pré-oficial pre_submit_validation) que executa a validação do lado do servidor.
emc
1
Ainda é uma validação do lado do cliente, mesmo que esteja usando o AJAX para fazer a validação. O cliente precisa executar o JavaScript em primeiro lugar para que qualquer validação ocorra. No entanto ... ainda achei esta resposta útil para validação de pré-envio. Obrigado!
precisa saber é
7

Há duas etapas no método: primeiro, uma função para salvar os dados do campo metabox personalizado (conectado ao save_post) e, segundo, uma função para ler esse novo post_meta (que você acabou de salvar), validá-lo e modificar o resultado de salvando conforme necessário (também conectado ao save_post, mas após o primeiro). A função validadora, se a validação falhar, na verdade altera o post_status de volta para "pendente", impedindo efetivamente a publicação da postagem.

Como a função save_post é chamada muito, cada função tem verificações para executar apenas quando o usuário pretende publicar e apenas para o seu tipo de postagem personalizado (mycustomtype).

Normalmente, também adiciono algumas mensagens de aviso personalizadas para ajudar o usuário a saber por que a postagem não foi publicada, mas essas foram um pouco complicadas de incluir aqui ...

Não testei esse código exato, mas é uma versão simplificada do que fiz em configurações de tipo de postagem personalizadas em larga 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 vários campos metabox, basta adicionar mais marcadores de conclusão, recuperar mais post_meta e fazer mais testes.

somático
fonte
1

você deve verificar / validar seu valor de meta campo no ajax, ou seja, quando o usuário clicar no botão "Publicar / Atualizar". Aqui estou validando o produto woocommerce com o meta campo "product_number" para o valor vazio.

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

Depois disso, adicione a função manipulador 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
fonte
0

Só queria acrescentar que, para ler as variáveis ​​de postagem, usando a solução da Bainternet, você terá que analisar a string $_POST['form_data']usando a parse_strfunção PHP (apenas para poupar algum tempo de pesquisa).

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

Então você pode acessar cada variável apenas usando $varname. Por exemplo, se você tiver um meta campo chamado "my_meta", poderá acessá-lo assim:

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