Take the 2-minute tour ×
WordPress Development Stack Exchange is a question and answer site for WordPress developers and administrators. It's 100% free, no registration required.

I have a function that defines a custom field on a post type. Say the field is "subhead".

When the post is saved, I want to do some validation on the input, and display an error message on the post edit screen if necessary. Something like:

// Handle post updating
function wpse_update_post_custom_values($post_id, $post) {

    // Do some checking...
    if($_POST['subhead'] != 'value i expect') {

        // Add an error here
        $errors->add('oops', 'There was an error.');

    }

    return $errors;

} 
add_action('save_post','wpse_update_post_custom_values',1,2);

I'm trying to hook this to the save_post action, but I can't figure out how to handle errors. There doesn't appear to be an error object passed into the function, and if i create my own WP_Error obj and return it, it's not respected by whatever mechanism spits out errors on the post edit page.

I currently have an on-page error message inside my custom meta box, but this is less than ideal--I'd rather have a big, red, up-at-the-top error like WP normally displays.

Any ideas?

UPDATE:

Based on @Denis' answer, I tried a few different things. Storing errors as a global didn't work, because Wordpress does a redirect during the save_post process, which kills the global before you can display it.

I ended up storing them in a meta field. The problem with this is that you need to clear them out, or they won't go away when you navigate to another page, so I had to add another function attached to the admin_footer that just clears out the errors.

I wouldn't have expected that error handling for something so common (updating posts) would be this clunky. Am I missing something obvious or is this the best approach?

// Handle post updating
function wpse_5102_update_post_custom_values($post_id, $post) {

    // To keep the errors in
    $errors = false;

    // Do some validation...
    if($_POST['subhead'] != 'value i expect') {

        // Add an error here
        $errors .= 'whoops...there was an error.';

    }

    update_option('my_admin_errors', $errors);

    return;

} 
add_action('save_post','wpse_5102_update_post_custom_values',1,2);


// Display any errors
function wpse_5102_admin_notice_handler() {

    $errors = get_option('my_admin_errors');

    if($errors) {

        echo '<div class="error"><p>' . $errors . '</p></div>';

    }   

}
add_action( 'admin_notices', 'wpse_5102_admin_notice_handler' );


// Clear any errors
function wpse_5102__clear_errors() {

    update_option('my_admin_errors', false);

}
add_action( 'admin_footer', 'wpse_5102_clear_errors' );
share|improve this question
    
Good question. I think you could get rid of the admin_footer hook if you clear out the errors at the end of your notice handler function. Simplifies things just a bit. –  Geert May 3 '11 at 6:54
    
How are you dealing with repopulating the form fields (with the possible invalid data)? –  Geert May 3 '11 at 6:58
    
I have a basic question. What Wordpress php file is this in? –  user5721 May 26 '11 at 23:25
    
@Karen This would be in a custom plugin file, or in your functions.php. –  MathSmath May 27 '11 at 4:38
    
I might be missing something obvious, but would it be slightly more efficient to run update_option('my_admin_errors', false); immediately after the if statement at the end of wpse_5102_admin_notice_handler()? –  Andrew Odri Nov 30 '12 at 22:55
show 1 more comment

6 Answers

up vote 3 down vote accepted

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.

share|improve this answer
    
Thanks for pointing me in this direction! I ended up using a meta to store errors, because I had issues trying to do it as a global or a property. I'm updating my answer right now to explain how I'm doing it... please let me know if this is the kind of thing you were suggesting, or if there's a better way that I'm not getting. –  MathSmath Dec 10 '10 at 0:15
    
That kind of thing, yeah. Maybe store it in a session variable, on second thoughts, though. This, in order to enable multiple authors to edit posts at the same time. :-) Also, I believe it's not possible to store false in an option. Store an empty string instead. –  Denis Dec 10 '10 at 9:35
add comment

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' );
share|improve this answer
    
fix for the session version: at the first time of using the session variable don't use .= only = if you turn on the debugging, you can check why... –  user18140 Jul 13 '12 at 13:12
2  
I've been doing this too, but if you release a plugin to a wide audience like that people will end up hating you for it. Wordpress doesn't instantiate sessions because it's designed to be stateless and not need them, and some weird server setups will break it. Use the transients API - codex.wordpress.org/Transients_API instead of sessions and you'll maintain compatibility. Just thought it was worth flagging a reason why not to do this here. –  pospi Sep 12 '12 at 1:37
    
@pospi this seems to have similar issues as the original use of the get_option and update_option functions. So I guess the solution would be to append the current user's ID to the key? –  Gazillion Oct 24 '13 at 16:55
    
Yeah that would totally work! So long as you add something to uniquely identify the user you will avoid messages being mixed up between logged in users (: –  pospi Oct 28 '13 at 0:23
add comment

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.

share|improve this answer
    
Could you elaborate on "Since the post ID is part of the transient name"? I created a class to handle error messages using this technique but I require my constructor to pass a user_ID. Does the transient API use the user_id when hashing the key? (I ask because the codex doesn't seem to mention this) –  Gazillion Oct 24 '13 at 17:37
add comment

Why don't you validate your field with the help of some Javascript? I think this would be the best approach for this.

share|improve this answer
    
Thanks for the suggestion! What I left out of the question (for simplicity sake) is that I'm trying to handle file upload errors, so it needs to be server-side. Thanks for the suggestion though! –  MathSmath Dec 10 '10 at 16:33
    
javascript validating doesn't prevent from some attacks, server-side validation is the only secure one. Furthermore, wordpress offer some good tools to validate user data. But you're right if it just check some values before sending data to server, you can save some time in low server ^^ –  nderambure Mar 14 '11 at 23:50
add comment

Trying to use the script above, I ran into a strange problem. Two messages are shown on the edit screen, after the post update. One is showing state of the content from previous save and another one from the current. For example, if I save the post properly and then make an error, first one is "error" and second one is "ok" - altough they are generated in the same time. If I change the script and append only one message (e.g. "error"), initiate one update with "error" and after that another one with "ok", "error" message stays (is displayed for the second time). I must save with "ok" once again to get rid of it. I really don't know what's wrong, I've tested it on three different local servers and there's the same issue on each one of them. If anyone has any idea or suggestion, please help!

share|improve this answer
    
I did some more tests of the simplier, second version of script which I've mentioned above and it seems that if the "error" message is really appended to session array, it is shown on edit screen. If there is no message (everything is "ok") and previous message was error, it appears on the screen. What is strange, it is generated on the time of saving (not cached) - I've checked it using date() in the error message body. I'm totally confused now. –  jlub Sep 8 '11 at 17:55
    
Ok, in case anyone else is pulling hair out of his head - it turned out that the Wordpress revisions system was the problem (some kind of bug probably?). I've disabled it and now everything is just fine. –  user8594 Sep 12 '11 at 9:41
add comment

I've written a plugin that adds in a flash error handling for post edit screens and prevents posts being published until required fields are filled out:

https://github.com/interconnectit/required-fields

It allows you to make any post fields mandatory but you can use the API it provides to make any custom fields required too with a customisable error message and validation function. It defaults to checking if the field is empty or not.

share|improve this answer
    
Very cool. Will definitely use this in future projects. –  MathSmath Dec 5 '12 at 16:23
    
Don't hesitate to add any issues on github if you come across them. I need to document the API a bit better too as there are some adiditional filters you can use. –  sanchothefat Dec 7 '12 at 14:13
add comment

protected by Community Nov 12 '12 at 5:34

Thank you for your interest in this question. Because it has attracted low-quality answers, posting an answer now requires 10 reputation on this site.

Would you like to answer one of these unanswered questions instead?

Not the answer you're looking for? Browse other questions tagged or ask your own question.