Add featured image column for Custom Post Type

I recently added a feature to a client’s website that shows a post’s featured image in the edit-posts screen in the admin backend of WordPress. You might be thinking to yourself: Can’t I just find a plugin that does for me? Well, yes, of course you can. But most of them just add your new image column to the end of the list of columns and the column title is usually something boring like “featured image”. If you code it yourself you can “inject” the column where you want it, make it a link so you can click it to edit your post/page, and customise the CSS so you have a cool little icon as the header. Doing it this way you also gain a further understanding of how things work in the WordPress ecosystem.

The easiest way, I thought, of getting inspiration was to look at (and mostly copy) Woocommerce. Its developers’ have already had to solve this problem because they use a custom post type to be able to showcase and sell products. So I dug into the woocommerce source code and found exactly what I needed.

The 2 hooks used by Woo are manage_edit-{$post_type}_columns and manage_{$post_type}_custom_column. The first hook is used to create the column and assign a heading to it. The second one loops through all the posts (of the post type) and then you are supposed to conditionally check you’re in the right column, and populate that row. BUT, I discovered a problem when actually trying to use the second one, I couldn’t get anything to happen with it. Woo may be doing something else to make things happen somewhere else that wasn’t obvious to me. After some more digging I settled on the hook that was going to solve my problem: manage_${post_type}_posts_custom_column. While manage_edit-{$post_type}_columns does indeed work, it has been superceded by a newer hook: manage_{$post_type}_posts_columns.

Let’s get to it then:

You can simply add the extra column you need and be done with it, but I wanted my featured image to be in the same place that WooCommerce puts it: right next to the checkbox, i.e. as the second column. There are many ways to accomplish this using any variation of array_slice() but I again chose to simply copy the way it was done in the WooCommerce code. In my case the custom post type I have is called “artworks”. This is how you add the column:

add_filter( 'manage_artworks_posts_columns', 'artworks_header_columns', 10, 1 );

function artworks_header_columns($columns) {
    $new_columns = array();

	if ( isset( $columns['cb'] ) ) {
		$new_columns['cb'] = $columns['cb'];
		unset( $columns['cb'] );
	}

	$new_columns['image'] = '<span class="aw-column-icon">' . __( 'Image', 'sempervirens') . '</span>'; 

	$columns           = array_merge( $new_columns, $columns );

	return $columns;
}

I chose to make the image “clickable” so you can go straight to edit-post screen and I also chose a custom size for the thumbnail. This is how you loop through each post item and populate the row for the new column:

add_filter( 'manage_artworks_posts_custom_column', 'artworks_column', 10, 2 );

function artworks_column($column_name, $id) {
    if ($column_name === 'image') {
        echo '<a href="' . get_edit_post_link() . '">';
        the_post_thumbnail( [150, 150] );
        echo '</a>';
    }
}

That’s all you need to get your new image column and populate it with an image. If you leave it like this, it will work, but it might not look too pretty. I copied the styling I needed from WooCommerce again and inserted it into a new CSS file to be enqueued using the 'admin_enqueue_scripts' hook. This is the CSS styling I used:

table.wp-list-table .column-image {
    width: 52px;
    text-align: center;
    white-space: nowrap;
}

table.wp-list-table td.column-image img {
    margin: 0;
    width: auto;
    height: auto;
    max-width: 50px;
    max-height: 50px;
    vertical-align: middle;
}

@media only screen and (max-width: 782px) { 
    table.wp-list-table .column-image {   
        display: none;
        text-align: left;
        padding-bottom: 0;
    }
    table.wp-list-table td.column-image::before {
        display: none!important;
    }
}

table.wp-list-table span.aw-column-icon::before {
    font-family: Dashicons;
    font-weight: 400;
    font-variant: normal;
    text-transform: none;
    line-height: 1;
    -webkit-font-smoothing: antialiased;
    margin: 0;
    text-indent: 0;
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    text-align: center;
    content: "\f128";
}

table.wp-list-table span.aw-column-icon {
    display: block;
    text-indent: -9999px;
    position: relative;
    height: 1em;
    width: 1em;
    margin: 0 auto;
}

I used the same media query from WooCommerce to avoid having the thumbnail stick out like a sore thumb when viewing the page on a mobile device. You can enqueue the CSS into the admin side like this:

wp_enqueue_style( 'awcol-admin-styles' , get_stylesheet_directory_uri() . '/css/semper-artwork-column-admin.css' );
add_action( 'admin_enqueue_scripts', 'awcol-admin-styles' );

Here’s the full PHP, remember to drop it into your functions.php file of your child theme.

add_filter( 'manage_artworks_posts_columns', 'artworks_header_columns', 10, 1 );

function artworks_header_columns($columns) {
    $new_columns = array();

	if ( isset( $columns['cb'] ) ) {
		$new_columns['cb'] = $columns['cb'];
		unset( $columns['cb'] );
	}

	$new_columns['image'] = '<span class="aw-column-icon">' . __( 'Image', 'sempervirens') . '</span>'; 

	$columns           = array_merge( $new_columns, $columns );

	return $columns;
}

add_filter( 'manage_artworks_posts_custom_column', 'artworks_column', 10, 2 );

function artworks_column($column_name, $id) {
    if ($column_name === 'image') {
        echo '<a href="' . get_edit_post_link() . '">';
        the_post_thumbnail( [150, 150] );
        echo '</a>';
    }
}

wp_enqueue_style( 'awcol-admin-styles' , get_stylesheet_directory_uri() . '/css/semper-artwork-column-admin.css' );
add_action( 'admin_enqueue_scripts', 'awcol-admin-styles' );

2 Comments

  1. Thanks a lot for your very clean and excellent code
    I could not use the its style but instead I used this code:

    // Format the column width with CSS
    add_action(‘admin_head’, ‘add_admin_styles’);
    function add_admin_styles() {
    echo ‘.column-image {width: 60px;}’;
    }
    and it work good
    so I thought I share it with you
    Thank you again

Leave a Reply

Your email address will not be published. Required fields are marked *

This site is protected by reCAPTCHA and the Google Privacy Policy and Terms of Service apply.