WordPress: Order custom post type by custom fields in the admin area

If you’re using custom post types in WordPress, it’s highly likely that these posts will need to be organized in the admin area by a method other than the date they were posted. In our example, we’ll be working with Movies, and the custom post type movie, sadly, the default layout is sorely lacking:

before2

The solution is a little long-winded, but we are able to customize this area to our needs, so let’s assume that we’re going to be using WordPress to manage a database of movies.

We will create a custom post type called movie and we will need to organize these posts by the custom fields: year_of_release, and genre.

Useful plugins:
More Types
More Fields

    1. Adding the columns to the admin area.

      Add this code to your functions.php

      add_action('manage_movie_posts_columns', 'manage_movie_posts_columns');
      
      function manage_movie_posts_columns($post_columns) {
          $post_columns = array(
              'cb' => $post_columns['cb'],
              'title' => 'Movie Title',
              'genre' => 'Genre',
              'year_of_release' => 'Released in'
              );
          return $post_columns;
      }

      This will tell WordPress that when we’re looking at our custom post type movies We should use this array for our post columns.

      WordPress automatically recognizes this function, because we have named it manage_movie_posts_columns, where movie is ANY custom post type.

      Our columns are formed in the $post_columns array, where the KEY is the custom field, and the VALUE is the column title. The exception to this is ‘cb’ which is short for check box, and should never change from this default value.

    2. Making our columns sortable

      Add this code to your functions.php

      add_filter( 'manage_edit-movie_sortable_columns', 'movie_column_register_sortable' );
      
      function movie_column_register_sortable( $post_columns ) {
          $post_columns = array(
              'genre' => 'genre',
              'year_of_release' => 'year_of_release'
              );
      
          return $post_columns;
      }

      This function is very similar to the previous one, however, this one defines which columns are sortable, and by what custom field we should sort them by.

      The array $post_columns has the same KEYS as the previous function, but its values are now the same key as the custom fields. When a user clicks the sortable column, we will get an orderby $GET variable which is the custom field associated with the column. For example, if we click on the column Released in to sort it by the year the movies were released in, WordPress will pass the $GET variable orderby with the value ‘year_of_release’.

    3. Modifying the query

      Add this code to your functions.php

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

      This function modifies the query for the custom post list in the WordPress admin. We have two checks; one for custom post type to make sure we only affect the movie post type, and the other to see if the $GET variable orderby is set.

      The rest is straightforward, and all things working correctly, this should allow us to order our columns!

    4. Output the column values to the post type admin area

      Add this code to your functions.php

      add_action('manage_posts_custom_column', 'manage_movie_custom_column',10,2);
      
      function manage_movie_custom_column($column_key,$post_id) {
          global $pagenow;
          $post = get_post($post_id);
          if ($post->post_type=='movie' && is_admin() && $pagenow=='edit.php')  {
              echo ( get_post_meta($post_id,$column_key,true) ) ? get_post_meta($post_id,$column_key,true) : "Undefined";
          }
      }

      This is the final function which ties it all together by drawing the columns into our admin area for the custom post type.

      This function is called each time the loop iterates over a column for each returned post. We check that we are indeed in the ‘movie’ post type, and that we’re actually in the WordPress admin area. This is probably a bit redundant, but it’s just to be safe. If those checks are passed, we output the current posts custom field value by using the $column_key variable (which is what we had set way back in the first function in this tutorial – $column_key in this case will be either ‘genre’ or ‘year_of_release’), and querying its meta values. If the query is unsuccessful, we will just echo Undefined, and call it a day.


Our final layout should look more like this, which is much, much more useful!

after1