2026年11月14日

2026年11月14日

Customize WordPress Admin List Columns: Add, Remove, Reorder, Sort

This article is a localized edition of the Japanese original. Read the Japanese original

The WordPress admin "Posts" list shows columns for Title, Author, Categories, Tags, Comments and Date. If you want to see featured images or custom field values in the list, or get rid of columns you never use, you change the columns with code in your theme's functions.php (or in your own plugin).

This article covers four things, in order:

  • Adding, removing and reordering columns
  • Showing values in the columns you added
  • Making a column sortable by clicking its header
  • Editing a custom field from Quick Edit

Back up your theme before you change any code. Edits to a parent theme are lost when it updates, so put the code in a child theme or a code-snippet plugin.

Hooks you will use

Hook Type Purpose
manage_{post_type}_posts_columns Filter Change the list of columns (keys and headings)
manage_{post_type}_posts_custom_column Action Print the cell content of the columns you added
manage_edit-{post_type}_sortable_columns Filter Register columns that can be sorted
pre_get_posts Action Adjust the query when sorting
quick_edit_custom_box Action Add input fields to Quick Edit

{post_type} is replaced by the post type name. For regular posts it is post, so the hook name is manage_post_posts_columns (with post twice). For pages it is page, giving manage_page_posts_columns. The sortable-columns filter uses the screen ID (such as edit-post), so it looks like manage_edit-post_sortable_columns.

Columns on the Users list are changed with a different hook (manage_users_columns). See "How to add custom columns to the WordPress Users list" for details.

Step 1: Add, remove and reorder columns

This example removes the Tags and Comments columns from the post list and adds a thumbnail column in front of the title.

<?php
// functions.php: change the columns of the post list
add_filter( 'manage_post_posts_columns', function ( $columns ) {
	// Remove columns you don't need
	unset( $columns['tags'], $columns['comments'] );

	// Insert a thumbnail column right before the title column
	$new_columns = array();
	foreach ( $columns as $key => $label ) {
		if ( 'title' === $key ) {
			$new_columns['thumbnail'] = 'Thumbnail';
		}
		$new_columns[ $key ] = $label;
	}
	return $new_columns;
} );

The $columns value the filter receives is an array of "column key => heading", and the order of that array is the order of the columns. The keys of the default columns are:

Key Column
cb Bulk action checkbox
title Title
author Author
categories Categories
tags Tags
comments Comments
date Date

You must keep the keys of the default columns unchanged. If you move categories to a different key such as category, WordPress no longer prints its content and the column stays empty. When reordering, copy each key and heading over as is, like the example above.

Step 2: Show values in the column you added

Cells in a column you added are empty, so you print their content with the manage_{post_type}_posts_custom_column action. This action passes two values, the column key and the post ID, so pass 2 as the fourth argument of add_action().

<?php
// functions.php: output the content of the thumbnail column
add_action( 'manage_post_posts_custom_column', function ( $column, $post_id ) {
	if ( 'thumbnail' !== $column ) {
		return;
	}
	$thumbnail = get_the_post_thumbnail( $post_id, array( 60, 60 ) );
	if ( $thumbnail ) {
		printf(
			'<a href="%s">%s</a>',
			esc_url( get_edit_post_link( $post_id ) ),
			$thumbnail
		);
	} else {
		echo '—';
	}
}, 10, 2 );

The HTML returned by get_the_post_thumbnail() is already escaped by WordPress. Escape the link URL to the post editor with esc_url().

Step 3: Add a custom field column to a custom post type

From here on, the examples assume a custom post type book with a custom field named price. Replace the post type and field names with those on your site.

<?php
// functions.php: add a "Price" column to the book list
add_filter( 'manage_book_posts_columns', function ( $columns ) {
	$columns['price'] = 'Price';
	return $columns;
} );

// Output the content of the "Price" column
add_action( 'manage_book_posts_custom_column', function ( $column, $post_id ) {
	if ( 'price' !== $column ) {
		return;
	}
	$price = get_post_meta( $post_id, 'price', true );
	if ( '' === $price ) {
		echo '—';
		return;
	}
	// data-price lets Quick Edit (step 5) read the value
	printf(
		'<span class="book-price" data-price="%1$s">%2$s yen</span>',
		esc_attr( $price ),
		esc_html( number_format( (int) $price ) )
	);
}, 10, 2 );

Custom field values are entered by users, so escape them with esc_html() or esc_attr() when you print them. How to register custom fields is explained in "How to add custom fields in WordPress without a plugin".

Step 4: Make a column sortable by clicking its header

When you register a column as sortable, its header becomes a link, and clicking it adds orderby=price to the URL. WordPress does not know how to sort by price, though, so you tell it in pre_get_posts to sort by the custom field value.

<?php
// functions.php: make the "Price" column sortable
add_filter( 'manage_edit-book_sortable_columns', function ( $columns ) {
	$columns['price'] = 'price';
	return $columns;
} );

// When orderby=price, sort by the custom field as a number
add_action( 'pre_get_posts', function ( $query ) {
	if ( ! is_admin() || ! $query->is_main_query() ) {
		return;
	}
	if ( 'book' !== $query->get( 'post_type' ) ) {
		return;
	}
	if ( 'price' === $query->get( 'orderby' ) ) {
		$query->set( 'meta_key', 'price' );
		$query->set( 'orderby', 'meta_value_num' );
	}
} );

meta_value_num sorts the values as numbers. To sort them as strings, use meta_value instead.

When you set meta_key, posts that do not have that custom field disappear from the list while it is sorted. If you want every post in the sorted list, it helps to give posts with no price a value too (for example 0).

Step 5: Edit the custom field from Quick Edit

Next, add a price field to "Quick Edit" in the list. You need three things: the field markup, the save handler, and JavaScript that fills the field with the current value.

Field markup and saving

<?php
// functions.php: add a "Price" field to Quick Edit
add_action( 'quick_edit_custom_box', function ( $column_name, $post_type ) {
	if ( 'book' !== $post_type || 'price' !== $column_name ) {
		return;
	}
	wp_nonce_field( 'book_quick_edit', 'book_quick_edit_nonce' );
	?>
	<fieldset class="inline-edit-col-right">
		<div class="inline-edit-col">
			<label>
				<span class="title">Price</span>
				<span class="input-text-wrap"><input type="number" name="book_price" min="0" value=""></span>
			</label>
		</div>
	</fieldset>
	<?php
}, 10, 2 );

// Update the price when Quick Edit is saved
add_action( 'save_post_book', function ( $post_id ) {
	if ( ! isset( $_POST['book_quick_edit_nonce'] ) ) {
		return;
	}
	$nonce = sanitize_text_field( wp_unslash( $_POST['book_quick_edit_nonce'] ) );
	if ( ! wp_verify_nonce( $nonce, 'book_quick_edit' ) ) {
		return;
	}
	if ( ! current_user_can( 'edit_post', $post_id ) ) {
		return;
	}
	if ( isset( $_POST['book_price'] ) && '' !== $_POST['book_price'] ) {
		update_post_meta( $post_id, 'price', absint( $_POST['book_price'] ) );
	}
} );

// Load the JavaScript only on the book list screen (edit.php)
add_action( 'admin_enqueue_scripts', function ( $hook_suffix ) {
	if ( 'edit.php' !== $hook_suffix ) {
		return;
	}
	$screen = get_current_screen();
	if ( ! $screen || 'book' !== $screen->post_type ) {
		return;
	}
	wp_enqueue_script(
		'book-quick-edit',
		get_stylesheet_directory_uri() . '/js/book-quick-edit.js',
		array( 'jquery', 'inline-edit-post' ),
		'1.0.0',
		true
	);
} );

quick_edit_custom_box passes the column name and the post type name, so here too pass 2 as the fourth argument (without it, the callback does not get enough arguments and throws an error). The field appears when the custom column you added in step 3 exists.

JavaScript that fills in the current value

When Quick Edit opens, the field is empty. The script reads the data-price value printed in the list cell and puts it into the field. Save it in your child theme as js/book-quick-edit.js.

jQuery( function ( $ ) {
	// Keep WordPress's own Quick Edit opening logic and add to it
	var wpInlineEdit = inlineEditPost.edit;

	inlineEditPost.edit = function ( id ) {
		wpInlineEdit.apply( this, arguments );

		var postId = 0;
		if ( typeof id === 'object' ) {
			postId = parseInt( this.getId( id ), 10 );
		}
		if ( postId > 0 ) {
			var price = $( '#post-' + postId ).find( '.book-price' ).data( 'price' );
			$( '#edit-' + postId )
				.find( 'input[name="book_price"]' )
				.val( price !== undefined ? price : '' );
		}
	};
} );

If the list shows the new price after you save, you are done.

Step 6: Set column widths

The thumbnail column has no fixed width, so images can show up large or squeeze the other columns. Each column gets a class named column-(key), so add CSS to the list screen only.

<?php
// functions.php: print CSS only on the post list screen (edit.php)
add_action( 'admin_head-edit.php', function () {
	echo '<style>
		.column-thumbnail { width: 70px; }
		.column-thumbnail img { width: 60px; height: 60px; object-fit: cover; }
		.column-price { width: 100px; }
	</style>';
} );

admin_head-edit.php is an action that runs only inside the head of the post list screen.

When it does not show up as expected

  • The column does not appear: Check the post type name in the hook name. Regular posts use manage_post_posts_columns, and a custom post type book uses manage_book_posts_columns.
  • The column is there but empty: Check that the add_action() call for manage_{post_type}_posts_custom_column has 10, 2, and that the key you compare against $column is the same key you set in step 1.
  • The column is hidden: Open "Screen Options" at the top right of the list screen and make sure the column is checked.
  • Sorting does not change the order: Check that the conditions in pre_get_posts (the post type name and the orderby value) match the sortable registration in step 4.

Summary

  • Add, remove and reorder columns with manage_{post_type}_posts_columns, and print their content with manage_{post_type}_posts_custom_column.
  • Keep the keys of the default columns unchanged. If you change a key, its content is not printed.
  • Register sortable columns with manage_edit-{post_type}_sortable_columns and set the sort order in pre_get_posts.
  • Quick Edit support takes three parts: quick_edit_custom_box, a save handler, and JavaScript that fills in the current value.
  • For another example of adding columns to the post list, see "How to add custom columns to the WordPress post list".

Questions about WordPress? The publisher of this site is based in Japan and replies in Japanese. Contact (Japanese)

お気軽にご相談ください

お見積りへ お問い合わせへ
▲