Ordering custom posts by meta field date

I’ve tried every combination of examples here on the boards and nothing seems to get me what I need. I have an events post type with multiple fields in a custom meta box, one of which is a date field that saves in the form yyyymmdd. I need to query only the events that occur today and in the future, and sort in ASC order by date field. This will be used in a custom post type archive page.

Metabox function:

function events_metabox() {
global $post;
$typename = 'events';

$meta = get_post_meta($post->ID, $typename, true);

$date = ( !empty( $meta['date'] ) ) ? $meta['date'] : '';
$start = ( !empty( $meta['start'] ) ) ? $meta['start'] : '';
$end = ( !empty( $meta['end'] ) ) ? $meta['end'] : '';
$location = ( !empty( $meta['location'] ) ) ? $meta['location'] : '';
$form = ( !empty( $meta['form'] ) ) ? $meta['form'] : '';

wp_nonce_field( $typename, $typename . "-nonce" );
?>
<script type="text/javascript">
    jQuery(document).ready(function() {
        jQuery('#events_date').datepicker({
        dateFormat : 'yymmdd'
        });
    });

</script>
<div class="field">
    <label for="<?php echo $typename; ?>_address">Location:</label>
    <textarea id="<?php echo $typename; ?>_address" name="<?php echo $typename; ?>[location]" class="widefat"><?php echo $location; ?></textarea>
    <em class="field-summary summary">Event location.</em>
</div>
<div class="field">
    <label for="<?php echo $typename; ?>_phone">Event Date:</label>
    <input type="text" id="<?php echo $typename; ?>_date" name="<?php echo $typename; ?>[date]" value="<?php echo $date; ?>" />
    <em class="field-summary summary">Event date.</em>
</div>
<div class="field">
    <label for="<?php echo $typename; ?>_email">Start Time:</label>
    <input type="text" id="<?php echo $typename; ?>_start" name="<?php echo $typename; ?>[start]" value="<?php echo $start; ?>" />
    <em class="field-summary summary">Start time of event.</em>
</div>
<div class="field">
    <label for="<?php echo $typename; ?>_email">End Time:</label>
    <textarea id="<?php echo $typename; ?>_end" name="<?php echo $typename; ?>[end]"><?php echo $end; ?></textarea>
    <em class="field-summary summary">End time of event.</em>
</div>
<div class="field">
    <label for="<?php echo $typename; ?>_form">Web Form:</label>
    <textarea id="<?php echo $typename; ?>_form" name="<?php echo $typename; ?>[form]" class="widefat"><?php echo $form; ?></textarea>
    <em class="field-summary summary">Web Form.</em>
</div>
<?php } ?>

Function saving the custom meta fields:

function events_save_meta($post_id, $post) {
$typename = 'events';
$id = $post->ID;    

if(!isset($_POST[$typename])){
    return $id;
}

$meta = $_POST[$typename];

if (!wp_verify_nonce($_POST[$typename . "-nonce"], $typename)) return $id;

if ( defined('DOING_AUTOSAVE') && DOING_AUTOSAVE )
    return $id;

if( $typename != $_POST['post_type'] )
    return $id;

update_post_meta($id, $typename, $meta);
}

Post Query:

 $args = array(
 'post_type'   => 'events',
 'meta_key' => 'date',
 'orderby' => 'meta_value_num',
 'order' => 'ASC',
 'meta_query' => array(
  array(
     'key' => 'date',
     'value' => date('Ymd'),
     'compare' => '>=',
     'type' => 'NUMERIC'
  )
 )
);

$events_query = new WP_Query( $args );

Solutions Collecting From Web of "Ordering custom posts by meta field date"

You are not querying/saving the correct meta_key. For example, looking at your code, you pass $typename variable to update_post_meta() as meta_key and $typename = 'events'. But later in the query you are querying for meta_key = date. Also, you pass $meta as meta_value and in your actual code $meta is an array containing multiple values (location, date, start, etc).

 $typename = 'events';
 //$_POST[$typename] is actually an array
 $meta = $_POST[$typename];
 ......
 .....
 update_post_meta($id, $typename, $meta);

If you don’t touch the HTML of the meta box, you have to change the saving code and the query. For example:

add_action('save_post', 'events_save_meta');
function events_save_meta($post_id) {

    $typename = 'events';

    if ( isset($_POST['post_type']) && 'events' == $_POST['post_type'] ) {
            //You may need to change 'edit_post' for the correct capability set when register 'events' post type
        if ( !current_user_can( 'edit_post', $post_id ) ) {
                 return;
            }
    }

    if( !isset( $_POST[$typename . "-nonce"] ) || !wp_verify_nonce($_POST[$typename . "-nonce"], $typename) ) {
            return;
    }

    if( isset($_POST[$typename]['date']) ) {
         update_post_meta($post_id, 'date', $_POST[$typename]['date']);
    } else {
         delete_post_meta($post_id, 'date');
    }

 }

Now you have a meta field with meta_key = 'date' and you can query for this meta_key:

 $args = array(
      'post_type'   => 'events',
      'meta_key' => 'date',
      'meta_value' => current_time('Ymd'),
      'meta_compare' => '>=',
      'orderby' => 'meta_value_num',
      'order' => 'ASC'
      );

 $events_query = new WP_Query( $args );