spacer

This summer I’ve been busy with my GSoC project, which involved making columns sortable on list-type screens in the WordPress administration area. Yesterday, that work was included in trunk, so if you’re on the bleeding edge (3.1-alpha), you should see something like this:

spacer

That’s all very nice, you say, but how do I make sortable columns of my own? First, let’s make a plain, old, non-sortable column:

// Register the column
function price_column_register( $columns ) {
	$columns['price'] = __( 'Price', 'my-plugin' );
 
	return $columns;
}
add_filter( 'manage_edit-post_columns', 'price_column_register' );

Nothing new here. We’re just using a well-known hook to add a Price column on the posts screen. Then, with another hook, we’re displaying the value, which is stored in a custom field in this case:

// Display the column content
function price_column_display( $column_name, $post_id ) {
	if ( 'price' != $column_name )
		return;
 
	$price = get_post_meta($post_id, 'price', true);
	if ( !$price )
		$price = '<em>' . __( 'undefined', 'my-plugin' ) . '</em>';
 
	echo $price;
}
add_action( 'manage_posts_custom_column', 'price_column_display', 10, 2 );

Now comes the interesting part:

// Register the column as sortable
function price_column_register_sortable( $columns ) {
	$columns['price'] = 'price';
 
	return $columns;
}
add_filter( 'manage_edit-post_sortable_columns', 'price_column_register_sortable' );

We first need to tell WordPress that this is a sortable column. As you can see, the hook name is very similar to the one we used to register the column in the first place. 1

There’s just one more thing we need to do. Since WordPress doesn’t know how to handle ‘orderby=price’, we’ll have to teach it, by altering the query variables:

function price_column_orderby( $vars ) {
	if ( isset( $vars['orderby'] ) && 'price' == $vars['orderby'] ) {
		$vars = array_merge( $vars, array(
			'meta_key' => 'price',
			'orderby' => 'meta_value_num'
		) );
	}
 
	return $vars;
}
add_filter( 'request', 'price_column_orderby' );

We’re basically telling it to order by the ‘price’custom field we displayed before. 2

And that’s all there is to it. This is how it should look:

spacer

Here’s the full code, for convenience: https://gist.github.com/906872

Update: With the CodePress Admin Columns plugin you can manage admin columns through a GUI.

Notes:

  1. The first ‘price’represents the internal column name, while the second is the value sent to the ?orderby= query variable. ↩
  2. More info on meta_value_num. ↩

Reactions (3)

  • Whatโ€™s new and exciting in WordPress 3.1 | WPCandy says:
    23 Feb 2011 at 5:31 pm

    [...] got caught up and have been put off for 3.1.ย  This project was a GSoC project of Cristi Burca, who has even shared how to make our own columns sortable as [...]

  • Outstanding New features of WordPress 3.1(Reinhardt) - Wordpress Arena says:
    4 Apr 2011 at 11:40 am

    [...] This project was a GSoC project of Cristi Burca, On “How to Create your own sortable columns“. [...]

  • Limitations on Sortable Columns | Ipstenu on Tech says:
    12 Sep 2011 at 11:33 pm

    [...] very helpful links:Stereo Interactive & Design » WordPress 3.1 sortable admin tablesCreate your own sortable columns by scribuThese both told you how to add columns to the posts table. But what I wanted to do was add a column [...]

Comments (80)

  • spacer Victor Teixeira says:
    14 Aug 2010 at 7:42 am

    Ok, but what if the price was a number like 1,402.95?

    How can the database sort it if this is not stored as a double or float?

    • spacer scribu says:
      14 Aug 2010 at 2:19 pm

      You can cast it:

      (SELECT CAST(meta_value as decimal) ...)

  • spacer Jamie says:
    17 Aug 2010 at 5:13 pm

    Does this change apply for all custom post types as well?
    Would the hook be manage_edit-[posttypesingular]_sortable_columns ?

    • spacer scribu says:
      17 Aug 2010 at 5:15 pm

      Yep.

  • spacer cotton says:
    26 Aug 2010 at 2:32 pm

    can i easily add this functionality without having to upgrade to trunk, on production site?

    • spacer scribu says:
      26 Aug 2010 at 2:51 pm

      Unfortunately, no. A lot of code was refactored to make this possible, so you will have to wait until WordPress 3.1 is released.

  • spacer Murph says:
    20 Sep 2010 at 8:55 pm

    When using the manage_edit-post_columns hook to add a column to the $columns array, is there a best practice for positioning that column relative to the others?

    (I wish PHP’s array_push() had a second $pos argument so one could specify an index position.)

    Thanks very much for your blog and contributions to WordPress, scribu.

    • spacer Murph says:
      20 Sep 2010 at 9:19 pm

      I ended up implementing the following solution, but perhaps there’s something more elegant. Nonetheless, I want to share this in case anyone else needs to do something similar:


      $newcol = array_slice($columns, 0, 1);
      $newcol = array_merge($newcol, array('foto'=>'Foto'));
      $columns = array_merge($newcol, array_slice($columns, 1));
      return $columns;

      • spacer scribu says:
        20 Sep 2010 at 9:55 pm

        Yeah, there really isn’t a more straightforward way. Here’s an array_insert() function I just cooked up:

        gist.github.com/588429

        • spacer Murph says:
          20 Sep 2010 at 11:54 pm

          Pardon me for asking, but do you think a function like
          wp_add_list_column( $objecttype, $keyname, $value, $callback, [$pos])
          could ever make it into core?

          Great array insert function, btw.

          • spacer scribu says:
            21 Sep 2010 at 12:29 am

            Not in that form, I don’t think. You might want to check this out though:

            core.trac.wordpress.org/ticket/14776#comment:3

            Note the column_*() methods.

  • spacer Idealien says:
    20 Sep 2010 at 9:59 pm

    For custom post types I use the manage_edit-[posttype]_columns filter to create anew the entire array in order I’d like to display it. Then use a switch / case on the particular elements that are not standard WP. There was a very thorough example of this somewhere online that escapes me now, but I’ve put up the meaningful parts in a code example at wordpress.pastebin.com/KaqLxMcF

  • spacer Joe says:
    21 Dec 2010 at 9:31 pm

    Good stuff.

    This article made me realize it’s time to get my custom meta data “start date”, to start storing data into a date object in the SQL. Right now they are VarChar, with the data saving as m/d/Y, so sorting columns are only sorting by month number.

    My question, is there a way to tell your SQL “teach” function to read the data as STRTOTIME? I’m aware this is not efficient, but it’s going to take me some time to convert my site structure to use proper datefields so i’d like to have a temporary fix.

    • spacer scribu says:
      21 Dec 2010 at 10:02 pm

      You’ll want to use the str_to_date() function in MySQL:

      dev.mysql.com/doc/refman/5.0/en/date-and-time-functions.html

      • spacer Joe says:
        21 Dec 2010 at 11:45 pm

        works like a charm. :)

        $orderby = “(SELECT STR_TO_DATE(meta_value,’%m/%d/%Y’) FROM $wpdb->postmeta WHERE post_id = $wpdb->posts.ID AND meta_key = ‘event_start_date’)” . $wp_query->get(‘order’);

        • spacer scribu says:
          21 Dec 2010 at 11:50 pm

          You’ll want to re-validate that ‘order’parameter, if you don’t want SQL injections.

  • spacer Justin says:
    1 Jan 2011 at 11:34 pm

    I know it’s probably not a super common use case, but is there any filter in place by which a plugin could disable AJAX sorting on their CPT admin page?

    • spacer scribu says:
      3 Jan 2011 at 9:28 pm

      Columns are non-sortable by default. So, if you don’t want sorting, just don’t do anything. :)

      • spacer Justin says:
        3 Jan 2011 at 9:39 pm

        Cool! That’s true for custom columns, but for what I want, it should work just to unset $columns["date" / "title"] in the sortable column name function. Thanks for the quick reply!

  • spacer Joe says:
    5 Jan 2011 at 12:00 am

    Anyone confirm this method is working fine in RC2?

    • spacer Joe says:
      5 Jan 2011 at 1:12 am

      Everything is fine in 3.1 RC2 except that If the custom post type is registered as ‘hierarchical’=> true, then the column will not populate with the data.

      • spacer Justin says:
        5 Jan 2011 at 1:57 am

        Try manage_pages_custom_columns instead of manage posts custom column

  • spacer Frankie Jarrett says:
    11 Jan 2011 at 12:02 pm

    scribu,

    This one little feature I was really hoping would make it to 3.1 – good information as always, thanks for sharing! Also, GREAT work on helping to make multiple taxonomy queries possible in 3.1 :)

    So, I’m using Justin Tadlock’s awesome Entry Views extension to store view counts in a custom field, and I’d really love to be able to sort my various post types by view count!

    But I can’t seem to get things working properly…as soon as I click the “Views” column name to do some sorting, all the posts disappear.

    The URI then has “orderby=Views” in it…is there an easy way to add more parameters to the query? i.e. “meta_key=Views&orderby=meta_value_num”?

    According to Justin’s examples, those are the parameters he uses to sort the data…please, pardon my noob dev skills.

    //Frankie

    • spacer scribu says:
      11 Jan 2011 at 12:59 pm

      You can use the ‘request’filter to add the parameters:

      function my_alter_request( $vars ) {
        if ( isset( $vars['orderby'] ) && 'Views' == $vars['orderby'] ) {
          $vars = array_merge( $vars, array(
            'meta_key' => 'Views',
            'orderby' => 'meta_value_num'
          ) );
        }
       
        return $vars;
      }
      add_filter( 'request', 'my_alter_request' );

      I’ll update the example.

      • spacer Frankie Jarrett says:
        11 Jan 2011 at 1:14 pm

        Wow, that worked perfectly.

        Thank you, sir!

        //Frankie

  • spacer John Kolbert says:
    12 Jan 2011 at 7:18 am

    Can you add a default sorted column? Such as if you wanted the posts sorted by price by default rather then the order by which they were posted?

    • spacer scribu says:
      12 Jan 2011 at 2:14 pm

      You can use the ‘request’filter again:

      function my_default_orderby( $vars ) {
        $screen = get_current_screen();
       
        if ( 'edit' == $screen->base && 'my_ptype' == $screen->post_type ) {
          if ( !isset( $vars['orderby'] ) ) {
            $vars['orderby'] = 'price';
          }
        }
       
        return $vars;
      }
      if ( is_admin() )
      	add_filter( 'request', 'my_default_orderby' );
      • spacer Frankie Jarrett says:
        12 Jan 2011 at 11:51 pm

        that is B.A.

      • spacer Frankie Jarrett says:
        12 Jan 2011 at 11:57 pm

        Seems to be working great in the Admin but getting

        Fatal error: Call to undefined function get_current_screen()

        on the front end :/

        Running WP 3.1 RC2-17258

        //Frankie

        • spacer scribu says:
          13 Jan 2011 at 12:11 am

          Note the correction.

  • spacer John Kolbert says:
    13 Jan 2011 at 4:47 am

    Works great! I added ‘order’=> ‘asc’to the array_merge for the default_orderby. Thanks so much for this great write up!

  • spacer goto10 says:
    8 Feb 2011 at 6:22 pm

    This is a fantastic feature to have in the WP core. Thanks for your hard work! Prior to this, I was pulling off something similar using tablesorter, a javascript solution. Of course, a core solution is much more desirable.

    I have run into a scenario with the WP implementation where I have not been able to get sorting to work properly.

    I have a custom post type which uses a custom taxonomy. I’m imposing a limit of a single term to each post (using a custom meta box drop down on the edit post screen for the CPT). The term for the taxonomy is assigned using the standard wp_set_object_terms() function. How can I make the taxonomy column sortable?

    A few more details…I’m not storing my columns in a meta key. The columns that I’m trying to sort are stored as term IDs. I’m getting the name of the columns using get_the_terms(). Therefore, the {name}_column_orderby function will not work for me.

  • spacer gweedo says:
    23 Feb 2011 at 7:23 pm

    Wow… Fantastic addition and writeup. Was very easily able to write a plug-in off this for a custom jobbie we’re doing.

    Thanks for posting this!

  • spacer Greg Kerstin says:
    24 Feb 2011 at 1:24 am

    When I start sorting by custom taxonomy using your demo, I only am able to view 6 entries. Is there a way to include more entries?
    Thank you for the help, I stumbled on your site since 3.1 came out today.

    • spacer scribu says:
      24 Feb 2011 at 1:34 am

      I think you’re confusing sorting with filtering. Sorting by a custom taxonomy would require some custom SQL, not provided in my example.

  • spacer Olaf says:
    24 Feb 2011 at 7:56 am

    Hi scribu,

    great tutorial, just a small addition for people like me that would like the columns to be sortable in pages and custom post types as well.

    // Register the column as sortable
    function price_column_register_sortable( $columns ) {
    $columns['price'] = ‘price’;

    return $columns;
    }
    add_filter( ‘manage_edit-post_sortable_columns’, ‘price_column_register_sortable’);
    add_filter( ‘manage_edit-page_sortable_columns’, ‘price_column_register_sortable’);

    add_action(‘wp’, ‘add_sortable_price_for_custom_post_types’);

    function add_sortable_price_for_custom_post_types(){
    $args=array(
    ‘public’ => true,
    ‘_builtin’=> false
    );
    $post_types=get_post_types($args);
    foreach ($post_types as $post_type ) {
    add_filter( ‘manage_edit-’.$post_type.’_sortable_columns’, ‘price_column_register_sortable’);
    }
    }

    cheers,
    olaf

  • spacer Richard Sweeney says:
    25 Feb 2011 at 8:00 pm

    Amazing – just what I was looking for! Now I can order an ‘events’custom post type by date!

    Is there a way to filter the the admin to only display events that have yet to occur? Maybe by comparing the value of the stored date to the current time? Might one even be able to switch views so as to view past AND future events with some kind of toggle switch?! Wish I had the skills to solve this myself..!

  • spacer sebastien says:
    5 Mar 2011 at 6:01 pm

    Great post !

    I have a custom post_type “product” and a taxonomy for this post_type. This taxonomy is “color̶

gipoco.com is neither affiliated with the authors of this page nor responsible for its contents. This is a safe-cache copy of the original web site.