Meta-Boxes for CustomPostType cause PHP Errors and Notices in “Add New” view

Start by reading the notices–they tell you very explicitly what the problem is.

Let’s start with the first one:

Notice: Undefined index: _wr_event_speaker in /Users/my/htdocs/wr/wp-content/themes/wr/functions.php on line 246

First, this is just a “notice”. Meaning that no error has actually occurred. PHP is just telling you that something isn’t quite right, but that it skipped over the problem and continued execution of the rest of the script.

Next, the notice itself is “Undefined index: _wr_event_speaker”. “Undefined index” means that you’re trying to access an array key that doesn’t actually exist (the key being “_wr_event_speaker”). In the case of meta boxes, you’re probably doing something like:

<input type="text" name="something" value="<?php echo $my_array['_wr_event_speaker'] ?>" />

But since you’re creating a NEW post, there is no value set for _wr_event_speaker yet, so you’re trying to echo something that doesn’t exist, and the notice is triggered. This explains why the notices only happen on new posts–old posts DO have a value set for _wr_event_speaker, so there’s no problem.

Now, look at the very end of the notice. It tells you that the notice was triggered on line 246 in the file “/Users/my/htdocs/wr/wp-content/themes/wr/functions.php”. This is where you’ll see the offending code (which probably looks something like my example above).

You can avoid these kinds of warnings in a lot of different ways. All of them involve checking if the array key is actually set before you try to access it. One way (if you want to do it inline) is to use “Ternary operators” in your echo statement, like so:

<input type="text" name="something" value="<?php echo ( isset( $my_array['_wr_event_speaker'] ) ? $my_array['_wr_event_speaker'] : '' ); ?>" />

This says to php: “if $my_array[‘_wr_event_speaker’] is set, print its value, otherwise print an empty string”. And it will stop the notice from being tripped.

It’s a best practice to always check whether or not an array key or object property exists before trying to print it.

EDIT BASED ON OP’S COMMENTS

Here are the modifications I’d suggest based on the code snip you posted. It look like a lot, but I’ve added some comments to (I hope) make it more clear. The gist of it is, besides using an “isset” (the original crux of your issue), you should always add the below boilerplate when hooking any function to the save_post action. There is some weirdness that needs to be accounted for to avoid future issues.

add_action('save_post', 'save_details');

function save_details($post_id){

    // Check for autosaves and quickedits. This is really important.
    // These types of saves DON'T pass in any custom meta box values, so for autosaves
    // and quickedits, just bail right away, or our post meta values will be
    // overwritten with blank ones!
    if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE || (defined('DOING_AJAX') && DOING_AJAX) ) 
    return;

    // The "save_post" action runs whenever any item of any type is saved, so you have to figure out what kind of item this is, and handle it accordingly.
    // Otherwise, your DB will fill up with blank values for this post meta, associated with all post types.
    $post_type = isset($_POST['post_type']) ? $_POST['post_type'] : '';

    switch($post_type) {

        // If this is the "post" post type
        case "post":

            // Update the _wr_event_review value
            $wr_event_review = isset($_POST['_wr_event_review']) ? wp_filter_post_kses($_POST['_wr_event_review']) : '';
            update_post_meta($post->ID, 'event_review', $wr_event_review);

            break;

    }

}

Edit

Note: you should really be sanitizing the input at this point. Looks like this is a textarea? In which case, you at least want to pass $_POST["_wr_event_review"] through wp_filter_post_kses() before saving.