WordPress: Adding Custom Columns


This entry is part of my WordPress development series, providing tutorials on specific things you can do in WordPress. Read some more?

This tutorial is going to show you how to take the metadata stored in your custom meta box (or boxes) from your custom post type and display it as columns on the browse or “All” page – for my custom post type, that would be the page “Cats”. This is a great way to show some extra information about your custom posts at once without having to go to each individual post. Continuing on from the previous tutorial, I am going to display the age and favourite toy metadata that I stored for my cat Azaezel.

For simplicity, we will continue to work in our functions.php file. You can edit this file by going to Appearance > Editor in your WordPress admin panel, or using a text editor with FTP.

To begin, we first have to create the columns. We do this by using the function add_filter().

add_filter( 'manage_cf_cats_posts_columns' , 'custom_cat_columns' );

function custom_cat_columns( $cat_columns ) {
	$cat_columns = array(
		'cb' => '<input type="checkbox" />',
		'title' => 'Cats',
		'age' => 'Age',
		'toy' => 'Favourite Toy',
		'date' => 'Date'

	return $cat_columns;

The first parameter is the name of the filter the second parameter is hooked to. It is in the form of (for WordPress versions 3.1+) manage_${post_type}_posts_columns. For previous WordPress versions, use manage_edit-${post_type}_columns (which also works with newer versions of WordPress too). The second parameter is the name of our function that displays our columns.

The checkbox, title, and date are automatically shown by default as that is what is supported by my custom post type. We want to include the checkbox (for mass actions) and title (of course), and I’m going to still include the publish date, but it is really up to you on what you’d like to include and what information you feel is most relevant to see at a quick glance.

There’s a couple of different ways to add in our columns. The first way is by adding and/or removing specific columns only. The second way, shown above, is replacing all the columns. Personally I prefer this way as it gives me a visual representation in my mind (top to bottom is the order of all the columns from left to right), but you can check out the Codex for the other way if you like.

To create our columns, we’re simply using an array with name/value pairs. The name on the left is what we use to work with the columns (you’ll see below in our switch/case) and the value on the right is what we see at the top of our columns.

Empty Columns

Now at this point we can see the age and favourite toy columns have been added (date is there, just not shown in the screenshot), but we don’t see any of our metadata. Why? Because we have to display our custom metadata!

add_action( 'manage_posts_custom_column', 'manage_cat_columns', 10, 2 );

function manage_cat_columns( $cat_columns, $cat_post_id ) {

	switch( $cat_columns ) {

		// If displaying the 'age' column
		case 'age' :

			// Get the post metadata
			$cf_cat_age = get_post_meta( $cat_post_id, '_cf_cat_age', true );

			// If no age is found, output a default message
			if ( empty( $cf_cat_age ) ) {
				echo 'Age Unknown';
			// Otherwise, output the age
			else {
				echo $cf_cat_age;

		// If displaying the 'toy' column
		case 'toy' :

			// Get the post metadata
			$cf_cat_toy = get_post_meta( $cat_post_id, '_cf_cat_toy', true );

			// If no toy is found, output a default message
			if ( empty( $cf_cat_toy ) ) {
				echo 'Favourite Toy Unknown';
			// Otherwise, output the favourite toy
			else {
				echo $cf_cat_toy;

		// Just break out of the switch statement for everything else
		default :

First we have our add_action() function. The first parameter manage_${post_type}_posts_custom_column is “called whenever a value for a custom column should be output for a custom post type” (from the Codex). It is available for WordPress versions 3.1+ (use manage_posts_custom_column for earlier versions, though it does work in newer versions too). The second is our function that displays the values for each custom post in the columns. The third and fourth are the priority (10, which is default) and the number of arguments our function, from the second parameter, accepts (which is 2). The default number of arguments if left out is 1, so it is important to include this as our function accepts 2. Otherwise, the metadata in our columns will not show up.

As mentioned, our function takes two parameters. The first is the name of the columns, and the second is ID of the post. We use a switch/case to go through each custom column (in my example, the age and the favourite toy). We don’t have to worry about the defaults such as the title and date. In each case, we retrieve the metadata (recognize get_post_meta() from the previous tutorial?) and if it is empty, display a default message. Otherwise, it is not empty and we display the metadata.

Columns with Metadata

And that’s it! Now we are able to see the metadata associated with our custom posts.

If you’ve added custom meta boxes to the built-in posts or pages, adding custom columns for the metadata is relatively the same as for custom post types. Instead of using the filters manage_${post_type}_posts_columns or manage_edit-${post_type}_columns, use manage_posts_columns for posts, or manage_pages_columns for pages. Then rather than using the action manage_${post_type}_posts_custom_column, use manage_posts_custom_column for posts and pages.

Stay tuned for the next instalment where I show how to make your custom columns sortable!

Comments, questions? Share your thoughts below!