Validating content in WordPress Custom Post Types is not particularly simple in WordPress without the use of a plugin or Javascript (normally jQuery).
What I am going to show you here is how to validate input and replace the default admin message with our own error message.
Here is a very simple custom content type that contains just a title field. I have built this as a plugin but it could just as easy be inside the theme function file.
The end product will look like this
Note that the green success message has been removed
wp-content/plugins/ddkp-music-collection.php
<?php /* Plugin Name: Music Collection Post Types Plugin URI: http://kevinphillips.co.nz Description: Learning Custom Post Types Author: Kevin Phillips Version: 0.1 Author URI: http://kevinphillips.co.nz */
/** * Set up the post types */ add_action( 'init', 'ddkp_music_collection_register_post_types' );
/** * Register music collection post types */ function ddkp_music_collection_register_post_types() { // Set up the args for the music_album post type. $album_args = array( 'public' => true, 'query_var' => 'music_album', 'rewrite' => array( 'slug' => 'music/album', 'with_front' => false, ), 'supports' => array( 'title', 'thumbnail '), 'labels' => array( 'name' => 'Albums', 'singular_name' => 'Album', 'add_new' => 'Add New Album', 'add_new_item' => 'Add New Album', 'edit_item' => 'Edit Album', 'new_item' => 'New Album', 'view_item' => 'View Album', 'search_items' => 'Search Albums', 'not_found' => 'No Album Found', 'not_found_in_trash' => 'No Album found in trash', ) ); // Register the music album post type register_post_type( 'music_album', $album_args ); }
As you can see I have only added support for “title” and “thumbnail”
So currently if a user adds a new “Album” and then publishes it without a title the post type will save and will give you the message “Post published. View Post” and if you look in the “All Albums” you get a post that has been published without a title. “(no title)“
You need to understand that WordPress is always going to save a post, regardless because that is the workflow of adding a new post, what we are going to do is add some actions and filters.
The first thing we need to do is hook into the “save_post()” function.
/** * Add Action save_post * Note that we have specified 2 arguments, * these will be the post id and the post itself. */ add_action( 'save_post', 'album_save_post', 10, 2 );
Now lets add the function “album_save_post” with two args
/** * Function that will hook into save_post() * * @param int Post ID * @param Object the post * @return void */ function album_save_post( $album_id, $album ) { // First we only want music_album post types // and we don't want any auto saves if( defined('DOING_AUTOSAVE') && DOING_AUTOSAVE || $album->post_type != 'music_album' ) return; // Setup an empty array to hold our errors. // Even though we are only validating one field this // technique can be used for multiple fields $errors = array(); // Validation filters $title = $album->post_title; if ( ! $title ) { $errors['title'] = "The title field is required"; } // You can add more validation filters here! // if we have errors lets setup some messages if ( ! empty( $errors ) ) { // we must remove this action or it will // loop for ever @see codex remove_action( 'save_post', 'album_save_post' ); // save the errors as option so we can call // them back later update_option( 'album_errors', $errors ); // Change post from published to draft $album->post_status = 'draft'; // update the post wp_update_post( $album ); // we must add back this action add_action('save_post', 'album_save_post'); // admin_notice is create by a $_GET['message'] with // a number that wordpress uses to display the admin // message so we will add a filter for replacing // default admin // message with a redirect add_filter( 'redirect_post_location', 'album_post_redirect_filter' ); } }
We are now going to create the function that
removes the default admin notice and replace
it with a $_GET variable that our own function
can hook onto.
/** * Redirect Filter * * @param array * @return array */ function album_post_redirect_filter( $location ) { $location = remove_query_arg( 'message', $location ); // add our new query sting $location = add_query_arg( 'album', 'error', $location ); // return the location query string return $location; }
We are now going to add the custom admin notice
// Add new admin message add_action( 'admin_notices', 'album_post_error_admin_message' );
/** * Function to add custom admin message */ function album_post_error_admin_message() { // Check to see if isset( $_GET['album'] ) // we can use different values if we want if ( isset( $_GET['album'] ) && $_GET['album'] == 'error' ) { // lets get the errors from the option album_errors $errors = get_option('album_errors'); // now delete the option album errors delete_option('album_errors'); $display = '<div id="notice" class="error"><ul>'; // Because we are storing as an array we // should loop through them foreach ( $errors as $error ) { $display .= '<li>' . $error . '</li>'; } $display .= '</ul></div>'; // finally echo out our display echo $display; // add some jQuery // I know I said without Javascript, all // this does is add red border to the // input field. // You don't need this ?> <script> jQuery(function($) { $("#title").css({"border": "1px solid red"}) }); </script> <?php } }
That’s it. You can this to any number of fields on your custom post type.