Correct Approach for Validating Custom Field Input

I have a custom post type with several custom fields. I am looking to do some validation on these fields because they will be used downstream by other services. So, it is important that it can’t be saved until it is correctly entered. The validation is reasonably complex and requires custom logic.

Unfortunately, it also won’t work to use a plugin in this particular case.

Read More

Is there an ideal hook to use in this case? At a high level — whats the best way to go about this.

Related posts

Leave a Reply

2 comments

  1. (Taken from my answer to a similar question posted here)

    There are two steps to this method: first, a function to save your custom metabox field data (hooked to save_post), and second, a function to read that new post_meta (which you just saved), validate it, and modify the result of saving as necessary (also hooked to save_post, but after the first). The validator function, if validation fails, actually changes the post_status right back to “pending”, effectively preventing the post from being published.

    Since the save_post function gets called a lot, each function has checks to only execute when the user means to publish, and only for your custom post type (mycustomtype).

    I also typically add some custom notice messages to help the user know why their post didn’t publish, but those got a bit complicated to include here…

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

    For multiple metabox fields, just add more completion markers and retrieve more post_meta and do more tests..