ne publiez pas de type de publication personnalisé si un champ de métadonnées n'est pas valide

12

J'ai un type de message personnalisé (CPT) appelé event. J'ai une meta box pour le type avec plusieurs champs. Je souhaite valider certains champs avant de publier un événement. Par exemple, si la date d'un événement n'est pas spécifiée, je voudrais afficher un message d'erreur informatif, enregistrer l'événement pour une modification ultérieure, mais empêcher la publication de cet événement. Le statut «en attente» pour un poste CPT sans toutes les informations nécessaires est-il la bonne façon de le traiter?

Quelle est la meilleure pratique pour effectuer la validation des champs CPT et empêcher la publication d'un article, mais enregistrez-le pour une édition ultérieure.

Merci beaucoup, Dasha

dashaluna
la source
Un petit coup de pouce pour vous rappeler que cette question nécessite toujours une réponse acceptée ..;) Si aucune des réponses ne répond à votre question, veuillez envisager de mettre à jour votre question avec des commentaires supplémentaires détaillant ce qui n'a pas été résolu (ou où vous pourriez avoir besoin d'aide, le cas échéant).
t31os

Réponses:

14

Vous pouvez empêcher la publication de tout enregistrer avec des hacks JQuery mineurs et valider les champs avant de les enregistrer côté client ou côté serveur avec ajax:

nous ajoutons d'abord notre JavaScript pour capturer l'événement de soumission / publication et l'utiliser pour soumettre notre propre fonction ajax avant la soumission réelle:

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

puis nous créons la fonction pour effectuer la validation proprement dite:

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

vous pouvez toujours le modifier un peu pour faire la validation uniquement pour votre type de publication en ajoutant une vérification conditionnelle pour my_publish_admin_hookfonctionner pour votre type de publication et pour valider côté client mais je préfère côté serveur.

Bainternet
la source
N'y a-t-il aucun moyen côté serveur de le faire?
Jeff
1
C'est une façon côté serveur de le faire.
Bainternet
1
Peut-être que je comprends mal quelque chose. Il semble que vous utilisiez simplement PHP pour rendre JavaScript qui effectue la validation. Ce n'est pas une validation côté serveur. Je ne comprends pas vraiment comment cela pre_submit_validations'intègre.
Jeff
Le premier my_publish_admin_hookbloc intercepte la soumission côté client - mais il effectue ensuite un appel AJAX au serveur (pré-soumission officielle pre_submit_validation) qui effectue la validation côté serveur.
emc
1
Il s'agit toujours d'une validation côté client, même si elle utilise AJAX pour effectuer la validation. Le client doit exécuter le JavaScript en premier lieu pour qu'une validation ait lieu. Cependant ... J'ai toujours trouvé cette réponse utile pour la validation de la pré-soumission. Merci!
cr0ybot
7

La méthode comporte deux étapes: premièrement, une fonction pour enregistrer vos données de champ de métabox personnalisé (accroché à save_post), et deuxièmement, une fonction pour lire ce nouveau post_meta (que vous venez d'enregistrer), le valider et modifier le résultat de enregistrer si nécessaire (également accroché à save_post, mais après le premier). La fonction de validation, en cas d'échec de la validation, redéfinit en fait le post_status sur "en attente", empêchant ainsi la publication de la publication.

Puisque la fonction save_post est souvent appelée, chaque fonction a des vérifications à exécuter uniquement lorsque l'utilisateur veut publier, et uniquement pour votre type de publication personnalisé (mycustomtype).

J'ajoute généralement des messages de notification personnalisés pour aider l'utilisateur à savoir pourquoi leur message n'a pas été publié, mais ceux-ci sont devenus un peu compliqués à inclure ici ...

Je n'ai pas testé ce code exact, mais c'est une version simplifiée de ce que j'ai fait dans les configurations de type de message personnalisé à grande échelle.

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

Pour plusieurs champs de metabox, ajoutez simplement plus de marqueurs d'achèvement et récupérez plus de post_meta et faites plus de tests.

somatique
la source
1

vous devez vérifier / valider la valeur de votre méta-champ sur ajax, c'est-à-dire lorsque l'utilisateur clique sur le bouton "Publier / Mettre à jour". Ici, je valide un produit woocommerce ayant le champ méta "numéro_produit" pour une valeur vide.

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

Après cela, ajoutez la fonction de gestionnaire 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
la source
0

Je voulais juste ajouter que pour lire les variables de publication, en utilisant la solution de Bainternet, vous devrez analyser la chaîne en $_POST['form_data']utilisant la parse_strfonction PHP (juste pour vous faire gagner du temps de recherche).

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

Ensuite, vous pouvez accéder à chaque variable en utilisant simplement $varname. Par exemple, si vous avez un champ méta appelé "my_meta", vous y accéderez comme ceci:

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