If you use a plug-in or template code to place custom fields on the post or page editor screen, recent changes to WordPress may result in your custom data being deleted or lost.
Assuming you’ve placed a simple metabox on the post editor holding a text input named “custom_data”, here’s the standard way of hooking save_post to save it:
function save_custom_data($post_id, $post) {
if (!$post_id) $post_id = $_POST['post_ID'];
if (!$post_id) return $post;
$customdata = $_POST['custom_data'];
if ($customdata) {
add_post_meta($post_id, 'custom_data', $customdata, true) or
update_post_meta($post_id, 'custom_data', $customdata);
} else {
delete_post_meta($post_id, 'custom_data');
}
}
add_action('save_post', 'save_custom_data', 11, 2);
This code will save the “custom_data” text in the post meta table or delete it if no text is supplied (you could also save an empty field, or provide a default value of course). This code will work correctly when you test it, but contains a major bug which will result in your custom data being deleted, as well as one minor bug.
The problem arises when the post is updated using the “Quick Edit” feature on the post list screen. In this situation, WordPress still calls the save_post action, but your “custom_data” field isn’t in the posted data (the $_POST[] array). Hence your save code will assume an empty field was supplied and take the appropriate action (in the example above, it will be deleted).
The fix is to specifically test that at least one of your custom fields has been posted and if not, do nothing. To effect this, the above code would be modified as follows:
if ( (!$post_id) || (!isset($_POST['custom_data'])) ) return $post;
The additional minor problem is that save_post is also called when WordPress autosaves posts. When you save data indexed by post ID via save_post, unless you test for autosaves you’ll end up with superfluous data being stored for every single autosave because these generate additional rows in the Posts table. While there’s no real problem with the example above, apart from unnecessary growth of the post meta table, if the data is being saved in a custom table which you subsequently search, there will be a major problem with incorrect post IDs being returned.
Fortunately the fix is again very simple: ensure you are saving an actual Post or Page by testing the post_type field of $post. Autosaves have a post_type of “revision” because technically they are neither posts nor pages. Here’s the modifed code taking into account the previous problem:
if ( (!$post_id) || (!isset($_POST['custom_data'])) || ($post->post_type != 'post') ) return $post;
Obviously “post” should be changed to “page” if required, or test for both. You could simply test for “revision”, but WordPress is just as likely to introduce new post types creating a future problems.


Thanks for this tip which has helped me a lot
However I’ve deleted all together the 2nd line of your code :
if (!$post_id) $post_id = $_POST['post_ID'];because it didn’t seem to be of any use.
Yeah, that’s really a throw-back to earlier versions of WP. I haven’t seen any places in WP in recent versions where $post_id isn’t set when the action is called.
I should also say there is a new “standard” way of testing for revisions and getting the original “real” post ID, however you still need to check that your plug-in fields are present in $_POST[] because they won’t be when the quick editor is used instead of the full post editor screen.
is there ? Plugin development is new to me, and I’m eager to learn all the tricks to make decent code.
Also the API could be better documented sometimes.
Is there a reason I might not be experiencing this?
I’m using the latest version of WP and the only function I use for saving is:
function save_salary(){
global $post;
update_post_meta($post->ID, “salary”, $_POST["salary"]);
}
Is there a downside to what I’m doing?
The possible downside depends on where you’re calling save_salary. If you’re hooking the save_post event then you risk the problem I mentioned when a post is edited using the Quick Editor, or even when a comment is made on the post. At the very least you should test that you actually have the salary field –
if (isset($_POST["salary"])) ....Also, if you’re expecting that “salary” is a pure number, you should typecast it so that any errors will be spotted when the post is saved, not when the value is being used, ie
(float) $_POST["salary"].