5

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,

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'];
    }
}
2
  • It would be helpful if we knew exactly what you've already done ... can you add some code snippets and call out exactly where you're having issues?
    – EAMann
    Commented Sep 15, 2010 at 15:08
  • @EAMann - I've added the code now, any help much appreciated!
    – Mr. G
    Commented Sep 15, 2010 at 15:52

1 Answer 1

6

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');
2
  • Thanks Werner, very helpful... I'm now struggling to find a way of saving the date as a UNIX timestamp yet keep it legible on the admin screens. Any ideas?
    – Mr. G
    Commented Sep 17, 2010 at 14:11
  • I have updated the answer to illustrate how to convert to a timestamp for saving, and to convert the saved timestamp back for the end user's use. That just deals with your specific case, though. In real life I would consider using a meta-box with select controls which allows the user to construct the date (and optionally, the time) of the event. Such an implementation is a little bit more involving, and also falls outside your question's scope.
    – Werner
    Commented Sep 22, 2010 at 13:57

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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