Automatically sorting custom post type admin area by a custom field

I have created a custom post type to display future events, with the event’s date stored in a custom field (YYYY/MM/DD format). I’d like the admin screen for this custom post type to be automatically sorted by the event date custom field.

Having tried out MikeSchnickel’s excellent tutorial on creating a ‘sort by’ column, I think I’ve worked out that I need to use something similar to the parse_query filter he uses. But I can’t seem to adapt it to my needs,

Read More

I’m pretty new to customizing wordpress like this, so some simple guidance would be much appreciated!

Here’s my code to register the custom type post (gs_events), add meta box for the custom field (event_date), and set up custom columns for the admin screen….

add_action('init', 'my_custom_init');

function my_custom_init() {
  $labels = array(
    'name' => _x('Events', 'post type general name'),
    'singular_name' => _x('Event', 'post type singular name'),
    'add_new' => _x('Add New', 'event'),
    'add_new_item' => __('Add New Event'),
    'edit_item' => __('Edit Event'),
    'new_item' => __('New Event'),
    'view_item' => __('View Event'),
    'search_items' => __('Search Events'),
    'not_found' =>  __('No events found'),
    'not_found_in_trash' => __('No events found in Trash'), 
    'parent_item_colon' => ''
  );
  $args = array(
    'labels' => $labels,
    'public' => true,
    'publicly_queryable' => true,
    'show_ui' => true, 
    'query_var' => true,
    'rewrite' => array('slug' => 'events'),
    'capability_type' => 'post',
    'hierarchical' => false,
    'menu_position' => 5,
    'supports' => array('title','editor','thumbnail','comments')
  ); 
  register_post_type('gs_events',$args);
}

register_taxonomy("Location", array("gs_events"), array("hierarchical" => true, "label" => "Cities", "singular_label" => "City", "rewrite" => true));

add_action("admin_init", "admin_init");

function admin_init(){
  add_meta_box("event_date-meta", "Event Date", "event_date", "gs_events", "side", "high");
}

function event_date(){
  global $post;
  $custom = get_post_custom($post->ID);
  $event_date = $custom["event_date"][0];
  ?>
  <label>Date:</label>
  <input name="event_date" value="<?php echo $event_date; ?>" />
  <?php
}

add_action('save_post', 'save_details');

function save_details(){
  global $post;
  update_post_meta($post->ID, "event_date", $_POST["event_date"]);
}

add_action("manage_posts_custom_column",  "events_custom_columns");
add_filter("manage_edit-gs_events_columns", "events_edit_columns");

function events_edit_columns($columns){
  $columns = array(
    "cb" => "<input type="checkbox" />",
    "title" => "Venue",
    "location" => "Location",
    "event_date" => "Date",
  );

  return $columns;
}
function events_custom_columns($column){
  global $post;

  switch ($column) {
    case "event_date":
      $custom = get_post_custom();
      echo $custom["event_date"][0];
      break;
    case "location":
      echo get_the_term_list($post->ID, 'Location', '', ', ','');
      break;
  }
}

And I reckon I need to add some modification of this code from Mike Schnickels’s aforementioned tutorial, but I’m not sure how to implement it in this case…

add_filter( 'parse_query', 'sort_movie_by_meta_value' );
function sort_movie_by_meta_value($query) {
    global $pagenow;
    if (is_admin() && $pagenow=='edit.php' &&
            isset($_GET['post_type']) && isset($_GET['post_type'])=='movie' && 
            isset($_GET['sortby'])  && $_GET['sortby'] !='None')  {
        $query->query_vars['orderby'] = 'meta_value';
        $query->query_vars['meta_key'] = $_GET['sortby'];
    }
}

Related posts

Leave a Reply

1 comment

  1. Rather save the event meta field date(s) as a unix-timestamp, instead of a string, or you’ll be making life too difficult for yourself. It just makes date comparisons so much easier.

    Here’s an example of how to convert your YYYY/MM/DD format to a unix timestamp:

    $date = '2010/09/22';
    $dateParts = explode('/', trim($date));
    if (count($dateParts) == 3) {
        $timestamp = mktime(0, 0, 0, $dateParts[1], $dateParts[2], $dateParts[0]);
    } else {
        $timestamp = 0; 
        // The input value is dodgy, therefore the timestamp is set to 0, which is 
        // effectively 1970-01-01T00:00:00Z.
    }
    

    To convert back again for user editing and displaying, it’s as simple as:

    $displayValue = date('Y/m/d', $timestamp);
    

    I’d also recommend that you name your custom field something more specific, like gs_event_date?

    After you have done that, create your filter:

    function gs_events_pre_get_posts($query) {
    
        // Note: Use the $pagenow global for finer grained checking, 
        // if you want to. There are many examples out there.
    
        // Your question pertains to admin use only...
    
        if (is_admin()) {
    
            // Present the posts in your meta_key field's order in admin
    
            if (isset($query->query_vars['post_type'])) {
                if ($query->query_vars['post_type'] == 'gs_events') {
    
                    $query->set('meta_key', 'gs_event_date');
                    $query->set('orderby', 'meta_value');
                    $query->set('order', 'ASC');
    
                    // ...and if you only want your future events to be 
                    // displayed in admin, you can uncomment the following:
    
                    // $query->set('meta_compare', '>=');
                    // $query->set('meta_value', time());
    
                    // Note: The use of time() is quick-and-dirty here, 
                    // in reality you'll need to adjust the timezone, 
                    // check server-time vs local time, etc.
                }
            }
        }
    }
    

    Add your filter…

    add_filter('pre_get_posts' , 'gs_events_pre_get_posts');