Add validation and error handling when saving custom fields?

admin2025-06-05  2

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

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 edited Dec 10, 2010 at 0:25 MathSmath asked Dec 9, 2010 at 21:57 MathSmathMathSmath 5,5984 gold badges26 silver badges23 bronze badges 6
  • 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 Commented May 3, 2011 at 6:54
  • 1 How are you dealing with repopulating the form fields (with the possible invalid data)? – Geert Commented May 3, 2011 at 6:58
  • 1 I have a basic question. What Wordpress php file is this in? – user5721 Commented May 26, 2011 at 23:25
  • @Karen This would be in a custom plugin file, or in your functions.php. – MathSmath Commented May 27, 2011 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 Commented Nov 30, 2012 at 22:55
 |  Show 1 more comment

7 Answers 7

Reset to default 7

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.

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's update_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 use header() and get_post_edit_link() to prevent the post from being saved.

<?php

/**
*   Performs validation before saving/inserting custom post type
*/
function custom_post_site_save($post_id, $post_data) {
    // If this is just a revision, don't do anything.
    if (wp_is_post_revision($post_id))
        return;

    if ($post_data['post_type'] == 'my_custom_post_type') {
        // Deny post titles with less than 5 characters
        if (strlen($post_data['post_title'] < 5)) {
            header('Location: '.get_edit_post_link($post_id, 'redirect'));
            exit;
        }
    }
}
add_action( 'pre_post_update', 'custom_post_site_save', 10, 2);

If you to notify the user what went wrong, check this gist: https://gist.github/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/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.

转载请注明原文地址:http://conceptsofalgorithm.com/Algorithm/1749064228a316046.html

最新回复(0)