I’m trying to do some server side validation of post fields (custom and/or non-custom fields). Validation works just fine, but I can’t seem to stop the post from saving if validation fails.

I tried hooks like save_post, publish_post, wp_insert_post_data, etc. All of these hooks are being called but I can’t stop the post from saving unless I use wp_die(). To be clear, I do not want to change the post status; I just want to return to the post page (unsaved) and show a message when the validation of a field fails.

I think this is pretty basic stuff, but whatever I do the post is being saved.

UPDATE:

OK, so the pre_post_update hook is an option. However, on a validation failure I need to use wp_redirect to get back to the edit page without saving. I’m storing the invalidation msgs and showing them on the page, but this way all the $_POST data is gone… which of course is not acceptable. Is there really no other way to do this?

Here’s my code so far:

add_action('pre_post_update', 'validate_meta', 99, 2);
function validate_meta($post_id){

    if ( defined('DOING_AUTOSAVE') && DOING_AUTOSAVE ) return $post_id;

    if (!isset($_POST['post_type']) )  return $post_id;

    if ( !current_user_can( 'edit_posts', $post_id ) ) return $post_id;

    $errors = array();

    if(trim($_POST['post_title']) == ''){
        $errors[] = new WP_Error('cpt_validation_titke',  'Bitte einen Titel eintragen', 'error');
    }

    if (!empty($errors)) {
        add_user_meta(get_current_user_id(), 'admin_notices', $errors, true);
        $url = admin_url( 'post.php?post=" . $post_id ) . "&action=edit';
        //exit;
        wp_redirect( $url );
        exit;     
    }
    return $_POST;
}

// Display any errors
add_action( 'admin_notices', 'admin_notice_handler' );
function admin_notice_handler() {
    $user_id = get_current_user_id();
    $admin_notices = get_user_meta($user_id, 'admin_notices', true);

    if(!empty($admin_notices)){
        $html="";

        if(is_wp_error($admin_notices[0])){

            delete_user_meta($user_id, 'admin_notices');

            foreach($admin_notices AS $notice){

                $msgs = $notice->get_error_messages();

                if(!empty($msgs)){
                    $msg_type = $notice->get_error_data();
                    if(!empty($notice_type)){
                        $html .= '<div class="'.$msg_type.'">';
                    } else {                    
                        $html .= '<div class="error">';
                        $html .= '<p><strong>Validation errors</strong></p>';
                    }

                    foreach($msgs as $msg){
                        $html .= '<p>- '.$msg.'</p>';
                    }                    
                    $html .= '</div>';                   
                }
            }
        }

        echo $html;
    }
}

5 s
5

You can capture the form submission by creating a small plugin / or by editing your theme functions file, and you can do this using a ajax hook. In the plugin you would load this on the edit post page:

jQuery(document).ready(function(){

jQuery('#post').submit(function(){
        var request = jQuery(this).serializeArray();
        request.push({name: 'action', value: 'check_some_stuff'});

        jQuery.post(ajaxurl, request, function(response){
            if(response.error){
                response = jQuery.parseJSON(response);
            jQuery('#local-storage-notice').after('<div class="error">'+response.error+'</div>');
        });
                return false;
        } else {
            return true;
        }
    });

});

When you return false, it will stop the form from submission.

The ajax will call a function check_some_stuff. The request gets send as $_POST. You can then validate server side all you want:

add_action( 'wp_ajax_check_some_stuff', 'check_some_stuff' );

public function check_some_stuff()
{
    //validate some stuff here
    $valid = false;
    if($valid){
        $results = array('msg'=>'You win');
        print json_encode($results);
    } else {
        $results = array('error'=>'<pre>'+print_r($_POST, true)+'</pre>');
        print json_encode($results);
    }
    die();
}

I can go in more detail on how to add the javascript in if you need.

Leave a Reply

Your email address will not be published. Required fields are marked *