Add action links to your plugin

What are action links?

Action links are the additional menu items under your plugin’s name on the plugins.php page. By default, you’ll always see Active/Deactivate there and, if you’re not on multisite, you’ll also see the option to delete a plugin.

Now, with added action links:

What action links should I add?

I think it’s really helpful to give the user some additional choices when they start using your plugin, especially from the same menu they used to activate it. Here are a few options you could use.

  • Add a ‘Settings’ link: sometimes users can cast around looking for your Settings page so placing a ‘Settings’ menu item here is ideal. On the Discussion Board plugin, the Settings page is a submenu page of the main Discussion Board menu. I don’t want anyone to find it difficult to locate so I’ve added a Settings link that’s visible to the user as soon as they activate the plugin from the plugins.php page.
  • Add a ‘Support’ link: another advantage of having additional links here is that they appear right next to the ‘Deactivate’ link. So if the user has decided not to continue with your plugin, you have one last chance to catch their attention here before they deactivate. So it’s a great place to add a link to your support page.
  • Add an ‘Upgrade’ link: You can also provide a direct link to a premium version of your plugin, if you have one. This will encourage users to purchase the upgrade.

Adding the action links

Adding the action links is really straightforward. This is the code from the Discussion Board plugin. You can modify this for your own plugin:

function filter_action_links( $links ) {
 $links['settings'] = '<a href="' . admin_url( 'edit.php?post_type=discussion-topics&page=discussion_board' ) . '">' . __( 'Settings', 'wp-discussion-board' ) . '</a>';
 $links['support'] = '<a href="">' . __( 'Support', 'wp-discussion-board' ) . '</a>';
 // Check to see if Pro version already installed
 if( class_exists( 'CT_DB_Pro_Admin' ) ) {
  $links['upgrade'] = '<a href="">' . __( 'Upgrade', 'wp-discussion-board' ) . '</a>';
 return $links;
add_filter( 'plugin_action_links_wp-discussion-board/wp-discussion-board.php', 'filter_action_links', 10, 1 );

The code makes use of the plugin_action_links_(plugin_file_name) filter. You can find some documentation here. To find the file name of your plugin, you can insert this code in your main plugin file:

$plugin_file_name = basename( __FILE__ );

Your plugin basename is the name of your plugin’s main file and will now be stored in the $plugin_file_name variable.

Adding the Settings link

The filter passes the $links array in. All you need to do is add elements to this array. The first action link I wanted to add was to the ‘Settings’ page:

$links['settings'] = '<a href="' . admin_url( 'edit.php?post_type=discussion-topics&page=discussion_board' ) . '">' . __( 'Settings', 'wp-discussion-board' ) . '</a>';

I created a new element in the $links array with the settings key and a link to the Settings page as its value;

Adding a Support link

Using the same method, I created a support element with a link to the support page as the value.

Adding an Upgrade link

The only difference with the upgrade link is that it checks whether the premium version of the plugin is already installed. This isn’t strictly necessary but I think it’s a nice touch to remove the ‘upgrade’ option once the user has upgraded.

I use the class_exists method to check whether a plugin is installed or not.

Tools for plugin developers

If you’re a plugin developer and you’d like a better way to track how your plugins are being used, please check out the Wisdom plugin, which allows you to gather all kinds of data from your plugins after they’ve been activated on users’ sites.

White screen of death after plugin activation

What do we mean by the white screen of death

In this post, I’m talking about a specific type of failure after activating a plugin. There are numerous descriptions of how to solve different types of white screen failure at the end of this article. The error under discussion in this post occurs immediately after activating a plugin and you receive a message like the following:

The page isn't responding is currently unable to handle this request
HTTP Error 500

After activation, your site is no longer accessible and panic ensues…

Quickly get the site back

As outlined in the articles listed below, the quick way to gain back access to your site is to FTP to your plugins folder and delete the plugin you’ve just installed. That should immediately restore your site. For information on how to fix the error, read on…

The error log is your friend

Luckily, when I encountered this problem recently with the Discussion Board Pro plugin, the error had been written to the error_log file that can be found in the root directory of the WordPress installation. This contained the following key piece of information:

[22-Mar-2017 02:48:35 UTC] PHP Fatal error:  Can't use function return value in write context in /home/accountname/public_html/wp-content/plugins/discussion-board-pro/inc/functions-boards.php on line 408

I was able to go straight to the file identified. There, I saw that I’d written the following conditional:

if( ! empty( ctdb_topic_board_id() ) ) {
  // Code here

The error message in the log clearly identifies that I shouldn’t have tried to incorporate a value returned directly from a function, i.e. from ctdb_topic_board_id(). PHP doesn’t want to let you use empty() or isset() on a function, it prefers you to use a variable.

What I needed to do was this:

$topic_board_id = ctdb_topic_board_id();
if( ! empty( $topic_board_id ) ) {
  // Code here

First I stored the value returned from the function in a variable. Then I checked whether the variable was empty. In other words, I didn’t wrap the function name inside the empty() check.

What happens if error_log offers no clue?

If you check error_log and there’s no helpful information there, then you’ll need to be more methodical in tracking down the bug.

As a first step, open the main plugin file to edit and comment out any actions and required files. Upload the file via FTP to the plugins directory and reload the site. Assuming the white screen error has been fixed (though you may have created a different error), you can begin to go methodically through each function call and required file, commenting them back in one by one, re-uploading and refreshing to test. As soon as you find where the problem occurs you can start to look for a fix.

PHP Versions

This error was only being thrown on PHP 5.4.xx. It might be that if you are using a different version of PHP you don’t see an error. The problem with this is that if you don’t test on different versions, you won’t necessarily spot errors before they get out into the wild. The Wisdom plugin is a useful tool here as you can use it to find out what versions of PHP are active on your users’ servers.

Articles on solving the white screen

If this particular case wasn’t helpful, you can try the following articles: – discusses various causes and solutions of white screens, including plugin incompatibility, WordPress version incompatibility, conflicts with other plugins, theme errors, PHP parse errors, and exceeding memory limits. It’s a really comprehensive article in that it takes you through a significant number of problems and solutions and provides options for troubleshooting. – the codex article on common WordPress errors. This offers a few more options to the article above. – the consistently useful Theme Foundry blog offers some variations on possible causes.

Get Wisdom – data capture for plugin developers

One day, I found myself staring at my plugin’s page in the WordPress directory, wondering why there was such a difference between the number of downloads recorded and the number of active installations. I looked around and it appeared to be the same story for every plugin. The information on the Statistics tab seemed so limited and gave me no real clue as to what was going on. So I decided to create a tool to help.

Wisdom is, I think, the first WordPress plugin that allows plugin developers to gather and analyse meaningful data on how their plugins are being used. If you’re a plugin developer, you embed some Wisdom code into your plugin which will then transmit data back to your website. Your website collects all the data and presents it to you through filterable charts.

How do you currently measure how your plugins are used?

Let’s say that you are a plugin author. Perhaps you have a few plugins on the repository that you have released to the community after you developed them for some client work. Alternatively, you might sell plugins as a sideline or main business, either through a freemium model, via marketplaces like Code Canyon, or via your own site. Unless you have created your own data-collection and feedback system, there are limits to how effectively you can assess how your plugins are used or measure their success. Typically, you might rely on user feedback, support tickets, user reviews, or refund requests. The problem with this is that you often only hear from your users when something goes wrong. While it’s obviously essential to hear back from users when they have problems, it’s good to get some perspective as well. Wisdom allows you to get some perspective.

The statistics tab on the WordPress repository (above) has limited usefulness. It will display the number of downloads per days and a rough indication of the distribution of the different versions of your plugin. But it doesn’t give you any insight into how your plugin is being used.

By contrast with the repository stats, Wisdom gives you detailed analytics.

Main features

What does it do?

Wisdom tracks the usage of your plugin on the sites where it’s installed. You may already have noticed similar functionality when activating certain plugins. Yoast SEO and Easy Digital Downloads, for example, both ask permission to track usage, with EDD offering an incentive to do so. Wisdom is a ready-built system to include this kind of functionality in your plugin(s). It handles user opt-in, specifies what data to collect, and provides a dashboard for receiving and viewing the data.

What data does it collect?

Every time an admin activates your plugin and opts into tracking, Wisdom will start to send back data to your own website. This includes information about your plugin (such as version number), other plugins active and deactivated on the site, information about WordPress (including version number and language), theme information, and server information.

There’s also the possibility to have Wisdom send back data on what settings are being used within your plugin. This means you can evaluate what features are popular and which are not used, helping you to concentrate your development efforts (or improve your marketing and support documentation).

Deactivation form

One of the issues that Wisdom is designed to address is the mystery of why users choose to deactivate your plugin. There is a deactivation form displayed to the user at the moment they click on the ‘Deactivate’ link to deactivate your plugin. The user is invited to select one or more reasons for wanting to deactivate the plugin, e.g. ‘Set up is too difficult’, ‘Lack of documentation’, and there’s a free-text field for the user to leave some additional comments if they wish.

The deactivation form is filterable so you can add your own options and wording if you wish.

How does it work?

If you’re using Wisdom to gather data about your plugin, first you need to include a small code snippet and file in your plugin. This is all that’s needed to handle user opt-ins and send data to your own site where you install the Wisdom plugin itself. This collects all the data sent from the many installations of your plugin.

For more detailed guidance on how to set up Wisdom, take a look at its Support page.

How many plugins can be tracked?

You can track as many plugins as you wish using Wisdom. There are plans available for tracking one plugin, up to three plugins, or unlimited plugins.

Data Protection

There is increasing volume in the WordPress community about collecting usage data. While there’s a debate to be had about the benefits of collecting and analysing such data against the needs of the individual to protect their privacy, from the point of view of the developer the advantages in gathering analytical data is indisputable.

As far as Wisdom is concerned it’s important to know (if you are planning to use it with a plugin hosted in the repository) that it follows the WordPress guidelines on ‘phoning home’. That’s item 7 in the Detailed Plugin Guidelines page:

7. The plugin may not “phone home” or track users without their informed, explicit, opt-in consent.

In the interest of protecting user privacy, plugins may not contact external servers without the explicit consent of the user via requiring registration with a service or a checkbox within the settings. This method is called ‘opt in.’ Documentation on how any user data is collected, and used, should be included in the plugin’s readme, preferably with a clearly stated privacy policy.

This restriction includes the following:

No unauthorized collection of user data. Users may be asked to submit information but it cannot be automatically recorded without explicit confirmation from the user.

Wisdom requests the user’s permission through a standard WordPress notice. The user clearly has the option to allow or reject tracking. This notice appears immediately after the plugin being tracked is activated and no data will be collected unless the user opts in.

One complication in collecting data is to define what is sensitive and what not. Most of the data, such as server environment, WordPress version, plugin options, and so on, are anonymous. However, if you are a developer, there are some very good reasons for wanting to collect the email addresses of the admins of the websites where your plugin is installed – mainly for marketing purposes. With this in mind, Wisdom offers a couple of different ways to make clear to the user if you intend to collect their email address (assuming you want to grab emails – there is an option that doesn’t include the email address).

  • The first option is a single notice that requests opt-in to tracking and clearly states that this will include the gathering of the admin email address.
  • The second option is to request opt-in to tracking with one notice then, if accepted, request permission to collect the email address in a second notice.

The advantage of the first option is that it is less intrusive for the user – it’s one notice then gone. The advantage of the second option is that some users may be happy to opt-in to tracking but not to email collection. It’s your choice which you use.

Of course, the wording can be filtered if you would like to add your own custom message.

For plugins that are not distributed via the repository, opt-in is not compulsory. Information can be gathered silently in the background though it is strongly recommended that you make clear in your documentation that this is taking place.

Why would you need this?

Hopefully, the answer to this question is pretty clear from the above. Information about how your plugin is being used now will allow you to make informed decisions about how to develop the plugin in the future.

  • You can learn what features your plugin is missing, and find out which features are being used and which are being ignored.
  • You can reduce the number of support tickets you have to deal with. By being proactive with your development, you will improve the quality of your plugin and head off potential support requests before they arise.
  • You can troubleshoot support queries more quickly by reading off information about a user’s environment direct from your own dashboard.
  • You have the opportunity to increase conversions to your premium products. If you’re collecting email addresses, you can focus your marketing directly towards people you know who are already using your products.
  • You will be able to build relationships with clients and users who would previously have been unknown to you.
  • You take guesswork out of the equation.

Find out more about Wisdom here.

Add content to empty EDD checkout page

Easy Digital Downloads is a great piece of software if you’re selling plugins and themes. I’m using it on the Wisdom plugin site (Wisdom allows plugin developers to get information about where and how their plugins are being used). Because this website only sells one product, I’ve enabled the EDD feature to redirect the user straight to the checkout page after adding the product to their basket.

What this can mean is that a user might click on the Checkout link in the main navigation menu when they haven’t yet added the product to the cart. By default, Easy Digital Downloads just shows a simple message in this situation:

It’s fine as far as it goes: it’s factually accurate but doesn’t provide the user with any further options. (The default WooCommerce checkout page adds a ‘Return to Store’ button if there’s nothing in the cart). However, rather than just add a link back to the homepage, I thought it would be better to add a widget area to this page that would allow me to be more flexible with additional content – notably, I wanted to add the option for the user to add the product to their cart direct from this page without needing to go elsewhere on the site.

In the theme’s functions.php file, I registered a new widget area specifically for the empty checkout page:

function singularity_widgets_init() {
  register_sidebar( array(
   'name' => esc_html__( 'EDD Empty Checkout Page', 'singularity' ),
   'id' => 'empty-checkout-page',
   'description' => esc_html__( 'Add widgets here.', 'singularity' ),
   'before_widget' => '<section id="%1$s" class="widget %2$s">',
   'after_widget' => '</section>',
   'before_title' => '<h5 class="widget-title">',
   'after_title' => '</h5>',
  ) );
add_action( 'widgets_init', 'singularity_widgets_init' );

(Note that I’m using a theme I’ve developed myself so I’m happy adding this to the functions.php file. If you’re using a commercial theme, you should probably be using a child theme.)

Because EDD is well coded it was easy to find a hook – edd_cart_empty – that I could use to add the widget area. Note that this hook only fires if the checkout page is empty – we don’t want to display this additional content when the user has a product in their cart.

function singularity_add_widget_to_checkout() {
  dynamic_sidebar( 'empty-checkout-page' );
add_action( 'edd_cart_empty', 'singularity_add_widget_to_checkout' );

Now, there’s a new widget area available on the page when the checkout is empty. I added the Download Details widget and now the user can purchase the product direct from the empty checkout page.

Of course, you can add any content here you want. It just seemed that the purchase shortcode was the most natural – especially on a site selling just one product.

EDD Empty Cart

You could, as it turns out, use the EDD Empty Cart plugin to achieve something similar – though this particular extension doesn’t include a widget area.

Better Contact Details

Better Contact Details adds settings for all your different contact details, such as phone numbers, email address and postal address as well as links to your accounts on all the major social media services, like Twitter, Facebook, Instagram and so on.

Read More