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' );
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:
When saving the post, append errors and notices to the session:
Print notices and errors and then clean the messages in the session:
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.Then, just retrieve that error message on the next page load and display it. I also delete it so it wont get displayed twice.
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: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.
When
save_post
runs, it has already saved the post on the database.Looking into WordPress core code, more specifically at the
wp-includes/post.php
‘supdate_post()
function, there is no built-in way to intercept a request before it is saved on the database.However, we can hook
pre_post_update
and useheader()
andget_post_edit_link()
to prevent the post from being saved.If you to notify the user what went wrong, check this gist: https://gist.github.com/Luc45/09f2f9d0c0e574c0285051b288a0f935
Why don’t you validate your field with the help of some Javascript?
I think this would be the best approach for this.
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!
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.