Try Tuts+ Premium, Get Cash Back!
Writing Extensible Plugins With Actions and Filters

Writing Extensible Plugins With Actions and Filters

One of the many things you will find when investigating a good plugin developer’s source code are custom hooks and filters that the developer has placed throughout the plugin. The presence of these action hooks and filters make the plugin “extensible”, meaning that other plugins and themes can manipulate or add onto the behavior of the plugin.

Writing extensible plugins is something I’d like to strongly encourage you to do. There are a lot of great reasons why you should do it, but very few (if any) reasons why you should avoid this practice.

We are going to look at several elements of extensible plugins:

  • An explanation of what extensible plugins are
  • Reasons why you should write extensible plugins
  • The basic tools you need
  • How you need to write your plugins to make them extensible
  • Simple examples of hooks and filters to illustrate how you might use them

One important note: this tutorial will be using purely procedural based programming techniques. Everything I talk about here still applies when using Object Oriented Programming (OOP), but it is simpler to first learn these techniques in a procedural setting.


What Is an Extensible Plugin?

An extensible plugin is one that can be modified and extended beyond its original purpose by another plugin or theme. When a plugin is extensible, other plugins (or themes) can alter the behavior or output of the plugin. For example, ecommerce plugins allow add-on payment gateways that permit purchases to be processed via additional payment systems. These payment gateways are separate plugins that simply connect to the core plugin and extend its functionality.

Any and all plugins can be extensible, though only a small minority of published plugins are. In order to be extensible, or modular (another term for the same thing), a plugin’s developer must make a conscious decision to make it that way by implementing the necessary elements that make it possible for other plugins and themes to tie into the core plugin’s behavior.


Why Write Extensible Plugins?

There are a lot of good reasons to write extensible plugins, but one of the main reasons is that there simply isn’t a good reason not to write your plugins this way, especially not when your plugins are released to the WordPress community, either as free or paid plugins.

When you write extensible plugins, you make it possible for other developers to extend your plugin and make it even better, but without ever changing the core source code. You also make it significantly easier for developers and users to adapt the plugin to suit their needs better. Let me give you an example: in my Easy Digital Downloads plugin there is a discount code system. Discount codes are restricted to a single use per user, so if a user tries to apply the same discount on two different purchases, they will receive an error. One of my real-world users found that she did not want to limit discounts to a single use per user, so I gave her a simple function that she dropped into a new custom plugin and the restriction was removed, without touching any core plugin code.

Extensible code also makes other developers extremely happy when they find it because their job of adapting your code just became much, much easier.


The Basic Tools / Functions

There are several key tools you need in order to write extensible plugins. If you have written any plugins or themes before reading this, you are probably at least somewhat familiar with these functions, even if it is only because you have seen them used.

Before I show you the functions you will use, let’s talk about two main concepts first: hooks and filters.

An action hook is a place in your plugin that can be “hooked” into by functions (both in your plugin and other plugins) in order to have their code executed at that point. When an action hook runs, all functions that are connected, or “hooked”, to it will run as well.

A filter hook is also a place in your plugin for other functions to tie into, but they work slightly differently than actions. Filters allow for data to be manipulated or modified before it is used.

The key difference between actions and filters is that actions are usually used for executing functions and filters are usually used for manipulating data.

Unless you’re already highly familiar with actions and filters, I’d strongly encourage you to go read the Codex entry on them.

For actions there are four main functions:

  • do_action() – this defines a hookable location for actions
  • add_action() – this attaches a function to a hook created with do_action()
  • has_action() – this checks to see if an action has been registered with do_action()
  • remove_action() – this removes an action that was set with add_action()

Of these four, you will use do_action() and add_action() the most.

For filters there are also four main functions:

  • apply_filters() – this creates a hookable location for custom filters to tie into
  • add_filter() – this attaches a custom filter to a hook created with apply_filters()
  • has_filter() – this checks to see if a filter has been registered with apply_filters()
  • remove_filter() – this removes a filter previously connected to apply_filters()

As with actions, apply_filters() and add_filter() are the two you will use the most.

If you’re confused at this point, do not worry, we are going to look at how to actually use these in the next section.


Implementation in Your Own Plugins

In order to make your plugin truly extensible, you need to use the key functions mentioned above throughout the entire plugin. At first you may find it difficult, cumbersome, annoying, or many other applicable adjectives, to constantly place these additional functions throughout your code, especially when you do not see an immediate benefit or use for them.

What you will find, however, is that once you are in the habit of writing your plugins with all of these functions in mind, it will become second nature to include them.

There are a few main scenarios where you will use filters in your plugins:

  • When arrays are setup. Filters will be added here so that other plugins can modify the data before it is used.
  • When data objects are setup. Just like with arrays, you will use a filter on objects so that other developers can alter the object before it is used.
  • When data strings are setup. With a filter available on a string, other developers can change the entire string, alter parts of it, or add onto it.

Of the scenarios above, it is most common to use filters when data is returned or just before it is used. For example, if you have a plugin that performs a posts query, it’s best to pass the array of query arguments through a filter before they are passed to get_posts() or WP_Query so that others can manipulate the query before it is made.

When it comes to actions, there are also several main instances where you will place them:

  • Before a task is executed.
  • After a task is executed.
  • Within your markup to allow additional markup to be inserted.

Let’s consider a few examples now.

1. Displaying HTML With a Shortcode

Shortcodes that output HTML are extremely common (actually they are probably the most common of all shortcodes), and one of the ways that we can make our plugin’s shortcodes more friendly to other developers is by providing a way for them to alter the contents of the shortcode, but without requiring that it be deregistered and registered again.

All shortcodes return rather than echoing their contents, which means that the data outputted to the screen is going to be in the form of a string before it is returned. Because the entire HTML output is in the form of a string, you can pass the string through a filter before returning it. Doing so will make it possible for other developers to alter the HTML of your shortcode.

A developer may want to add additional markup before and after the default HTML: with the filter in place, they can do that.

Your shortcode may look something like this:

function wptp_sample_shortcode( atts, $content = null ) {

	$html = '<div class="wptp_shortcode">';
		$html .= '<p>Contents of the sample shortcode</p>';
	$html .= '</div>';

	return $html;

}

We can improve this by adding a filter to the return, like so:

function wptp_sample_shortcode( atts, $content = null ) {

	$html = '<div class="wptp_shortcode">';
		$html .= '<p>Contents of the sample shortcode</p>';
	$html .= '</div>';

	return apply_filters( 'wptp_shortcode_html', $html );

}

The HTML in our shortcode can now be modified like this:

function wptp_modify_html( $html ) {
	return '<div class="extra_div">' . $html . '</div>';
}
add_filter( 'wptp_shortcode_html', 'wptp_modify_html' );

This will result in the original HTML created in the shortcode being wrapped with another div tag.

2. Querying Posts

Performing custom queries in plugins is a common practice. Let’s assume for a moment that you have written a plugin that registers a custom post type called “books”, and in your plugin is a function to show created books. Your function to query the books might look something like this:

function wptp_show_books() {

	$query_args = array(
		'post_type' => 'books',
		'posts_per_page' => 5
	);

	$books = new WP_Query( $query_args );
	if( $books->have_posts() ) :
		while( $books->have_posts() ) : $books->the_post()
			// show info about each book here
		endwhile;
	endif;
	wp_reset_postdata();

}

But what if a user wanted to modify the kinds of books that were returned, perhaps selecting only books from a specific category? You can make this much easier for them by doing this:

function wptp_show_books() {

	$query_args = array(
		'post_type' => 'books',
		'posts_per_page' => 5,
		'author' => 3
	);

	$books = new WP_Query( apply_filters( 'wptp_books_query', $query_args ) ) ;
	if( $books->have_posts() ) :
		while( $books->have_posts() ) : $books->the_post()
			// show info about each book here
		endwhile;
	endif;
	wp_reset_postdata();

}

The only change I made was to add a filter around the $query_args, which means other developers (or users) can modify the query arguments before they are actually passed to WP_Query. For example, we could set the query to only show books from author 3 like this:

function wptp_alter_books_query( $args ) {
	$args['author'] = 3;
	return $args;
}
add_filter( 'wptp_books_query', 'wptp_alter_books_query' );

3. Extending Markup

Let’s extend on example number 2 now and make it even better. We already added a filter that allows users to modify the query, now let’s add a few hooks to let us alter the HTML that is created.

First we’ll modify our original HTML a bit:

function wptp_show_books() {

	$query_args = array(
		'post_type' => 'books',
		'posts_per_page' => 5,
		'author' => 3
	);

	$books = new WP_Query( apply_filters( 'wptp_books_query', $query_args ) ;
	if( $books->have_posts() ) :

		echo '<div class="wptp_books">';

			while( $books->have_posts() ) : $books->the_post()

				echo '<div class="wptp_book">';

					echo '<h3 class="wptp_book_title">' . get_the_title() . '</h3>';

				echo '</div>';

			endwhile;

		echo '</div>';

	endif;
	wp_reset_postdata();

}

We would now like to make it possible for developers to add in extra markup at various points, such as the following:

  • Before any HTML is outputted
  • After the ending HTML
  • Before the title of each book
  • After the title of each book

You can imagine a scenario where a user would want to add a thumbnail before or after the book title. To make this possible, we use do_action() to create hookable locations, like this:

function wptp_show_books() {

	$query_args = array(
		'post_type' => 'books',
		'posts_per_page' => 5,
		'author' => 3
	);

	$books = new WP_Query( apply_filters( 'wptp_books_query', $query_args ) );
	if( $books->have_posts() ) :

		do_action( 'wptp_books_before' );
		echo '<div class="wptp_books">';

			while( $books->have_posts() ) : $books->the_post()

				echo '<div class="wptp_book">';

					do_action( 'wptp_before_book_title', get_the_ID() );

					echo '<h3 class="wptp_book_title">' . get_the_title() . '</h3>';

					do_action( 'wptp_after_book_title', get_the_ID() );

				echo '</div>';

			endwhile;

		echo '</div>';
		do_action( 'wptp_books_after' );

	endif;
	wp_reset_postdata();

}

Note that the two inner hooks (surrounding the title) have a second parameter of get_the_ID(). This variable, which will be the ID of the book, will be available as a parameter to any hooked function. To add in a book thumbnail, for example, we can do this:

function wptp_show_book_image( $book_id ) {
	echo get_the_post_thumbnail( $book_id, 'thumbnail' );
}
add_action( 'wptp_before_book_title', 'wptp_show_book_image' );

Real World Examples

I would like to now show you some real world examples of plugins that are extensible, including samples of some of their extensible functions.

1. Soliloquy

Soliloquy is a powerful WordPress responsive image slider plugin that makes creating and maintaining responsive, efficient, secure and SEO friendly image sliders a breeze.

Nearly everything in this plugin is extensible. Here’s just one example:

$labels = apply_filters( 'tgmsp_post_type_labels', array(
	'name' 					=> __( 'Soliloquy', 'soliloquy' ),
	'singular_name' 		=> __( 'Soliloquy', 'soliloquy' ),
	'add_new' 				=> __( 'Add New', 'soliloquy' ),
	'add_new_item' 			=> __( 'Add New Soliloquy Slider', 'soliloquy' ),
	'edit_item' 			=> __( 'Edit Soliloquy Slider', 'soliloquy' ),
	'new_item' 				=> __( 'New Soliloquy Slider', 'soliloquy' ),
	'view_item' 			=> __( 'View Soliloquy Slider', 'soliloquy' ),
	'search_items' 			=> __( 'Search Soliloquy Sliders', 'soliloquy' ),
	'not_found' 			=> __( 'No Soliloquy Sliders found', 'soliloquy' ),
	'not_found_in_trash' 	=> __( 'No Soliloquy Sliders found in trash', 'soliloquy' ),
	'parent_item_colon' 	=> '',
	'menu_name' 			=> __( 'Soliloquy', 'soliloquy' )
) );

$args = apply_filters( 'tgmsp_post_type_args', array(
	'labels' 				=> $labels,
	'public' 				=> true,
	'exclude_from_search' 	=> true,
	'show_ui' 				=> true,
	'show_in_admin_bar'		=> false,
	'rewrite'				=> false,
	'query_var'				=> false,
	'menu_position' 		=> 100,
	'menu_icon' 			=> plugins_url( 'css/images/menu-icon.png', dirname( __FILE__ ) ),
	'supports' 				=> array( 'title' )
) );

This is how Thomas Griffin (the plugin’s developer) sets up the arguments for both the custom post type labels and attributes. The presence of his two filters, tgmsp_post_type_labels and tgmsp_post_type_args, make it very simple for other developers to rename the slider post type or change what the post type supports.

2. bbPress

By far one of my personal favorite plugins of all time, bbPress is a fully featured forum plugin for WordPress. The entire plugin is a perfect example of how to make your plugins extensible, as it literally has actions and filters everywhere. It has one particular filter that is applied when retrieving the content of a forum:

function bbp_get_forum_content( $forum_id = 0 ) {
	$forum_id = bbp_get_forum_id( $forum_id );

	// Check if password is required
	if ( post_password_required( $forum_id ) )
		return get_the_password_form();

	$content = get_post_field( 'post_content', $forum_id );

	return apply_filters( 'bbp_get_forum_content', $content, $forum_id );
}

Before the content of the forum is returned, it is passed through a filter called bbp_get_forum_content that makes it possible for a developer to modify the content before it is ever displayed.

3. Easy Digital Downloads

Easy Digital Downloads, or EDD, is one of my plugins that was built to make it exceptionally easy to sell digital products through WordPress. As with most ecommerce plugins, EDD has a checkout process that the buyer goes through so they can enter their personal and payment details. After all of that info is collected, it all goes to a payment gateway (a system for processing the payment), but before it goes to the gateway, a filter is applied that allows the data to be manipulated before it is used by the payment system:

$purchase_data = apply_filters(
	'edd_purchase_data_before_gateway',
	$purchase_data,
	$valid_data
);

The presence of this filter makes it possible to adjust purchase amounts (perhaps for special discounts), add taxation, perhaps add or remove products from the purchase, and much, much more.


Conclusion

Extensible plugins benefit everyone: the original developer, other developers, and the users themselves.

There are so many reasons why you should write your plugins with extendable code in mind, so why don’t you?

The tools presented here are everything that you need to get started. Have questions? Ask away!

Pippin Williamson is mordauk on Codecanyon
Note: Want to add some source code? Type <pre><code> before it and </code></pre> after it. Find out more
  • http://krogsgard.com Brian Krogsgard

    Great post, Pippin.

    I’m a big fan of extensible code for both plugins and themes. As I’ve gotten into creating more custom plugins that I reuse from client site to client site, I sometimes forget that I can really allow for filters on just about everything. The practice has been pretty standard for me in themes for a while, but these are some great examples on how I can improve my plugins. Thanks!

  • http://zslabs.com Zach

    Awesome article Pippin! I’ve learned just about everything I know about writing extensible code from you and articles like this really drive that point home. Thanks again!

  • Ben

    In the last code example in ’3. Extending Markup’, is missing an add_action().

    • http://pippinsplugins.com Pippin
      Author

      Yep, you’re right, thanks for noticing.

      • http://wp.envato.com/ Japh Thomson
        Staff

        I’ve fixed that up now. Thanks for pointing it out :)

  • http://ruturaaj.com Ruturaaj

    Extensible code is good… but I’ve a query; may the experienced people please help me understand how WordPress works behind the scenes. Personally, I always felt like too many Filters and Actions will slow down my WordPress site. Every new Filter, Action will ask the WordPress to stop its normal work-flow and see if something else is to be done. I feel this may open just too many threads in the background thereby adding load on Server processing.

    It’s quite likely that I’m under-estimating the power of PHP here; but for me, all the Filters and Actions are “parsed” out by WordPress. There is no table in database that has all Filters and Actions (or is there?). So, it’s all parsing each theme and plugin file and then executing hook functions when an event occurs. I find it very hard to convince as “efficient way of code execution” especially when there are too many Filters and/or Actions. Again, I know the phrase “too many” is just too generic and one must have bench-marked the process. If none of us (including WordPress developers) have bench-marked the process then I’m not sure if anyone of us have an idea of “too many means how many”.

    But before anything else… please tell me one thing… is my understanding correct? How WordPress sorts out on Filters and Actions? Is this a myth if I say too many Filters and/or Actions (or it’s merely parsing to get the Filters and Actions out of code, then too many Plugins as well) may just slow down the WordPress execution or will put a load on Server?

    Waiting for your reply…

    Cheers,

    Ruturaaj.

    • http://pippinsplugins.com Pippin
      Author

      Adding actions and filters do not slow your system down at all. If they do, it is so microscopically small that it’d be nearly impossible to measure.

      Hooks and filters (which are technically the same thing) are all stored in a global variable, and checking if a action/filter is registered is nothing more than checking if the hook key exists within the global variable.

      • http://www.ruturaaj.com Ruturaaj

        Thanks for the clarification. Once the list of hooks and filters is loaded, it’s just checking an array for the key… not much of a processor load here for sure. But before that, how WordPress load all Filters and Action hooks into that Global Variable? We plugin or theme developers don’t make any database entry or there is no XML file where we define the list of Actions, Filters supported/exposed by a theme and plugin. So, my common sense tells me that WordPress will need to parse all the active plugin and theme’s PHP files for “do_action” and “add_filter” code lines and prepare the list in that magical global variable. This is my point of confusion… how WordPress works here? How it lists all plugins and actions for later use? For me, preparing this list per Viewer session is not an efficient idea. Why can’t we just have a XML file, defining all the filters/actions exposed by Plugin?! So, WordPress core will simply refer to this XML file and move on. I’m not sure how WordPress works; but if WordPress never existed and someone asks me to develop a package like WordPress, this is how I will implement the concept of Filters and Actions. I won’t ask my core program to go through all the PHP files and see what are the page templates, Filters, Action hooks exposed etc.

        Secondly, will WordPress go and check this global variable on every page/post render to see if there is something to more to do? I mean this is how I feel the concept of Filters and Actions is implemented, right? This is what we call “polling”. This is the area where I feel the process may affect the code execution due to too many filters and actions, because the core flow of code will get interrupted that many times. My overview tells me that the main process will be paused until the Action hook function or Filter function completes its task.

        Oh, am I sounding too much obsessed with the speed of code execution and related stuff??!! ha ha ha. Well, we all are fortunate to live in an era where the Micro-electronics is allowing Application Developers to take luxury of processing speed; we’re moving from faster processor to fastest and then even faster. So, we can surely ignore the code execution latency to a certain extent, favoring the coding flexibility.

        • http://pippinsplugins.com Pippin
          Author

          These are really good questions. I’m going to refer you to a really great article on Smashing Magazine that goes into great detail on how actions and filters work: http://wp.smashingmagazine.com/2012/02/16/inside-wordpress-actions-filters/

          Ultimately, no, there is zero performance impact.

          • http://ruturaaj.com Ruturaaj

            Wow!! Now that’s some content to read and study!! Thanks a bunch for sharing this link with me. I will go through the text and will study it to understand how exactly WordPress works.

  • http://prop-14.com Randy

    Fantastic article as always Pippin. WooCommerce is another example of a plugin with lots of hooks and such. You can customize almost anything.

  • Pingback: アクションとフックで拡張性のあるプラグインを書く方法 | WordPress ニュース WP NEWS

  • http://www.dreamsmedia.in/ Harish Chouhan

    Thanks for the great article Pippin. I am going to use these ideas in my plugin. One thing I find little confusing when reading anything about hooks and filters is, mixed terms such as, Hooks, Filters, Filter hooks, Action hooks, etc..
    Can you simplify this? is it just Filters and Actions?

    • http://pippinsplugins.com Pippin
      Author

      Sure, the terms can definitely get confusing.

      The term “hook” refers to both actions and filters, which are both types of hooks.

      An “action hook” is the same thing as saying an “action”.

      A “filter hook” is the same thing as saying a “filter”.

      Make more sense?

  • Pingback: This Week In WordPress: Sep 17, 2012 - Max Foundry

  • http://www.patrickrauland.com Patrick Rauland

    I’m building a plugin that extends another plugin right now. Seeing how easy it is I’ll be adding hooks to my own plugins soon enough.

  • http://thematosoup.com Slobodan

    Pippin,

    Awesome tutorial, considering this one of WordPress’ best practices is an absolute must.

    I wish I had this on mind when I was coding Fanciest Author Box, but it’s never too late to improve it.

    We’re currently working on our first theme for ThemeForest and this post, as well as that looong “WP Theme Forward Compatibility – Shortcodes/CPTs” discussion (which most developers should read – http://themeforest.net/forums/thread/wp-theme-forward-compatibility-shortcodescpts/75050) made us decide to drop portfolio functionality out of the theme and into a stand-alone, free plugin that should play nice with other themes, but also should be extensible so (hopefully) other theme developers can use it in their themes and stop locking their users.

    Just my opinion, but WPTuts+ needs a dedicated “Best Practices” category.

    • http://pippinsplugins.com Pippin
      Author

      Nope, never too late!

      Very glad to hear that you’re taking the Forward Compatibility discussion seriously. A lot of theme designers / developers simply dismiss its importance.

  • Pingback: WordPress Plugin Hooks - Extending Functionality - Tom McFarlin

  • Pingback: Tweet Parade (no. 37 Sep 2012) | gonzoblog.nl

  • Pingback: WordPress Plugin Development Resources : WPMayor

  • http://foxnet.fi/en Sami Keijonen

    Mr. Pippin knows how to make solid plugins, there is no question about that.

    But are my eyes tired. Should this line

    $books = new WP_Query( apply_filters( ‘wptp_books_query’, $query_args ) ;

    be

    $books = new WP_Query( apply_filters( ‘wptp_books_query’, $query_args ) ) ;

    in the beginning of the chapter 3.

    • http://pippinsplugins.com Pippin
      Author

      Yep, as Zane said below, that is definitely an error. Thanks for noticing!

  • http://zanematthew.com/ Zane Matthew

    Yes, thats a syntax error, your response is correct.

  • Andrew

    Thank you for this article, a must read. Just what I needed for it to finally all come together!

  • Pingback: Best of Tuts+ in September 2012 | Pixeldome

  • Pingback: The Beginner’s Guide to WordPress Actions and Filters | Wordpress Webdesigner

  • http://www.facebook.com/roberto.martinez.blanco.k Roberto Martínez Blanco

    This is a really useful tutorial to debut in WordPress, maybe you should include a section for ajax call handling, because a lot of people don’t know how it works in WordPress…

    Thanx for the great work

  • Giorgos

    In the text below
    Before I show you the functions you will use, let’s talk about two main concepts first: hooks and filters.

    you should say actions and filters instead of hooks and filters.

    Your tutorials are very usefull. Keep writing…

  • Pingback: Custom Database Tables: Creating an API | Wptuts+

  • Pingback: Using bbPress as a Support Forum | Wordpress Webdesigner

  • Pingback: Using bbPress as a Support Forum | Wptuts+

  • Pingback: Using bbPress as a Support Forum | fresher+

  • Pingback: Extending WordPress Theme Customizer Boilerplate