Building your first WordPress plugin (part 2)

Default avatar.
October 30, 2012
Building your first WordPress plugin (part 2).

ThumbnailIn the previous part of our series we created the base for a WordPress plugin recognisible by the core. Today we are going to learn how to actually alter the default functionality of the core.

The concept of hooks, actions, and filters is responsible for that; being the real heart of the whole WordPress plugins system.

Everything starts from the hooks” provided by the core itself.

What is a hook”? It is a specially marked place in the code (of any script), where some deliberately registered — hooked into” — functions can be executed in the order defined upon registration.

WordPress has two types of hooks that differ in their purpose:

  • Action hook: marks the place to perform an action, for example, process input and store results in a database
  • Filter hook: marks the place to apply a modification to a value (normally provided as variable), so that the following code will use the adjusted value

Let’s dive into the details…

Working with actions

The common logic of WordPress actions is very simple:

  1. Mark the place, where the custom code should go, with an action hook” and its parameters
  2. Create the action function that executes the new code using (if needed) parameters provided by the hook
  3. Register the action (#2) to be performed when the hook (#1) is fired with some priority
  4. When WordPress loads the requested page and finds the hook, it will look for all functions hooked into” it and execute them one by one in accordance with their priority

To perform task #1 we have the do_​action’ function:

do_action($tag, $arg_1, $arg_2, ... , $arg_n);

It accepts following parameters: $tag — the hook name” that helps to identify the certain hook and distinguish it among others; $arg_​1, $arg_​2, … , $arg_​n — values for actions to accept as parameters. There could be as many arguments as needed — from zero up to any reasonable amount.

WordPress itself has a lot of predefined hooks to use:

do_action( 'init' );

This is very straightforward case with no additional parameters. This hook is fired when the most of WordPress is set up and time has come to register custom objects, like custom post type, for example.

do_action('save_post', $post_id, $post);

In this example the hook is fired when post is saved and gives two additional parameters to operate with — post_​id and post object containing all the data from the saved post.

But creating hooks is not only a privilege of the core team; every developer can make a custom hook for the plugin (or theme). Thanks to this we have a lot of power, for example, theme frameworks allow child themes to alter not only styles but even the markup of parents without overwriting whole files.

do_action( 'my_truly_custom_hook' );

When we have found (or created) a proper hook and created a custom function for it we should register the latest for the execution with add_​action’.

add_action($tag, $function_to_add, $priority, $accepted_args_number);

As it could be expected the add_​action’ method accepts two obligatory parameters: $tag: the name of the appropriate hook and $function_​to_​add: the name of the function that should be executed. The other two parameters are optional: $priority: an integer to specify the order in which the registered functions are executed (by default, 10), $accepted_​args_​number: number of arguments that the registered function is going to accept (by default, 1).

Let’s look at an example to illustrate the whole process. Suppose we’d like to add a small notice at the bottom of our site. We could use the wp_​footer’ hook for this because it’s a part of obligatory footer code that every theme should include.

function msp_helloworld_footer_notice(){ 
 echo "<div id='msp-helloworld-notice'>Hello, I'm your custom notice</div>";
add_action('wp_footer', 'msp_helloworld_footer_notice');

In this example we create a prefixed function that simply outputs the notice’s markup (the importance of the prefixes we have discussed in the previous article, so please refer to it for details) and then hooked it into the wp_​footer’. Once we include this code in the our plugin file (also discussed in the previous article), we’ll see the result on the site.


Working with filters

Filters operate with the same logic as actions. The only difference is that they do not just execute some piece of code in a certain place. They execute this code TO MODIFY some value given to them by the hook. This means that every filter hook has the associated value (in most cases carried by a variable).

The function performing filtering should take this value, alter it somehow and then return it for further usage. So that the syntax of functions responsible for hooks and filters is a bit different.

apply_filters($tag, $value_to_filter, $arg_1, $arg_2, ... , $arg_n);

The function apply_​filter’ creates a filter hook with $tag name and the obligatory parameter $value_​to_​filter (it could be empty, but should be present for best practice). Other arguments are optional and work the same way as for actions.

filter_function($value_to_filter, $arg_1, $arg_2, ... , $arg_n){
 //filtering code goes here
 return $value_to_filter; //value has to be returned back

This is a skeleton of filter function demonstrating that is should a) accept at least one argument, the value for modification; and b) return the value at the end.

add_filter($tag, $function_to_add, $priority, $accepted_args);

The function add_​filter’ registers a function with a name given as the $function_​to_​add argument for the $tag filter hook. The optional arguments — $priority and $accepted_​args — work in the same way as for action hooks.

Let us demonstrate the whole process in action: a common plugin task is to add some content at end of a post. If we look closer at the the_​content’ template tag (queryposts​.com/​f​u​n​c​t​i​o​n​/​t​h​e​_​c​o​ntent), which is normally used to output a post’s content in a theme, we will find that it contains following filter hook:

$content = apply_filters('the_content', $content);

Using this hook we can easily add something to the end of the post in the following way:

function msp_helloworld_post_footer($content) { 
 $content .= "<div class='msp-helloworld-post-footer'><p>Hello, I'm your custom post footer</p></div>";
 return $content;
add_filter('the_content', 'msp_helloworld_post_footer', 100);

Please notice that we use quite large number for priority here to ensure that all default filters have been applied before our msp_​helloworld_​post_​footer’. After including the code in the plugin’s file we should see the result on the site:


How to find hooks

It should be obvious by now that for implementing action and filter functionality we need to know what hooks are available.

The WordPress Codex provides an Action Reference with most of action hooks fired on typical page load and a Filter Reference with a list of commonly used filters. These references are useful to understand the order of actions and the logic of filters so that you’ll be able to choose where and when functionality can and should be injected.

After that you are ready for the trip into the source code. You can just perform a search through the WordPress files for the do_​action’ and apply_​filters’ keywords to find the hook you need.

Understanding WordPress query logic could also help you work out where some hooks can be looked for.

Finally, you can refer to the WordPress Hooks Database that contains full information about the hooks in the core files.

Advanced operations with hooks

As well as being added to your plugin, actions and filters can also be removed with a similar syntax.

Actions can be removed in the following manner:

remove_action($tag, $function_to_remove, $priority, $accepted_args);
remove_all_actions($tag, $priority);

As you have probably guessed remove_​action’ removes a particular action registered for a particular hook (you have to state correctly the priority and number of arguments as they were used on registration), and remove_​all_​actions’ helps to remove all actions registered with a certain hook with a given priority (if the priority argument is omitted the function will remove all actions).

You have probably heard about a popular security recommendation to hide the WordPress version from the head section of the site. This is a job for remove_​action’.

First of all let’s find the code that hooks the wp_​generator’ function to print the version information by browsing /wp-includes/default-filters.php. The code doing this looks as follows:

add_action('wp_head', 'wp_generator');

To eliminate the effect of this code we should somewhere in our plugin, include the opposite function:

remove_action('wp_head', 'wp_generator');

Filters can be removed in a similar way:

remove_filter($tag, $function_to_remove, $priority, $accepted_args);
remove_all_filters($tag, $priority);

The Plugin API also provides developers with a way to detect whether the particular hook has registered functions to execute:

has_action($tag, $function_to_check);
has_filter($tag, $function_to_check);

Both functions check whether a particular action or filter is registered for a hook and returns: true on success, false on failure. Inside the hooked function we have an ability to check what hook has triggered its execution in the following way:

if('hook_to_check_name' === current_filter()){
 //do stuff related to 'hook_to_check_name' hook

Despite the name, the current_​filter’ works not only with filters but with actions as well. For the full set of Plugin API functions refer to the Codex.

Real-world case

Let us dig up the plugin skeleton that we prepared in the previous part of the series, and breath some life into it.

We are going to fill-in the core.php’ file (the central part of our plugin intended to carry the most of functionality) with the code that solves a real-world task with the help of actions and filters.

What we are going to do? Suppose your WordPress site accepts guest posts from different authors, but does not give them permission to create their own accounts for posting. It means that the user, who has published the article, and the real author of it (the guest) are different people. You’ll need to ensure that the actual author receives credit. This can be done with custom taxonomy.

Let us create a custom taxonomy to handle the guest author’s name (as a term) and short author’s bio (as a description). We would be able to assign author’s names as any other taxonomy’s terms (as tags) to posts. After that it becomes possible to output an author’s box right after the post’s text. Here is the code:

/** Hook plugin's action and filters **/
function msp_helloworld_init(){
 add_action('init', 'msp_helloworld_taxonomies');
 add_filter('the_content', 'msp_helloworld_author_block_filter');
 add_filter('post_class', 'msp_helloworld_post_class');
add_action('plugins_loaded', 'msp_helloworld_init');

/** Register custom taxonomy **/
function msp_helloworld_taxonomies(){
 $args = array(
 'labels' => array(
 'name' => 'Guest authors',
 'singular_name' => 'Guest author'
 'show_in_nav_menus' => false 
 register_taxonomy('gauthor', array('post'), $args);

/** Create author's box markup **/
function msp_helloworld_author_block(){
 global $post;
 $author_terms = wp_get_object_terms($post->ID, 'gauthor');
 $name = stripslashes($author_terms[0]->name);
 $url = esc_url(get_term_link($author_terms[0]));
 $desc = wp_filter_post_kses($author_terms[0]->description);
 $out = "<div class='gauthor-info'>";
 $out .= "<h5>This is a guest post by <a href='{$url}'>{$name}</a></h5>";
 $out .= "<div class='gauthor-desc'>{$desc}</div></div>";

 return $out;

/** Add author's box to the end of the post **/
function msp_helloworld_author_block_filter($content){
 $content .= msp_helloworld_author_block();
 return $content;

/** Add custom CSS class to the post's container **/
function msp_helloworld_post_class($post_class){
 global $post;
 $author_terms = wp_get_object_terms($post->ID, 'gauthor');
 $post_class[] = 'gauthor';
 return $post_class;

As you can see, we have created an action to register a custom taxonomy and applied it to the init’ hook — this is a recommended practice. After that we have created the template tag responsible for the author box’s markup using native WordPress functions like wp_​get_​object_​terms’. After that we attached this box to the end of post content using the the_​content’ filter hook. And finally we have added the custom CSS class for the guest posts’ container for styling flexibility in the theme. After applying some styles we can see the result:



Actions and filters are the most important part of any WordPress development. Now that you understand their logic and behaviour, you’re prepared for your own experiments.

Click here to download our extended Hello World” plugin example to use as skeleton for your own development.

What uses have you found for WordPress actions and filters? What would you like to see covered in the next part of this series? Let us know in the comments.

Featured image, Module image via Shutterstock

Anna Ladoshkina

Anna Ladoshkina is a freelance web designer and developer who likes to build pretty things with WordPress and write about it. Connect with Anna on Twitter (@foralien) or on her website, www​.foralien​.com.

Read Next

Are Simple Websites Better For Business?

As web design technologies raise the bar on what it is possible to achieve on a realistic budget, there’s a rising deba…

Apple Opts for AR over VR at WWDC

An Apple VR headset has been one of the most widely-rumored devices of the last few years, and it was finally settled a…

Exciting New Tools for Designers, June 2023

We’re halfway through 2023 already, and the number of incredible apps, tools, and resources for designers is mounting.

3 Essential Design Trends, June 2023

This month we are focusing on three trends within a bigger website design trend – different navigation menu styles and …

15 Best New Fonts, May 2023

The choices you make when selecting a typeface have more impact on your design than almost any other decision, so it’s …

10+ Best Tools & Resources for Web Designers and Agencies (2023 updated)

Having the ability to envision a tastefully designed website (i.e., the role creativity plays) is important. But being …

20 Best New Websites, May 2023

This month, there are tons of great new agency websites to get excited about. 3D animated prisms are a popular theme, a…

How to Find the Right White Label Website Builder for Your Agency

Web design agencies face a lot of obstacles in closing the deal with new clients. One of the most common ones is the ar…

Exciting New Tools For Designers, May 2023

There are hundreds of new tools for designers and developers released each month. We sift through them all to bring you…

3 Essential Design Trends, May 2023

All three of the website design trends here mimic something bigger going on in the tech space, from a desire to have mo…

10 Best AI Tools for Web Designers (2023)

It’s time to stop worrying if AI is going to take your job and instead start using AI to expand the services you can of…

10 Best Marketing Agency Websites (Examples, Inspo, and Templates!)

Marketers are skilled in developing strategies, producing visual assets, writing text with high impact, and optimizing …