How to add custom content under plugin row in WordPress admin plugin list?

Searching Codex or Google you can find some lists of WordPress hooks, but believe me, them are not useful if you don’t know where, when and how they are triggered.

While coding for WordPress, the question “Which hook should I use?” is very common and frequent, but believe me, a list of all WordPress hooks, if it exists, will not help you to answer, because if you don’t know where, when and how an hook is fired it’s unuseful just know that it exists.

So, when you have such a question, first thing to do is look at WordPress core code.

If you look at the address bar in the browser, when viewing plugins list page, you’ll see http://example.com/wp-admin/plugins.php.

So, go and open the file /wp-admin/plugins.php.

If you think it’s a mess, I’m agree with you. However, if you try to unsderstand the code, you’ll see that the output is done by this line: $wp_list_table->display();, so there is an object, $wp_list_table that has a method display.

If you have some experience in WordPress, you’ll immediately understand where to look for this object. If not, just check where in the file $wp_list_table is defined. You’ll find this line:

$wp_list_table = _get_list_table('WP_Plugins_List_Table');

Now you can guess, that exist a class named 'WP_Plugins_List_Table'.

With a little of experience, you’ll know that this class is one of the class in WordPress that extend WP_List_Table, however, if you don’t know that, just look at the files in wp-admin/includes folder, looking for a file that is named in a way similar to the class, or maybe using a text editor launch a search for the line 'class WP_Plugins_List_Table' in all the php files inside wp-admin folder.

In both cases you’ll fine the file where the class is defined, it is wp-admin/includes/class-wp-plugins-list-table.php.

Open that file and look at code. You’ll find a method named single_row and, even if the class code is almost unreadable, you can guess that this method is used to display the singular plugin row.

Last 2 lines of that method are:

do_action( 'after_plugin_row', $plugin_file, $plugin_data, $status );
do_action( "after_plugin_row_$plugin_file", $plugin_file, $plugin_data, $status );

So you find the hook you are looking for:

The first runs for all plugin rows, the second is a dynamic hook so is different for every plugin.

So, if you want to output something after a specific plugin row, you have to use "after_plugin_row_$plugin_file" hook, where $plugin_file can be retrieved inside main plugin file using plugin_basename( __FILE__ );

An example of what you can get:

Cats

The plugin code used for the output in the image above is:

/**
* Plugin Name: Code is Best Documentation
* Description: Look at me, I'm the proof.
*/

$path = plugin_basename( __FILE__ );

add_action("after_plugin_row_{$path}", function( $plugin_file, $plugin_data, $status ) {
  echo '<tr class="active"><td>&nbsp;</td><td colspan="2">
        <img src="http://upload.wikimedia.org/wikipedia/commons/thumb/9/93/Cat_poster_2.jpg/297px-Cat_poster_2.jpg" alt="Some Cats" />
        </td></tr>';
}, 10, 3 );