Wordpress - Add validation and error handling when saving custom fields?

Store errors in your class or as a global, possibly in a transient or meta, and display them in admin notices on POST requests. WP does not feature any flash message handler.


I suggest to use sessions since this will not create strange effects when two users editing at the same time. So this is what I do:

Sessions are not started by wordpress. So you need to start a session in your plugin, functions.php or even wp-config.php:

if (!session_id())
  session_start();

When saving the post, append errors and notices to the session:

function my_save_post($post_id, $post) {
   if($something_went_wrong) {
     //Append error notice if something went wrong
     $_SESSION['my_admin_notices'] .= '<div class="error"><p>This or that went wrong</p></div>';
     return false; //might stop processing here
   }
   if($somthing_to_notice) {  //i.e. successful saving
     //Append notice if something went wrong
     $_SESSION['my_admin_notices'] .= '<div class="updated"><p>Post updated</p></div>';
   }

   return true;
} 
add_action('save_post','my_save_post');

Print notices and errors and then clean the messages in the session:

function my_admin_notices(){
  if(!empty($_SESSION['my_admin_notices'])) print  $_SESSION['my_admin_notices'];
  unset ($_SESSION['my_admin_notices']);
}
add_action( 'admin_notices', 'my_admin_notices' );

Based on pospi's suggestion to use transients, I came up with the following. The only problem is there is no hook to put the message below the h2 where other messages go, so I had to do a jQuery hack to get it there.

First, save the error message duing your save_post (or similar) handler. I give it a short lifetime of 60 seconds, so it is there just long enough for the redirect to happen.

if($has_error)
{
  set_transient( "acme_plugin_error_msg_$post_id", $error_msg, 60 );
}

Then, just retrieve that error message on the next page load and display it. I also delete it so it wont get displayed twice.

add_action('admin_notices', 'acme_plugin_show_messages');

function acme_plugin_show_messages()
{
  global $post;
  if ( false !== ( $msg = get_transient( "acme_plugin_error_msg_{$post->ID}" ) ) && $msg) {
    delete_transient( "acme_plugin_error_msg_{$post->ID}" );
    echo "<div id=\"acme-plugin-message\" class=\"error below-h2\"><p>$msg</p></div>";
  }
}

Since admin_notices fires before the primary page content is generated, the notice is not where the other post edit messages go, so I had to use this jQuery to move it there:

jQuery('h2').after(jQuery('#acme-plugin-message'));

Since the post ID is part of the transient name, this should work in most multi-user environments except when multiple users are concurrently editing the same post.