While developing my Thematic Maps WordPress plugin I wanted a Settings link on the Plugins list page for quick access to the plugin options page:

By default, WordPress displays Activate, Delete, Deactivate, and Update links on the Plugins page. To add additional links I had to leverage filters and hooks! I found a great reference at the WordPress Codex describing how to add links to the Plugin admin page using two built-in hooks.

  1. plugin_action_links
  2. plugin_action_links_{$plugin_file_name}

Why the need for both? When would I want to use versus the other? The Codex reference does not explain the pros and cons of either and it took me a bit of stack tracing to understand how WordPress uses these two hooks. I learned plugin_action_links fires for each plugin installed on my site while plugin_action_links_{$plugin_file_name} fires for a single plugin. I chose plugin_action_links_{$plugin_file_name} so that I would not have to create logic in my callback to filter out all the other plugins.

Since I am writing my plugin with an OOP approach I had to translate the procedural calls in the Codex reference to my class methods. I got lost in translation for a bit when I lost track of the plugin's bootstrap startup file name. I was building $plugin_file_name using plugin_basename(__FILE__) which created the wrong name. I was saving the class file name instead of the plugin's bootstrap startup file located in the plugin's root directory.

At first my callback was not firing when the Plugins page was built. After many an echo and print_r I realized the hook I was creating was actually thematic-files/class-thematic-maps.php when I should have been creating the hook thematic-maps/themaptic-maps.php! This was happening because I was calling plugin_basename() in the Thematic_Maps class which was located in the class-thematic-maps.php file. I'm using a modified version of the WordPress Plugin Boilerplate which does not store the bootstrap file's directory/filename and decided to add that information to the Thematic Maps class constructor.

Step 1, add the plugin file name to the class for reference during activation. I chose to add this to the constructor.

function run_thematic_maps( $plugin_file_name ) {

	$plugin = new Thematic_Maps( $plugin_file_name );
	$plugin->run();

}

run_thematic_maps( plugin_basename(__FILE__) );

Step 2, add a new filter to the Thematic_Maps->define_admin_hooks() method that adds the the plugin_action_links_{$plugin_file_name} hook

public function define_admin_hooks() {
	...
	/**
	 * Admin settings and pages
	 */
	 $this->loader->add_filter( 'plugin_action_links_' . $this->plugin_file_name, 
	 	$plugin_admin, 
		'add_plugin_links', 10, 2 );
	 
}

Step 3, add the add_plugin_links callback to the Thematic_Maps_Admin class. Note, order matters on the array_merge.

public function add_plugin_links( $links, $plugin_file ) {

	$plugin_links = array(
		'Settings',
	);

	return array_merge( $plugin_links, $links );

}

I found these articles helpful when developing this functionality