WordPress Development Stack Exchange is a question and answer site for WordPress developers and administrators. Join them; it only takes a minute:

Sign up
Here's how it works:
  1. Anybody can ask a question
  2. Anybody can answer
  3. The best answers are voted up and rise to the top

I'm rebuilding a metabox for a plugin and it now won't save the data I enter. The HTML is almost exactly the same as before, but the save_meta function just don't work. I've read through quite a few tutorials, checked out tons of questions here on StackExchange and several other sites and tried to identify any easy pitfalls, but none of those seem to be the problem. Could someone check this out and show me what I missed here?


This is all in a class.

The array in the time_date_meta function is for another function that returns the HTML. As far as I can tell, this isn't the problem. The HTML field appears correctly and has nearly the same source code as the manually written-out HTML fields I had before. The differences between the hand-written HTML and this function's output are things like the name, class, and id attributes.

When I edit a post that already has metadata from before I rewrote this metabox, only the time and location fields show the correct data. I don't have any with the video URL and the date doesn't work at all.

function __construct() {

    // Add Seminar time and date meta box
    add_action( 'load-post.php', array( $this, 'seminar_create_meta_box' ) );
    add_action( 'load-post-new.php', array( $this, 'seminar_create_meta_box' ) );

    // Save meta data
    add_action( 'save_post', array( $this, 'save_meta' ), 10, 2 );


function seminar_create_meta_box() {

    add_meta_box( 'cemb_seminar_meta', 'Seminar Info', array ( $this, 'time_date_meta'), 'cemb_seminar', 'side', 'high' );

} // End of seminar_create_meta_box()

function time_date_meta( $post ) {

    // Grab data
    global $post;

    $checks = array( 'date', 'hour', 'minute', 'ampm', 'location' );
    $metas  = array();

    foreach ( $checks as $check ) {

        $meta_key   = 'cemb_seminar_' . $check;
        $meta_value = get_post_meta( $post->ID, $meta_key, true );
        $date       = ( $check == 'date' && empty( $meta_value ) ? time() : date( 'D, n/j/Y', strtotime( $meta_value ) ) );
        $value      = ( $check == 'date' ? $date : esc_attr( $meta_value ) );
        $metas[$check]  = ( !empty( $meta_value ) ? $value : '' );

    } // End of $checks foreach

    // Get optional video URL
    $meta_value         = get_post_meta( $post->ID, 'cemb_seminar_video_url', true );
    $metas['videourl']  = ( !empty( $meta_value ) ? esc_url( $meta_value ) : '' );

    // Security
    wp_nonce_field( basename( __FILE__ ), 'cemb_seminar_nonce' );

    // Output
    <div class="cemb_seminar_meta">

            $datepicker_args['class']       = 'seminar_date';
            $datepicker_args['id']          = 'cemb_seminar_date';
            $datepicker_args['label']       = 'Date';
            $datepicker_args['value']       = $metas['date'];

            echo $this->toolkit->date_picker( $datepicker_args ); ?></li>

            $time_args['class']                 = 'floatright';
            $time_args['id']                    = 'cemb_seminar_time';
            $time_args['label']                 = 'Time';

            $time_args['hours']['class']        = 'seminar_time';
            $time_args['hours']['id']           = 'cemb_seminar_hour';
            $time_args['hours']['military']     = false;
            $time_args['hours']['value']        = $metas['hour']; 

            $time_args['minutes']['class']      = 'seminar_time';
            $time_args['minutes']['id']         = 'cemb_seminar_minute';
            $time_args['minutes']['mintype']    = 'quarters';
            $time_args['minutes']['value']      = $metas['minute']; 

            $time_args['ampm']['class']         = 'seminar_time';
            $time_args['ampm']['id']            = 'cemb_seminar_ampm';
            $time_args['ampm']['value']         = $metas['ampm']; 

            echo $this->toolkit->time_fields( $time_args ); ?></li>

            $input_args['class']        = 'seminar_location';
            $input_args['id']           = 'cemb_seminar_location';
            $input_args['inputtype']    = 'text';
            $input_args['label']        = 'Location';
            $input_args['value']        = $metas['location'];

            echo $this->toolkit->input_field( $input_args ); ?></li>

            $input_args['class']        = 'seminar_video';
            $input_args['id']           = 'cemb_seminar_video_url';
            $input_args['inputtype']    = 'text';
            $input_args['label']        = 'Video URL';
            $input_args['value']        = $metas['videourl'];

            echo $this->toolkit->input_field( $input_args ); ?></li>

    </div> <?php

} // End of seminar_meta_box()

function save_meta( $post_id ) {

    if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) {

        return $post_id;

    } // End of Auto-Save check

    if ( $_POST['post_type'] == 'cemb_seminar' ) {

        if ( !current_user_can( 'edit_post', $post_id ) ) {

            return $post_id;

        } elseif ( !current_user_can( 'edit_page', $post_id ) ) { 

            return $post_id; 

        } // End of capability check

    } // End of post_type check

    if ( empty( $_POST['cemb_seminar_nonce'] ) && check_admin_referer( basename( __FILE__ ), 'cemb_seminar_nonce' ) ) {

        return $post_id;

    } else {

        $checks = array( 'date', 'hour', 'minute', 'ampm', 'location', 'video_url' );

        foreach ( $checks as $check ) {

            $meta_key   = 'cemb_seminar_' . $check;
            $posted     = $_POST[$meta_key];

            if ( empty( $posted ) && $posted != 'cemb_seminar_video_url' ) {

                // Return an error message if any field but video_url is empty
                $msg_args   = array( 'which' => 'empty', 'field' => $meta_key );
                $notices[]  = $this->display_notices( $msg_args );          

            } else {

                if ( $meta_key == 'cemb_seminar_date' ) {

                    // Get the posted date and convert it to PHP time
                    $new_meta_value = ( isset( $posted ) ? strtotime( $posted ) : '' );

                } else {

                    // Get the posted data and sanitize it for use as an HTML class.
                    $new_meta_value = ( isset( $posted ) ? sanitize_html_class( $posted ) : '' );

                } // End of $meta_key check

                // Get the meta value of the custom field key.
                $meta_value = get_post_meta( $post_id, $meta_key, true );

                if ( $new_meta_value && $meta_value == '' ) {

                    // If a new meta value was added and there was no previous value, add it.
                    add_post_meta( $post_id, $meta_key, $new_meta_value, true );

                } elseif ( $new_meta_value && $new_meta_value != $meta_value ) {

                    // If the new meta value does not match the old value, update it.
                    update_post_meta( $post_id, $meta_key, $new_meta_value );

                } elseif ( $new_meta_value == '' && $meta_value ) {

                    // If there is no new meta value but an old value exists, delete it.
                    delete_post_meta( $post_id, $meta_key, $meta_value );

                } // End of meta value checks

            } // End of empty check

        } // End of $checks foreach

        $semester_meta = get_post_meta( $post_id, '_semester', true );

        if ( empty( $semester_meta ) ) {

            $semester = $this->determine_semester( $date ) . ' ' . date( 'Y', $date );

            update_post_meta( $post_id, '_semester', $semester );

        } // End of empty check

    } // End of nonce check

} // End of save_meta()
share|improve this question
Are you sure it isn't saving or isn't displaying in your box correctly? if you do a var_dump(get_post_custom($post->ID)) do you see the data? Also, I'd probably switch check admin referrer to a nonce check. I'm debugging my own save_post function right now and I found it helpful to update_option('debug_dump') through every step to find where it was failing. die('message') might also help you pinpoint the solution. Or to save yourself time you could use: deluxeblogtips.com/meta-box – helgatheviking Sep 20 '12 at 17:34
Yes, I have another meta box on the same page that shows me each meta data's value. I also put a value in the Location field and submitted. The var_dump you recommended and it doesn't show the value I put into the field. Since I found the meta_box plugin, I've been seriously debating switching, but I can't help thinking I'm just one line of code away from having this down. – Slushman Sep 20 '12 at 18:28
I can't test this exactly because it is missing the toolkit variable/method. So I created a test input as the following <input type="text" name="cemb_seminar_date" value="<?php echo $metas['date']; ?>" /> ` it saves and regurgitates correctly. – helgatheviking Sep 20 '12 at 19:00
I didn't realize I didn't have Debug turned on for my dev site. When I turned it on, I discovered there was an issue with how I registered a stylesheet. Not sure why this affects saving metabox data, but it did. I fixed that and all but two of my metaboxes are now saving. Video URL and the date still don't work. Thanks for your help Helga, I'll post more as I figure this out. – Slushman Sep 20 '12 at 20:52
Update: the date field wasn't displaying data because it was using the input type date, which apparently conflicts with jQuery's datepicker. Switching to a regular text field and everything works nicely. Still working on the URL field. – Slushman Sep 20 '12 at 21:29

There were three issues:

The first wasn't visible in the code presented. a wp_register_styles call was put into the constructor, which caused errors and somehow prevented saving post metadata.

Second, the date field was a HTML5 date field, which conflisted with jQuery's datepicker. Changing it to a text field fixed that.

Third, the final if statement in the save_meta function would evaluate true whether the metakey existed or not. If it did exist, it wouldn't get updated since that statement had the add_post_meta function. The second conditional statement ($new_meta_value && $new_meta_value != $meta_value) would be true in both cases and used the update_post_meta function, which will also create a new metakey if it doesn't already exist.

share|improve this answer
Glad you got it sorted out! – helgatheviking Sep 21 '12 at 4:12

Your Answer


By posting your answer, you agree to the privacy policy and terms of service.

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