WordPress actions and filters, also known as hooks, are ways to “subscribe” to various parts of the WordPress codebase.
Actions allow you to execute your own code at specific points in the WordPress action hierarchy. As WordPress loads from top to bottom, various actions are triggered, which can be hooked into in order to execute code.
Filters, on the other hand, give you the ability to modify some data using your own code.
Filters change something. Actions do something.
Filters are an easier concept to understand than actions, so we’ll start with that first.
Let’s look at a code sample:
$price = 3.99;
$price = apply_filters( 'get_price', $price );
Code language: PHP (php)
The price starts at 3.99
. Then apply_filters
is called. It passes the variable $price
to any subscribers to the filter.
Since there are no subscribers yet, the price will remain the same.That data flows through the filter and is returned as-is.
Now say, in another file, that I want to add some sales tax to this price. I can add myself as a subscriber to the price via the filter name.
add_filter( 'get_price', 'my_plugin_add_sales_tax_to_price' );
function my_plugin_add_sales_tax_to_price( $price ) {
return $price + 1; // Add a dollar sales tax.
}
Code language: PHP (php)
Now the $price
variable is 4.99 after the filter has been applied.
Here’s a quick diagram of the flow between both plugins when apply_filters
is called.
Let’s say a third plugin got in the mix, but this time at a lower priority. This one also subscribes to the same filter and subtracts 50 cents from the overall total.
add_filter( 'get_price', 'my_plugin_add_discount', 15 );
function my_plugin_add_discount( $price ) {
return $price - 0.5; // remove fifty cents
}
Code language: PHP (php)
Since this third plugin’s filter is a priority 15, it runs after the 2nd plugin’s filter.
The 2nd plugin didn’t specify a priority, so we’ll assume the priority is 10. When $price
finally hits the new filter, the price is already set at 4.99. We just take that value, subtract 50 cents, and return it back.
The default for all priorities is 10, whether you are using an action or filter.
Here’s a diagram showing the process:
Set a high priority to change things before others, and a low priority to change things after others.
One thing to keep in mind is that filters return something. Whether it’s the original value or not is up to those subscribing to the filter.
Let’s move onto actions, where we can execute code at certain predefined places.
Let’s look at another code sample, this time executing an action:
<ul>
<?php
do_action( 'list_item' );
?>
</ul>
Code language: PHP (php)
It doesn’t look like much, but the code is allowing others to add items to its list.
There’s an unordered list is currently empty. That is, until another item subscribes to the action. In this case, the action is named list_item
.
Let’s add a action subscriber, which will output a list item.
add_action( 'list_item', 'my_plugin_2_add_list_item' );
function my_plugin_2_add_list_item() {
?>
<li>List Item One</li>
<?php
}
Code language: PHP (php)
We now have “hooked in” to the action, and the result is an unordered list with one item:
<ul>
<li>List Item One</li>
</ul>
Code language: HTML, XML (xml)
What if another plugin, at priority 15, decides to also add a list item?
add_action( 'list_item', 'my_plugin_3_add_list_item', 15 );
function my_plugin_3_add_list_item() {
?>
<li>List Item Two</li>
<?php
}
Code language: PHP (php)
You would end up with two list items:
<ul>
<li>List Item One</li>
<li>List Item Two</li>
</ul>
Code language: HTML, XML (xml)
Let’s look at a diagram of the process:
The first plugin loads, and down the road performs a do_action
, triggering the action. Two other plugins are hooked into (subscribed) to the action, and fire at different priorities.
To put it another way, actions are more like ripples in a pond. The initial action is tossing a rock in a pond. The ripples are all the actions that are based off of the impact.
Actions don’t typically return anything.
In this introduction to hooks, I presented two new concepts: actions and filters. Let’s do a few brain teasers before moving on to the next lesson.
<?php
$price = 23;
$price = apply_filters( 'product_price', $price );
echo $price;
Code language: PHP (php)
The answer is: 23
Since $price
is being set at 23
and there are no subscribers to the filter product_price
, the apply_filters
in this case is just acting as a flowthrough. As a result, the output is 23.
<?php
$price = 23;
$price = apply_filters( 'product_price', $price );
add_filter( 'product_price', 'my_plugin_new_price' );
function my_plugin_new_price( $price ) {
return 24;
}
echo $price;
Code language: PHP (php)
The answer is: 23
In this case, apply_filters
is running filter product_price
before the filter is subscribed to, so the price remains 23.
<?php
add_filter( 'product_price', 'my_plugin_new_price' );
function my_plugin_new_price( $price ) {
return $price + 2;
}
add_filter( 'product_price', 'my_plugin_2_new_price', 9 );
function my_plugin_2_new_price( $price ) {
return $price / 2;
}
$price = apply_filters( 'product_price', 20 );
echo $price;
Code language: PHP (php)
The answer is: 12
Two filters are subscribed to the filter product_price
. One is set at priority 9, and the other at priority 10. Remember that 10 is the default priority for hooks if the priority is not set.
When apply_filters
is called, it passes 20. The filter with priority 9 runs first, dividing the price by 2. This results in a return value of 10.
The filter with priority ten runs next, which adds 2 to the total, resulting in the return value of 12.
True or False?
The answer is: true
Priority one (1) is executed before something with priority twenty (20). Since it’s running first, it has a higher priority. The rule of thumb here is if you want to change something first, use a higher priority. If you want to change things after others, use a lower priority.
<?php
add_action( 'my_plugin_loaded', 'my_callback_plugin_loaded' );
function my_callback_plugin_loaded() {
echo 'Plugin loaded';
}
do_action( 'my_plugin_loaded' );
Code language: PHP (php)
The answer is: Plugin Loaded
An action subscribing to my_plugin_loaded
is created with a callback function my_callback_plugin_loaded
.
The do_action( 'my_plugin_loaded' )
triggers the action and any subscribers.
As a result, the callback function my_callback_plugin_loaded
is called and echos out “Plugin Loaded.”
<?php
add_action( 'my_plugin_loaded', 'my_callback_plugin_loaded' );
function my_callback_plugin_loaded() {
echo apply_filters( 'my_sanitization_filter', 'Hello World!' );
}
add_filter( 'my_sanitization_filter', '__return_empty_string' );
do_action( 'my_plugin_loaded' );
Code language: PHP (php)
True or false.
The answer is: True
An action subscribing to my_plugin_loaded
is created with a callback function my_callback_plugin_loaded
.
The do_action( 'my_plugin_loaded' )
triggers the action and any subscribers.
As a result, the callback function my_callback_plugin_loaded
is called. The apply_filters runs filter my_sanitization_filter
, which will run the callbacks of any subscribers and pass the results through.
Since a filter was added with a callback of WordPress function __return_empty_string
, an empty string is returned and the output is empty.