← Back to notes
snippet 1 min read PHP 7.4+ WP 5.8+

Add Custom Columns and Filterable Dropdowns to WordPress Admin Post Lists

Add an ISBN column and a taxonomy dropdown filter to a WordPress custom post type in the admin list table.

Updated Sep 10, 2026 #wordpress #admin #custom-post-types #php #snippet

Admin list tables become much more useful when editors can see important metadata without opening every post. This example adds an ISBN column to a book custom post type and adds a filterable Book genre dropdown backed by the book_genre taxonomy.

Change the post type, taxonomy, and meta key to match the content model on your site. Add the snippet to a plugin or child theme’s functions.php file.

Add a custom column

functions.php
add_filter( 'manage_book_posts_columns', function( $columns ) {
$columns['book_isbn'] = __( 'ISBN', 'my-site' );
return $columns;
} );
add_action( 'manage_book_posts_custom_column', function( $column, $post_id ) {
if ( 'book_isbn' === $column ) {
echo esc_html( get_post_meta( $post_id, '_book_isbn', true ) ?: '' );
}
}, 10, 2 );

The manage_{post_type}_posts_columns filter defines the table headings, while manage_{post_type}_posts_custom_column renders the cell for each row. The value is escaped at output time because post meta should not be trusted as HTML.

Add a taxonomy dropdown filter

functions.php
add_action( 'restrict_manage_posts', function() {
$screen = get_current_screen();
if ( ! $screen || 'edit-book' !== $screen->id ) {
return;
}
wp_dropdown_categories( array(
'show_option_all' => __( 'All book genres', 'my-site' ),
'taxonomy' => 'book_genre',
'name' => 'book_genre',
'orderby' => 'name',
'order' => 'ASC',
'hide_empty' => false,
'show_count' => true,
'hierarchical' => true,
'option_none_value' => '',
'selected' => isset( $_GET['book_genre'] ) ? absint( $_GET['book_genre'] ) : 0,
) );
} );
add_action( 'pre_get_posts', function( $query ) {
if ( ! is_admin() || ! $query->is_main_query() || 'book' !== $query->get( 'post_type' ) ) {
return;
}
$term_id = isset( $_GET['book_genre'] ) ? absint( $_GET['book_genre'] ) : 0;
if ( $term_id ) {
$query->set( 'tax_query', array(
array(
'taxonomy' => 'book_genre',
'field' => 'term_id',
'terms' => $term_id,
),
) );
}
} );

restrict_manage_posts places the control above the list table. pre_get_posts applies the selected term to the main admin query, so pagination and result counts remain correct.

Keep filters scoped

Always check the current screen or post type. An unscoped callback can add a genre dropdown to unrelated admin screens or change front-end queries. WordPress’s references for custom post list columns and restrict_manage_posts cover the underlying extension points.

For another admin workflow, see how to disable Gutenberg for selected post types or roles.