What is the difference between “manage_{$post_type}_posts_columns” and “manage_edit-{$post_type}_columns”?

It has to do with the way the admin post table is constructed. WordPress uses a class WP_Posts_List_Table to generate and handle that table. You’ll notice that there are a few tables in the admin area similar: Plugins, Terms, Users, etc. They each are their own class, but they all extend from a base class of WP_List_Table.

manage_edit-{$post_type}_columns is a more generic filter that is set (but not called) in WP_List_Table. And, it is actually manage_{$screen->id}_columns. The callback is the get_columns method for the table object.

add_filter( "manage_{$this->screen->id}_columns", array( &$this, 'get_columns' ), 0 );

This filter is used by the get_column_headers() function for retrieving the columns.

So where does manage_{$post_type}_posts_columns then? Remember the method get_columns() that is call for the filter manage_{$screen->id}_columns, the WP_Posts_List_Table class over-rides the base method from WP_List_Table. In WP_Posts_List_Table::get_columns() is where the filter manage_{$post_type}_posts_columns is called.

To recap:

  1. A WP_Posts_List_Table object is created
  2. It’s parent class WP_List_Table adds $this->get_columns() to the hook manage_{$screen->id}_columns
  3. The function get_column_headers() calls the filter manage_{$screen->id}_columns
  4. WP_Posts_List_Table has over-ridden the method get_columns()
  5. Inside of WP_Posts_List_Table::get_columns(), it calls the filter manage_{$post_type}_posts_columns This is where your manage_{$post_type}_posts_columns hook would run
  6. WP_Posts_List_Table::get_columns() will return the columns and then run the remaining filters for manage_{$screen->id}_columns

Which one should you use? I don’t know. We know that manage_{$post_type}_posts_columns can only be called for post types, whereas manage_edit-{$post_type}_columns may match a different admin page (although I’m not sure if it would).