Use Action Links to direct users straight to your WordPress plugin’s admin page

I’ve recently come across repeated discussions (especially on the wp-hackers mailing list) debating where plugin authors should place their custom admin pages. I discussed that question directly in my previous post, and basically stated that the plugin’s admin page can go any number of places, depending on what the plugin does. Some people disagree with this argument, saying that all plugin admin screens should go under one menu — usually “Settings” or “Plugins”, depending on whom you ask.

While I disagree, they do raise one good point: many end users will have trouble finding your admin page because they have come to expect such pages to all be dumped under Settings. Many plugin authors solve this by hard coding a link into the plugin Description, but this really isn’t the right place for that, and it can create inappropriate clutter in certain situations1. There is a better way.

WordPress 2.5 makes it fairly easy for plugin authors to add “action” links to the Plugin Management screen, like so:

Screen shot of a "Settings" link next to the normal plugin "Deactivate" link

We can do this in two steps: Add a short function to add the link, and attach that function to the appropriate WordPress filter. I will use my Pull-Quotes plugin for the example.

First, let’s add the attachment. We’re going to create a function called “filter_plugin_actions” and attach it to the existing “plugin_action_hooks” hook. To my mind, it makes sense to do this right after we’ve added the plugin page itself. Thus we might end up with something like this:

function add_settings_page() {
   if( current_user_can('switch_themes') ) {
      add_submenu_page( 'themes.php', 'Pull-Quote Settings', 'Pull-Quotes', 'switch_themes', 'pull-quotes', array(&$this,'settings_page'), 'test' );
      add_filter( 'plugin_action_links', array(&$this, 'filter_plugin_actions'), 10, 2 );
   }
}

Pretty straightforward for the most part. Note that I wrapped it all in a current_user_can() check so that both the page and the link only appear to users who can use them. If you’re wondering why function names are wrapped in the array(&$this ______), it’s because I wrap all of my plugin functions in a PHP class to avoid function name conflicts with other plugins. (It also makes code much more reuseable). If you don’t choose to do that, you can get rid of a little baggage and do something like add_filter( 'plugin_action_links', 'myplugin_filter_plugin_actions', 10, 2 );

Now for the function2 that actually adds the link. Let’s get started:

function filter_plugin_actions($links, $file) {
   static $this_plugin;
   if( ! $this_plugin ) $this_plugin = plugin_basename(__FILE__);

   if( $file == $this_plugin ){

First off, this filter is going to be called for every single plugin row on the Plugins page, but we only want it to add a link for our plugin. So we make a variable $this_plugin that holds the name of the plugin file that we’re in right now, and we make the variable static so that plugin_basename() only has to be called once. Then, we start an if() block to contain the actual filter code — that is, we only add the link if we’re on the row for this plugin. Next:

$settings_link = '<a href="themes.php?page=pull-quotes">Settings</a>';

That’s extremely straightforward: we assign the link HTML to a variable. The final step is to add the link to the $links[] array. (For most purposes, I recommend putting the new link before existing links.) Choose ONE of the following, but not both:

array_unshift( $links, $settings_link ); // before other links
$links[] = $settings_link; // ... or after other links

Finally we close up our if() and return $links back to the main program flow:

   }
   return $links;
}

Update: Please, please, please don’t get cute with the text of the link. Name it “Settings”, or “Manage”, or something that is fairly standard to the existing WordPress interface. Oh, and it’s helpful to international users if you wrap it in the __() function, like so:

$settings_link = '<a href="themes.php?page=pull-quotes">' . __('Settings') . '</a>';

That’s all there is to it!

Previously: On Plugin Design and Integration

Next: How to make your plugin’s admin link back to your home page without cluttering up the GUI.

1: e.g. The various “plugins used” plugins

2: Thanks to Dion Hulse. a.k.a. DD32, for writing the “demo” plugin from which I learned this. You saved me some source code spelunking.

This entry was posted in GUI Goodness, Webcraft and tagged , , , , , , . Bookmark the permalink.

17 Responses to Use Action Links to direct users straight to your WordPress plugin’s admin page

  1. Viper007Bond says:

    Can’t believe I didn’t know about this. This is incredibly handy!

  2. Strider says:

    V — you’re the guy who got me started on plugins. Nice to know I can teach you something! ;)

  3. Viper007Bond says:

    Haha! Yeah, we all always have something to learn. :)

  4. Ozh says:

    Pretty cool Stephen. I’m adding this into my next plugin :)

  5. kahi says:

    I totally agree that this “Settings” link can be very, very useful. But also I’m quite afraid of that inconsistency that could happen, if plugin developers would not use the filter as you recommend. Hopefully will this get own filter.

  6. Strider says:

    Kahi –

    I personally like the idea of adding something to core so that when a person adds an admin menu page, it has a parameter to automatically add a link to the Manage Plugins page as well. Then it would be really consistent.

    I’ve already seen another author (*cough*) use this on a plugin of his own, and he put the Settings link _after_ Deactivate. (Alphabetical maybe?) Is he wrong? No, but it is different. So, you’re right. I can show people how to do the link, but personal preferences will range far and wide and it will be inconsistent. Training plugin authors is like herding cats. ;)

    Part of why I’m writing these articles is to educate authors on what I consider “elegant” coding practices, as well as various “best practices” such as the upcoming article on using arrays for saving options. A lot of plugin authors put the settings links in the plugin description, so even if link order or name is a bit idiosyncratic, using action links at all is still a step up. So… even if applied inconsistently, these tips will still be an improvement.

    [Update: rewrote last paragraph a bit]

  7. Kim says:

    Nice feature Strider. I’ve already implemented it in my latest WordPress eCommerce plugin, which I will be releasing withing a couple of weeks!

    Thanks a lot!

  8. Vladimir says:

    I thought about implementing this in my Show Me Options plugin but guessing the options page is not the way how this should work. WP provide a native way to link to the options page.

    [Link added by editor]

  9. Great post. Thanks for sharing and teaching,
    Andy

  10. Love it! Thx for dropping this link on wp-hackers, I’ll be sure to talk about it in my next WordPress newsletter!

  11. Mark Hannant says:

    It amazing that something so glaringly useful hasn’t been done before.

    When plugins build up (and they build up fast thanks to Joost!) having access to all plugin settings from one page will help massively.

  12. Stephen says:

    There’s a better method coming in WordPress 2.7 — I’ll do a writeup soon.

    Basically, each plugin page row will have a plugin_action_links_{plugin}, which means you won’t have to call the hook for every plugin row as you do in the method described above.

  13. Daiv says:

    This is a great tip, thanx alot.
    If 2.7 will have a different method of doing this, would be great to know what that is, and how to set up for backwards compatible.

  14. Stephen says:

    Actually, WordPress 2.7 includes a significant improvement — I expect to do a writeup soon.

    In short, we will have new hooks specific to each plugin’s row on the Plugins page, which means your plugin no longer needs to run down the list asking “Are you my mommy?”

    The new hook is plugin_action_links_<__FILE__>, which is only called for the plugin that matches __FILE__.

    [Update: Heh. Responding to commenter who was responding to me. Infinite Loop! Run!]

  15. Pingback: Pressography

  16. Adam says:

    I can see how this would be very useful and definately worth implementing.

  17. That is an easy way to do it. Thanks for this helpful information.

Leave a Reply

Your email address will not be published.

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>